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 *);
static int kev_used = 0;
#endif
+static unsigned tls_creds_expire = 0;
+
/*************************************************
* Expand string; give error on failure *
*************************************************/
# 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;
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:
(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*/
#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;
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);
}
-/* 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)
+ {
+ /* 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)
{
- tls_watch_trigger_time = 0;
- tls_watch_triggered();
+ /* 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 */
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;
}
return FALSE;
}
-
/* Environment cleanup: The GnuTLS library uses SSLKEYLOGFILE in the environment
and writes a file by that name. Our OpenSSL code does the same, using keying
info from the library API.