Testsuite: change port used for identd test
[users/jgh/exim.git] / src / src / exim.c
index 2b6297bf5d73524fbc6ac0945e33797134c50b2e..d62e9239b1d07ae6f904ca894dd8899b39b65fa7 100644 (file)
@@ -23,6 +23,10 @@ Also a few functions that don't naturally fit elsewhere. */
 # endif
 #endif
 
+#ifndef _TIME_H
+# include <time.h>
+#endif
+
 extern void init_lookup_list(void);
 
 
@@ -106,7 +110,7 @@ if (use_malloc)
   pcre_free = function_store_free;
   }
 if (caseless) options |= PCRE_CASELESS;
-yield = pcre_compile(CCS pattern, options, (const char **)&error, &offset, NULL);
+yield = pcre_compile(CCS pattern, options, CCSS &error, &offset, NULL);
 pcre_malloc = function_store_get;
 pcre_free = function_dummy_free;
 if (yield == NULL)
@@ -202,7 +206,7 @@ va_end(ap);
 static void
 term_handler(int sig)
 {
-  exit(1);
+exit(1);
 }
 
 
@@ -292,7 +296,7 @@ will wait for ever, so we panic in this instance. (There was a case of this
 when a bug in a function that calls milliwait() caused it to pass invalid data.
 That's when I added the check. :-)
 
-We assume it to be not worth sleeping for under 100us; this value will
+We assume it to be not worth sleeping for under 50us; this value will
 require revisiting as hardware advances.  This avoids the issue of
 a zero-valued timer setting meaning "never fire".
 
@@ -306,7 +310,7 @@ milliwait(struct itimerval *itval)
 sigset_t sigmask;
 sigset_t old_sigmask;
 
-if (itval->it_value.tv_usec < 100 && itval->it_value.tv_sec == 0)
+if (itval->it_value.tv_usec < 50 && itval->it_value.tv_sec == 0)
   return;
 (void)sigemptyset(&sigmask);                           /* Empty mask */
 (void)sigaddset(&sigmask, SIGALRM);                    /* Add SIGALRM */
@@ -377,6 +381,25 @@ return 0;
 *          Clock tick wait function              *
 *************************************************/
 
+#ifdef _POSIX_MONOTONIC_CLOCK
+/* Amount CLOCK_MONOTONIC is behind realtime, at startup. */
+static struct timespec offset_ts;
+
+static void
+exim_clock_init(void)
+{
+struct timeval tv;
+if (clock_gettime(CLOCK_MONOTONIC, &offset_ts) != 0) return;
+(void)gettimeofday(&tv, NULL);
+offset_ts.tv_sec = tv.tv_sec - offset_ts.tv_sec;
+offset_ts.tv_nsec = tv.tv_usec * 1000 - offset_ts.tv_nsec;
+if (offset_ts.tv_nsec >= 0) return;
+offset_ts.tv_sec--;
+offset_ts.tv_nsec += 1000*1000*1000;
+}
+#endif
+
+
 /* Exim uses a time + a pid to generate a unique identifier in two places: its
 message IDs, and in file names for maildir deliveries. Because some OS now
 re-use pids within the same second, sub-second times are now being used.
@@ -388,7 +411,7 @@ function prepares for the time when things are faster - and it also copes with
 clocks that go backwards.
 
 Arguments:
-  then_tv      A timeval which was used to create uniqueness; its usec field
+  tgt_tv       A timeval which was used to create uniqueness; its usec field
                  has been rounded down to the value of the resolution.
                  We want to be sure the current time is greater than this.
   resolution   The resolution that was used to divide the microseconds
@@ -398,26 +421,45 @@ Returns:       nothing
 */
 
 void
-exim_wait_tick(struct timeval *then_tv, int resolution)
+exim_wait_tick(struct timeval * tgt_tv, int resolution)
 {
 struct timeval now_tv;
 long int now_true_usec;
 
-(void)gettimeofday(&now_tv, NULL);
-now_true_usec = now_tv.tv_usec;
-now_tv.tv_usec = (now_true_usec/resolution) * resolution;
+#ifdef _POSIX_MONOTONIC_CLOCK
+struct timespec now_ts;
+
+if (clock_gettime(CLOCK_MONOTONIC, &now_ts) == 0)
+  {
+  now_ts.tv_sec += offset_ts.tv_sec;
+  if ((now_ts.tv_nsec += offset_ts.tv_nsec) >= 1000*1000*1000)
+    {
+    now_ts.tv_sec++;
+    now_ts.tv_nsec -= 1000*1000*1000;
+    }
+  now_tv.tv_sec = now_ts.tv_sec;
+  now_true_usec = (now_ts.tv_nsec / (resolution * 1000)) * resolution;
+  now_tv.tv_usec = now_true_usec;
+  }
+else
+#endif
+  {
+  (void)gettimeofday(&now_tv, NULL);
+  now_true_usec = now_tv.tv_usec;
+  now_tv.tv_usec = (now_true_usec/resolution) * resolution;
+  }
 
-if (exim_tvcmp(&now_tv, then_tv) <= 0)
+while (exim_tvcmp(&now_tv, tgt_tv) <= 0)
   {
   struct itimerval itval;
   itval.it_interval.tv_sec = 0;
   itval.it_interval.tv_usec = 0;
-  itval.it_value.tv_sec = then_tv->tv_sec - now_tv.tv_sec;
-  itval.it_value.tv_usec = then_tv->tv_usec + resolution - now_true_usec;
+  itval.it_value.tv_sec = tgt_tv->tv_sec - now_tv.tv_sec;
+  itval.it_value.tv_usec = tgt_tv->tv_usec + resolution - now_true_usec;
 
   /* We know that, overall, "now" is less than or equal to "then". Therefore, a
   negative value for the microseconds is possible only in the case when "now"
-  is more than a second less than "then". That means that itval.it_value.tv_sec
+  is more than a second less than "tgt". That means that itval.it_value.tv_sec
   is greater than zero. The following correction is therefore safe. */
 
   if (itval.it_value.tv_usec < 0)
@@ -431,14 +473,21 @@ if (exim_tvcmp(&now_tv, then_tv) <= 0)
     if (!f.running_in_test_harness)
       {
       debug_printf("tick check: " TIME_T_FMT ".%06lu " TIME_T_FMT ".%06lu\n",
-        then_tv->tv_sec, (long) then_tv->tv_usec,
+        tgt_tv->tv_sec, (long) tgt_tv->tv_usec,
                now_tv.tv_sec, (long) now_tv.tv_usec);
-      debug_printf("waiting " TIME_T_FMT ".%06lu\n",
+      debug_printf("waiting " TIME_T_FMT ".%06lu sec\n",
         itval.it_value.tv_sec, (long) itval.it_value.tv_usec);
       }
     }
 
   milliwait(&itval);
+
+  /* Be prapared to go around if the kernel does not implement subtick
+  granularity (GNU Hurd) */
+
+  (void)gettimeofday(&now_tv, NULL);
+  now_true_usec = now_tv.tv_usec;
+  now_tv.tv_usec = (now_true_usec/resolution) * resolution;
   }
 }
 
@@ -901,7 +950,7 @@ fprintf(fp, "Support for:");
 #ifndef DISABLE_OCSP
   fprintf(fp, " OCSP");
 #endif
-#ifdef SUPPORT_PIPE_CONNECT
+#ifndef DISABLE_PIPE_CONNECT
   fprintf(fp, " PIPE_CONNECT");
 #endif
 #ifndef DISABLE_PRDR
@@ -920,7 +969,7 @@ fprintf(fp, "Support for:");
   fprintf(fp, " DMARC");
 #endif
 #ifdef TCP_FASTOPEN
-  deliver_init();
+  tcp_init();
   if (f.tcp_fastopen_ok) fprintf(fp, " TCP_Fast_Open");
 #endif
 #ifdef EXPERIMENTAL_LMDB
@@ -929,7 +978,7 @@ fprintf(fp, "Support for:");
 #ifdef EXPERIMENTAL_QUEUEFILE
   fprintf(fp, " Experimental_QUEUEFILE");
 #endif
-#ifdef EXPERIMENTAL_SRS
+#if defined(EXPERIMENTAL_SRS) || defined(EXPERIMENTAL_SRS_NATIVE)
   fprintf(fp, " Experimental_SRS");
 #endif
 #ifdef EXPERIMENTAL_ARC
@@ -1065,6 +1114,9 @@ show_db_version(fp);
 #ifdef SUPPORT_I18N
   utf8_version_report(fp);
 #endif
+#ifdef SUPPORT_SPF
+  spf_lib_version_report(fp);
+#endif
 
   for (auth_info * authi = auths_available; *authi->driver_name != '\0'; ++authi)
     if (authi->version_report)
@@ -1213,9 +1265,9 @@ void *dlhandle;
 void *dlhandle_curses = dlopen("libcurses." DYNLIB_FN_EXT, RTLD_GLOBAL|RTLD_LAZY);
 
 dlhandle = dlopen("libreadline." DYNLIB_FN_EXT, RTLD_GLOBAL|RTLD_NOW);
-if (dlhandle_curses != NULL) dlclose(dlhandle_curses);
+if (dlhandle_curses) dlclose(dlhandle_curses);
 
-if (dlhandle != NULL)
+if (dlhandle)
   {
   /* Checked manual pages; at least in GNU Readline 6.1, the prototypes are:
    *   char * readline (const char *prompt);
@@ -1225,9 +1277,7 @@ if (dlhandle != NULL)
   *fn_addhist_ptr = (void(*)(const char*))dlsym(dlhandle, "add_history");
   }
 else
-  {
   DEBUG(D_any) debug_printf("failed to load readline: %s\n", dlerror());
-  }
 
 return dlhandle;
 }
@@ -1666,6 +1716,12 @@ make quite sure. */
 
 setlocale(LC_ALL, "C");
 
+/* Get the offset between CLOCK_MONOTONIC and wallclock */
+
+#ifdef _POSIX_MONOTONIC_CLOCK
+exim_clock_init();
+#endif
+
 /* Set up the default handler for timing using alarm(). */
 
 os_non_restarting_signal(SIGALRM, sigalrm_handler);
@@ -2787,6 +2843,11 @@ for (i = 1; i < argc; i++)
       msg_action = MSG_DELIVER;
       deliver_give_up = TRUE;
       }
+   else if (Ustrcmp(argrest, "G") == 0)
+      {
+      msg_action = MSG_SETQUEUE;
+      queue_name_dest = argv[++i];
+      }
     else if (Ustrcmp(argrest, "mad") == 0)
       {
       msg_action = MSG_MARK_ALL_DELIVERED;
@@ -3067,11 +3128,15 @@ for (i = 1; i < argc; i++)
 
     else if (Ustrcmp(argrest, "o") == 0) {}
 
-    /* -oP <name>: set pid file path for daemon */
+    /* -oP <name>: set pid file path for daemon
+       -oPX:       delete pid file of daemon */
 
     else if (Ustrcmp(argrest, "P") == 0)
       override_pid_file_path = argv[++i];
 
+    else if (Ustrcmp(argrest, "PX") == 0)
+      delete_pid_file();
+
     /* -or <n>: set timeout for non-SMTP acceptance
        -os <n>: set timeout for SMTP acceptance */
 
@@ -3574,11 +3639,15 @@ an error return. The following code should cope with both types of system.
  in the call to exim_setugid().
 
 However, if this process isn't running as root, setgroups() can't be used
-since you have to be root to run it, even if throwing away groups. Not being
-root here happens only in some unusual configurations. We just ignore the
-error. */
+since you have to be root to run it, even if throwing away groups.
+Except, sigh, for Hurd - where you can.
+Not being root here happens only in some unusual configurations. */
 
-if (setgroups(0, NULL) != 0 && setgroups(1, group_list) != 0 && !unprivileged)
+if (  !unprivileged
+#ifndef OS_SETGROUPS_ZERO_DROPS_ALL
+   && setgroups(0, NULL) != 0
+#endif
+   && setgroups(1, group_list) != 0)
   exim_fail("exim: setgroups() failed: %s\n", strerror(errno));
 
 /* If the configuration file name has been altered by an argument on the
@@ -4064,11 +4133,13 @@ count. Only an admin user can use the test interface to scan for email
 if (!f.admin_user)
   {
   BOOL debugset = (debug_selector & ~D_v) != 0;
-  if (deliver_give_up || f.daemon_listen || malware_test_file ||
-     (count_queue && queue_list_requires_admin) ||
-     (list_queue && queue_list_requires_admin) ||
-     (queue_interval >= 0 && prod_requires_admin) ||
-     (debugset && !f.running_in_test_harness))
+  if (  deliver_give_up || f.daemon_listen || malware_test_file
+     || count_queue && queue_list_requires_admin
+     || list_queue && queue_list_requires_admin
+     || queue_interval >= 0 && prod_requires_admin
+     || queue_name_dest && prod_requires_admin
+     || debugset && !f.running_in_test_harness
+     )
     exim_fail("exim:%s permission denied\n", debugset? " debugging" : "");
   }
 
@@ -4165,13 +4236,9 @@ now for those OS that require the first call to os_getloadavg() to be done as
 root. There will be further calls later for each message received. */
 
 #ifdef LOAD_AVG_NEEDS_ROOT
-if (receiving_message &&
-      (queue_only_load >= 0 ||
-        (f.is_inetd && smtp_load_reserve >= 0)
-      ))
-  {
+if (  receiving_message
+   && (queue_only_load >= 0 || (f.is_inetd && smtp_load_reserve >= 0)))
   load_average = OS_GETLOADAVG();
-  }
 #endif
 
 /* The queue_only configuration option can be overridden by -odx on the command
@@ -4297,6 +4364,11 @@ if (msg_action_arg > 0 && msg_action != MSG_DELIVER && msg_action != MSG_LOAD)
     for (i = msg_action_arg; i < argc; i++)
       if (!queue_action(argv[i], msg_action, NULL, 0, 0))
         yield = EXIT_FAILURE;
+    switch (msg_action)
+      {
+      case MSG_REMOVE: MSG_DELETE: case MSG_FREEZE: case MSG_THAW: break;
+      default: printf("\n"); break;
+      }
     }
 
   else if (!queue_action(argv[msg_action_arg], msg_action, argv, argc,
@@ -4480,31 +4552,9 @@ if (list_config)
   }
 
 
-/* Initialise subsystems as required */
-#ifndef DISABLE_DKIM
-  {
-# ifdef MEASURE_TIMING
-  struct timeval t0;
-  gettimeofday(&t0, NULL);
-# endif
-  dkim_exim_init();
-# ifdef MEASURE_TIMING
-  report_time_since(&t0, US"dkim_exim_init (delta)");
-# endif
-  }
-#endif
-
-  {
-#ifdef MEASURE_TIMING
-  struct timeval t0;
-  gettimeofday(&t0, NULL);
-#endif
-  deliver_init();
-#ifdef MEASURE_TIMING
-  report_time_since(&t0, US"deliver_init (delta)");
-#endif
-  }
+/* Initialise subsystems as required. */
 
+tcp_init();
 
 /* Handle a request to deliver one or more messages that are already on the
 queue. Values of msg_action other than MSG_DELIVER and MSG_LOAD are dealt with
@@ -4699,6 +4749,23 @@ if (f.daemon_listen || f.inetd_wait_mode || queue_interval > 0)
     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Daemon cannot be run when "
       "mua_wrapper is set");
     }
+
+# ifndef DISABLE_TLS
+  /* This also checks that the library linkage is working and we can call
+  routines in it, so call even if tls_require_ciphers is unset */
+    {
+# ifdef MEASURE_TIMING
+    struct timeval t0, diff;
+    (void)gettimeofday(&t0, NULL);
+# endif
+    if (!tls_dropprivs_validate_require_cipher(FALSE))
+      exit(1);
+# ifdef MEASURE_TIMING
+    report_time_since(&t0, US"validate_ciphers (delta)");
+# endif
+    }
+#endif
+
   daemon_go();
   }
 
@@ -4814,8 +4881,9 @@ if (verify_address_mode || f.address_test_mode)
     {
     while (recipients_arg < argc)
       {
-      uschar *s = argv[recipients_arg++];
-      while (*s != 0)
+      /* Supplied addresses are tainted since they come from a user */
+      uschar * s = string_copy_taint(argv[recipients_arg++], TRUE);
+      while (*s)
         {
         BOOL finished = FALSE;
         uschar *ss = parse_find_address_end(s, FALSE);
@@ -4823,16 +4891,16 @@ if (verify_address_mode || f.address_test_mode)
         test_address(s, flags, &exit_value);
         s = ss;
         if (!finished)
-          while (*(++s) != 0 && (*s == ',' || isspace(*s)));
+          while (*++s == ',' || isspace(*s)) ;
         }
       }
     }
 
   else for (;;)
     {
-    uschar *s = get_stdinput(NULL, NULL);
-    if (s == NULL) break;
-    test_address(s, flags, &exit_value);
+    uschar * s = get_stdinput(NULL, NULL);
+    if (!s) break;
+    test_address(string_copy_taint(s, TRUE), flags, &exit_value);
     }
 
   route_tidyup();
@@ -4959,9 +5027,9 @@ if (host_checking)
   if (!sender_ident_set)
     {
     sender_ident = NULL;
-    if (f.running_in_test_harness && sender_host_port != 0 &&
-        interface_address != NULL && interface_port != 0)
-      verify_get_ident(1413);
+    if (f.running_in_test_harness && sender_host_port
+       && interface_address && interface_port)
+      verify_get_ident(1223);          /* note hardwired port number */
     }
 
   /* In case the given address is a non-canonical IPv6 address, canonicalize
@@ -5326,13 +5394,13 @@ while (more)
 
     raw_sender = string_copy(sender_address);
 
-    /* Loop for each argument */
+    /* Loop for each argument (supplied by user hence tainted) */
 
     for (int i = 0; i < count; i++)
       {
       int start, end, domain;
-      uschar *errmess;
-      uschar *s = list[i];
+      uschar * errmess;
+      uschar * s = string_copy_taint(list[i], TRUE);
 
       /* Loop for each comma-separated address */