/[imapfilter]/imapfilter/file.c
ViewVC logotype

Diff of /imapfilter/file.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.56 by lefcha, Sun Jul 27 18:39:34 2003 UTC revision 1.57 by lefcha, Thu Jul 31 15:53:19 2003 UTC
# Line 1  Line 1 
1  #include <stdio.h>  #include <stdio.h>
2  #include <unistd.h>  #include <string.h>
3  #include <errno.h>  #include <errno.h>
4    #include <unistd.h>
5  #include <sys/types.h>  #include <sys/types.h>
 #include <regex.h>  
 #include <string.h>  
 #include <stdlib.h>  
 #include <ctype.h>  
 #include <limits.h>  
6  #include <sys/stat.h>  #include <sys/stat.h>
7  #include <fcntl.h>  #include <fcntl.h>
 #include <time.h>  
8    
9  #include "config.h"  #include "config.h"
10  #include "imapfilter.h"  #include "imapfilter.h"
11  #include "data.h"  #include "pathnames.h"
   
 #ifdef SSL_TLS  
 #include <openssl/ssl.h>  
 #include <openssl/x509.h>  
 #include <openssl/pem.h>  
 #endif  
12    
13    
 extern char logfile[PATH_MAX];  
 extern unsigned int options;  
 extern char charset[CHARSET_LEN];  
 extern unsigned int flags;  
 extern unsigned int interval;  
 extern long timeout;  
