Make BOOL unsigned; fix resulting latent bugs
[exim.git] / src / src / daemon.c
index de794f693ddc54713f2cb3b8b4be4900be833949..779518f9f3b3c607599a19fd359182880cae2d2b 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2009 */
+/* Copyright (c) University of Cambridge 1995 - 2016 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions concerned with running Exim as a daemon */
@@ -145,7 +145,7 @@ int dup_accept_socket = -1;
 int max_for_this_host = 0;
 int wfsize = 0;
 int wfptr = 0;
-int use_log_write_selector = log_write_selector;
+int save_log_selector = *log_selector;
 uschar *whofrom = NULL;
 
 void *reset_point = store_get(0);
@@ -206,11 +206,11 @@ memory is reclaimed. */
 
 whofrom = string_append(whofrom, &wfsize, &wfptr, 3, "[", sender_host_address, "]");
 
-if ((log_extra_selector & LX_incoming_port) != 0)
+if (LOGGING(incoming_port))
   whofrom = string_append(whofrom, &wfsize, &wfptr, 2, ":", string_sprintf("%d",
     sender_host_port));
 
-if ((log_extra_selector & LX_incoming_interface) != 0)
+if (LOGGING(incoming_interface))
   whofrom = string_append(whofrom, &wfsize, &wfptr, 4, " I=[",
     interface_address, "]:", string_sprintf("%d", interface_port));
 
@@ -338,11 +338,12 @@ the generalized logging code each time when the selector is false. If the
 selector is set, check whether the host is on the list for logging. If not,
 arrange to unset the selector in the subprocess. */
 
-if ((log_write_selector & L_smtp_connection) != 0)
+if (LOGGING(smtp_connection))
   {
   uschar *list = hosts_connection_nolog;
+  memset(sender_host_cache, 0, sizeof(sender_host_cache));
   if (list != NULL && verify_check_host(&list) == OK)
-    use_log_write_selector &= ~L_smtp_connection;
+    save_log_selector &= ~L_smtp_connection;
   else
     log_write(L_smtp_connection, LOG_MAIN, "SMTP connection from %s "
       "(TCP/IP connection count = %d)", whofrom, smtp_accept_count + 1);
@@ -372,7 +373,7 @@ if (pid == 0)
 
   /* May have been modified for the subprocess */
 
-  log_write_selector = use_log_write_selector;
+  *log_selector = save_log_selector;
 
   /* Get the local interface address into permanent store */
 
@@ -382,7 +383,7 @@ if (pid == 0)
 
   /* Check for a tls-on-connect port */
 
-  if (host_is_tls_on_connect_port(interface_port)) tls_on_connect = TRUE;
+  if (host_is_tls_on_connect_port(interface_port)) tls_in.on_connect = TRUE;
 
   /* Expand smtp_active_hostname if required. We do not do this any earlier,
   because it may depend on the local interface address (indeed, that is most
@@ -639,7 +640,7 @@ if (pid == 0)
         the data structures if necessary. */
 
         #ifdef SUPPORT_TLS
-        tls_close(FALSE);
+        tls_close(TRUE, FALSE);
         #endif
 
         /* Reset SIGHUP and SIGCHLD in the child in both cases. */
@@ -650,8 +651,8 @@ if (pid == 0)
         if (geteuid() != root_uid && !deliver_drop_privilege)
           {
           signal(SIGALRM, SIG_DFL);
-          (void)child_exec_exim(CEE_EXEC_PANIC, FALSE, NULL, FALSE, 2, US"-Mc",
-            message_id);
+          (void)child_exec_exim(CEE_EXEC_PANIC, FALSE, NULL, FALSE,
+           2, US"-Mc", message_id);
           /* Control does not return here. */
           }
 
@@ -735,6 +736,7 @@ 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. */
 
+log_close_all();
 store_reset(reset_point);
 sender_host_address = NULL;
 }
@@ -864,10 +866,10 @@ while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
   /* If it wasn't an accepting process, see if it was a queue-runner
   process that we are tracking. */
 
-  if (queue_pid_slots != NULL)
+  if (queue_pid_slots)
     {
-    for (i = 0; i < queue_run_max; i++)
-      {
+    int max = atoi(expand_string(queue_run_max));
+    for (i = 0; i < max; i++)
       if (queue_pid_slots[i] == pid)
         {
         queue_pid_slots[i] = 0;
@@ -876,7 +878,6 @@ while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
           queue_run_count, (queue_run_count == 1)? "" : "es");
         break;
         }
-      }
     }
   }
 }
