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