14  extern char *home;  extern char *home;
15    
 #ifdef ENCRYPTED_PASSWORDS  
 char *passphr = NULL;           /* Master password to access the passwords  
                                  * file. */  
   
 #endif  
   
   
 /*  
  * Find the path to configuration file, open it and call parse_config().  
  */  
 int  
 read_config(char *cfg)  
 {  
         int r;  
         FILE *fd;  
         char *c;  
   
         c = NULL;  
   
         if (cfg == NULL) {  
                 cfg = c = (char *)xmalloc(PATH_MAX * sizeof(char));  
                 snprintf(cfg, PATH_MAX, "%s/%s", home, ".imapfilterrc");  
         }  
 #ifdef DEBUG  
         fprintf(stderr, "debug: configuration file: '%s'\n", cfg);  
 #endif  
 #ifdef CHECK_PERMISSIONS  
         check_file_perms(cfg, S_IRUSR | S_IWUSR);  
 #endif  
         fd = fopen(cfg, "r");  
         if (fd == NULL)  
                 fatal(ERROR_FILE_OPEN, "opening config file %s; %s\n", cfg,  
                     strerror(errno));  
   
         if (c != NULL)  
                 xfree(c);  
   
         if ((r = parse_config(fd)))  
                 fatal(ERROR_CONFIG_PARSE,  
                     "parse error in config file at row %d\n", r);  
   
         fclose(fd);  
   
 #ifdef DEBUG  
         fprintf(stderr, "debug: options: %0#10x '%s'\n", options, charset);  
 #endif  
   
         return 0;  
 }  
   
   
 /*  
  * Parse configuration file.  
  */  
 int  
 parse_config(FILE * fd)  
 {  
         int i, r;  
         unsigned int row;  
         char line[LINE_MAX];  
         regex_t creg[13];  
         regmatch_t match[11];  
         const char *reg[13] = {  
                 "^([[:blank:]]*\n|#.*\n)$",  
   
                 "^[[:blank:]]*ACCOUNT[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]+"  
                 "(([[:graph:]]+):([[:graph:]]*)|([[:graph:]]+))@"  
                 "([[:alnum:].-]+)(:[[:digit:]]+)?[[:blank:]]*"  
                 "([[:blank:]]SSL2|[[:blank:]]SSL3|[[:blank:]]TLS1)?"  
                 "[[:blank:]]*\n$",  
   
                 "^[[:blank:]]*FOLDER[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]+"  
                 "([[:print:]]+)[[:blank:]]*\n$",  
   
                 "^[[:blank:]]*FILTER[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]*"  
                 "([[:blank:]]OR|[[:blank:]]AND)?[[:blank:]]*\n$",  
   
                 "^[[:blank:]]*ACTION[[:blank:]]+(DELETE|"  
                 "COPY[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)|"  
                 "MOVE[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)|"  
                 "RCOPY[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]+"  
                 "(\"[[:print:]]*\"|[[:graph:]]+)|"  
                 "RMOVE[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]+"  
                 "(\"[[:print:]]*\"|[[:graph:]]+)|"  
                 "FLAG[[:blank:]]+(REPLACE|ADD|REMOVE)[[:blank:]]+"  
                 "([[:alpha:],]+)|"  
                 "LIST)[[:blank:]]*([[:graph:]]*)[[:blank:]]*\n$",  
   
                 "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|"  
                 "AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*"  
                 "(ANSWERED|DELETED|DRAFT|FLAGGED|NEW|OLD|RECENT|SEEN|"  
                 "UNANSWERED|UNDELETED|UNDRAFT|UNFLAGGED|UNSEEN)[[:blank:]]*\n$",  
   
                 "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|"  
                 "AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*"  
                 "(BCC|BODY|CC|FROM|SUBJECT|TEXT|TO)[[:blank:]]+"  
                 "(\"[[:print:]]*\"|[[:graph:]]+)[[:blank:]]*\n$",  
   
                 "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|"  
                 "AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*"  
                 "(HEADER)[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)"  
                 "[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)[[:blank:]]*\n$",  
   
                 "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|"  
                 "AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*"  
                 "(LARGER|SMALLER|OLDER|NEWER)[[:blank:]]+([[:digit:]]+)"  
                 "[[:blank:]]*\n$",  
   
                 "^[[:blank:]]*JOB[[:blank:]]+([[:alnum:],_-]+)[[:blank:]]+"  
                 "([[:alnum:],_-]+)[[:blank:]]*\n$",  
   
                 "^[[:blank:]]*(SET[[:blank:]])?[[:blank:]]*(LOGFILE|CHARSET)"  
                 "[[:blank:]]*=[[:blank:]]*(\"[[:print:]]*\"|[[:graph:]]+)"  
                 "[[:blank:]]*\n$",  
   
                 "^[[:blank:]]*(SET[[:blank:]])?[[:blank:]]*(ERRORS|EXPUNGE|"  
                 "HEADERS|NAMESPACE|SUBSCRIBE)[[:blank:]]*=[[:blank:]]*"  
                 "(YES|NO)[[:blank:]]*\n$",  
   
                 "^[[:blank:]]*(SET[[:blank:]])?[[:blank:]]*(DAEMON|TIMEOUT)"  
                 "[[:blank:]]*=[[:blank:]]*([[:digit:]]+)\n$"  
         };  
   
         r = row = 0;  
   
         for (i = 0; i < 13; i++)  
                 regcomp(&creg[i], reg[i], REG_EXTENDED | REG_ICASE);  
   
         /* First process all the variables.  This is done because some  
          * variables' arguments are used before the other commands are  
          * processed. */  
         while (fgets(line, LINE_MAX - 1, fd))  
                 if (!regexec(&creg[10], line, 4, match, 0) ||  
                     !regexec(&creg[11], line, 4, match, 0) ||  
                     !regexec(&creg[12], line, 4, match, 0))  
                         set_options(line, match);  
   
         /* Then rewind and process everything else. */  
         fseek(fd, 0L, SEEK_SET);  
         while (fgets(line, LINE_MAX - 1, fd)) {  
                 row++;  
                 if (!regexec(&creg[0], line, 0, match, 0))  
                         continue;  
                 else if (!regexec(&creg[1], line, 9, match, 0))  
                         set_account(line, match);  
                 else if (!regexec(&creg[2], line, 3, match, 0))  
                         r = set_mboxgrp(line, match);  
                 else if (!regexec(&creg[3], line, 3, match, 0))  
                         r = set_filter(line, match);  
                 else if (!regexec(&creg[4], line, 11, match, 0))  
                         r = set_action(line, match);  
                 else if (!regexec(&creg[5], line, 5, match, 0))  
                         r = set_mask(line, match, MASK_MATCH_1);  
                 else if (!regexec(&creg[6], line, 6, match, 0))  
                         r = set_mask(line, match, MASK_MATCH_2);  
                 else if (!regexec(&creg[7], line, 7, match, 0))  
                         r = set_mask(line, match, MASK_MATCH_3);  
                 else if (!regexec(&creg[8], line, 6, match, 0))  
                         r = set_mask(line, match, MASK_MATCH_4);  
                 else if (!regexec(&creg[9], line, 3, match, 0))  
                         r = set_job(line, match);  
                 /* Skip variable processing. */  
                 else if (!regexec(&creg[10], line, 4, match, 0) ||  
                             !regexec(&creg[11], line, 4, match, 0) ||  
                     !regexec(&creg[12], line, 4, match, 0));  
                 else  
                         return row;  
   
                 if (r == ERROR_CONFIG_PARSE)  
                         return row;  
         }  
   
         for (i = 0; i < 13; i++)  
                 regfree(&creg[i]);  
   
         destroy_unneeded();  
   
         return 0;  
 }  
   
   
 /*  
  * Signal SIGHUP received, destroy all data structures and reread the  
  * configuration file.  
  */  
 void  
 reread_config(char *cfg)  
 {  
         destroy_all();  
         read_config(cfg);  
         read_passwords();  
   
         flags &= ~(FLAG_SIGHUP_RECEIVED);  
 }  
   
   
 /*  
  * Set other options found in config file.  
  */  
 void  
 set_options(char *line, regmatch_t * m)  
 {  
         if (!strncasecmp(line + m[2].rm_so, "logfile", 7)) {  
                 if (*logfile == '\0') {  
                         if (*(line + m[3].rm_so) == '"' &&  
                             *(line + m[3].rm_eo - 1) == '"')  
                                 strncat(logfile, line + m[3].rm_so + 1,  
                                     min((m[3].rm_eo - m[3].rm_so - 2),  
                                         PATH_MAX - 1));  
                         else  
                                 strncat(logfile, line + m[3].rm_so,  
                                     min((m[3].rm_eo - m[3].rm_so),  
                                         PATH_MAX - 1));  
                 }  
         } else if (!strncasecmp(line + m[2].rm_so, "charset", 7)) {  
                 if (*(line + m[3].rm_so) == '"' &&  
                     *(line + m[3].rm_eo - 1) == '"')  
                         strncat(charset, line + m[3].rm_so + 1,  
                             min((m[3].rm_eo - m[3].rm_so - 2),  
                                 CHARSET_LEN - 1));  
                 else  
                         strncat(charset, line + m[3].rm_so,  
                             min((m[3].rm_eo - m[3].rm_so), CHARSET_LEN - 1));  
         } else if (!strncasecmp(line + m[2].rm_so, "errors", 6)) {  
                 if (!strncasecmp(line + m[3].rm_so, "yes", 3))  
                         options |= OPTION_ERRORS;  
                 else  
                         options &= ~(OPTION_ERRORS);  
         } else if (!strncasecmp(line + m[2].rm_so, "expunge", 7)) {  
                 if (!strncasecmp(line + m[3].rm_so, "yes", 3))  
                         options |= OPTION_EXPUNGE;  
                 else  
                         options &= ~(OPTION_EXPUNGE);  
         } else if (!strncasecmp(line + m[2].rm_so, "header", 6)) {  
                 if (!strncasecmp(line + m[3].rm_so, "yes", 3))  
                         options |= OPTION_HEADERS;  
                 else  
                         options &= ~(OPTION_HEADERS);  
         } else if (!strncasecmp(line + m[2].rm_so, "namespace", 9)) {  
                 if (!strncasecmp(line + m[3].rm_so, "yes", 3))  
                         options |= OPTION_NAMESPACE;  
                 else  
                         options &= ~(OPTION_NAMESPACE);  
         } else if (!strncasecmp(line + m[2].rm_so, "subscribe", 9)) {  
                 if (!strncasecmp(line + m[3].rm_so, "yes", 3))  
                         options |= OPTION_SUBSCRIBE;  
                 else  
                         options &= ~(OPTION_SUBSCRIBE);  
         } else if (!strncasecmp(line + m[2].rm_so, "timeout", 7)) {  
                 errno = 0;  
                 timeout = strtol(line + m[3].rm_so, NULL, 10);  
                 if (errno)  
                         timeout = 0;  
         } else if (!strncasecmp(line + m[2].rm_so, "daemon", 6) &&  
             !(options & OPTION_DAEMON_MODE)) {  
                 options |= OPTION_DAEMON_MODE;  
                 errno = 0;  
                 interval = strtoul(line + m[3].rm_so, NULL, 10);  
                 if (errno)  
                         interval = 0;  
         }  
 }  
   
   
 #ifdef ENCRYPTED_PASSWORDS  
 /*  
  * Open password file and call parse_passwords().  
  */  
 int  
 read_passwords(void)  
 {  
         FILE *fd;  
         char pwfile[PATH_MAX];  
   
         if (!(flags & FLAG_BLANK_PASSWORD))  
                 return ERROR_CONFIG_PARSE;  
   
         if (!passphr) {  
                 passphr = (char *)smalloc(PASSPHRASE_LEN);  
                 *passphr = '\0';  
         }  
         snprintf(pwfile, PATH_MAX, "%s/%s", home, ".imapfilter/passwords");  
 #ifdef DEBUG  
         fprintf(stderr, "debug: passwords file: '%s'\n", pwfile);  
 #endif  
   
         if (!exists_file(pwfile))  
                 return ERROR_FILE_OPEN;  
   
 #ifdef CHECK_PERMISSIONS  
         check_file_perms(pwfile, S_IRUSR | S_IWUSR);  
 #endif  
   
         fd = fopen(pwfile, "r");  
         if (fd == NULL)  
                 fatal(ERROR_FILE_OPEN, "opening passwords file %s; %s\n",  
                     pwfile, strerror(errno));  
   
         parse_passwords(fd);  
   
         fclose(fd);  
   
         return 0;  
 }  
   
   
 /*  
  *  Parse unencrypted password file.  
  */  
 int  
 parse_passwords(FILE * fd)  
 {  
         int t;  
         char *pe;  
         char user[USERNAME_LEN], serv[SERVER_LEN];  
         unsigned char *buf;  
         char *c, *cp, *line;  
         regex_t creg;  
         regmatch_t match[4];  
         const char *reg;  
   
         t = 3;  
         pe = NULL;  
         reg = "([[:alnum:].-]+) ([[:graph:]]+) ([[:graph:]]+)";  
   
         if (!(flags & FLAG_DAEMON_MODE)) {  
                 do {  
                         fseek(fd, 0L, SEEK_SET);  
                         printf("Enter master passphrase: ");  
                         get_password(passphr, PASSPHRASE_LEN);  
                 } while (decrypt_passwords(&buf, fd) && --t != 0);  
   
                 if (!t)  
                         return ERROR_PASSPHRASE;  
         } else if (decrypt_passwords(&buf, fd))  
                 fatal(ERROR_DECRYPT,  
                     "failed decrypting passwords in daemon mode\n");  
   
         c = cp = sstrdup(buf);  
   
         regcomp(&creg, reg, REG_EXTENDED | REG_ICASE);  
   
         line = strtok_r(c, "\n", &c);  
         while (line != NULL && !regexec(&creg, line, 4, match, 0)) {  
                 user[0] = serv[0] = '\0';  
   
                 strncat(serv, line + match[1].rm_so,  
                     min(match[1].rm_eo - match[1].rm_so, SERVER_LEN - 1));  
                 strncat(user, line + match[2].rm_so,  
                     min(match[2].rm_eo - match[2].rm_so, USERNAME_LEN - 1));  
   
                 if ((pe = (char *)find_password(user, serv)))  
                         strncat(pe, line + match[3].rm_so,  
                             min(match[3].rm_eo - match[3].rm_so,  
                                 PASSWORD_LEN - 1));  
   
                 line = strtok_r(NULL, "\n", &c);  
         }  
   
         regfree(&creg);  
         sfree(cp);  
         sfree(buf);  
   
         return 0;  
 }  
   
