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

Contents of /imapfilter/file.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.52 - (show annotations)
Mon May 19 22:38:15 2003 UTC (20 years, 11 months ago) by lefcha
Branch: MAIN
Changes since 1.51: +31 -14 lines
File MIME type: text/plain
Added support for config file rereading when SIGHUP received.

1 #include <stdio.h>
2 #include <unistd.h>
3 #include <errno.h>
4 #include <sys/types.h>
5 #include <regex.h>
6 #include <string.h>
7 #include <stdlib.h>
8 #include <ctype.h>
9 #include <limits.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <time.h>
13
14 #include "config.h"
15 #include "imapfilter.h"
16 #include "data.h"
17
18 #ifdef SSL_TLS
19 #include <openssl/ssl.h>
20 #include <openssl/x509.h>
21 #include <openssl/pem.h>
22 #endif
23
24
25 extern char logfile[PATH_MAX];
26 extern unsigned int options;
27 extern char charset[CHARSET_LEN];
28 extern unsigned int flags;
29 extern unsigned int interval;
30 extern long timeout;
31 extern char *home;
32
33 #ifdef ENCRYPTED_PASSWORDS
34 char *passphr = NULL; /* Master password to access the passwords
35 * file. */
36
37 #endif
38
39
40 /*
41 * Find the path to configuration file, open it and call parse_config().
42 */
43 int
44 read_config(char *cfg)
45 {
46 int r;
47 FILE *fd;
48 char *c;
49
50 c = NULL;
51
52 if (cfg == NULL) {
53 cfg = c = (char *)xmalloc(PATH_MAX * sizeof(char));
54 snprintf(cfg, PATH_MAX, "%s/%s", home, ".imapfilterrc");
55 }
56 #ifdef DEBUG
57 fprintf(stderr, "debug: configuration file: '%s'\n", cfg);
58 #endif
59 #ifdef CHECK_PERMISSIONS
60 check_file_perms(cfg, S_IRUSR | S_IWUSR);
61 #endif
62 fd = fopen(cfg, "r");
63 if (fd == NULL)
64 fatal(ERROR_FILE_OPEN, "opening config file %s; %s\n", cfg,
65 strerror(errno));
66
67 if (c != NULL)
68 xfree(c);
69
70 if ((r = parse_config(fd)))
71 fatal(ERROR_CONFIG_PARSE,
72 "parse error in config file at row %d\n", r);
73
74 fclose(fd);
75
76 #ifdef DEBUG
77 fprintf(stderr, "debug: options: %0#10x '%s'\n", options, charset);
78 #endif
79
80 return 0;
81 }
82
83
84 /*
85 * Parse configuration file.
86 */
87 int
88 parse_config(FILE * fd)
89 {
90 int i, r;
91 unsigned int row;
92 char line[LINE_MAX];
93 regex_t creg[13];
94 regmatch_t match[11];
95 const char *reg[13] = {
96 "^([[:blank:]]*\n|#.*\n)$",
97
98 "^[[:blank:]]*ACCOUNT[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]+"
99 "(([[:graph:]]+):([[:graph:]]*)|([[:graph:]]+))@"
100 "([[:alnum:].-]+)(:[[:digit:]]+)?[[:blank:]]*"
101 "([[:blank:]]SSL|[[:blank:]]SSL2|[[:blank:]]SSL3|"
102 "[[:blank:]]TLS1)?[[:blank:]]*\n$",
103
104 "^[[:blank:]]*FOLDER[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]+"
105 "([[:print:]]+)[[:blank:]]*\n$",
106
107 "^[[:blank:]]*FILTER[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]*"
108 "([[:blank:]]OR|[[:blank:]]AND)?[[:blank:]]*\n$",
109
110 "^[[:blank:]]*ACTION[[:blank:]]+(DELETE|"
111 "COPY[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)|"
112 "MOVE[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)|"
113 "RCOPY[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]+"
114 "(\"[[:print:]]*\"|[[:graph:]]+)|"
115 "RMOVE[[:blank:]]+([[:alnum:]_-]+)[[:blank:]]+"
116 "(\"[[:print:]]*\"|[[:graph:]]+)|"
117 "FLAG[[:blank:]]+(REPLACE|ADD|REMOVE)[[:blank:]]+"
118 "([[:alpha:],]+)|"
119 "LIST)[[:blank:]]*([[:graph:]]*)[[:blank:]]*\n$",
120
121 "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|"
122 "AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*"
123 "(ANSWERED|DELETED|DRAFT|FLAGGED|NEW|OLD|RECENT|SEEN|"
124 "UNANSWERED|UNDELETED|UNDRAFT|UNFLAGGED|UNSEEN)[[:blank:]]*\n$",
125
126 "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|"
127 "AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*"
128 "(BCC|BODY|CC|FROM|SUBJECT|TEXT|TO)[[:blank:]]+"
129 "(\"[[:print:]]*\"|[[:graph:]]+)[[:blank:]]*\n$",
130
131 "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|"
132 "AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*"
133 "(HEADER)[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)"
134 "[[:blank:]]+(\"[[:print:]]*\"|[[:graph:]]+)[[:blank:]]*\n$",
135
136 "^[[:blank:]]*(MASK[[:blank:]])?[[:blank:]]*(OR[[:blank:]]|"
137 "AND[[:blank:]])?[[:blank:]]*(NOT[[:blank:]])?[[:blank:]]*"
138 "(LARGER|SMALLER|OLDER|NEWER)[[:blank:]]+([[:digit:]]+)"
139 "[[:blank:]]*\n$",
140
141 "^[[:blank:]]*JOB[[:blank:]]+([[:alnum:],_-]+)[[:blank:]]+"
142 "([[:alnum:],_-]+)[[:blank:]]*\n$",
143
144 "^[[:blank:]]*(SET[[:blank:]])?[[:blank:]]*(LOGFILE|CHARSET)"
145 "[[:blank:]]*=[[:blank:]]*(\"[[:print:]]*\"|[[:graph:]]+)"
146 "[[:blank:]]*\n$",
147
148 "^[[:blank:]]*(SET[[:blank:]])?[[:blank:]]*(ERRORS|EXPUNGE|"
149 "HEADERS|NAMESPACE|SUBSCRIBE|WARNING)[[:blank:]]*=[[:blank:]]*"
150 "(YES|NO)[[:blank:]]*\n$",
151
152 "^[[:blank:]]*(SET[[:blank:]])?[[:blank:]]*(DAEMON|TIMEOUT)"
153 "[[:blank:]]*=[[:blank:]]*([[:digit:]]+)\n$"
154 };
155
156 r = row = 0;
157
158 for (i = 0; i < 13; i++)
159 regcomp(&creg[i], reg[i], REG_EXTENDED | REG_ICASE);
160
161 /* First process all the variables. This is done because some
162 * variables' arguments are used before the other commands are
163 * processed. */
164 while (fgets(line, LINE_MAX - 1, fd))
165 if (!regexec(&creg[10], line, 4, match, 0) ||
166 !regexec(&creg[11], line, 4, match, 0) ||
167 !regexec(&creg[12], line, 4, match, 0))
168 set_options(line, match);
169
170 /* Then rewind and process everything else. */
171 fseek(fd, 0L, SEEK_SET);
172 while (fgets(line, LINE_MAX - 1, fd)) {
173 row++;
174 if (!regexec(&creg[0], line, 0, match, 0))
175 continue;
176 else if (!regexec(&creg[1], line, 9, match, 0))
177 set_account(line, match);
178 else if (!regexec(&creg[2], line, 3, match, 0))
179 r = set_mboxgrp(line, match);
180 else if (!regexec(&creg[3], line, 3, match, 0))
181 r = set_filter(line, match);
182 else if (!regexec(&creg[4], line, 11, match, 0))
183 r = set_action(line, match);
184 else if (!regexec(&creg[5], line, 5, match, 0))
185 r = set_mask(line, match, MASK_MATCH_1);
186 else if (!regexec(&creg[6], line, 6, match, 0))
187 r = set_mask(line, match, MASK_MATCH_2);
188 else if (!regexec(&creg[7], line, 7, match, 0))
189 r = set_mask(line, match, MASK_MATCH_3);
190 else if (!regexec(&creg[8], line, 6, match, 0))
191 r = set_mask(line, match, MASK_MATCH_4);
192 else if (!regexec(&creg[9], line, 3, match, 0))
193 r = set_job(line, match);
194 /* Skip variable processing. */
195 else if (!regexec(&creg[10], line, 4, match, 0) ||
196 !regexec(&creg[11], line, 4, match, 0) ||
197 !regexec(&creg[12], line, 4, match, 0));
198 else
199 return row;
200
201 if (r == ERROR_CONFIG_PARSE)
202 return row;
203 }
204
205 for (i = 0; i < 13; i++)
206 regfree(&creg[i]);
207
208 destroy_unneeded();
209
210 return 0;
211 }
212
213
214 /*
215 * Signal SIGHUP received, destroy all data structures and reread the
216 * configuration file.
217 */
218 void
219 reread_config(char *cfg)
220 {
221 destroy_all();
222 read_config(cfg);
223 read_passwords();
224
225 flags &= ~(FLAG_SIGHUP_RECEIVED);
226 }
227
228
229 /*
230 * Set other options found in config file.
231 */
232 void
233 set_options(char *line, regmatch_t * m)
234 {
235 if (!strncasecmp(line + m[2].rm_so, "logfile", 7)) {
236 if (*logfile == '\0') {
237 if (*(line + m[3].rm_so) == '"' &&
238 *(line + m[3].rm_eo - 1) == '"')
239 strncat(logfile, line + m[3].rm_so + 1,
240 min((m[3].rm_eo - m[3].rm_so - 2),
241 PATH_MAX - 1));
242 else
243 strncat(logfile, line + m[3].rm_so,
244 min((m[3].rm_eo - m[3].rm_so),
245 PATH_MAX - 1));
246 }
247 } else if (!strncasecmp(line + m[2].rm_so, "charset", 7)) {
248 if (*(line + m[3].rm_so) == '"' &&
249 *(line + m[3].rm_eo - 1) == '"')
250 strncat(charset, line + m[3].rm_so + 1,
251 min((m[3].rm_eo - m[3].rm_so - 2),
252 CHARSET_LEN - 1));
253 else
254 strncat(charset, line + m[3].rm_so,
255 min((m[3].rm_eo - m[3].rm_so), CHARSET_LEN - 1));
256 } else if (!strncasecmp(line + m[2].rm_so, "errors", 6)) {
257 if (!strncasecmp(line + m[3].rm_so, "yes", 3))
258 options |= OPTION_ERRORS;
259 else
260 options &= ~(OPTION_ERRORS);
261 } else if (!strncasecmp(line + m[2].rm_so, "expunge", 7)) {
262 if (!strncasecmp(line + m[3].rm_so, "yes", 3))
263 options |= OPTION_EXPUNGE;
264 else
265 options &= ~(OPTION_EXPUNGE);
266 } else if (!strncasecmp(line + m[2].rm_so, "header", 6)) {
267 if (!strncasecmp(line + m[3].rm_so, "yes", 3))
268 options |= OPTION_HEADERS;
269 else
270 options &= ~(OPTION_HEADERS);
271 } else if (!strncasecmp(line + m[2].rm_so, "namespace", 9)) {
272 if (!strncasecmp(line + m[3].rm_so, "yes", 3))
273 options |= OPTION_NAMESPACE;
274 else
275 options &= ~(OPTION_NAMESPACE);
276 } else if (!strncasecmp(line + m[2].rm_so, "subscribe", 9)) {
277 if (!strncasecmp(line + m[3].rm_so, "yes", 3))
278 options |= OPTION_SUBSCRIBE;
279 else
280 options &= ~(OPTION_SUBSCRIBE);
281 } else if (!strncasecmp(line + m[2].rm_so, "warning", 7)) {
282 if (!strncasecmp(line + m[3].rm_so, "yes", 3))
283 options |= OPTION_WARNING;
284 else
285 options &= ~(OPTION_WARNING);
286 } else if (!strncasecmp(line + m[2].rm_so, "timeout", 7)) {
287 errno = 0;
288 timeout = strtol(line + m[3].rm_so, NULL, 10);
289 if (errno)
290 timeout = 0;
291 } else if (!strncasecmp(line + m[2].rm_so, "daemon", 6) &&
292 !(options & OPTION_DAEMON_MODE)) {
293 options |= OPTION_DAEMON_MODE;
294 errno = 0;
295 interval = strtoul(line + m[3].rm_so, NULL, 10);
296 if (errno)
297 interval = 0;
298 }
299 }
300
301
302 #ifdef ENCRYPTED_PASSWORDS
303 /*
304 * Open password file and call parse_passwords().
305 */
306 int
307 read_passwords(void)
308 {
309 FILE *fd;
310 char pwfile[PATH_MAX];
311
312 if (!(flags & FLAG_BLANK_PASSWORD))
313 return ERROR_CONFIG_PARSE;
314
315 snprintf(pwfile, PATH_MAX, "%s/%s", home, ".imapfilter/passwords");
316 #ifdef DEBUG
317 fprintf(stderr, "debug: passwords file: '%s'\n", pwfile);
318 #endif
319
320 if (!exists_file(pwfile))
321 return ERROR_FILE_OPEN;
322
323 #ifdef CHECK_PERMISSIONS
324 check_file_perms(pwfile, S_IRUSR | S_IWUSR);
325 #endif
326
327 fd = fopen(pwfile, "r");
328 if (fd == NULL)
329 fatal(ERROR_FILE_OPEN, "opening passwords file %s; %s\n",
330 pwfile, strerror(errno));
331
332 parse_passwords(fd);
333
334 fclose(fd);
335
336 return 0;
337 }
338
339
340 /*
341 * Parse unencrypted password file.
342 */
343 int
344 parse_passwords(FILE * fd)
345 {
346 int t;
347 char *pe;
348 char user[USERNAME_LEN], serv[SERVER_LEN];
349 unsigned char *buf;
350 char *c, *cp, *line;
351 regex_t creg;
352 regmatch_t match[4];
353 const char *reg;
354 int r;
355
356 t = 3;
357 pe = NULL;
358 reg = "([[:alnum:].-]+) ([[:graph:]]+) ([[:graph:]]+)";
359
360 if (!passphr) {
361 passphr = (char *)smalloc(PASSPHRASE_LEN);
362 *passphr = '\0';
363
364 do {
365 fseek(fd, 0L, SEEK_SET);
366 printf("Enter master passphrase: ");
367 get_password(passphr, PASSPHRASE_LEN);
368 } while ((r = decrypt_passwords(&buf, fd)) && --t != 0);
369
370 if (!t)
371 return ERROR_PASSPHRASE;
372 } else
373 decrypt_passwords(&buf, fd);
374
375 c = cp = sstrdup(buf);
376
377 regcomp(&creg, reg, REG_EXTENDED | REG_ICASE);
378
379 line = strtok_r(c, "\n", &c);
380 while (line != NULL && !regexec(&creg, line, 4, match, 0)) {
381 user[0] = serv[0] = '\0';
382
383 strncat(serv, line + match[1].rm_so,
384 min(match[1].rm_eo - match[1].rm_so, SERVER_LEN - 1));
385 strncat(user, line + match[2].rm_so,
386 min(match[2].rm_eo - match[2].rm_so, USERNAME_LEN - 1));
387
388 if ((pe = (char *)find_password(user, serv)))
389 strncat(pe, line + match[3].rm_so,
390 min(match[3].rm_eo - match[3].rm_so,
391 PASSWORD_LEN - 1));
392
393 line = strtok_r(NULL, "\n", &c);
394 }
395
396 regfree(&creg);
397 sfree(cp);
398 sfree(buf);
399
400 return 0;
401 }
402
403
404 /*
405 * Store encrypted passwords to file.
406 */
407 int
408 store_passwords(account_t * accts[])
409 {
410 char pwfile[PATH_MAX];
411 FILE *fd;
412
413 snprintf(pwfile, PATH_MAX, "%s/%s", home, ".imapfilter/passwords");
414
415 create_file(pwfile, S_IRUSR | S_IWUSR);
416
417 fd = fopen(pwfile, "w");
418
419 if (fd == NULL)
420 fatal(ERROR_FILE_OPEN, "opening passwords file %s; %s\n",
421 pwfile, strerror(errno));
422
423 encrypt_passwords(fd, accts);
424
425 fclose(fd);
426
427 return 0;
428 }
429
430 #endif /* ENCRYPTED_PASSWORDS */
431
432
433 /*
434 * Create $HOME/.imapfilter directory.
435 */
436 int
437 create_homedir(void)
438 {
439 char *hdn;
440
441 hdn = ".imapfilter";
442
443 if (home != NULL)
444 if (chdir(home))
445 error("could not change directory; %s\n",
446 strerror(errno));
447
448 if (!exists_dir(hdn)) {
449 if (mkdir(hdn, S_IRUSR | S_IWUSR | S_IXUSR))
450 error("could not create directory %s; %s\n", hdn,
451 strerror(errno));
452 }
453 #ifdef CHECK_PERMISSIONS
454 else {
455 check_dir_perms(hdn, S_IRUSR | S_IWUSR | S_IXUSR);
456 }
457 #endif
458
459 return 0;
460 }
461
462
463 /*
464 * Check if a file exists.
465 */
466 int
467 exists_file(char *fname)
468 {
469 struct stat fs;
470
471 if (access(fname, F_OK))
472 return 0;
473
474 stat(fname, &fs);
475 if (!S_ISREG(fs.st_mode)) {
476 error("file %s not a regular file\n", fname);
477 return ERROR_FILE_OPEN;
478 }
479 return 1;
480 }
481
482
483 /*
484 * Check if a directory exists.
485 */
486 int
487 exists_dir(char *dname)
488 {
489 struct stat ds;
490
491 if (access(dname, F_OK))
492 return 0;
493
494 stat(dname, &ds);
495 if (!S_ISDIR(ds.st_mode)) {
496 error("file %s not a directory\n", dname);
497 return ERROR_FILE_OPEN;
498 }
499 return 1;
500 }
501
502
503 /*
504 * Create a file with the specified permissions.
505 */
506 int
507 create_file(char *fname, mode_t mode)
508 {
509 int fd;
510
511 fd = 0;
512
513 if (!exists_file(fname)) {
514 fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, mode);
515 if (fd == -1) {
516 error("could not create file %s; %s\n", fname,
517 strerror(errno));
518 return ERROR_FILE_OPEN;
519 }
520 close(fd);
521 }
522 return 0;
523 }
524
525
526 #ifdef CHECK_PERMISSIONS
527 /*
528 * Check the permissions of a file.
529 */
530 int
531 check_file_perms(char *fname, mode_t mode)
532 {
533 struct stat fs;
534
535 if (stat(fname, &fs)) {
536 error("getting file %s status; %s\n", fname,
537 strerror(errno));
538 return ERROR_TRIVIAL;
539 }
540 if (!S_ISREG(fs.st_mode)) {
541 error("file %s not a regular file\n", fname);
542 return ERROR_TRIVIAL;
543 }
544 if ((fs.st_mode & 00777) != mode) {
545 error("warning: improper file %s permissions\n", fname);
546 error("warning: file's mode should be %o not %o\n", mode,
547 fs.st_mode & 00777);
548 return ERROR_TRIVIAL;
549 }
550 return 0;
551 }
552
553
554 /*
555 * Check the permissions of a directory.
556 */
557 int
558 check_dir_perms(char *dname, mode_t mode)
559 {
560 struct stat ds;
561
562 if (stat(dname, &ds)) {
563 error("getting file %s status; %s\n", dname,
564 strerror(errno));
565 return ERROR_TRIVIAL;
566 }
567 if (!S_ISDIR(ds.st_mode)) {
568 error("file %s not a directory\n", dname);
569 return ERROR_TRIVIAL;
570 }
571 if ((ds.st_mode & 00777) != mode) {
572 error("warning: improper dir %s permissions\n", dname);
573 error("warning: dir's mode should be %o not %o\n", mode,
574 ds.st_mode & 00777);
575 return ERROR_TRIVIAL;
576 }
577 return 0;
578 }
579
580 #endif /* CHECK_PERMISSIONS */
581
582
583 #ifdef SSL_TLS
584 /*
585 * Get SSL/TLS certificate check it, maybe ask user about it and act
586 * accordingly.
587 */
588 int
589 imf_ssl_cert(SSL * ssl)
590 {
591 X509 *cert;
592 unsigned char md[EVP_MAX_MD_SIZE];
593 unsigned int mdlen;
594
595 mdlen = 0;
596
597 if (!(cert = SSL_get_peer_certificate(ssl)))
598 return ERROR_SSL;
599
600 if (!(X509_digest(cert, EVP_md5(), md, &mdlen)))
601 return ERROR_SSL;
602
603 switch (imf_ssl_check_cert(cert, md, &mdlen)) {
604 case SSL_CERT_NONEXISTENT:
605 imf_ssl_print_cert(cert, md, &mdlen);
606 if (flags & FLAG_DAEMON_MODE ||
607 imf_ssl_new_cert(cert) == SSL_CERT_ACTION_REJECT)
608 goto abort;
609 break;
610 case SSL_CERT_MISMATCH:
611 imf_ssl_print_cert(cert, md, &mdlen);
612 if (flags & FLAG_DAEMON_MODE ||
613 imf_ssl_cert_mismatch() == SSL_CERT_ACTION_ABORT)
614 goto abort;
615 break;
616 case SSL_CERT_OK:
617 if (options & OPTION_DETAILS_VERBOSE)
618 imf_ssl_print_cert(cert, md, &mdlen);
619 }
620
621 X509_free(cert);
622 return 0;
623
624 abort:
625 X509_free(cert);
626 return ERROR_SSL;
627 }
628
629
630 /*
631 * Check if the SSL/TLS certificate exists in the certificates file.
632 */
633 int
634 imf_ssl_check_cert(X509 * pcert, unsigned char *pmd, unsigned int *pmdlen)
635 {
636 int r;
637 FILE *fd;
638 X509 *cert;
639 unsigned char md[EVP_MAX_MD_SIZE];
640 unsigned int mdlen;
641 char *cfn;
642
643 r = SSL_CERT_NONEXISTENT;
644 cert = NULL;
645 cfn = ".imapfilter/certificates";
646
647 if (!exists_file(cfn))
648 return SSL_CERT_NONEXISTENT;
649
650 fd = fopen(cfn, "r");
651 if (fd == NULL)
652 return ERROR_FILE_OPEN;
653
654 while ((cert = PEM_read_X509(fd, &cert, NULL, NULL)) != NULL) {
655 if (X509_subject_name_cmp(cert, pcert) != 0 ||
656 X509_issuer_name_cmp(cert, pcert) != 0)
657 continue;
658
659 if (!X509_digest(cert, EVP_md5(), md, &mdlen) ||
660 *pmdlen != mdlen)
661 continue;
662
663 if (memcmp(pmd, md, mdlen) != 0) {
664 r = SSL_CERT_MISMATCH;
665 break;
666 }
667 r = SSL_CERT_OK;
668 break;
669 }
670
671 fclose(fd);
672 X509_free(cert);
673
674 return r;
675 }
676
677
678 /*
679 * Print information about the SSL/TLS certificate.
680 */
681 void
682 imf_ssl_print_cert(X509 * cert, unsigned char *md, unsigned int *mdlen)
683 {
684 unsigned int i;
685 char *c;
686
687 c = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
688 printf("Server certificate subject: %s\n", c);
689 xfree(c);
690
691 c = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
692 printf("Server certificate issuer: %s\n", c);
693 xfree(c);
694
695 printf("Server key fingerprint: ");
696 for (i = 0; i < *mdlen; i++)
697 printf(i != *mdlen - 1 ? "%02X:" : "%02X\n", md[i]);
698 }
699
700
701 /*
702 * Ask the user to reject/accept the SSL/TLS certificate.
703 */
704 int
705 imf_ssl_new_cert(X509 * cert)
706 {
707 FILE *fd;
708 char c, *cfn, buf[LINE_MAX];
709
710 do {
711 printf("(R)eject, accept (t)emporarily or "
712 "accept (p)ermanently? ");
713 fgets(buf, LINE_MAX, stdin);
714 c = tolower(*buf);
715 } while (c != 'r' && c != 't' && c != 'p');
716
717 if (c == 'r')
718 return SSL_CERT_ACTION_REJECT;
719 else if (c == 't')
720 return SSL_CERT_ACTION_ACCEPT;
721
722 cfn = ".imapfilter/certificates";
723
724 create_file(cfn, S_IRUSR | S_IWUSR);
725
726 fd = fopen(cfn, "a");
727 if (fd == NULL)
728 return SSL_CERT_ACTION_REJECT;
729
730 PEM_write_X509(fd, cert);
731
732 fclose(fd);
733
734 return SSL_CERT_ACTION_ACCEPT;
735 }
736
737
738 /*
739 * Ask user to proceed, while a fingerprint mismatch in the SSL/TLS
740 * certificate was found.
741 */
742 int
743 imf_ssl_cert_mismatch(void)
744 {
745 char c, buf[LINE_MAX];
746
747 do {
748 printf("WARNING: SSL/TLS certificate fingerprint mismatch.\n"
749 "Proceed with the connection (y/n)? ");
750 fgets(buf, LINE_MAX, stdin);
751 c = tolower(*buf);
752 } while (c != 'y' && c != 'n');
753
754 if (c == 'y')
755 return SSL_CERT_ACTION_CONTINUE;
756 else
757 return SSL_CERT_ACTION_ABORT;
758 }
759
760 #endif /* SSL_TLS */

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26