X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Ftls.c;h=0df99845c58a1169691fb4e2400d10f096ddf012;hb=f517c5879577b17586548fd4ba70ce9cfb862369;hp=d213fefd69b9fc1454d095e8bac9f440dc6bc1f4;hpb=c3bb5a29480ecbd971e206a1efbd4ad3d23e6e93;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/tls.c b/src/src/tls.c index d213fefd6..0df99845c 100644 --- a/src/src/tls.c +++ b/src/src/tls.c @@ -38,7 +38,7 @@ functions from the OpenSSL or GNU TLS libraries. */ static void tls_per_lib_daemon_init(void); static void tls_per_lib_daemon_tick(void); -static void tls_server_creds_init(void); +static unsigned tls_server_creds_init(void); static void tls_server_creds_invalidate(void); static void tls_client_creds_init(transport_instance *, BOOL); static void tls_client_creds_invalidate(transport_instance *); @@ -82,6 +82,8 @@ static struct kevent kev[KEV_SIZE]; static int kev_used = 0; #endif +static unsigned tls_creds_expire = 0; + /************************************************* * Expand string; give error on failure * *************************************************/ @@ -156,24 +158,29 @@ return FALSE; # endif # ifdef EXIM_HAVE_KEVENT { -uschar * s; -int fd1, fd2, i, cnt = 0; +uschar * s, * t; +int fd1, fd2, i, j, cnt = 0; struct stat sb; +#ifdef OpenBSD +struct kevent k_dummy; +struct timespec ts = {0}; +#endif errno = 0; if (Ustrcmp(filename, "system,cache") == 0) return TRUE; for (;;) { - if (!(s = Ustrrchr(filename, '/'))) return FALSE; - if ((lstat(CCS filename, &sb)) < 0) { s = US"lstat"; goto bad; } if (kev_used > KEV_SIZE-2) { s = US"out of kev space"; goto bad; } + if (!(s = Ustrrchr(filename, '/'))) return FALSE; + s = string_copyn(filename, s - filename); /* mem released by tls_set_watch */ /* The dir open will fail if there is a symlink on the path. Fine; it's too much effort to handle all possible cases; just refuse the preload. */ if ((fd2 = open(CCS s, O_RDONLY | O_NOFOLLOW)) < 0) { s = US"open dir"; goto bad; } + if ((lstat(CCS filename, &sb)) < 0) { s = US"lstat"; goto bad; } if (!S_ISLNK(sb.st_mode)) { if ((fd1 = open(CCS filename, O_RDONLY | O_NOFOLLOW)) < 0) @@ -202,15 +209,23 @@ for (;;) if (!(S_ISLNK(sb.st_mode))) break; - s = store_get(1024, FALSE); - if ((i = readlink(CCS filename, s, 1024)) < 0) { s = US"readlink"; goto bad; } - filename = s; - *(s += i) = '\0'; - store_release_above(s+1); + t = store_get(1024, FALSE); + Ustrncpy(t, s, 1022); + j = Ustrlen(s); + t[j++] = '/'; + if ((i = readlink(CCS filename, (void *)(t+j), 1023-j)) < 0) { s = US"readlink"; goto bad; } + filename = t; + *(t += i+j) = '\0'; + store_release_above(t+1); } +#ifdef OpenBSD +if (kevent(tls_watch_fd, &kev[kev_used-cnt], cnt, &k_dummy, 1, &ts) >= 0) + return TRUE; +#else if (kevent(tls_watch_fd, &kev[kev_used-cnt], cnt, NULL, 0, NULL) >= 0) return TRUE; +#endif s = US"kevent"; bad: @@ -281,20 +296,6 @@ struct timespec t = {0}; (void) kevent(fd, NULL, 0, &kev, 1, &t); #endif } - -/* Called, after a delay for multiple file ops to get done, from -the daemon when any of the watches added (above) fire. - -Dump the set of watches and arrange to reload cached creds (which -will set up new watches). */ - -static void -tls_watch_triggered(void) -{ -DEBUG(D_tls) debug_printf("watch triggered\n"); - -tls_daemon_creds_reload(); -} #endif /*EXIM_HAVE_INOTIFY*/ @@ -317,7 +318,7 @@ if (tls_watch_fd < 0) return; #ifdef EXIM_HAVE_KEVENT /* Close the files we had open for kevent */ -for (int fd, i = 0; i < kev_used; i++) +for (int i = 0; i < kev_used; i++) { (void) close((int) kev[i].ident); kev[i].ident = (uintptr_t)-1; @@ -333,12 +334,15 @@ tls_watch_fd = -1; static void tls_daemon_creds_reload(void) { +unsigned lifetime; + #ifdef EXIM_HAVE_KEVENT tls_watch_invalidate(); #endif tls_server_creds_invalidate(); -tls_server_creds_init(); +tls_creds_expire = (lifetime = tls_server_creds_init()) + ? time(NULL) + lifetime : 0; tls_client_creds_reload(TRUE); } @@ -355,19 +359,45 @@ opt_unset_or_noexpand(const uschar * opt) -/* Called every time round the daemon loop */ +/* Called every time round the daemon loop. -void +If we reloaded fd-watcher, return the old watch fd +having modified the global for the new one. Otherwise +return -1. +*/ + +int tls_daemon_tick(void) { +int old_watch_fd = tls_watch_fd; + tls_per_lib_daemon_tick(); #if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT) -if (tls_watch_trigger_time && time(NULL) >= tls_watch_trigger_time + 5) +if (tls_creds_expire && time(NULL) >= tls_creds_expire) { - tls_watch_trigger_time = 0; - tls_watch_triggered(); + /* The server cert is a selfsign, with limited lifetime. Dump it and + generate a new one. Reload the rest of the creds also as the machinery + is all there. */ + + DEBUG(D_tls) debug_printf("selfsign cert rotate\n"); + tls_creds_expire = 0; + tls_daemon_creds_reload(); + return old_watch_fd; + } +else if (tls_watch_trigger_time && time(NULL) >= tls_watch_trigger_time + 5) + { + /* Called, after a delay for multiple file ops to get done, from + the daemon when any of the watches added (above) fire. + Dump the set of watches and arrange to reload cached creds (which + will set up new watches). */ + + DEBUG(D_tls) debug_printf("watch triggered\n"); + tls_watch_trigger_time = tls_creds_expire = 0; + tls_daemon_creds_reload(); + return old_watch_fd; } #endif +return -1; } /* Called once at daemon startup */ @@ -440,6 +470,9 @@ Returns: the character int tls_ungetc(int ch) { +if (ssl_xfer_buffer_lwm <= 0) + log_write(0, LOG_MAIN|LOG_PANIC_DIE, "buffer underflow in tls_ungetc"); + ssl_xfer_buffer[--ssl_xfer_buffer_lwm] = ch; return ch; }