16    
17  /*  /*
18   * Store encrypted passwords to file.   * Create imapfilter's home directory.
  */  
 int  
 store_passwords(account_t ** accts)  
 {  
         char pwfile[PATH_MAX];  
         FILE *fd;  
   
         snprintf(pwfile, PATH_MAX, "%s/%s", home, ".imapfilter/passwords");  
   
         create_file(pwfile, S_IRUSR | S_IWUSR);  
   
         fd = fopen(pwfile, "w");  
   
         if (fd == NULL)  
                 fatal(ERROR_FILE_OPEN, "opening passwords file %s; %s\n",  
                     pwfile, strerror(errno));  
   
         encrypt_passwords(fd, accts);  
   
         fclose(fd);  
   
         return 0;  
 }  
   
 #endif                          /* ENCRYPTED_PASSWORDS */  
   
   
 /*  
  * Create $HOME/.imapfilter directory.  
19   */   */
20  int  int
21  create_homedir(void)  create_homedir(void)
22  {  {
         char *hdn;  
   
         hdn = ".imapfilter";  
   
23          if (home != NULL)          if (home != NULL)
24                  if (chdir(home))                  if (chdir(home))
25                          error("could not change directory; %s\n",                          error("could not change directory; %s\n",
26                              strerror(errno));                              strerror(errno));
27    
28          if (!exists_dir(hdn)) {          if (!exists_dir(PATHNAME_HOME_DIR)) {
29                  if (mkdir(hdn, S_IRUSR | S_IWUSR | S_IXUSR))                  if (mkdir(PATHNAME_HOME_DIR, S_IRUSR | S_IWUSR | S_IXUSR))
30                          error("could not create directory %s; %s\n", hdn,                          error("could not create directory %s; %s\n",
31                              strerror(errno));                              PATHNAME_HOME_DIR, strerror(errno));
32          }          }
33  #ifdef CHECK_PERMISSIONS  #ifdef CHECK_PERMISSIONS
34          else {          else {
35                  check_dir_perms(hdn, S_IRUSR | S_IWUSR | S_IXUSR);                  check_dir_perms(PATHNAME_HOME_DIR, S_IRUSR | S_IWUSR | S_IXUSR);
36          }          }
37  #endif  #endif
38    
# Line 572  check_dir_perms(char *dname, mode_t mode Line 156  check_dir_perms(char *dname, mode_t mode
156          }          }
157          return 0;          return 0;
158  }  }
   
