constification
[exim.git] / src / src / exim.c
index 06863347d81b7069c63334d390a0b761fee9d81a..4473373b3397d55b10ce8f749c3901af1d6b9c23 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) The Exim Maintainers 2020 - 2022 */
+/* Copyright (c) The Exim Maintainers 2020 - 2023 */
 /* Copyright (c) University of Cambridge 1995 - 2018 */
 /* See the file NOTICE for conditions of use and distribution. */
 /* SPDX-License-Identifier: GPL-2.0-or-later */
@@ -847,7 +847,7 @@ exit(EXIT_FAILURE);
 
 /* fail if a length is too long */
 static inline void
-exim_len_fail_toolong(int itemlen, int maxlen, const char *description)
+exim_len_fail_toolong(int itemlen, int maxlen, const char * description)
 {
 if (itemlen <= maxlen)
   return;
@@ -858,8 +858,10 @@ exit(EXIT_FAILURE);
 
 /* only pass through the string item back to the caller if it's short enough */
 static inline const uschar *
-exim_str_fail_toolong(const uschar *item, int maxlen, const char *description)
+exim_str_fail_toolong(const uschar * item, int maxlen, const char * description)
 {
+if (!item)
+  exim_fail("exim: bad item for: %s\n", description);
 exim_len_fail_toolong(Ustrlen(item), maxlen, description);
 return item;
 }
@@ -884,10 +886,10 @@ log_write(0, LOG_MAIN|LOG_PANIC,
 struct stat buf;
 
 if (0 == (fd < 0 ? stat(name, &buf) : fstat(fd, &buf)))
-{
+  {
   if (buf.st_uid == owner && buf.st_gid == group) return 0;
   log_write(0, LOG_MAIN|LOG_PANIC, "Wrong ownership on %s", name);
-}
+  }
 else log_write(0, LOG_MAIN|LOG_PANIC, "Stat failed on %s: %s", name, strerror(errno));
 
 #endif
@@ -896,6 +898,18 @@ return -1;
 }
 
 
+/* Bump the index for argv, checking for overflow,
+and return the argument. */
+
+static const uschar *
+next_argv(const uschar ** argv, int * pi, int argc, const uschar * where)
+{
+int i = *pi;
+if (++i >= argc) exim_fail("exim: bad item for: %s\n", where);
+return argv[*pi = i];
+}
+
+
 /*************************************************
 *         Extract port from host address         *
 *************************************************/
@@ -1026,47 +1040,53 @@ gstring * g = NULL;
 DEBUG(D_any) {} else g = show_db_version(g);
 
 g = string_cat(g, US"Support for:");
+#ifdef WITH_CONTENT_SCAN
+  g = string_cat(g, US" Content_Scanning");
+#endif
 #ifdef SUPPORT_CRYPTEQ
   g = string_cat(g, US" crypteq");
 #endif
+#ifdef EXPAND_DLFUNC
+  g = string_cat(g, US" Expand_dlfunc");
+#endif
 #if HAVE_ICONV
   g = string_cat(g, US" iconv()");
 #endif
 #if HAVE_IPV6
   g = string_cat(g, US" IPv6");
 #endif
-#ifdef HAVE_SETCLASSRESOURCES
-  g = string_cat(g, US" use_setclassresources");
-#endif
 #ifdef SUPPORT_PAM
   g = string_cat(g, US" PAM");
 #endif
 #ifdef EXIM_PERL
   g = string_cat(g, US" Perl");
 #endif
-#ifdef EXPAND_DLFUNC
-  g = string_cat(g, US" Expand_dlfunc");
-#endif
-#ifdef USE_TCP_WRAPPERS
-  g = string_cat(g, US" TCPwrappers");
-#endif
 #ifdef USE_GNUTLS
   g = string_cat(g, US" GnuTLS");
 #endif
+#ifdef SUPPORT_MOVE_FROZEN_MESSAGES
+  g = string_cat(g, US" move_frozen_messages");
+#endif
 #ifdef USE_OPENSSL
   g = string_cat(g, US" OpenSSL");
 #endif
+#if defined(CYRUS_PWCHECK_SOCKET)
+  g = string_cat(g, US" pwcheck");
+#endif
+#if defined(RADIUS_CONFIG_FILE)
+  g = string_cat(g, US" radius");
+#endif
 #ifndef DISABLE_TLS_RESUME
   g = string_cat(g, US" TLS_resume");
 #endif
 #ifdef SUPPORT_TRANSLATE_IP_ADDRESS
   g = string_cat(g, US" translate_ip_address");
 #endif
-#ifdef SUPPORT_MOVE_FROZEN_MESSAGES
-  g = string_cat(g, US" move_frozen_messages");
+#ifdef USE_TCP_WRAPPERS
+  g = string_cat(g, US" TCPwrappers");
 #endif
-#ifdef WITH_CONTENT_SCAN
-  g = string_cat(g, US" Content_Scanning");
+#ifdef HAVE_SETCLASSRESOURCES
+  g = string_cat(g, US" use_setclassresources");
 #endif
 #ifdef SUPPORT_DANE
   g = string_cat(g, US" DANE");
@@ -1359,17 +1379,15 @@ Argument:    the local part
 Returns:     the local part, quoted if necessary
 */
 
-uschar *
-local_part_quote(uschar *lpart)
+const uschar *
+local_part_quote(const uschar * lpart)
 {
 BOOL needs_quote = FALSE;
 gstring * g;
 
-for (uschar * t = lpart; !needs_quote && *t != 0; t++)
-  {
+for (const uschar * t = lpart; !needs_quote && *t; t++)
   needs_quote = !isalnum(*t) && strchr("!#$%&'*+-/=?^_`{|}~", *t) == NULL &&
     (*t != '.' || t == lpart || t[1] == 0);
-  }
 
 if (!needs_quote) return lpart;
 
@@ -1377,8 +1395,8 @@ g = string_catn(NULL, US"\"", 1);
 
 for (;;)
   {
-  uschar *nq = US Ustrpbrk(lpart, "\\\"");
-  if (nq == NULL)
+  uschar * nq = US Ustrpbrk(lpart, "\\\"");
+  if (!nq)
     {
     g = string_cat(g, lpart);
     break;
@@ -1531,7 +1549,7 @@ Returns:        DOES NOT RETURN
 */
 
 static void
-exim_usage(uschar *progname)
+exim_usage(const uschar * progname)
 {
 
 /* Handle specific program invocation variants */
@@ -1738,9 +1756,9 @@ Returns:    EXIT_SUCCESS if terminated successfully
 */
 
 int
-main(int argc, char **cargv)
+main(int argc, char ** cargv)
 {
-uschar **argv = USS cargv;
+const uschar ** argv = CUSS cargv;
 int  arg_receive_timeout = -1;
 int  arg_smtp_receive_timeout = -1;
 int  arg_error_handling = error_handling;
@@ -1789,20 +1807,20 @@ BOOL verify_address_mode = FALSE;
 BOOL verify_as_sender = FALSE;
 BOOL rcpt_verify_quota = FALSE;
 BOOL version_printed = FALSE;
-uschar *alias_arg = NULL;
-uschar *called_as = US"";
-uschar *cmdline_syslog_name = NULL;
-uschar *start_queue_run_id = NULL;
-uschar *stop_queue_run_id = NULL;
-uschar *expansion_test_message = NULL;
-const uschar *ftest_domain = NULL;
-const uschar *ftest_localpart = NULL;
-const uschar *ftest_prefix = NULL;
-const uschar *ftest_suffix = NULL;
-uschar *log_oneline = NULL;
-uschar *malware_test_file = NULL;
-uschar *real_sender_address;
-uschar *originator_home = US"/";
+const uschar * alias_arg = NULL;
+const uschar * called_as = US"";
+const uschar * cmdline_syslog_name = NULL;
+const uschar * start_queue_run_id = NULL;
+const uschar * stop_queue_run_id = NULL;
+const uschar * expansion_test_message = NULL;
+const uschar * ftest_domain = NULL;
+const uschar * ftest_localpart = NULL;
+const uschar * ftest_prefix = NULL;
+const uschar * ftest_suffix = NULL;
+uschar * log_oneline = NULL;
+const uschar * malware_test_file = NULL;
+const uschar * real_sender_address;
+uschar * originator_home = US"/";
 size_t sz;
 
 struct passwd *pw;
@@ -2022,7 +2040,14 @@ this here, because the -M options check their arguments for syntactic validity
 using mac_ismsgid, which uses this. */
 
 regex_ismsgid =
-  regex_must_compile(US"^(?:[^\\W_]{6}-){2}[^\\W_]{2}$", MCS_NOFLAGS, TRUE);
+  regex_must_compile(US"^(?:"
+         "[^\\W_]{" str(MESSAGE_ID_TIME_LEN) "}"
+         "-[^\\W_]{" str(MESSAGE_ID_PID_LEN) "}"
+         "-[^\\W_]{" str(MESSAGE_ID_SUBTIME_LEN) "}"
+       "|"
+         "(?:[^\\W_]{6}-){2}[^\\W_]{2}"                /* old ID format */
+       ")$",
+    MCS_NOFLAGS, TRUE);
 
 /* Precompile the regular expression that is used for matching an SMTP error
 code, possibly extended, at the start of an error message. Note that the
@@ -2139,8 +2164,8 @@ on the second character (the one after '-'), to save some effort. */
  for (i = 1; i < argc; i++)
   {
   BOOL badarg = FALSE;
-  uschar * arg = argv[i];
-  uschar * argrest;
+  const uschar * arg = argv[i];
+  const uschar * argrest;
   uschar switchchar;
 
   /* An argument not starting with '-' is the start of a recipients list;
@@ -2334,7 +2359,7 @@ on the second character (the one after '-'), to save some effort. */
        case 'I':
          if (Ustrlen(argrest) >= 1 && *argrest == ':')
            {
-           uschar *p = argrest+1;
+           const uschar * p = argrest+1;
            info_flag = CMDINFO_HELP;
            if (Ustrlen(p))
              if (strcmpic(p, CUS"sieve") == 0)
@@ -2661,9 +2686,9 @@ on the second character (the one after '-'), to save some effort. */
 #else
       {
       int ptr = 0;
-      macro_item *m;
+      macro_item * m;
       uschar name[24];
-      uschar *s = argrest;
+      const uschar * s = argrest;
 
       opt_D_used = TRUE;
       while (isspace(*s)) s++;
@@ -2817,10 +2842,14 @@ on the second character (the one after '-'), to save some effort. */
         if (i+1 < argc) argrest = argv[++i]; else { badarg = TRUE; break; }
       (void) exim_str_fail_toolong(argrest, EXIM_DISPLAYMAIL_MAX, "-f");
       if (!*argrest)
-        *(sender_address = store_get(1, GET_UNTAINTED)) = '\0';  /* Ensure writeable memory */
+       {
+        uschar * s = store_get(1, GET_UNTAINTED);      /* Ensure writeable memory */
+        *s = '\0';
+        sender_address = s;
+       }
       else
         {
-        uschar * temp = argrest + Ustrlen(argrest) - 1;
+        const uschar * temp = argrest + Ustrlen(argrest) - 1;
         while (temp >= argrest && isspace(*temp)) temp--;
         if (temp >= argrest && *temp == '.') f_end_dot = TRUE;
         allow_domain_literals = TRUE;
@@ -3138,7 +3167,8 @@ on the second character (the one after '-'), to save some effort. */
       {
       msg_action = MSG_SETQUEUE;
       queue_name_dest = string_copy_taint(
-       exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-MG"),
+       exim_str_fail_toolong(next_argv(argv, &i, argc, arg),
+                             EXIM_DRIVERNAME_MAX, "-MG"),
        GET_TAINTED);
       }
     else if (Ustrcmp(argrest, "mad") == 0) msg_action = MSG_MARK_ALL_DELIVERED;
@@ -3259,7 +3289,7 @@ on the second character (the one after '-'), to save some effort. */
       /* -oB: Set a connection message max value for remote deliveries */
       case 'B':
        {
-       uschar * p = argrest;
+       const uschar * p = argrest;
        if (!*p)
          if (i+1 < argc && isdigit((argv[i+1][0])))
            p = argv[++i];
@@ -3350,36 +3380,36 @@ on the second character (the one after '-'), to save some effort. */
 
        if (Ustrcmp(argrest, "a") == 0)
          sender_host_address = string_copy_taint(
-           exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMa"),
-           GET_TAINTED);
+           exim_str_fail_toolong(next_argv(argv, &i, argc, arg),
+                                 EXIM_IPADDR_MAX, "-oMa"), GET_TAINTED);
 
        /* -oMaa: Set authenticator name */
 
        else if (Ustrcmp(argrest, "aa") == 0)
          sender_host_authenticated = string_copy_taint(
-           exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMaa"),
-           GET_TAINTED);
+           exim_str_fail_toolong(next_argv(argv, &i, argc, arg),
+                                 EXIM_DRIVERNAME_MAX, "-oMaa"), GET_TAINTED);
 
        /* -oMas: setting authenticated sender */
 
        else if (Ustrcmp(argrest, "as") == 0)
          authenticated_sender = string_copy_taint(
-           exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMas"),
-           GET_TAINTED);
+           exim_str_fail_toolong(next_argv(argv, &i, argc, arg),
+                                 EXIM_EMAILADDR_MAX, "-oMas"), GET_TAINTED);
 
        /* -oMai: setting authenticated id */
 
        else if (Ustrcmp(argrest, "ai") == 0)
          authenticated_id = string_copy_taint(
-           exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMai"),
-           GET_TAINTED);
+           exim_str_fail_toolong(next_argv(argv, &i, argc, arg),
+                                 EXIM_EMAILADDR_MAX, "-oMai"), GET_TAINTED);
 
        /* -oMi: Set incoming interface address */
 
        else if (Ustrcmp(argrest, "i") == 0)
          interface_address = string_copy_taint(
-           exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMi"),
-           GET_TAINTED);
+           exim_str_fail_toolong(next_argv(argv, &i, argc, arg),
+                                 EXIM_IPADDR_MAX, "-oMi"), GET_TAINTED);
 
        /* -oMm: Message reference */
 
@@ -3389,7 +3419,7 @@ on the second character (the one after '-'), to save some effort. */
              exim_fail("-oMm must be a valid message ID\n");
          if (!f.trusted_config)
              exim_fail("-oMm must be called by a trusted user/config\n");
-           message_reference = argv[++i];
+           message_reference = next_argv(argv, &i, argc, arg);
          }
 
        /* -oMr: Received protocol */
@@ -3399,26 +3429,32 @@ on the second character (the one after '-'), to save some effort. */
          if (received_protocol)
            exim_fail("received_protocol is set already\n");
          else
-           received_protocol = string_copy_taint(
-             exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMr"),
-             GET_TAINTED);
+           if (++i >= argc) badarg = TRUE;
+           else
+             received_protocol = string_copy_taint(
+               exim_str_fail_toolong(argv[i], EXIM_DRIVERNAME_MAX, "-oMr"),
+               GET_TAINTED);
 
        /* -oMs: Set sender host name */
 
        else if (Ustrcmp(argrest, "s") == 0)
-         sender_host_name = string_copy_taint(
-           exim_str_fail_toolong(argv[++i], EXIM_HOSTNAME_MAX, "-oMs"),
-           GET_TAINTED);
+         if (++i >= argc) badarg = TRUE;
+         else
+           sender_host_name = string_copy_taint(
+             exim_str_fail_toolong(argv[i], EXIM_HOSTNAME_MAX, "-oMs"),
+             GET_TAINTED);
 
        /* -oMt: Set sender ident */
 
        else if (Ustrcmp(argrest, "t") == 0)
-         {
-         sender_ident_set = TRUE;
-         sender_ident = string_copy_taint(
-           exim_str_fail_toolong(argv[++i], EXIM_IDENTUSER_MAX, "-oMt"),
-           GET_TAINTED);
-         }
+         if (++i >= argc) badarg = TRUE;
+         else
+           {
+           sender_ident_set = TRUE;
+           sender_ident = string_copy_taint(
+             exim_str_fail_toolong(argv[i], EXIM_IDENTUSER_MAX, "-oMt"),
+             GET_TAINTED);
+           }
 
        /* Else a bad argument */
 
@@ -3446,7 +3482,9 @@ on the second character (the one after '-'), to save some effort. */
          exim_fail("exim: only uid=%d or uid=%d can use -oP and -oPX "
                     "(uid=%d euid=%d | %d)\n",
                     root_uid, exim_uid, getuid(), geteuid(), real_uid);
-       if (!*argrest) override_pid_file_path = argv[++i];
+       if (!*argrest)
+         if (++i < argc) override_pid_file_path = argv[i];
+         else badarg = TRUE;
        else if (Ustrcmp(argrest, "X") == 0) delete_pid_file();
        else badarg = TRUE;
        break;
@@ -3474,10 +3512,9 @@ on the second character (the one after '-'), to save some effort. */
       /* Limits: Is there a real limit we want here?  1024 is very arbitrary. */
 
       case 'X':
-       if (*argrest) badarg = TRUE;
+       if (*argrest || ++i >= argc) badarg = TRUE;
        else override_local_interfaces = string_copy_taint(
-         exim_str_fail_toolong(argv[++i], 1024, "-oX"),
-         GET_TAINTED);
+         exim_str_fail_toolong(argv[i], 1024, "-oX"), GET_TAINTED);
        break;
 
       /* -oY: Override creation of daemon notifier socket */
@@ -3515,7 +3552,7 @@ on the second character (the one after '-'), to save some effort. */
     which sets the host protocol and host name */
 
     if (!*argrest)
-      if (i+1 < argc) argrest = argv[++i]; else { badarg = TRUE; break; }
+      argrest = next_argv(argv, &i, argc, arg);
 
     if (*argrest)
       {
@@ -3601,8 +3638,14 @@ on the second character (the one after '-'), to save some effort. */
 
        else
          {
-         int intvl = readconf_readtime(*argrest ? argrest : argv[++i], 0, FALSE);
-         if (intvl <= 0)
+         int intvl;
+         const uschar * s;
+
+         if (*argrest) s = argrest;
+         else if (++i < argc) { badarg = TRUE; break; }
+         else s = argv[i];
+
+         if ((intvl = readconf_readtime(s, 0, FALSE)) <= 0)
            exim_fail("exim: bad time value %s: abandoned\n", argv[i]);
 
          for (qrunner * qq = qrunners; qq; qq = qq->next)
@@ -3693,8 +3736,8 @@ on the second character (the one after '-'), to save some effort. */
     tested. Otherwise variability of clock ticks etc. cause problems. */
 
     case 'T':
-    if (f.running_in_test_harness && Ustrcmp(argrest, "qt") == 0)
-      fudged_queue_times = string_copy_taint(argv[++i], GET_TAINTED);
+    if (f.running_in_test_harness && Ustrcmp(argrest, "qt") == 0 && ++i < argc)
+      fudged_queue_times = string_copy_taint(argv[i], GET_TAINTED);
     else badarg = TRUE;
     break;
 
@@ -4419,7 +4462,7 @@ if (bi_option)
   if (bi_command && *bi_command)
     {
     int i = 0;
-    uschar *argv[3];
+    const uschar * argv[3];
     argv[i++] = bi_command;    /* nonexpanded option so assume untainted */
     if (alias_arg) argv[i++] = alias_arg;
     argv[i++] = NULL;
@@ -4465,7 +4508,8 @@ if (!f.admin_user)
      || queue_name_dest && prod_requires_admin
      || debugset && !f.running_in_test_harness
      )
-    exim_fail("exim:%s permission denied\n", debugset ? " debugging" : "");
+    exim_fail("exim:%s permission denied; not admin\n",
+             debugset ? " debugging" : "");
   }
 
 /* If the real user is not root or the exim uid, the argument for passing
@@ -4481,7 +4525,7 @@ if (  real_uid != root_uid && real_uid != exim_uid
       )  )
    && !f.running_in_test_harness
    )
-  exim_fail("exim: Permission denied\n");
+  exim_fail("exim: Permission denied; not exim user or root\n");
 
 /* If the caller is not trusted, certain arguments are ignored when running for
 real, but are permitted when checking things (-be, -bv, -bt, -bh, -bf, -bF).
@@ -4747,7 +4791,7 @@ if (rcpt_verify_quota)
     exim_fail("exim: missing recipient for quota check\n");
   else
     {
-    verify_quota(argv[recipients_arg]);
+    verify_quota(US argv[recipients_arg]);     /*XXX we lose track of const here */
     exim_exit(EXIT_SUCCESS);
     }
 
@@ -5411,6 +5455,7 @@ if (host_checking)
     "**** This is not for real!\n\n",
       sender_host_address);
 
+  connection_id = getpid();
   memset(sender_host_cache, 0, sizeof(sender_host_cache));
   if (verify_check_host(&hosts_connection_nolog) == OK)
     {
@@ -5599,6 +5644,7 @@ because a log line has already been written for all its failure exists
 (usually "connection refused: <reason>") and writing another one is
 unnecessary clutter. */
 
+connection_id = getpid();
 if (smtp_input)
   {
   smtp_in = stdin;
@@ -5752,7 +5798,7 @@ for (BOOL more = TRUE; more; )
     {
     int rcount = 0;
     int count = argc - recipients_arg;
-    uschar **list = argv + recipients_arg;
+    const uschar ** list = argv + recipients_arg;
 
     /* These options cannot be changed dynamically for non-SMTP messages */
 
@@ -5770,7 +5816,7 @@ for (BOOL more = TRUE; more; )
       int start, end, domain;
       uschar * errmess;
       /* There can be multiple addresses, so EXIM_DISPLAYMAIL_MAX (tuned for 1) is too short.
-       * We'll still want to cap it to something, just in case. */
+      We'll still want to cap it to something, just in case. */
       uschar * s = string_copy_taint(
        exim_str_fail_toolong(list[i], BIG_BUFFER_SIZE, "address argument"),
        GET_TAINTED);
@@ -6105,6 +6151,7 @@ MORELOOP:
   deliver_localpart_data = deliver_domain_data =
   recipient_data = sender_data = NULL;
   acl_var_m = NULL;
+  lookup_value = NULL;                            /* Can be set by ACL */
 
   store_reset(reset_point);
   }