Update all copyright messages to cover 1995 - 2009. Remove tab from exim_checkaccess.src
[exim.git] / src / src / daemon.c
index dfd781116c019f1ae08bcfd42db4bec46f9c76b6..8e6d6673adf5f8e73539ba7fbc36f60e9a5c633d 100644 (file)
@@ -1,10 +1,10 @@
-/* $Cambridge: exim/src/src/daemon.c,v 1.4 2005/01/04 10:00:42 ph10 Exp $ */
+/* $Cambridge: exim/src/src/daemon.c,v 1.27 2009/11/16 19:50:36 nm4 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* Copyright (c) University of Cambridge 1995 - 2009 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions concerned with running Exim as a daemon */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions concerned with running Exim as a daemon */
@@ -39,8 +39,8 @@ static int   accept_retry_errno;
 static BOOL  accept_retry_select_failed;
 
 static int   queue_run_count = 0;
 static BOOL  accept_retry_select_failed;
 
 static int   queue_run_count = 0;
-static pid_t *queue_pid_slots;
-static smtp_slot *smtp_slots;
+static pid_t *queue_pid_slots = NULL;
+static smtp_slot *smtp_slots = NULL;
 
 static BOOL  write_pid = TRUE;
 
 
 static BOOL  write_pid = TRUE;
 
