OpenSSL: tls_eccurves list support. Bug 2955
[exim.git] / src / src / tls.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) The Exim Maintainers 2020 - 2022 */
6 /* Copyright (c) University of Cambridge 1995 - 2018 */
7 /* See the file NOTICE for conditions of use and distribution. */
8 /* SPDX-License-Identifier: GPL-2.0-or-later */
9
10 /* This module provides TLS (aka SSL) support for Exim. The code for OpenSSL is
11 based on a patch that was originally contributed by Steve Haslam. It was
12 adapted from stunnel, a GPL program by Michal Trojnara. The code for GNU TLS is
13 based on a patch contributed by Nikos Mavrogiannopoulos. Because these packages
14 are so very different, the functions for each are kept in separate files. The
15 relevant file is #included as required, after any any common functions.
16
17 No cryptographic code is included in Exim. All this module does is to call
18 functions from the OpenSSL or GNU TLS libraries. */
19
20
21 #include "exim.h"
22 #include "transports/smtp.h"
23
24 #if !defined(DISABLE_TLS) && !defined(USE_OPENSSL) && !defined(USE_GNUTLS)
25 # error One of USE_OPENSSL or USE_GNUTLS must be defined for a TLS build
26 #endif
27
28
29 /* Forward decl. */
30 static void tls_client_resmption_key(tls_support *, smtp_connect_args *,
31   smtp_transport_options_block *);
32
33
34 #if defined(MACRO_PREDEF) && !defined(DISABLE_TLS)
35 # include "macro_predef.h"
36 # ifdef USE_GNUTLS
37 #  include "tls-gnu.c"
38 # else
39 #  include "tls-openssl.c"
40 # endif
41 #endif
42
43 #ifndef MACRO_PREDEF
44
45 static void tls_per_lib_daemon_init(void);
46 static void tls_per_lib_daemon_tick(void);
47 static unsigned  tls_server_creds_init(void);
48 static void tls_server_creds_invalidate(void);
49 static void tls_client_creds_init(transport_instance *, BOOL);
50 static void tls_client_creds_invalidate(transport_instance *);
51 static void tls_daemon_creds_reload(void);
52 static BOOL opt_set_and_noexpand(const uschar *);
53 static BOOL opt_unset_or_noexpand(const uschar *);
54
55
56
57 /* This module is compiled only when it is specifically requested in the
58 build-time configuration. However, some compilers don't like compiling empty
59 modules, so keep them happy with a dummy when skipping the rest. Make it
60 reference itself to stop picky compilers complaining that it is unused, and put
61 in a dummy argument to stop even pickier compilers complaining about infinite
62 loops. */
63
64 #ifdef DISABLE_TLS
65 static void dummy(int x) { dummy(x-1); }
66 #else   /* most of the rest of the file */
67
68 const exim_tlslib_state null_tls_preload = {0};
69
70 /* Static variables that are used for buffering data by both sets of
71 functions and the common functions below.
72
73 We're moving away from this; GnuTLS is already using a state, which
74 can switch, so we can do TLS callouts during ACLs. */
75
76 static const int ssl_xfer_buffer_size = 4096;
77 #ifdef USE_OPENSSL
78 static uschar *ssl_xfer_buffer = NULL;
79 static int ssl_xfer_buffer_lwm = 0;
80 static int ssl_xfer_buffer_hwm = 0;
81 static int ssl_xfer_eof = FALSE;
82 static BOOL ssl_xfer_error = FALSE;
83 #endif
84
85 #ifdef EXIM_HAVE_KEVENT
86 # define KEV_SIZE 16    /* Eight file,dir pairs */
87 static struct kevent kev[KEV_SIZE];
88 static int kev_used = 0;
89 #endif
90
91 static unsigned tls_creds_expire = 0;
92
93 /*************************************************
94 *       Expand string; give error on failure     *
95 *************************************************/
96
97 /* If expansion is forced to fail, set the result NULL and return TRUE.
98 Other failures return FALSE. For a server, an SMTP response is given.
99
100 Arguments:
101   s         the string to expand; if NULL just return TRUE
102   name      name of string being expanded (for error)
103   result    where to put the result
104
105 Returns:    TRUE if OK; result may still be NULL after forced failure
106 */
107
108 static BOOL
109 expand_check(const uschar * s, const uschar * name,
110   uschar ** result, uschar ** errstr)
111 {
112 if (!s)
113   *result = NULL;
114 else if (  !(*result = expand_string(US s)) /* need to clean up const more */
115         && !f.expand_string_forcedfail
116         )
117   {
118   *errstr = US"Internal error";
119   log_write(0, LOG_MAIN|LOG_PANIC, "expansion of %s failed: %s", name,
120     expand_string_message);
121   return FALSE;
122   }
123 return TRUE;
124 }
125
126
127 #if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
128 /* Add the directory for a filename to the inotify handle, creating that if
129 needed.  This is enough to see changes to files in that dir.
130 Return boolean success.
131
132 The word "system" fails, which is on the safe side as we don't know what
133 directory it implies nor if the TLS library handles a watch for us.
134
135 The string "system,cache" is recognised and explicitly accepted without
136 setting a watch.  This permits the system CA bundle to be cached even though
137 we have no way to tell when it gets modified by an update.
138 The call chain for OpenSSL uses a (undocumented) call into the library
139 to discover the actual file.  We don't know what GnuTLS uses.
140
141 A full set of caching including the CAs takes 35ms output off of the
142 server tls_init() (GnuTLS, Fedora 32, 2018-class x86_64 laptop hardware).
143 */
144 static BOOL
145 tls_set_one_watch(const uschar * filename)
146 # ifdef EXIM_HAVE_INOTIFY
147 {
148 uschar buf[PATH_MAX];
149 ssize_t len;
150 uschar * s;
151
152 if (Ustrcmp(filename, "system,cache") == 0) return TRUE;
153 if (!(s = Ustrrchr(filename, '/'))) return FALSE;
154
155 for (unsigned loop = 20;
156      (len = readlink(CCS filename, CS buf, sizeof(buf))) >= 0; )
157   {                                             /* a symlink */
158   if (--loop == 0) { errno = ELOOP; return FALSE; }
159   filename = buf[0] == '/'
160     ? string_copyn(buf, (unsigned)len)  /* mem released by tls_set_watch */
161     : string_sprintf("%.*s/%.*s", (int)(s - filename), filename, (int)len, buf);
162   s = Ustrrchr(filename, '/');
163   }
164 if (errno != EINVAL)
165   return FALSE;                                 /* other error */
166
167 /* not a symlink */
168 s = string_copyn(filename, s - filename);       /* mem released by tls_set_watch */
169
170 DEBUG(D_tls) debug_printf("watch dir '%s'\n", s);
171
172 if (inotify_add_watch(tls_watch_fd, CCS s,
173       IN_ONESHOT | IN_CLOSE_WRITE | IN_DELETE | IN_DELETE_SELF
174       | IN_MOVED_FROM | IN_MOVED_TO | IN_MOVE_SELF) >= 0)
175   return TRUE;
176 DEBUG(D_tls) debug_printf("notify_add_watch: %s\n", strerror(errno));
177 return FALSE;
178 }
179 # endif
180 # ifdef EXIM_HAVE_KEVENT
181 {
182 uschar * s, * t;
183 int fd1, fd2, i, j, cnt = 0;
184 struct stat sb;
185 #ifdef OpenBSD
186 struct kevent k_dummy;
187 struct timespec ts = {0};
188 #endif
189
190 errno = 0;
191 if (Ustrcmp(filename, "system,cache") == 0) return TRUE;
192
193 for (;;)
194   {
195   if (kev_used > KEV_SIZE-2) { s = US"out of kev space"; goto bad; }
196   if (!(s = Ustrrchr(filename, '/'))) return FALSE;
197   s = string_copyn(filename, s - filename);     /* mem released by tls_set_watch */
198
199   /* The dir open will fail if there is a symlink on the path. Fine; it's too
200   much effort to handle all possible cases; just refuse the preload. */
201
202   if ((fd2 = open(CCS s, O_RDONLY | O_NOFOLLOW)) < 0) { s = US"open dir"; goto bad; }
203
204   if ((lstat(CCS filename, &sb)) < 0) { s = US"lstat"; goto bad; }
205   if (!S_ISLNK(sb.st_mode))
206     {
207     if ((fd1 = open(CCS filename, O_RDONLY | O_NOFOLLOW)) < 0)
208       { s = US"open file"; goto bad; }
209     DEBUG(D_tls) debug_printf("watch file '%s':\t%d\n", filename, fd1);
210     EV_SET(&kev[kev_used++],
211         (uintptr_t)fd1,
212         EVFILT_VNODE,
213         EV_ADD | EV_ENABLE | EV_ONESHOT,
214         NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND
215         | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE,
216         0,
217         NULL);
218     cnt++;
219     }
220   DEBUG(D_tls) debug_printf("watch dir  '%s':\t%d\n", s, fd2);
221   EV_SET(&kev[kev_used++],
222         (uintptr_t)fd2,
223         EVFILT_VNODE,
224         EV_ADD | EV_ENABLE | EV_ONESHOT,
225         NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND
226         | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE,
227         0,
228         NULL);
229   cnt++;
230
231   if (!(S_ISLNK(sb.st_mode))) break;
232
233   t = store_get(1024, GET_UNTAINTED);
234   Ustrncpy(t, s, 1022);
235   j = Ustrlen(s);
236   t[j++] = '/';
237   if ((i = readlink(CCS filename, (void *)(t+j), 1023-j)) < 0) { s = US"readlink"; goto bad; }
238   filename = t;
239   *(t += i+j) = '\0';
240   store_release_above(t+1);
241   }
242
243 #ifdef OpenBSD
244 if (kevent(tls_watch_fd, &kev[kev_used-cnt], cnt, &k_dummy, 1, &ts) >= 0)
245   return TRUE;
246 #else
247 if (kevent(tls_watch_fd, &kev[kev_used-cnt], cnt, NULL, 0, NULL) >= 0)
248   return TRUE;
249 #endif
250 s = US"kevent";
251
252 bad:
253 DEBUG(D_tls)
254   if (errno)
255     debug_printf("%s: %s: %s\n", __FUNCTION__, s, strerror(errno));
256   else
257     debug_printf("%s: %s\n", __FUNCTION__, s);
258 return FALSE;
259 }
260 # endif /*EXIM_HAVE_KEVENT*/
261
262
263 /* Create an inotify facility if needed.
264 Then set watches on the dir containing the given file or (optionally)
265 list of files.  Return boolean success. */
266
267 static BOOL
268 tls_set_watch(const uschar * filename, BOOL list)
269 {
270 rmark r;
271 BOOL rc = FALSE;
272
273 if (!filename || !*filename) return TRUE;
274 if (Ustrncmp(filename, "system", 6) == 0) return TRUE;
275
276 DEBUG(D_tls) debug_printf("tls_set_watch: '%s'\n", filename);
277
278 if (  tls_watch_fd < 0
279 # ifdef EXIM_HAVE_INOTIFY
280    && (tls_watch_fd = inotify_init1(O_CLOEXEC)) < 0
281 # endif
282 # ifdef EXIM_HAVE_KEVENT
283    && (tls_watch_fd = kqueue()) < 0
284 # endif
285    )
286     {
287     DEBUG(D_tls) debug_printf("inotify_init: %s\n", strerror(errno));
288     return FALSE;
289     }
290
291 r = store_mark();
292
293 if (list)
294   {
295   int sep = 0;
296   for (uschar * s; s = string_nextinlist(&filename, &sep, NULL, 0); )
297     if (!(rc = tls_set_one_watch(s))) break;
298   }
299 else
300   rc = tls_set_one_watch(filename);
301
302 store_reset(r);
303 if (!rc) DEBUG(D_tls) debug_printf("tls_set_watch() fail on '%s': %s\n", filename, strerror(errno));
304 return rc;
305 }
306
307
308 void
309 tls_watch_discard_event(int fd)
310 {
311 #ifdef EXIM_HAVE_INOTIFY
312 (void) read(fd, big_buffer, big_buffer_size);
313 #endif
314 #ifdef EXIM_HAVE_KEVENT
315 struct kevent kev;
316 struct timespec t = {0};
317 (void) kevent(fd, NULL, 0, &kev, 1, &t);
318 #endif
319 }
320 #endif  /*EXIM_HAVE_INOTIFY*/
321
322
323 void
324 tls_client_creds_reload(BOOL watch)
325 {
326 for(transport_instance * t = transports; t; t = t->next)
327   if (Ustrcmp(t->driver_name, "smtp") == 0)
328     {
329     tls_client_creds_invalidate(t);
330     tls_client_creds_init(t, watch);
331     }
332 }
333
334
335 void
336 tls_watch_invalidate(void)
337 {
338 if (tls_watch_fd < 0) return;
339
340 #ifdef EXIM_HAVE_KEVENT
341 /* Close the files we had open for kevent */
342 for (int i = 0; i < kev_used; i++)
343   {
344   DEBUG(D_tls) debug_printf("closing watch fd: %d\n", (int) kev[i].ident);
345   (void) close((int) kev[i].ident);
346   kev[i].ident = (uintptr_t)-1;
347   }
348 kev_used = 0;
349 #endif
350
351 close(tls_watch_fd);
352 tls_watch_fd = -1;
353 }
354
355
356 static void
357 tls_daemon_creds_reload(void)
358 {
359 unsigned lifetime;
360
361 #ifdef EXIM_HAVE_KEVENT
362 tls_watch_invalidate();
363 #endif
364
365 tls_server_creds_invalidate();
366
367 /* _expire is for a time-limited selfsign server cert */
368 tls_creds_expire = (lifetime = tls_server_creds_init())
369   ? time(NULL) + lifetime : 0;
370
371 tls_client_creds_reload(TRUE);
372 }
373
374
375 /* Utility predicates for use by the per-library code */
376 static BOOL
377 opt_set_and_noexpand(const uschar * opt)
378 { return opt && *opt && Ustrchr(opt, '$') == NULL; }
379
380 static BOOL
381 opt_unset_or_noexpand(const uschar * opt)
382 { return !opt || Ustrchr(opt, '$') == NULL; }
383
384
385
386 /* Called every time round the daemon loop.
387
388 If we reloaded fd-watcher, return the old watch fd
389 having modified the global for the new one. Otherwise
390 return -1.
391 */
392
393 int
394 tls_daemon_tick(void)
395 {
396 int old_watch_fd = tls_watch_fd;
397
398 tls_per_lib_daemon_tick();
399 #if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
400 if (tls_creds_expire && time(NULL) >= tls_creds_expire)
401   {
402   /* The server cert is a selfsign, with limited lifetime.  Dump it and
403   generate a new one.  Reload the rest of the creds also as the machinery
404   is all there. */
405
406   DEBUG(D_tls) debug_printf("selfsign cert rotate\n");
407   tls_creds_expire = 0;
408   tls_daemon_creds_reload();
409   return old_watch_fd;
410   }
411 else if (tls_watch_trigger_time && time(NULL) >= tls_watch_trigger_time + 5)
412   {
413   /* Called, after a delay for multiple file ops to get done, from
414   the daemon when any of the watches added (above) fire.
415   Dump the set of watches and arrange to reload cached creds (which
416   will set up new watches). */
417
418   DEBUG(D_tls) debug_printf("watch triggered\n");
419   tls_watch_trigger_time = tls_creds_expire = 0;
420   tls_daemon_creds_reload();
421   return old_watch_fd;
422   }
423 #endif
424 return -1;
425 }
426
427 /* Called once at daemon startup */
428
429 void
430 tls_daemon_init(void)
431 {
432 tls_per_lib_daemon_init();
433 }
434
435
436 /*************************************************
437 *        Timezone environment flipping           *
438 *************************************************/
439
440 static uschar *
441 to_tz(uschar * tz)
442 {
443 uschar * old = US getenv("TZ");
444 (void) setenv("TZ", CCS tz, 1);
445 tzset();
446 return old;
447 }
448
449 static void
450 restore_tz(uschar * tz)
451 {
452 if (tz)
453   (void) setenv("TZ", CCS tz, 1);
454 else
455   (void) os_unsetenv(US"TZ");
456 tzset();
457 }
458
459 /*************************************************
460 *        Many functions are package-specific     *
461 *************************************************/
462
463 #ifdef USE_GNUTLS
464 # include "tls-gnu.c"
465 # include "tlscert-gnu.c"
466 # define ssl_xfer_buffer (state_server.xfer_buffer)
467 # define ssl_xfer_buffer_lwm (state_server.xfer_buffer_lwm)
468 # define ssl_xfer_buffer_hwm (state_server.xfer_buffer_hwm)
469 # define ssl_xfer_eof (state_server.xfer_eof)
470 # define ssl_xfer_error (state_server.xfer_error)
471 #endif
472
473 #ifdef USE_OPENSSL
474 # include "tls-openssl.c"
475 # include "tlscert-openssl.c"
476 #endif
477
478
479
480 /*************************************************
481 *           TLS version of ungetc                *
482 *************************************************/
483
484 /* Puts a character back in the input buffer. Only ever
485 called once.
486 Only used by the server-side TLS.
487
488 Arguments:
489   ch           the character
490
491 Returns:       the character
492 */
493
494 int
495 tls_ungetc(int ch)
496 {
497 if (ssl_xfer_buffer_lwm <= 0)
498   log_write(0, LOG_MAIN|LOG_PANIC_DIE, "buffer underflow in tls_ungetc");
499
500 ssl_xfer_buffer[--ssl_xfer_buffer_lwm] = ch;
501 return ch;
502 }
503
504
505
506 /*************************************************
507 *           TLS version of feof                  *
508 *************************************************/
509
510 /* Tests for a previous EOF
511 Only used by the server-side TLS.
512
513 Arguments:     none
514 Returns:       non-zero if the eof flag is set
515 */
516
517 int
518 tls_feof(void)
519 {
520 return (int)ssl_xfer_eof;
521 }
522
523
524
525 /*************************************************
526 *              TLS version of ferror             *
527 *************************************************/
528
529 /* Tests for a previous read error, and returns with errno
530 restored to what it was when the error was detected.
531 Only used by the server-side TLS.
532
533 >>>>> Hmm. Errno not handled yet. Where do we get it from?  >>>>>
534
535 Arguments:     none
536 Returns:       non-zero if the error flag is set
537 */
538
539 int
540 tls_ferror(void)
541 {
542 return (int)ssl_xfer_error;
543 }
544
545
546 /*************************************************
547 *           TLS version of smtp_buffered         *
548 *************************************************/
549
550 /* Tests for unused chars in the TLS input buffer.
551 Only used by the server-side TLS.
552
553 Arguments:     none
554 Returns:       TRUE/FALSE
555 */
556
557 BOOL
558 tls_smtp_buffered(void)
559 {
560 return ssl_xfer_buffer_lwm < ssl_xfer_buffer_hwm;
561 }
562
563
564 #endif  /*DISABLE_TLS*/
565
566 void
567 tls_modify_variables(tls_support * dest_tsp)
568 {
569 modify_variable(US"tls_bits",                 &dest_tsp->bits);
570 modify_variable(US"tls_certificate_verified", &dest_tsp->certificate_verified);
571 modify_variable(US"tls_cipher",               &dest_tsp->cipher);
572 modify_variable(US"tls_peerdn",               &dest_tsp->peerdn);
573 #ifdef USE_OPENSSL
574 modify_variable(US"tls_sni",                  &dest_tsp->sni);
575 #endif
576 }
577
578
579 #ifndef DISABLE_TLS
580 /************************************************
581 *       TLS certificate name operations         *
582 ************************************************/
583
584 /* Convert an rfc4514 DN to an exim comma-sep list.
585 Backslashed commas need to be replaced by doublecomma
586 for Exim's list quoting.  We modify the given string
587 inplace.
588 */
589
590 static void
591 dn_to_list(uschar * dn)
592 {
593 for (uschar * cp = dn; *cp; cp++)
594   if (cp[0] == '\\' && cp[1] == ',')
595     *cp++ = ',';
596 }
597
598
599 /* Extract fields of a given type from an RFC4514-
600 format Distinguished Name.  Return an Exim list.
601 NOTE: We modify the supplied dn string during operation.
602
603 Arguments:
604         dn      Distinguished Name string
605         mod     list containing optional output list-sep and
606                 field selector match, comma-separated
607 Return:
608         allocated string with list of matching fields,
609         field type stripped
610 */
611
612 uschar *
613 tls_field_from_dn(uschar * dn, const uschar * mod)
614 {
615 int insep = ',';
616 uschar outsep = '\n';
617 uschar * ele;
618 uschar * match = NULL;
619 int len;
620 gstring * list = NULL;
621
622 while ((ele = string_nextinlist(&mod, &insep, NULL, 0)))
623   if (ele[0] != '>')
624     match = ele;        /* field tag to match */
625   else if (ele[1])
626     outsep = ele[1];    /* nondefault output separator */
627
628 dn_to_list(dn);
629 insep = ',';
630 len = match ? Ustrlen(match) : -1;
631 while ((ele = string_nextinlist(CUSS &dn, &insep, NULL, 0)))
632   if (  !match
633      || Ustrncmp(ele, match, len) == 0 && ele[len] == '='
634      )
635     list = string_append_listele(list, outsep, ele+len+1);
636 return string_from_gstring(list);
637 }
638
639
640 /* Compare a domain name with a possibly-wildcarded name. Wildcards
641 are restricted to a single one, as the first element of patterns
642 having at least three dot-separated elements.  Case-independent.
643 Return TRUE for a match
644 */
645 static BOOL
646 is_name_match(const uschar * name, const uschar * pat)
647 {
648 uschar * cp;
649 return *pat == '*'              /* possible wildcard match */
650   ?    *++pat == '.'            /* starts star, dot              */
651     && !Ustrchr(++pat, '*')     /* has no more stars             */
652     && Ustrchr(pat, '.')        /* and has another dot.          */
653     && (cp = Ustrchr(name, '.'))/* The name has at least one dot */
654     && strcmpic(++cp, pat) == 0 /* and we only compare after it. */
655   :    !Ustrchr(pat+1, '*')
656     && strcmpic(name, pat) == 0;
657 }
658
659 /* Compare a list of names with the dnsname elements
660 of the Subject Alternate Name, if any, and the
661 Subject otherwise.
662
663 Arguments:
664         namelist names to compare
665         cert     certificate
666
667 Returns:
668         TRUE/FALSE
669 */
670
671 BOOL
672 tls_is_name_for_cert(const uschar * namelist, void * cert)
673 {
674 uschar * altnames = tls_cert_subject_altname(cert, US"dns");
675 uschar * subjdn;
676 uschar * certname;
677 int cmp_sep = 0;
678 uschar * cmpname;
679
680 if ((altnames = tls_cert_subject_altname(cert, US"dns")))
681   {
682   int alt_sep = '\n';
683   while ((cmpname = string_nextinlist(&namelist, &cmp_sep, NULL, 0)))
684     {
685     const uschar * an = altnames;
686     while ((certname = string_nextinlist(&an, &alt_sep, NULL, 0)))
687       if (is_name_match(cmpname, certname))
688         return TRUE;
689     }
690   }
691
692 else if ((subjdn = tls_cert_subject(cert, NULL)))
693   {
694   int sn_sep = ',';
695
696   dn_to_list(subjdn);
697   while ((cmpname = string_nextinlist(&namelist, &cmp_sep, NULL, 0)))
698     {
699     const uschar * sn = subjdn;
700     while ((certname = string_nextinlist(&sn, &sn_sep, NULL, 0)))
701       if (  *certname++ == 'C'
702          && *certname++ == 'N'
703          && *certname++ == '='
704          && is_name_match(cmpname, certname)
705          )
706         return TRUE;
707     }
708   }
709 return FALSE;
710 }
711
712 /* Environment cleanup: The GnuTLS library uses SSLKEYLOGFILE in the environment
713 and writes a file by that name.  Our OpenSSL code does the same, using keying
714 info from the library API.
715 The GnuTLS support only works if exim is run by root, not taking advantage of
716 the setuid bit.
717 You can use either the external environment (modulo the keep_environment config)
718 or the add_environment config option for SSLKEYLOGFILE; the latter takes
719 precedence.
720
721 If the path is absolute, require it starts with the spooldir; otherwise delete
722 the env variable.  If relative, prefix the spooldir.
723 */
724 void
725 tls_clean_env(void)
726 {
727 uschar * path = US getenv("SSLKEYLOGFILE");
728 if (path)
729   if (!*path)
730     unsetenv("SSLKEYLOGFILE");
731   else if (*path != '/')
732     {
733     DEBUG(D_tls)
734       debug_printf("prepending spooldir to  env SSLKEYLOGFILE\n");
735     setenv("SSLKEYLOGFILE", CCS string_sprintf("%s/%s", spool_directory, path), 1);
736     }
737   else if (Ustrncmp(path, spool_directory, Ustrlen(spool_directory)) != 0)
738     {
739     DEBUG(D_tls)
740       debug_printf("removing env SSLKEYLOGFILE=%s: not under spooldir\n", path);
741     unsetenv("SSLKEYLOGFILE");
742     }
743 }
744
745 /*************************************************
746 *       Drop privs for checking TLS config      *
747 *************************************************/
748
749 /* We want to validate TLS options during readconf, but do not want to be
750 root when we call into the TLS library, in case of library linkage errors
751 which cause segfaults; before this check, those were always done as the Exim
752 runtime user and it makes sense to continue with that.
753
754 Assumes:  tls_require_ciphers has been set, if it will be
755           exim_user has been set, if it will be
756           exim_group has been set, if it will be
757
758 Returns:  bool for "okay"; false will cause caller to immediately exit.
759 */
760
761 BOOL
762 tls_dropprivs_validate_require_cipher(BOOL nowarn)
763 {
764 const uschar *errmsg;
765 pid_t pid;
766 int rc, status;
767 void (*oldsignal)(int);
768
769 /* If TLS will never be used, no point checking ciphers */
770
771 if (  !tls_advertise_hosts
772    || !*tls_advertise_hosts
773    || Ustrcmp(tls_advertise_hosts, ":") == 0
774    )
775   return TRUE;
776 else if (!nowarn && !tls_certificate)
777   log_write(0, LOG_MAIN,
778     "Warning: No server certificate defined; will use a selfsigned one.\n"
779     " Suggested action: either install a certificate or change tls_advertise_hosts option");
780
781 oldsignal = signal(SIGCHLD, SIG_DFL);
782
783 fflush(NULL);
784 if ((pid = exim_fork(US"cipher-validate")) < 0)
785   log_write(0, LOG_MAIN|LOG_PANIC_DIE, "fork failed for TLS check");
786
787 if (pid == 0)
788   {
789   /* in some modes, will have dropped privilege already */
790   if (!geteuid())
791     exim_setugid(exim_uid, exim_gid, FALSE,
792         US"calling tls_validate_require_cipher");
793
794   if ((errmsg = tls_validate_require_cipher()))
795     log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
796         "tls_require_ciphers invalid: %s", errmsg);
797   fflush(NULL);
798   exim_underbar_exit(EXIT_SUCCESS);
799   }
800
801 do {
802   rc = waitpid(pid, &status, 0);
803 } while (rc < 0 && errno == EINTR);
804
805 DEBUG(D_tls)
806   debug_printf("tls_validate_require_cipher child %d ended: status=0x%x\n",
807       (int)pid, status);
808
809 signal(SIGCHLD, oldsignal);
810
811 return status == 0;
812 }
813
814
815
816
817 static void
818 tls_client_resmption_key(tls_support * tlsp, smtp_connect_args * conn_args,
819   smtp_transport_options_block * ob)
820 {
821 #ifndef DISABLE_TLS_RESUME
822 hctx * h = &tlsp->resume_hctx;
823 blob b;
824 gstring * g;
825
826 DEBUG(D_tls) if (conn_args->host_lbserver)
827   debug_printf("TLS: lbserver '%s'\n", conn_args->host_lbserver);
828
829 # ifdef EXIM_HAVE_SHA2
830 exim_sha_init(h, HASH_SHA2_256);
831 # else
832 exim_sha_init(h, HASH_SHA1);
833 # endif
834 exim_sha_update_string(h, conn_args->host_lbserver);
835 # ifdef SUPPORT_DANE
836 if (conn_args->dane)
837   exim_sha_update(h,  CUS &conn_args->tlsa_dnsa, sizeof(dns_answer));
838 # endif
839 exim_sha_update_string(h, conn_args->host->address);
840 exim_sha_update(h,   CUS &conn_args->host->port, sizeof(conn_args->host->port));
841 exim_sha_update_string(h, conn_args->sending_ip_address);
842 exim_sha_update_string(h, openssl_options);
843 exim_sha_update_string(h, ob->tls_require_ciphers);
844 exim_sha_update_string(h, tlsp->sni);
845 # ifdef EXIM_HAVE_ALPN
846 exim_sha_update_string(h, ob->tls_alpn);
847 # endif
848 exim_sha_finish(h, &b);
849 for (g = string_get(b.len*2+1); b.len-- > 0; )
850   g = string_fmt_append(g, "%02x", *b.data++);
851 tlsp->resume_index = string_from_gstring(g);
852 DEBUG(D_tls) debug_printf("TLS: resume session index %s\n", tlsp->resume_index);
853 #endif
854 }
855
856 #endif  /*!DISABLE_TLS*/
857 #endif  /*!MACRO_PREDEF*/
858
859 /* vi: aw ai sw=2
860 */
861 /* End of tls.c */