SPDX: license tags (mostly by guesswork)
[exim.git] / src / src / daemon.c
index 4a3cb6adbeea99b1bd5a957442bcc5f72ccff690..0afc7ca86611cd8e98b97965ef8d3aa54c650715 100644 (file)
@@ -2,9 +2,10 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
+/* Copyright (c) The Exim Maintainers 2020 - 2022 */
 /* Copyright (c) University of Cambridge 1995 - 2018 */
-/* Copyright (c) The Exim Maintainers 2020 - 2021 */
 /* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-only */
 
 /* Functions concerned with running Exim as a daemon */
 
@@ -1132,13 +1133,43 @@ exim_exit(EXIT_SUCCESS);
 *      Listener socket for local work prompts   *
 *************************************************/
 
+ssize_t
+daemon_client_sockname(struct sockaddr_un * sup, uschar ** sname)
+{
+#ifdef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
+sup->sun_path[0] = 0;  /* Abstract local socket addr - Linux-specific? */
+return offsetof(struct sockaddr_un, sun_path) + 1
+  + snprintf(sup->sun_path+1, sizeof(sup->sun_path)-1, "exim_%d", getpid());
+#else
+*sname = string_sprintf("%s/p_%d", spool_directory, getpid());
+return offsetof(struct sockaddr_un, sun_path)
+  + snprintf(sup->sun_path, sizeof(sup->sun_path), "%s", sname);
+#endif
+}
+
+ssize_t
+daemon_notifier_sockname(struct sockaddr_un * sup)
+{
+#ifdef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
+sup->sun_path[0] = 0;  /* Abstract local socket addr - Linux-specific? */
+return offsetof(struct sockaddr_un, sun_path) + 1
+  + snprintf(sup->sun_path+1, sizeof(sup->sun_path)-1, "%s",
+              expand_string(notifier_socket));
+#else
+return offsetof(struct sockaddr_un, sun_path)
+  + snprintf(sup->sun_path, sizeof(sup->sun_path), "%s",
+              expand_string(notifier_socket));
+#endif
+}
+
+
 static void
 daemon_notifier_socket(void)
 {
 int fd;
 const uschar * where;
 struct sockaddr_un sa_un = {.sun_family = AF_UNIX};
-int len;
+ssize_t len;
 
 if (!notifier_socket || !*notifier_socket)
   {
@@ -1163,20 +1194,15 @@ if ((fd = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0)
 (void)fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
 #endif
 
+len = daemon_notifier_sockname(&sa_un);
+
 #ifdef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
-sa_un.sun_path[0] = 0; /* Abstract local socket addr - Linux-specific? */
-len = offsetof(struct sockaddr_un, sun_path) + 1
-  + snprintf(sa_un.sun_path+1, sizeof(sa_un.sun_path)-1, "%s",
-             expand_string(notifier_socket));
 DEBUG(D_any) debug_printf(" @%s\n", sa_un.sun_path+1);
 #else                  /* filesystem-visible and persistent; will neeed removal */
-len = offsetof(struct sockaddr_un, sun_path)
-  + snprintf(sa_un.sun_path, sizeof(sa_un.sun_path), "%s",
-             expand_string(notifier_socket));
 DEBUG(D_any) debug_printf(" %s\n", sa_un.sun_path);
 #endif
 
-if (bind(fd, (const struct sockaddr *)&sa_un, len) < 0)
+if (bind(fd, (const struct sockaddr *)&sa_un, (socklen_t)len) < 0)
   { where = US"bind"; goto bad; }
 
 #ifdef SO_PASSCRED             /* Linux */
@@ -1205,7 +1231,11 @@ bad:
 
 static uschar queuerun_msgid[MESSAGE_ID_LENGTH+1];
 
-/* Return TRUE if a sigalrm should be emulated */
+/* The notifier socket has something to read. Pull the message from it, decode
+and do the action.
+
+Return TRUE if a sigalrm should be emulated */
+
 static BOOL
 daemon_notification(void)
 {
@@ -1255,7 +1285,6 @@ for (struct cmsghdr * cp = CMSG_FIRSTHDR(&msg);
     {
     DEBUG(D_queue_run) debug_printf("%s: sender creds pid %d uid %d gid %d\n",
       __FUNCTION__, (int)cr->pid, (int)cr->uid, (int)cr->gid);
-    return FALSE;
     }
 # elif defined(LOCAL_CREDS)                            /* BSD-ish */
   struct sockcred * cr = (struct sockcred *) CMSG_DATA(cp);
@@ -1263,7 +1292,6 @@ for (struct cmsghdr * cp = CMSG_FIRSTHDR(&msg);
     {
     DEBUG(D_queue_run) debug_printf("%s: sender creds pid ??? uid %d gid %d\n",
       __FUNCTION__, (int)cr->sc_uid, (int)cr->sc_gid);
-    return FALSE;
     }
 # endif
   break;
@@ -1294,15 +1322,18 @@ switch (buf[0])
                (const struct sockaddr *)&sa_un, msg.msg_namelen) < 0)
       log_write(0, LOG_MAIN|LOG_PANIC,
        "%s: sendto: %s\n", __FUNCTION__, strerror(errno));
-    return FALSE;
+    break;
     }
+
+  case NOTIFY_REGEX:
+    regex_at_daemon(buf);
+    break;
   }
 return FALSE;
 }
 
 
 
-
 /*************************************************
 *              Exim Daemon Mainline              *
 *************************************************/
@@ -1346,7 +1377,7 @@ DEBUG(D_any|D_v) debug_selector |= D_pid;
 /* Allocate enough pollstructs for inetd mode plus the ancillary sockets;
 also used when there are no listen sockets. */
 
-fd_polls = store_get(sizeof(struct pollfd) * 3, FALSE);
+fd_polls = store_get(sizeof(struct pollfd) * 3, GET_UNTAINTED);
 
 if (f.inetd_wait_mode)
   {
@@ -1534,7 +1565,7 @@ if (f.daemon_listen && !f.inetd_wait_mode)
   sep = 0;
   while ((s = string_nextinlist(&list, &sep, NULL, 0)))
     pct++;
-  default_smtp_port = store_get((pct+1) * sizeof(int), FALSE);
+  default_smtp_port = store_get((pct+1) * sizeof(int), GET_UNTAINTED);
   list = daemon_smtp_port;
   sep = 0;
   for (pct = 0;
@@ -1623,7 +1654,7 @@ if (f.daemon_listen && !f.inetd_wait_mode)
     ipa->port = default_smtp_port[0];
     for (int i = 1; default_smtp_port[i] > 0; i++)
       {
-      ip_address_item *new = store_get(sizeof(ip_address_item), FALSE);
+      ip_address_item * new = store_get(sizeof(ip_address_item), GET_UNTAINTED);
 
       memcpy(new->address, ipa->address, Ustrlen(ipa->address) + 1);
       new->port = default_smtp_port[i];
@@ -1683,7 +1714,7 @@ if (f.daemon_listen && !f.inetd_wait_mode)
   for (ipa = addresses; ipa; ipa = ipa->next)
     listen_socket_count++;
   fd_polls = store_get(sizeof(struct pollfd) * (listen_socket_count + 2),
-                           FALSE);
+                           GET_UNTAINTED);
   for (struct pollfd * p = fd_polls; p < fd_polls + listen_socket_count + 2;
        p++)
     { p->fd = -1; p->events = POLLIN; }
@@ -1709,7 +1740,7 @@ if (f.daemon_listen)
 
   if (smtp_accept_max > 0)
     {
-    smtp_slots = store_get(smtp_accept_max * sizeof(smtp_slot), FALSE);
+    smtp_slots = store_get(smtp_accept_max * sizeof(smtp_slot), GET_UNTAINTED);
     for (int i = 0; i < smtp_accept_max; i++) smtp_slots[i] = empty_smtp_slot;
     }
   }
@@ -1746,15 +1777,19 @@ if (f.background_daemon)
   daemon as the result of a SIGHUP. In this case, there is no need to do
   anything, because the controlling terminal has long gone. Otherwise, fork, in
   case current process is a process group leader (see 'man setsid' for an
-  explanation) before calling setsid(). */
+  explanation) before calling setsid().
+  All other forks want daemon_listen cleared. Rather than blow a register, jsut
+  restore it here. */
 
   if (getppid() != 1)
     {
+    BOOL daemon_listen = f.daemon_listen;
     pid_t pid = exim_fork(US"daemon");
     if (pid < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE,
       "fork() failed when starting daemon: %s", strerror(errno));
     if (pid > 0) exit(EXIT_SUCCESS);      /* in parent process, just exit */
     (void)setsid();                       /* release controlling terminal */
+    f.daemon_listen = daemon_listen;
     }
   }
 
@@ -1991,7 +2026,7 @@ of them (and also if we are doing queue runs). */
 
 if (queue_interval > 0 && local_queue_run_max > 0)
   {
-  queue_pid_slots = store_get(local_queue_run_max * sizeof(pid_t), FALSE);
+  queue_pid_slots = store_get(local_queue_run_max * sizeof(pid_t), GET_UNTAINTED);
   for (int i = 0; i < local_queue_run_max; i++) queue_pid_slots[i] = 0;
   }
 
@@ -2092,7 +2127,7 @@ else if (f.daemon_listen)
              if (*--p == '}') *p = '\0';       /* drop EOL */
              while (isdigit(*--p)) ;           /* char before port */
 
-             i2->log = *p == ':'               /* no list yet? */
+             i2->log = *p == ':'               /* no list yet?     { */
                ? string_sprintf("%.*s{%s,%d}",
                  (int)(p - i2->log + 1), i2->log, p+1, ipa->port)
                : string_sprintf("%s,%d}", i2->log, ipa->port);