@@ -914,6 +915,7 @@ int *listen_sockets = NULL;
 int listen_socket_count = 0;
 ip_address_item *addresses = NULL;
 time_t last_connection_time = (time_t)0;
+int local_queue_run_max = atoi(expand_string(queue_run_max));
 
 /* If any debugging options are set, turn on the D_pid bit so that all
 debugging lines get the pid added. */
@@ -925,13 +927,12 @@ if (inetd_wait_mode)
   int on = 1;
 
   listen_socket_count = 1;
-  listen_sockets = store_get(sizeof(int *));
+  listen_sockets = store_get(sizeof(int));
   (void) close(3);
   if (dup2(0, 3) == -1)
-    {
     log_write(0, LOG_MAIN|LOG_PANIC_DIE,
         "failed to dup inetd socket safely away: %s", strerror(errno));
-    }
+
   listen_sockets[0] = 3;
   (void) close(0);
   (void) close(1);
@@ -955,8 +956,10 @@ if (inetd_wait_mode)
   /* As per below, when creating sockets ourselves, we handle tcp_nodelay for
   our own buffering; we assume though that inetd set the socket REUSEADDR. */
 
-  if (tcp_nodelay) setsockopt(3, IPPROTO_TCP, TCP_NODELAY,
-    (uschar *)(&on), sizeof(on));
+  if (tcp_nodelay)
+    if (setsockopt(3, IPPROTO_TCP, TCP_NODELAY, US &on, sizeof(on)))
+      log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to set socket NODELAY: %s",
+       strerror(errno));
   }
 
 
@@ -1042,13 +1045,13 @@ The preparation code decodes options and sets up the relevant data. We do this
 first, so that we can return non-zero if there are any syntax errors, and also
 write to stderr. */
 
