Fix daemon-SIGHUP on FreeBSD
[exim.git] / src / src / daemon.c
index c376f27c766b6853ff4e1e17a533e45dc45f376e..50c202c56f9f278c98b884ee987c1cf027ef663a 100644 (file)
@@ -128,11 +128,30 @@ if (smtp_out) smtp_printf("421 %s\r\n", FALSE, smtp_msg);
 /*************************************************
 *************************************************/
 
+#ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
+static void
+unlink_notifier_socket(void)
+{
+uschar * s = expand_string(notifier_socket);
+DEBUG(D_any) debug_printf("unlinking notifier socket %s\n", s);
+Uunlink(s);
+}
+#endif
+
+
 static void
 close_daemon_sockets(int daemon_notifier_fd,
   int * listen_sockets, int listen_socket_count)
 {
-if (daemon_notifier_fd >= 0) (void) close(daemon_notifier_fd);
+if (daemon_notifier_fd >= 0)
+  {
+  (void) close(daemon_notifier_fd);
+  daemon_notifier_fd = -1;
+#ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
+  unlink_notifier_socket();
+#endif
+  }
+
 for (int i = 0; i < listen_socket_count; i++) (void) close(listen_sockets[i]);
 }
 
@@ -963,16 +982,17 @@ daemon_die(void)
 {
 int pid;
 
+DEBUG(D_any) debug_printf("SIGTERM seen\n");
+#if !defined(DISABLE_TLS) && (defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT))
+tls_watch_invalidate();
+#endif
+
 if (daemon_notifier_fd >= 0)
   {
   close(daemon_notifier_fd);
   daemon_notifier_fd = -1;
 #ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
-    {
-    uschar * s = expand_string(notifier_socket);
-    DEBUG(D_any) debug_printf("unlinking notifier socket %s\n", s);
-    Uunlink(s);
-    }
+  unlink_notifier_socket();
 #endif
   }
 
@@ -1007,6 +1027,11 @@ const uschar * where;
 struct sockaddr_un sa_un = {.sun_family = AF_UNIX};
 int len;
 
+if (!notifier_socket || !*notifier_socket)
+  {
+  DEBUG(D_any) debug_printf("-oY used so not creating notifier socket\n");
+  return;
+  }
 if (override_local_interfaces && !override_pid_file_path)
   {
   DEBUG(D_any)
@@ -1417,6 +1442,7 @@ if (f.daemon_listen && !f.inetd_wait_mode)
 
   list = tls_in.on_connect_ports;
   sep = 0;
+  /* the list isn't expanded so cannot be tainted.  If it ever is we will trap here */
   while ((s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
     if (!isdigit(*s))
       {
@@ -2034,6 +2060,9 @@ malware_init();
 #ifdef SUPPORT_SPF
 spf_init();
 #endif
+#ifndef DISABLE_TLS
+tls_daemon_init();
+#endif
 
 /* Close the log so it can be renamed and moved. In the few cases below where
 this long-running process writes to the log (always exceptional conditions), it
@@ -2266,14 +2295,24 @@ for (;;)
 
   if (f.daemon_listen)
     {
-    int lcount, select_errno;
+    int lcount;
     int max_socket = 0;
     BOOL select_failed = FALSE;
     fd_set select_listen;
 
     FD_ZERO(&select_listen);
+#ifndef DISABLE_TLS
+    if (tls_watch_fd >= 0)
+      {
+      FD_SET(tls_watch_fd, &select_listen);
+      if (tls_watch_fd > max_socket) max_socket = tls_watch_fd;
+      }
+#endif
     if (daemon_notifier_fd >= 0)
+      {
       FD_SET(daemon_notifier_fd, &select_listen);
+      if (daemon_notifier_fd > max_socket) max_socket = daemon_notifier_fd;
+      }
     for (int sk = 0; sk < listen_socket_count; sk++)
       {
       FD_SET(listen_sockets[sk], &select_listen);
@@ -2311,14 +2350,16 @@ for (;;)
     old one had just finished. Preserve the errno from any select() failure for
     the use of the common select/accept error processing below. */
 
-    select_errno = errno;
-    handle_ending_processes();
-    errno = select_errno;
+      {
+      int select_errno = errno;
+      handle_ending_processes();
 
 #ifndef DISABLE_TLS
-    /* Create or rotate any required keys */
-    tls_daemon_init();
+      /* Create or rotate any required keys; handle (delayed) filewatch event */
+      tls_daemon_tick();
 #endif
+      errno = select_errno;
+      }
 
     /* Loop for all the sockets that are currently ready to go. If select
     actually failed, we have set the count to 1 and select_failed=TRUE, so as
@@ -2330,6 +2371,15 @@ for (;;)
 
       if (!select_failed)
        {
+#if !defined(DISABLE_TLS) && (defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT))
+       if (tls_watch_fd >= 0 && FD_ISSET(tls_watch_fd, &select_listen))
+         {
+         FD_CLR(tls_watch_fd, &select_listen);
+          tls_watch_trigger_time = time(NULL); /* Set up delayed event */
+         tls_watch_discard_event(tls_watch_fd);
+         break;        /* to top of daemon loop */
+         }
+#endif
        if (  daemon_notifier_fd >= 0
           && FD_ISSET(daemon_notifier_fd, &select_listen))
          {
@@ -2365,45 +2415,43 @@ for (;;)
           accept_retry_errno = errno;
           accept_retry_select_failed = select_failed;
           }
-        else
-          {
-          if (errno != accept_retry_errno ||
-              select_failed != accept_retry_select_failed ||
-              accept_retry_count >= 50)
+        else if (  errno != accept_retry_errno 
+               || select_failed != accept_retry_select_failed
+               || accept_retry_count >= 50)
             {
-            log_write(0, LOG_MAIN | ((accept_retry_count >= 50)? LOG_PANIC : 0),
+            log_write(0, LOG_MAIN | (accept_retry_count >= 50 ? LOG_PANIC : 0),
               "%d %s() failure%s: %s",
               accept_retry_count,
-              accept_retry_select_failed? "select" : "accept",
-              (accept_retry_count == 1)? "" : "s",
+              accept_retry_select_failed ? "select" : "accept",
+              accept_retry_count == 1 ? "" : "s",
               strerror(accept_retry_errno));
             log_close_all();
             accept_retry_count = 0;
             accept_retry_errno = errno;
             accept_retry_select_failed = select_failed;
             }
-          }
         accept_retry_count++;
         }
-
-      else
-        {
-        if (accept_retry_count > 0)
-          {
-          log_write(0, LOG_MAIN, "%d %s() failure%s: %s",
-            accept_retry_count,
-            accept_retry_select_failed? "select" : "accept",
-            (accept_retry_count == 1)? "" : "s",
-            strerror(accept_retry_errno));
-          log_close_all();
-          accept_retry_count = 0;
-          }
-        }
+      else if (accept_retry_count > 0)
+       {
+       log_write(0, LOG_MAIN, "%d %s() failure%s: %s",
+         accept_retry_count,
+         accept_retry_select_failed ? "select" : "accept",
+         accept_retry_count == 1 ? "" : "s",
+         strerror(accept_retry_errno));
+       log_close_all();
+       accept_retry_count = 0;
+       }
 
       /* If select/accept succeeded, deal with the connection. */
 
       if (accept_socket >= 0)
         {
+#ifdef TCP_QUICKACK /* Avoid pure-ACKs while in tls protocol pingpong phase */
+       /* Unfortunately we cannot be certain to do this before a TLS-on-connect
+       Client Hello arrives and is acked. We do it as early as possible. */
+       (void) setsockopt(accept_socket, IPPROTO_TCP, TCP_QUICKACK, US &off, sizeof(off));
+#endif
         if (inetd_wait_timeout)
           last_connection_time = time(NULL);
         handle_smtp_call(listen_sockets, listen_socket_count, accept_socket,