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