159  #endif                          /* CHECK_PERMISSIONS */  #endif                          /* CHECK_PERMISSIONS */
   
   
 #ifdef SSL_TLS  
 /*  
  * Get SSL/TLS certificate check it, maybe ask user about it and act  
  * accordingly.  
  */  
 int  
 imf_ssl_cert(conn_t * conn)  
 {  
         X509 *cert;  
         unsigned char md[EVP_MAX_MD_SIZE];  
         unsigned int mdlen;  
   
         mdlen = 0;  
   
         if (!(cert = SSL_get_peer_certificate(conn->ssl)))  
                 return ERROR_SSL;  
   
         if (!(X509_digest(cert, EVP_md5(), md, &mdlen)))  
                 return ERROR_SSL;  
   
         switch (imf_ssl_check_cert(cert, md, &mdlen)) {  
         case SSL_CERT_NONEXISTENT:  
                 imf_ssl_print_cert(cert, md, &mdlen);  
                 if (flags & FLAG_DAEMON_MODE ||  
                     imf_ssl_new_cert(cert) == SSL_CERT_ACTION_REJECT)  
                         goto abort;  
                 break;  
         case SSL_CERT_MISMATCH:  
                 imf_ssl_print_cert(cert, md, &mdlen);  
                 if (flags & FLAG_DAEMON_MODE ||  
                     imf_ssl_cert_mismatch() == SSL_CERT_ACTION_ABORT)  
                         goto abort;  
                 break;  
         case SSL_CERT_OK:  
                 if (options & OPTION_DETAILS_VERBOSE)  
                         imf_ssl_print_cert(cert, md, &mdlen);  
         }  
   
         X509_free(cert);  
         return 0;  
   
 abort:  
         X509_free(cert);  
         return ERROR_SSL;  
 }  
   
   
 /*  
  * Check if the SSL/TLS certificate exists in the certificates file.  
  */  
 int  
 imf_ssl_check_cert(X509 * pcert, unsigned char *pmd, unsigned int *pmdlen)  
 {  
         int r;  
         FILE *fd;  
         X509 *cert;  
         unsigned char md[EVP_MAX_MD_SIZE];  
         unsigned int mdlen;  
         char *cfn;  
   
         r = SSL_CERT_NONEXISTENT;  
         cert = NULL;  
         cfn = ".imapfilter/certificates";  
   
         if (!exists_file(cfn))  
                 return SSL_CERT_NONEXISTENT;  
   
         fd = fopen(cfn, "r");  
         if (fd == NULL)  
                 return ERROR_FILE_OPEN;  
   
         while ((cert = PEM_read_X509(fd, &cert, NULL, NULL)) != NULL) {  
                 if (X509_subject_name_cmp(cert, pcert) != 0 ||  
                     X509_issuer_name_cmp(cert, pcert) != 0)  
                         continue;  
   
                 if (!X509_digest(cert, EVP_md5(), md, &mdlen) ||  
                     *pmdlen != mdlen)  
                         continue;  
   
                 if (memcmp(pmd, md, mdlen) != 0) {  
                         r = SSL_CERT_MISMATCH;  
                         break;  
                 }  
                 r = SSL_CERT_OK;  
                 break;  
         }  
   
         fclose(fd);  
         X509_free(cert);  
   
         return r;  
 }  
   
   
 /*  
  * Print information about the SSL/TLS certificate.  
  */  
 void  
 imf_ssl_print_cert(X509 * cert, unsigned char *md, unsigned int *mdlen)  
 {  
         unsigned int i;  
         char *c;  
   
         c = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);  
         printf("Server certificate subject: %s\n", c);  
         xfree(c);  
   
         c = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);  
         printf("Server certificate issuer: %s\n", c);  
         xfree(c);  
   
         printf("Server key fingerprint: ");  
         for (i = 0; i < *mdlen; i++)  
                 printf(i != *mdlen - 1 ? "%02X:" : "%02X\n", md[i]);  
 }  
   
   
 /*  
  * Ask the user to reject/accept the SSL/TLS certificate.  
  */  
 int  
 imf_ssl_new_cert(X509 * cert)  
 {  
         FILE *fd;  
         char c, *cfn, buf[LINE_MAX];  
   
         do {  
                 printf("(R)eject, accept (t)emporarily or "  
                     "accept (p)ermanently? ");  
                 fgets(buf, LINE_MAX, stdin);  
                 c = tolower(*buf);  
         } while (c != 'r' && c != 't' && c != 'p');  
   
         if (c == 'r')  
                 return SSL_CERT_ACTION_REJECT;  
         else if (c == 't')  
                 return SSL_CERT_ACTION_ACCEPT;  
   
         cfn = ".imapfilter/certificates";  
   
         create_file(cfn, S_IRUSR | S_IWUSR);  
   
         fd = fopen(cfn, "a");  
         if (fd == NULL)  
                 return SSL_CERT_ACTION_REJECT;  
   
         PEM_write_X509(fd, cert);  
   
         fclose(fd);  
   
         return SSL_CERT_ACTION_ACCEPT;  
 }  
   
   
 /*  
  * Ask user to proceed, while a fingerprint mismatch in the SSL/TLS  
  * certificate was found.  
  */  
 int  
 imf_ssl_cert_mismatch(void)  
 {  
         char c, buf[LINE_MAX];  
   
         do {  
                 printf("WARNING: SSL/TLS certificate fingerprint mismatch.\n"  
                     "Proceed with the connection (y/n)? ");  
                 fgets(buf, LINE_MAX, stdin);  
                 c = tolower(*buf);  
         } while (c != 'y' && c != 'n');  
   
         if (c == 'y')  
                 return SSL_CERT_ACTION_CONTINUE;  
         else  
                 return SSL_CERT_ACTION_ABORT;  
 }  
   
 #endif                          /* SSL_TLS */  

Legend:
Removed from v.1.56  
changed lines
  Added in v.1.57

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26