-else if (daemon_listen)
+if (daemon_listen && !inetd_wait_mode)
   {
   int *default_smtp_port;
   int sep;
   int pct = 0;
   uschar *s;
-  uschar *list;
+  const uschar * list;
   uschar *local_iface_source = US"local_interfaces";
   ip_address_item *ipa;
   ip_address_item **pipa;
@@ -1071,8 +1074,7 @@ else if (daemon_listen)
 
     list = override_local_interfaces;
     sep = 0;
-    while ((s = string_nextinlist(&list,&sep,big_buffer,big_buffer_size))
-           != NULL)
+    while ((s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
       {
       uschar joinstr[4];
       uschar **ptr;
@@ -1096,11 +1098,11 @@ else if (daemon_listen)
         {
         joinstr[0] = sep;
         joinstr[1] = ' ';
-        *ptr = string_cat(*ptr, sizeptr, ptrptr, US"<", 1);
+        *ptr = string_catn(*ptr, sizeptr, ptrptr, US"<", 1);
         }
 
-      *ptr = string_cat(*ptr, sizeptr, ptrptr, joinstr, 2);
-      *ptr = string_cat(*ptr, sizeptr, ptrptr, s, Ustrlen(s));
+      *ptr = string_catn(*ptr, sizeptr, ptrptr, joinstr, 2);
+      *ptr = string_cat (*ptr, sizeptr, ptrptr, s);
       }
 
     if (new_smtp_port != NULL)
@@ -1127,13 +1129,13 @@ else if (daemon_listen)
 
   list = daemon_smtp_port;
   sep = 0;
-  while ((s = string_nextinlist(&list,&sep,big_buffer,big_buffer_size)) != NULL)
+  while ((s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
     pct++;
   default_smtp_port = store_get((pct+1) * sizeof(int));
   list = daemon_smtp_port;
   sep = 0;
   for (pct = 0;
-       (s = string_nextinlist(&list,&sep,big_buffer,big_buffer_size)) != NULL;
+       (s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size));
        pct++)
     {
     if (isdigit(*s))
@@ -1146,13 +1148,38 @@ else if (daemon_listen)
     else
       {
       struct servent *smtp_service = getservbyname(CS s, "tcp");
-      if (smtp_service == NULL)
+      if (!smtp_service)
         log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "TCP port \"%s\" not found", s);
       default_smtp_port[pct] = ntohs(smtp_service->s_port);
       }
     }
   default_smtp_port[pct] = 0;
 
+  /* Check the list of TLS-on-connect ports and do name lookups if needed */
+
+  list = tls_in.on_connect_ports;
+  sep = 0;
+  while ((s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
+    if (!isdigit(*s))
+      {
+      list = tls_in.on_connect_ports;
+      tls_in.on_connect_ports = NULL;
+      sep = 0;
+      while ((s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
+       {
+        if (!isdigit(*s))
+         {
+         struct servent *smtp_service = getservbyname(CS s, "tcp");
+         if (!smtp_service)
+           log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "TCP port \"%s\" not found", s);
+         s= string_sprintf("%d", (int)ntohs(smtp_service->s_port));
+         }
+       tls_in.on_connect_ports = string_append_listele(tls_in.on_connect_ports,
+           ':', s);
+       }
+      break;
+      }
+
   /* Create the list of local interfaces, possibly with ports included. This
   list may contain references to 0.0.0.0 and ::0 as wildcards. These special
   values are converted below. */
@@ -1250,7 +1277,7 @@ else if (daemon_listen)
 
   for (ipa = addresses; ipa != NULL; ipa = ipa->next)
     listen_socket_count++;
-  listen_sockets = store_get(sizeof(int *) * listen_socket_count);
+  listen_sockets = store_get(sizeof(int) * listen_socket_count);
 
   } /* daemon_listen but not inetd_wait_mode */
 
@@ -1355,8 +1382,7 @@ if (daemon_listen && !inetd_wait_mode)
       wildcard = ipa->address[0] == 0;
       }
 
-    listen_sockets[sk] = ip_socket(SOCK_STREAM, af);
-    if (listen_sockets[sk] < 0)
+    if ((listen_sockets[sk] = ip_socket(SOCK_STREAM, af)) < 0)
       {
       if (check_special_case(0, addresses, ipa, FALSE))
         {
@@ -1546,11 +1572,11 @@ originator_login = ((pw = getpwuid(exim_uid)) != NULL)?
 /* 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). */
 
-if (queue_interval > 0 && queue_run_max > 0)
+if (queue_interval > 0 && local_queue_run_max > 0)
   {
   int i;
-  queue_pid_slots = store_get(queue_run_max * sizeof(pid_t));
-  for (i = 0; i < queue_run_max; i++) queue_pid_slots[i] = 0;
+  queue_pid_slots = store_get(local_queue_run_max * sizeof(pid_t));
+  for (i = 0; i < local_queue_run_max; i++) queue_pid_slots[i] = 0;
   }
 
 /* Set up the handler for termination of child processes. */
@@ -1578,7 +1604,7 @@ if (inetd_wait_mode)
   log_write(0, LOG_MAIN,
     "exim %s daemon started: pid=%d, launched with listening socket, %s",
     version_string, getpid(), big_buffer);
-  set_process_info("daemon: pre-listening socket");
+  set_process_info("daemon(%s): pre-listening socket", version_string);
 
   /* set up the timeout logic */
   sigalrm_seen = 1;
@@ -1589,12 +1615,11 @@ else if (daemon_listen)
   int i, j;
   int smtp_ports = 0;
   int smtps_ports = 0;
-  ip_address_item *ipa;
-  uschar *p = big_buffer;
-  uschar *qinfo = (queue_interval > 0)?
-    string_sprintf("-q%s", readconf_printtime(queue_interval))
-    :
-    US"no queue runs";
+  ip_address_item * ipa;
+  uschar * p = big_buffer;
+  uschar * qinfo = queue_interval > 0
+    ? string_sprintf("-q%s", readconf_printtime(queue_interval))
+    : US"no queue runs";
 
   /* Build a list of listening addresses in big_buffer, but limit it to 10
   items. The style is for backwards compatibility.
@@ -1605,30 +1630,30 @@ else if (daemon_listen)
 
   for (j = 0; j < 2; j++)
     {
-    for (i = 0, ipa = addresses; i < 10 && ipa != NULL; i++, ipa = ipa->next)
+    for (i = 0, ipa = addresses; i < 10 && ipa; i++, ipa = ipa->next)
        {
        /* First time round, look for SMTP ports; second time round, look for
        SMTPS ports. For the first one of each, insert leading text. */
 
        if (host_is_tls_on_connect_port(ipa->port) == (j > 0))
          {
-         if (j == 0)
-           {
-           if (smtp_ports++ == 0)
+        if (j == 0)
+          {
+          if (smtp_ports++ == 0)
              {
              memcpy(p, "SMTP on", 8);
              p += 7;
              }
-           }
-         else
-           {
-           if (smtps_ports++ == 0)
+          }
+        else
+          {
+          if (smtps_ports++ == 0)
              {
              (void)sprintf(CS p, "%sSMTPS on",
-               (smtp_ports == 0)? "":" and for ");
-             while (*p != 0) p++;
+               smtp_ports == 0 ? "" : " and for ");
+             while (*p) p++;
              }
-           }
+          }
 
          /* Now the information about the port (and sometimes interface) */
 
@@ -1653,7 +1678,7 @@ else if (daemon_listen)
          }
        }
 
-    if (ipa != NULL)
+    if (ipa)
       {
       memcpy(p, " ...", 5);
       p += 4;
@@ -1663,18 +1688,29 @@ else if (daemon_listen)
   log_write(0, LOG_MAIN,
     "exim %s daemon started: pid=%d, %s, listening for %s",
     version_string, getpid(), qinfo, big_buffer);
-  set_process_info("daemon: %s, listening for %s", qinfo, big_buffer);
+  set_process_info("daemon(%s): %s, listening for %s",
+    version_string, qinfo, big_buffer);
   }
 
 else
   {
+  uschar * s = *queue_name
+    ? string_sprintf("-qG%s/%s", queue_name, readconf_printtime(queue_interval))
+    : string_sprintf("-q%s", readconf_printtime(queue_interval));
   log_write(0, LOG_MAIN,
-    "exim %s daemon started: pid=%d, -q%s, not listening for SMTP",
-    version_string, getpid(), readconf_printtime(queue_interval));
-  set_process_info("daemon: -q%s, not listening",
-    readconf_printtime(queue_interval));
+    "exim %s daemon started: pid=%d, %s, not listening for SMTP",
+    version_string, getpid(), s);
+  set_process_info("daemon(%s): %s, not listening", version_string, s);
   }
 
+/* Do any work it might be useful to amortize over our children
+(eg: compile regex) */
+
+dns_pattern_init();
+
+#ifdef WITH_CONTENT_SCAN
+malware_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
@@ -1756,7 +1792,7 @@ for (;;)
       re-exec is required. */
 
       if (queue_interval > 0 &&
-         (queue_run_max <= 0 || queue_run_count < queue_run_max))
+         (local_queue_run_max <= 0 || queue_run_count < local_queue_run_max))
         {
         if ((pid = fork()) == 0)
           {
@@ -1800,21 +1836,22 @@ for (;;)
             if (deliver_force_thaw) *p++ = 'f';
             if (queue_run_local) *p++ = 'l';
             *p = 0;
-            extra[0] = opt;
+           extra[0] = queue_name
+             ? string_sprintf("%sG%s", opt, queue_name) : opt;
 
             /* If -R or -S were on the original command line, ensure they get
             passed on. */
 
-            if (deliver_selectstring != NULL)
+            if (deliver_selectstring)
               {
-              extra[extracount++] = deliver_selectstring_regex? US"-Rr" : US"-R";
+              extra[extracount++] = deliver_selectstring_regex ? US"-Rr" : US"-R";
               extra[extracount++] = deliver_selectstring;
               }
 
-            if (deliver_selectstring_sender != NULL)
+            if (deliver_selectstring_sender)
               {
-              extra[extracount++] = deliver_selectstring_sender_regex?
-                US"-Sr" : US"-S";
+              extra[extracount++] = deliver_selectstring_sender_regex
+               ? US"-Sr" : US"-S";
               extra[extracount++] = deliver_selectstring_sender;
               }
 
@@ -1841,15 +1878,13 @@ for (;;)
         else
           {
           int i;
-          for (i = 0; i < queue_run_max; ++i)
-            {
+          for (i = 0; i < local_queue_run_max; ++i)
             if (queue_pid_slots[i] <= 0)
               {
               queue_pid_slots[i] = pid;
               queue_run_count++;
               break;
               }
-            }
           DEBUG(D_any) debug_printf("%d queue-runner process%s running\n",
             queue_run_count, (queue_run_count == 1)? "" : "es");
           }
@@ -2065,5 +2100,6 @@ for (;;)
 /* Control never reaches here */
 }
 
+/* vi: aw ai sw=2
+*/
 /* End of exim_daemon.c */
-