@@ -142,7 +142,7 @@ handle_smtp_call(int *listen_sockets, int listen_socket_count,
 {
 pid_t pid;
 union sockaddr_46 interface_sockaddr;
 {
 pid_t pid;
 union sockaddr_46 interface_sockaddr;
-SOCKLEN_T ifsize = sizeof(interface_sockaddr);
+EXIM_SOCKLEN_T ifsize = sizeof(interface_sockaddr);
 int dup_accept_socket = -1;
 int max_for_this_host = 0;
 int wfsize = 0;
 int dup_accept_socket = -1;
 int max_for_this_host = 0;
 int wfsize = 0;
@@ -186,13 +186,14 @@ if (smtp_in == NULL)
   goto ERROR_RETURN;
   }
 
   goto ERROR_RETURN;
   }
 
-/* Get the data for the local interface address. */
+/* Get the data for the local interface address. Panic for most errors, but
+"connection reset by peer" just means the connection went away. */
 
 if (getsockname(accept_socket, (struct sockaddr *)(&interface_sockaddr),
      &ifsize) < 0)
   {
 
 if (getsockname(accept_socket, (struct sockaddr *)(&interface_sockaddr),
      &ifsize) < 0)
   {
-  log_write(0, LOG_MAIN|LOG_PANIC, "getsockname() failed: %s",
-    strerror(errno));
+  log_write(0, LOG_MAIN | ((errno == ECONNRESET)? 0 : LOG_PANIC),
+    "getsockname() failed: %s", strerror(errno));
   smtp_printf("421 Local problem: getsockname() failed; please try again later\r\n");
   goto ERROR_RETURN;
   }
   smtp_printf("421 Local problem: getsockname() failed; please try again later\r\n");
   goto ERROR_RETURN;
   }
@@ -240,7 +241,7 @@ subprocess because it might take time. */
 
 if (smtp_load_reserve >= 0)
   {
 
 if (smtp_load_reserve >= 0)
   {
-  load_average = os_getloadavg();
+  load_average = OS_GETLOADAVG();
   if (smtp_reserve_hosts == NULL && load_average > smtp_load_reserve)
     {
     DEBUG(D_any) debug_printf("rejecting SMTP connection: load average = %.2f\n",
   if (smtp_reserve_hosts == NULL && load_average > smtp_load_reserve)
     {
     DEBUG(D_any) debug_printf("rejecting SMTP connection: load average = %.2f\n",
@@ -362,12 +363,15 @@ if (pid == 0)
   int i;
   int queue_only_reason = 0;
   int old_pool = store_pool;
   int i;
   int queue_only_reason = 0;
   int old_pool = store_pool;
-  int save_debug_selector = debug_selector; 
+  int save_debug_selector = debug_selector;
   BOOL local_queue_only;
   BOOL local_queue_only;
+  BOOL session_local_queue_only;
   #ifdef SA_NOCLDWAIT
   struct sigaction act;
   #endif
 
   #ifdef SA_NOCLDWAIT
   struct sigaction act;
   #endif
 
+  smtp_accept_count++;    /* So that it includes this process */
+
   /* May have been modified for the subprocess */
 
   log_write_selector = use_log_write_selector;
   /* May have been modified for the subprocess */
 
   log_write_selector = use_log_write_selector;
@@ -410,7 +414,7 @@ if (pid == 0)
   /* Initialize the queueing flags */
 
   queue_check_only();
   /* Initialize the queueing flags */
 
   queue_check_only();
-  local_queue_only = queue_only;
+  session_local_queue_only = queue_only;
 
   /* Close the listening sockets, and set the SIGCHLD handler to SIG_IGN.
   We also attempt to set things up so that children are automatically reaped,
 
   /* Close the listening sockets, and set the SIGCHLD handler to SIG_IGN.
   We also attempt to set things up so that children are automatically reaped,
@@ -419,7 +423,7 @@ if (pid == 0)
   extensive comment before the reception loop in exim.c for a fuller
   explanation of this logic. */
 
   extensive comment before the reception loop in exim.c for a fuller
   explanation of this logic. */
 
-  for (i = 0; i < listen_socket_count; i++) close(listen_sockets[i]);
+  for (i = 0; i < listen_socket_count; i++) (void)close(listen_sockets[i]);
 
   #ifdef SA_NOCLDWAIT
   act.sa_handler = SIG_IGN;
 
   #ifdef SA_NOCLDWAIT
   act.sa_handler = SIG_IGN;
@@ -433,16 +437,16 @@ if (pid == 0)
   /* Attempt to get an id from the sending machine via the RFC 1413
   protocol. We do this in the sub-process in order not to hold up the
   main process if there is any delay. Then set up the fullhost information
   /* Attempt to get an id from the sending machine via the RFC 1413
   protocol. We do this in the sub-process in order not to hold up the
   main process if there is any delay. Then set up the fullhost information
-  in case there is no HELO/EHLO. 
-  
-  If debugging is enabled only for the daemon, we must turn if off while 
-  finding the id, but turn it on again afterwards so that information about the 
+  in case there is no HELO/EHLO.
+
+  If debugging is enabled only for the daemon, we must turn if off while
+  finding the id, but turn it on again afterwards so that information about the
   incoming connection is output. */
   incoming connection is output. */
-  
+
   if (debug_daemon) debug_selector = 0;
   verify_get_ident(IDENT_PORT);
   host_build_sender_fullhost();
   if (debug_daemon) debug_selector = 0;
   verify_get_ident(IDENT_PORT);
   host_build_sender_fullhost();
-  debug_selector = save_debug_selector; 
+  debug_selector = save_debug_selector;
 
   DEBUG(D_any)
     debug_printf("Process %d is handling incoming connection from %s\n",
 
   DEBUG(D_any)
     debug_printf("Process %d is handling incoming connection from %s\n",
@@ -454,20 +458,27 @@ if (pid == 0)
   if (debug_daemon) debug_selector = 0;
 
   /* If there are too many child processes for immediate delivery,
   if (debug_daemon) debug_selector = 0;
 
   /* If there are too many child processes for immediate delivery,
-  set the local_queue_only flag, which is initialized from the
+  set the session_local_queue_only flag, which is initialized from the
   configured value and may therefore already be TRUE. Leave logging
   configured value and may therefore already be TRUE. Leave logging
-  till later so it will have a message id attached. */
+  till later so it will have a message id attached. Note that there is no
+  possibility of re-calculating this per-message, because the value of
+  smtp_accept_count does not change in this subprocess. */
 
 
-  if (smtp_accept_queue > 0 && smtp_accept_count >= smtp_accept_queue)
+  if (smtp_accept_queue > 0 && smtp_accept_count > smtp_accept_queue)
     {
     {
-    local_queue_only = TRUE;
+    session_local_queue_only = TRUE;
     queue_only_reason = 1;
     }
 
   /* Handle the start of the SMTP session, then loop, accepting incoming
   messages from the SMTP connection. The end will come at the QUIT command,
   when smtp_setup_msg() returns 0. A break in the connection causes the
     queue_only_reason = 1;
     }
 
   /* Handle the start of the SMTP session, then loop, accepting incoming
   messages from the SMTP connection. The end will come at the QUIT command,
   when smtp_setup_msg() returns 0. A break in the connection causes the
-  process to die (see accept.c). */
+  process to die (see accept.c).
+
+  NOTE: We do *not* call smtp_log_no_mail() if smtp_start_session() fails,
+  because a log line has already been written for all its failure exists
+  (usually "connection refused: <reason>") and writing another one is
+  unnecessary clutter. */
 
   if (!smtp_start_session())
     {
 
   if (!smtp_start_session())
     {
@@ -499,6 +510,7 @@ if (pid == 0)
       if (!ok)                            /* Connection was dropped */
         {
         mac_smtp_fflush();
       if (!ok)                            /* Connection was dropped */
         {
         mac_smtp_fflush();
+        smtp_log_no_mail();               /* Log no mail if configured */
         _exit(EXIT_SUCCESS);
         }
       if (message_id[0] == 0) continue;   /* No message was accepted */
         _exit(EXIT_SUCCESS);
         }
       if (message_id[0] == 0) continue;   /* No message was accepted */
@@ -507,6 +519,7 @@ if (pid == 0)
       {
       mac_smtp_fflush();
       search_tidyup();
       {
       mac_smtp_fflush();
       search_tidyup();
+      smtp_log_no_mail();                 /* Log no mail if configured */
       _exit((rc == 0)? EXIT_SUCCESS : EXIT_FAILURE);
       }
 
       _exit((rc == 0)? EXIT_SUCCESS : EXIT_FAILURE);
       }
 
@@ -540,26 +553,37 @@ if (pid == 0)
     store_reset(reset_point);
 
     /* If queue_only is set or if there are too many incoming connections in
     store_reset(reset_point);
 
     /* If queue_only is set or if there are too many incoming connections in
-    existence, local_queue_only will be TRUE. If it is not, check whether we
-    have received too many messages in this session for immediate delivery. If
-    not, and queue_only_load is set, check that the load average is below it.
-    Note that, once set, local_queue_only remains set for any subsequent
-    messages on the same SMTP connection. This is a deliberate choice; even
-    though the load average may fall, it doesn't seem right to deliver later
-    messages on the same call when not delivering earlier ones. */
-
-    if (!local_queue_only)
+    existence, session_local_queue_only will be TRUE. If it is not, check
+    whether we have received too many messages in this session for immediate
+    delivery. */
+
+    if (!session_local_queue_only &&
+        smtp_accept_queue_per_connection > 0 &&
+        receive_messagecount > smtp_accept_queue_per_connection)
       {
       {
-      if (smtp_accept_queue_per_connection > 0 &&
-          receive_messagecount > smtp_accept_queue_per_connection)
-        {
-        local_queue_only = TRUE;
-        queue_only_reason = 2;
-        }
-      else if (queue_only_load >= 0)
+      session_local_queue_only = TRUE;
+      queue_only_reason = 2;
+      }
+
+    /* Initialize local_queue_only from session_local_queue_only. If it is not
+    true, and queue_only_load is set, check that the load average is below it.
+    If local_queue_only is set by this means, we also set if for the session if
+    queue_only_load_latch is true (the default). This means that, once set,
+    local_queue_only remains set for any subsequent messages on the same SMTP
+    connection. This is a deliberate choice; even though the load average may
+    fall, it doesn't seem right to deliver later messages on the same call when
+    not delivering earlier ones. However, the are special circumstances such as
+    very long-lived connections from scanning appliances where this is not the
+    best strategy. In such cases, queue_only_load_latch should be set false. */
+
+    local_queue_only = session_local_queue_only;
+    if (!local_queue_only && queue_only_load >= 0)
+      {
+      local_queue_only = (load_average = OS_GETLOADAVG()) > queue_only_load;
+      if (local_queue_only)
         {
         {
-        local_queue_only = (load_average = os_getloadavg()) > queue_only_load;
-        if (local_queue_only) queue_only_reason = 3;
+        queue_only_reason = 3;
+        if (queue_only_load_latch) session_local_queue_only = TRUE;
         }
       }
 
         }
       }
 
@@ -603,8 +627,8 @@ if (pid == 0)
 
       if ((dpid = fork()) == 0)
         {
 
       if ((dpid = fork()) == 0)
         {
-        fclose(smtp_in);
-        fclose(smtp_out);
+        (void)fclose(smtp_in);
+        (void)fclose(smtp_out);
 
         /* Don't ever molest the parent's SSL connection, but do clean up
         the data structures if necessary. */
 
         /* Don't ever molest the parent's SSL connection, but do clean up
         the data structures if necessary. */
@@ -680,27 +704,28 @@ ERROR_RETURN:
 /* Close the streams associated with the socket which will also close the
 socket fds in this process. We can't do anything if fclose() fails, but
 logging brings it to someone's attention. However, "connection reset by peer"
 /* Close the streams associated with the socket which will also close the
 socket fds in this process. We can't do anything if fclose() fails, but
 logging brings it to someone's attention. However, "connection reset by peer"
-isn't really a problem, so skip that one. If the streams don't exist, something
-went wrong while setting things up. Make sure the socket descriptors are
-closed, in order to drop the connection. */
+isn't really a problem, so skip that one. On Solaris, a dropped connection can
+manifest itself as a broken pipe, so drop that one too. If the streams don't
+exist, something went wrong while setting things up. Make sure the socket
+descriptors are closed, in order to drop the connection. */
 
 if (smtp_out != NULL)
   {
 
 if (smtp_out != NULL)
   {
-  if (fclose(smtp_out) != 0 && errno != ECONNRESET)
+  if (fclose(smtp_out) != 0 && errno != ECONNRESET && errno != EPIPE)
     log_write(0, LOG_MAIN|LOG_PANIC, "daemon: fclose(smtp_out) failed: %s",
       strerror(errno));
   smtp_out = NULL;
   }
     log_write(0, LOG_MAIN|LOG_PANIC, "daemon: fclose(smtp_out) failed: %s",
       strerror(errno));
   smtp_out = NULL;
   }
-else close(accept_socket);
+else (void)close(accept_socket);
 
 if (smtp_in != NULL)
   {
 
 if (smtp_in != NULL)
   {
-  if (fclose(smtp_in) != 0 && errno != ECONNRESET)
+  if (fclose(smtp_in) != 0 && errno != ECONNRESET && errno != EPIPE)
     log_write(0, LOG_MAIN|LOG_PANIC, "daemon: fclose(smtp_in) failed: %s",
       strerror(errno));
   smtp_in = NULL;
   }
     log_write(0, LOG_MAIN|LOG_PANIC, "daemon: fclose(smtp_in) failed: %s",
       strerror(errno));
   smtp_in = NULL;
   }
-else close(dup_accept_socket);
+else (void)close(dup_accept_socket);
 
 /* Release any store used in this process, including the store used for holding
 the incoming host address and an expanded active_hostname. */
 
 /* Release any store used in this process, including the store used for holding
 the incoming host address and an expanded active_hostname. */
@@ -776,6 +801,72 @@ return FALSE;
 
 
 
 
 
 
+/*************************************************
+*         Handle terminating subprocesses        *
+*************************************************/
+
+/* Handle the termination of child processes. Theoretically, this need be done
+only when sigchld_seen is TRUE, but rumour has it that some systems lose
+SIGCHLD signals at busy times, so to be on the safe side, this function is
+called each time round. It shouldn't be too expensive.
+
+Arguments:  none
+Returns:    nothing
+*/
+
+static void
+handle_ending_processes(void)
+{
+int status;
+pid_t pid;
+
+while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
+  {
+  int i;
+  DEBUG(D_any) debug_printf("child %d ended: status=0x%x\n", (int)pid,
+    status);
+
+  /* If it's a listening daemon for which we are keeping track of individual
+  subprocesses, deal with an accepting process that has terminated. */
+
+  if (smtp_slots != NULL)
+    {
+    for (i = 0; i < smtp_accept_max; i++)
+      {
+      if (smtp_slots[i].pid == pid)
+        {
+        if (smtp_slots[i].host_address != NULL)
+          store_free(smtp_slots[i].host_address);
+        smtp_slots[i] = empty_smtp_slot;
+        if (--smtp_accept_count < 0) smtp_accept_count = 0;
+        DEBUG(D_any) debug_printf("%d SMTP accept process%s now running\n",
+          smtp_accept_count, (smtp_accept_count == 1)? "" : "es");
+        break;
+        }
+      }
+    if (i < smtp_accept_max) continue;  /* Found an accepting process */
+    }
+
+  /* If it wasn't an accepting process, see if it was a queue-runner
+  process that we are tracking. */
+
+  if (queue_pid_slots != NULL)
+    {
+    for (i = 0; i < queue_run_max; i++)
+      {
+      if (queue_pid_slots[i] == pid)
+        {
+        queue_pid_slots[i] = 0;
+        if (--queue_run_count < 0) queue_run_count = 0;
+        DEBUG(D_any) debug_printf("%d queue-runner process%s now running\n",
+          queue_run_count, (queue_run_count == 1)? "" : "es");
+        break;
+        }
+      }
+    }
+  }
+}
+
 
 
 /*************************************************
 
 
 /*************************************************
@@ -804,6 +895,7 @@ There are no arguments to this function, and it never returns. */
 void
 daemon_go(void)
 {
 void
 daemon_go(void)
 {
+struct passwd *pw;
 int *listen_sockets = NULL;
 int listen_socket_count = 0;
 ip_address_item *addresses = NULL;
 int *listen_sockets = NULL;
 int listen_socket_count = 0;
 ip_address_item *addresses = NULL;
@@ -898,7 +990,9 @@ if (daemon_listen)
   order to perform an "open" on the kernel memory file). */
 
   #ifdef LOAD_AVG_NEEDS_ROOT
   order to perform an "open" on the kernel memory file). */
 
   #ifdef LOAD_AVG_NEEDS_ROOT
-  if (queue_only_load >= 0 || smtp_load_reserve >= 0) (void)os_getloadavg();
+  if (queue_only_load >= 0 || smtp_load_reserve >= 0 ||
+       (deliver_queue_load_max >= 0 && deliver_drop_privilege))
+    (void)os_getloadavg();
   #endif
 
   /* If -oX was used, disable the writing of a pid file unless -oP was
   #endif
 
   /* If -oX was used, disable the writing of a pid file unless -oP was
@@ -1122,26 +1216,35 @@ if (daemon_listen)
     }
   }
 
     }
   }
 
-/* We now close all open file descriptors that we know about, and disconnect
-from the controlling terminal, unless background_daemon is unset. This is
-always unset when debugging, but can also be forced. Most modern Unixes seem to
-have setsid() for getting rid of the controlling terminal. For any OS that
-doesn't, setsid() can be #defined as a no-op, or as something else. */
+/* The variable background_daemon is always false when debugging, but
+can also be forced false in order to keep a non-debugging daemon in the
+foreground. If background_daemon is true, close all open file descriptors that
+we know about, but then re-open stdin, stdout, and stderr to /dev/null.
+
+This is protection against any called functions (in libraries, or in
+Perl, or whatever) that think they can write to stderr (or stdout). Before this
+was added, it was quite likely that an SMTP connection would use one of these
+file descriptors, in which case writing random stuff to it caused chaos.
+
+Then disconnect from the controlling terminal, Most modern Unixes seem to have
+setsid() for getting rid of the controlling terminal. For any OS that doesn't,
+setsid() can be #defined as a no-op, or as something else. */
 
 if (background_daemon)
   {
 
 if (background_daemon)
   {
-  log_close_all();  /* Just in case anything was logged earlier */
-  search_tidyup();  /* Just in case any were used in reading the config. */
-  close(0);         /* Get rid of stdin/stdout/stderr */
-  close(1);
-  close(2);
+  log_close_all();    /* Just in case anything was logged earlier */
+  search_tidyup();    /* Just in case any were used in reading the config. */
+  (void)close(0);           /* Get rid of stdin/stdout/stderr */
+  (void)close(1);
+  (void)close(2);
+  exim_nullstd();     /* Connect stdin/stdout/stderr to /dev/null */
   log_stderr = NULL;  /* So no attempt to copy paniclog output */
 
   /* If the parent process of this one has pid == 1, we are re-initializing the
   log_stderr = NULL;  /* So no attempt to copy paniclog output */
 
   /* If the parent process of this one has pid == 1, we are re-initializing the
-  daemon as the result of a SIGHUP. In this case, there is no need to do any
-  forking, because the controlling terminal has long gone. Otherwise, fork,
-  in case current process is a process group leader (see 'man setsid' for an
-  explanation). */
+  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(). */
 
   if (getppid() != 1)
     {
 
   if (getppid() != 1)
     {
@@ -1172,7 +1275,6 @@ if (daemon_listen)
     {
     BOOL wildcard;
     ip_address_item *ipa2;
     {
     BOOL wildcard;
     ip_address_item *ipa2;
-    int retries = 9;
     int af;
 
     if (Ustrchr(ipa->address, ':') != NULL)
     int af;
 
     if (Ustrchr(ipa->address, ':') != NULL)
@@ -1244,19 +1346,22 @@ if (daemon_listen)
         {
         DEBUG(D_any) debug_printf("wildcard IPv4 bind() failed after IPv6 "
           "listen() success; EADDRINUSE ignored\n");
         {
         DEBUG(D_any) debug_printf("wildcard IPv4 bind() failed after IPv6 "
           "listen() success; EADDRINUSE ignored\n");
-        close(listen_sockets[sk]);
+        (void)close(listen_sockets[sk]);
         goto SKIP_SOCKET;
         }
       msg = US strerror(errno);
       addr = wildcard? ((af == AF_INET6)? US"(any IPv6)" : US"(any IPv4)") :
         ipa->address;
         goto SKIP_SOCKET;
         }
       msg = US strerror(errno);
       addr = wildcard? ((af == AF_INET6)? US"(any IPv6)" : US"(any IPv4)") :
         ipa->address;
-      if (retries-- <= 0)
+      if (daemon_startup_retries <= 0)
         log_write(0, LOG_MAIN|LOG_PANIC_DIE,
           "socket bind() to port %d for address %s failed: %s: "
           "daemon abandoned", ipa->port, addr, msg);
       log_write(0, LOG_MAIN, "socket bind() to port %d for address %s "
         log_write(0, LOG_MAIN|LOG_PANIC_DIE,
           "socket bind() to port %d for address %s failed: %s: "
           "daemon abandoned", ipa->port, addr, msg);
       log_write(0, LOG_MAIN, "socket bind() to port %d for address %s "
-        "failed: %s: waiting before trying again", ipa->port, addr, msg);
-      sleep(30);
+        "failed: %s: waiting %s before trying again (%d more %s)",
+        ipa->port, addr, msg, readconf_printtime(daemon_startup_sleep),
+        daemon_startup_retries, (daemon_startup_retries > 1)? "tries" : "try");
+      daemon_startup_retries--;
+      sleep(daemon_startup_sleep);
       }
 
     DEBUG(D_any)
       }
 
     DEBUG(D_any)
@@ -1287,7 +1392,7 @@ if (daemon_listen)
 
     DEBUG(D_any) debug_printf("wildcard IPv4 listen() failed after IPv6 "
       "listen() success; EADDRINUSE ignored\n");
 
     DEBUG(D_any) debug_printf("wildcard IPv4 listen() failed after IPv6 "
       "listen() success; EADDRINUSE ignored\n");
-    close(listen_sockets[sk]);
+    (void)close(listen_sockets[sk]);
 
     /* Come here if there has been a problem with the socket which we
     are going to ignore. We remove the address from the chain, and back up the
 
     /* Come here if there has been a problem with the socket which we
     are going to ignore. We remove the address from the chain, and back up the
@@ -1335,12 +1440,11 @@ if (running_in_test_harness || write_pid)
   if (pid_file_path[0] == 0)
     pid_file_path = string_sprintf("%s/exim-daemon.pid", spool_directory);
 
   if (pid_file_path[0] == 0)
     pid_file_path = string_sprintf("%s/exim-daemon.pid", spool_directory);
 
-  f = Ufopen(pid_file_path, "wb");
+  f = modefopen(pid_file_path, "wb", 0644);
   if (f != NULL)
     {
   if (f != NULL)
     {
-    fprintf(f, "%d\n", (int)getpid());
-    fchmod(fileno(f), 0644);
-    fclose(f);
+    (void)fprintf(f, "%d\n", (int)getpid());
+    (void)fclose(f);
     DEBUG(D_any) debug_printf("pid written to %s\n", pid_file_path);
     }
   else
     DEBUG(D_any) debug_printf("pid written to %s\n", pid_file_path);
     }
   else
@@ -1364,6 +1468,14 @@ cannot do this. */
 
 exim_setugid(exim_uid, exim_gid, geteuid()==root_uid, US"running as a daemon");
 
 
 exim_setugid(exim_uid, exim_gid, geteuid()==root_uid, US"running as a daemon");
 
+/* Update the originator_xxx fields so that received messages as listed as
+coming from Exim, not whoever started the daemon. */
+
+originator_uid = exim_uid;
+originator_gid = exim_gid;
+originator_login = ((pw = getpwuid(exim_uid)) != NULL)?
+  string_copy_malloc(US pw->pw_name) : US"exim";
+
 /* Get somewhere to keep the list of queue-runner pids if we are keeping track
 of them (and also if we are doing queue runs). */
 
 /* Get somewhere to keep the list of queue-runner pids if we are keeping track
 of them (and also if we are doing queue runs). */
 
@@ -1501,8 +1613,7 @@ for (;;)
   struct sockaddr_in accepted;
   #endif
 
   struct sockaddr_in accepted;
   #endif
 
-  SOCKLEN_T len = sizeof(accepted);
-  int status;
+  EXIM_SOCKLEN_T len;
   pid_t pid;
 
   /* This code is placed first in the loop, so that it gets obeyed at the
   pid_t pid;
 
   /* This code is placed first in the loop, so that it gets obeyed at the
@@ -1523,19 +1634,20 @@ for (;;)
       if ((pid = fork()) == 0)
         {
         int sk;
       if ((pid = fork()) == 0)
         {
         int sk;
-        
+
         DEBUG(D_any) debug_printf("Starting queue-runner: pid %d\n",
           (int)getpid());
 
         /* Disable debugging if it's required only for the daemon process. We
         DEBUG(D_any) debug_printf("Starting queue-runner: pid %d\n",
           (int)getpid());
 
         /* Disable debugging if it's required only for the daemon process. We
-        leave the above message, because it ties up with the "child ended" 
+        leave the above message, because it ties up with the "child ended"
         debugging messages. */
 
         if (debug_daemon) debug_selector = 0;
         debugging messages. */
 
         if (debug_daemon) debug_selector = 0;
+
         /* Close any open listening sockets in the child */
 
         /* Close any open listening sockets in the child */
 
-        for (sk = 0; sk < listen_socket_count; sk++) close(listen_sockets[sk]);
+        for (sk = 0; sk < listen_socket_count; sk++)
+          (void)close(listen_sockets[sk]);
 
         /* Reset SIGHUP and SIGCHLD in the child in both cases. */
 
 
         /* Reset SIGHUP and SIGCHLD in the child in both cases. */
 
@@ -1549,6 +1661,8 @@ for (;;)
           {
           uschar opt[8];
           uschar *p = opt;
           {
           uschar opt[8];
           uschar *p = opt;
+          uschar *extra[5];
+          int extracount = 1;
 
           signal(SIGALRM, SIG_DFL);
           *p++ = '-';
 
           signal(SIGALRM, SIG_DFL);
           *p++ = '-';
@@ -1559,8 +1673,29 @@ for (;;)
           if (deliver_force_thaw) *p++ = 'f';
           if (queue_run_local) *p++ = 'l';
           *p = 0;
           if (deliver_force_thaw) *p++ = 'f';
           if (queue_run_local) *p++ = 'l';
           *p = 0;
+          extra[0] = opt;
+
+          /* If -R or -S were on the original command line, ensure they get
+          passed on. */
+
+          if (deliver_selectstring != NULL)
+            {
+            extra[extracount++] = deliver_selectstring_regex? US"-Rr" : US"-R";
+            extra[extracount++] = deliver_selectstring;
+            }
+
+          if (deliver_selectstring_sender != NULL)
+            {
+            extra[extracount++] = deliver_selectstring_sender_regex?
+              US"-Sr" : US"-S";
+            extra[extracount++] = deliver_selectstring_sender;
+            }
+
+          /* Overlay this process with a new execution. */
+
+          (void)child_exec_exim(CEE_EXEC_PANIC, FALSE, NULL, TRUE, extracount,
+            extra[0], extra[1], extra[2], extra[3], extra[4]);
 
 
-          (void)child_exec_exim(CEE_EXEC_PANIC, FALSE, NULL, TRUE, 1, opt);
           /* Control never returns here. */
           }
 
           /* Control never returns here. */
           }
 
@@ -1611,7 +1746,7 @@ for (;;)
 
   if (daemon_listen)
     {
 
   if (daemon_listen)
     {
-    int sk, lcount;
+    int sk, lcount, select_errno;
     int max_socket = 0;
     BOOL select_failed = FALSE;
     fd_set select_listen;
     int max_socket = 0;
     BOOL select_failed = FALSE;
     fd_set select_listen;
@@ -1624,31 +1759,42 @@ for (;;)
       }
 
     DEBUG(D_any) debug_printf("Listening...\n");
       }
 
     DEBUG(D_any) debug_printf("Listening...\n");
-    
-    /* In rare cases we may have had a SIGCHLD signal in the time between 
-    setting the handler (below) and getting back here. If so, pretend that the 
+
+    /* In rare cases we may have had a SIGCHLD signal in the time between
+    setting the handler (below) and getting back here. If so, pretend that the
     select() was interrupted so that we reap the child. This might still leave
     select() was interrupted so that we reap the child. This might still leave
-    a small window when a SIGCHLD could get lost. However, since we use SIGCHLD 
+    a small window when a SIGCHLD could get lost. However, since we use SIGCHLD
     only to do the reaping more quickly, it shouldn't result in anything other
     than a delay until something else causes a wake-up. */
 
     if (sigchld_seen)
       {
       lcount = -1;
     only to do the reaping more quickly, it shouldn't result in anything other
     than a delay until something else causes a wake-up. */
 
     if (sigchld_seen)
       {
       lcount = -1;
-      errno = EINTR;  
+      errno = EINTR;
       }
     else
       }
     else
-      {      
+      {
       lcount = select(max_socket + 1, (SELECT_ARG2_TYPE *)&select_listen,
         NULL, NULL, NULL);
       lcount = select(max_socket + 1, (SELECT_ARG2_TYPE *)&select_listen,
         NULL, NULL, NULL);
-      }   
+      }
 
     if (lcount < 0)
       {
       select_failed = TRUE;
       lcount = 1;
       }
 
     if (lcount < 0)
       {
       select_failed = TRUE;
       lcount = 1;
       }
-      
+
+    /* Clean up any subprocesses that may have terminated. We need to do this
+    here so that smtp_accept_max_per_host works when a connection to that host
+    has completed, and we are about to accept a new one. When this code was
+    later in the sequence, a new connection could be rejected, even though an
+    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;
+
     /* 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
     to use the common error code for select/accept below. */
     /* 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
     to use the common error code for select/accept below. */
@@ -1662,6 +1808,7 @@ for (;;)
           {
           if (FD_ISSET(listen_sockets[sk], &select_listen))
             {
           {
           if (FD_ISSET(listen_sockets[sk], &select_listen))
             {
+            len = sizeof(accepted);
             accept_socket = accept(listen_sockets[sk],
               (struct sockaddr *)&accepted, &len);
             FD_CLR(listen_sockets[sk], &select_listen);
             accept_socket = accept(listen_sockets[sk],
               (struct sockaddr *)&accepted, &len);
             FD_CLR(listen_sockets[sk], &select_listen);
@@ -1743,57 +1890,7 @@ for (;;)
     tv.tv_sec = queue_interval;
     tv.tv_usec = 0;
     select(0, NULL, NULL, NULL, &tv);
     tv.tv_sec = queue_interval;
     tv.tv_usec = 0;
     select(0, NULL, NULL, NULL, &tv);
-    }
-
-  /* Handle the termination of a child process. Theoretically, this need
-  be done only when sigchld_seen is TRUE, but rumour has it that some systems
-  lose SIGCHLD signals at busy times, so to be on the safe side, just
-  do it each time round. It shouldn't be too expensive. */
-
-  while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
-    {
-    int i;
-    DEBUG(D_any) debug_printf("child %d ended: status=0x%x\n", (int)pid,
-      status);
-
-    /* If it's a listening daemon, deal with an accepting process that has
-    terminated. */
-
-    if (daemon_listen)
-      {
-      for (i = 0; i < smtp_accept_max; i++)
-        {
-        if (smtp_slots[i].pid == pid)
-          {
-          if (smtp_slots[i].host_address != NULL)
-            store_free(smtp_slots[i].host_address);
-          smtp_slots[i] = empty_smtp_slot;
-          if (--smtp_accept_count < 0) smtp_accept_count = 0;
-          DEBUG(D_any) debug_printf("%d SMTP accept process%s now running\n",
-            smtp_accept_count, (smtp_accept_count == 1)? "" : "es");
-          break;
-          }
-        }
-      if (i < smtp_accept_max) continue;  /* Found an accepting process */
-      }
-
-    /* If it wasn't an accepting process, see if it was a queue-runner
-    process, if we are keeping track of them. */
-
-    if (queue_interval > 0)
-      {
-      for (i = 0; i < queue_run_max; i++)
-        {
-        if (queue_pid_slots[i] == pid)
-          {
-          queue_pid_slots[i] = 0;
-          if (--queue_run_count < 0) queue_run_count = 0;
-          DEBUG(D_any) debug_printf("%d queue-runner process%s now running\n",
-            queue_run_count, (queue_run_count == 1)? "" : "es");
-          break;
-          }
-        }
-      }
+    handle_ending_processes();
     }
 
   /* Re-enable the SIGCHLD handler if it has been run. It can't do it
     }
 
   /* Re-enable the SIGCHLD handler if it has been run. It can't do it
@@ -1818,7 +1915,8 @@ for (;;)
     int sk;
     log_write(0, LOG_MAIN, "pid %d: SIGHUP received: re-exec daemon",
       getpid());
     int sk;
     log_write(0, LOG_MAIN, "pid %d: SIGHUP received: re-exec daemon",
       getpid());
-    for (sk = 0; sk < listen_socket_count; sk++) close(listen_sockets[sk]);
+    for (sk = 0; sk < listen_socket_count; sk++)
+      (void)close(listen_sockets[sk]);
     alarm(0);
     signal(SIGHUP, SIG_IGN);
     sighup_argv[0] = exim_path;
     alarm(0);
     signal(SIGHUP, SIG_IGN);
     sighup_argv[0] = exim_path;