Check configure file permissions even for non-default files if still privileged
[exim.git] / src / src / exim.c
index c54470bd6e56062503db41ab92a3a5131b75f8ce..0d8f2449274a8d3e33ad46afcab9dacfe5fb15df 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/exim.c,v 1.66 2010/06/05 11:13:29 pdp Exp $ */
+/* $Cambridge: exim/src/src/exim.c,v 1.71 2010/06/07 00:12:42 pdp Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -681,161 +681,12 @@ else
 
 
 
-/*************************************************
-*         Decode bit settings for log/debug      *
-*************************************************/
-
-/* This function decodes a string containing bit settings in the form of +name
-and/or -name sequences, and sets/unsets bits in a bit string accordingly. It
-also recognizes a numeric setting of the form =<number>, but this is not
-intended for user use. It's an easy way for Exim to pass the debug settings
-when it is re-exec'ed.
-
-The log options are held in two unsigned ints (because there became too many
-for one). The top bit in the table means "put in 2nd selector". This does not
-yet apply to debug options, so the "=" facility sets only the first selector.
-
-The "all" selector, which must be equal to 0xffffffff, is recognized specially.
-It sets all the bits in both selectors. However, there is a facility for then
-unsetting certain bits, because we want to turn off "memory" in the debug case.
-
-A bad value for a debug setting is treated as an unknown option - error message
-to stderr and die. For log settings, which come from the configuration file,
-we write to the log on the way out...
-
-Arguments:
-  selector1      address of the first bit string
-  selector2      address of the second bit string, or NULL
-  notall1        bits to exclude from "all" for selector1
-  notall2        bits to exclude from "all" for selector2
-  string         the configured string
-  options        the table of option names
-  count          size of table
-  which          "log" or "debug"
-
-Returns:         nothing on success - bomb out on failure
-*/
-
-static void
-decode_bits(unsigned int *selector1, unsigned int *selector2, int notall1,
-  int notall2, uschar *string, bit_table *options, int count, uschar *which)
-{
-uschar *errmsg;
-if (string == NULL) return;
-
-if (*string == '=')
-  {
-  char *end;    /* Not uschar */
-  *selector1 = strtoul(CS string+1, &end, 0);
-  if (*end == 0) return;
-  errmsg = string_sprintf("malformed numeric %s_selector setting: %s", which,
-    string);
-  goto ERROR_RETURN;
-  }
-
-/* Handle symbolic setting */
-
-else for(;;)
-  {
-  BOOL adding;
-  uschar *s;
-  int len;
-  bit_table *start, *end;
-
-  while (isspace(*string)) string++;
-  if (*string == 0) return;
-
-  if (*string != '+' && *string != '-')
-    {
-    errmsg = string_sprintf("malformed %s_selector setting: "
-      "+ or - expected but found \"%s\"", which, string);
-    goto ERROR_RETURN;
-    }
-
-  adding = *string++ == '+';
-  s = string;
-  while (isalnum(*string) || *string == '_') string++;
-  len = string - s;
-
-  start = options;
-  end = options + count;
-
-  while (start < end)
-    {
-    bit_table *middle = start + (end - start)/2;
-    int c = Ustrncmp(s, middle->name, len);
-    if (c == 0)
-      {
-      if (middle->name[len] != 0) c = -1; else
-        {
-        unsigned int bit = middle->bit;
-        unsigned int *selector;
-
-        /* The value with all bits set means "force all bits in both selectors"
-        in the case where two are being handled. However, the top bit in the
-        second selector is never set. When setting, some bits can be excluded.
-        */
-
-        if (bit == 0xffffffff)
-          {
-          if (adding)
-            {
-            *selector1 = 0xffffffff ^ notall1;
-            if (selector2 != NULL) *selector2 = 0x7fffffff ^ notall2;
-            }
-          else
-            {
-            *selector1 = 0;
-            if (selector2 != NULL) *selector2 = 0;
-            }
-          }
-
-        /* Otherwise, the 0x80000000 bit means "this value, without the top
-        bit, belongs in the second selector". */
-
-        else
-          {
-          if ((bit & 0x80000000) != 0)
-            {
-            selector = selector2;
-            bit &= 0x7fffffff;
-            }
-          else selector = selector1;
-          if (adding) *selector |= bit; else *selector &= ~bit;
-          }
-        break;  /* Out of loop to match selector name */
-        }
-      }
-    if (c < 0) end = middle; else start = middle + 1;
-    }  /* Loop to match selector name */
-
-  if (start >= end)
-    {
-    errmsg = string_sprintf("unknown %s_selector setting: %c%.*s", which,
-      adding? '+' : '-', len, s);
-    goto ERROR_RETURN;
-    }
-  }    /* Loop for selector names */
-
-/* Handle disasters */
-
-ERROR_RETURN:
-if (Ustrcmp(which, "debug") == 0)
-  {
-  fprintf(stderr, "exim: %s\n", errmsg);
-  exit(EXIT_FAILURE);
-  }
-else log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "%s", errmsg);
-}
-
-
-
 /*************************************************
 *          Show supported features               *
 *************************************************/
 
-/* This function is called for -bV and for -d to output the optional features
-of the current Exim binary.
+/* This function is called for -bV/--version and for -d to output the optional
+features of the current Exim binary.
 
 Arguments:  a FILE for printing
 Returns:    nothing
@@ -1054,7 +905,7 @@ if (fixed_never_users[0] > 0)
   fprintf(f, "%d\n", (unsigned int)fixed_never_users[i]);
   }
 
-fprintf(f, "Size of off_t: %d\n", sizeof(off_t));
+fprintf(f, "Size of off_t: " SIZE_T_FMT "\n", sizeof(off_t));
 
 /* This runtime check is to help diagnose library linkage mismatches which
 result in segfaults and the like; as such, it's left until the end,
@@ -1383,6 +1234,12 @@ This is a feature to make the lives of binary distributors easier. */
 #ifdef EXIM_USERNAME
 if (route_finduser(US EXIM_USERNAME, &pw, &exim_uid))
   {
+  if (exim_uid == 0)
+    {
+    fprintf(stderr, "exim: refusing to run with uid 0 for \"%s\"\n",
+      EXIM_USERNAME);
+    exit(EXIT_FAILURE);
+    }
   exim_gid = pw->pw_gid;
   }
 else
@@ -1638,16 +1495,6 @@ running in an unprivileged state. */
 
 unprivileged = (real_uid != root_uid && original_euid != root_uid);
 
-/* If the first argument is --help, set usage_wanted and pretend there
-are no arguments. This will cause a brief message to be given.   We do
-the message generation downstream so we can pick up how we were invoked */
-
-if (argc > 1 && Ustrcmp(argv[1], "--help") == 0)
-  {
-  argc = 1;
-  usage_wanted = TRUE;
-  }
-
 /* Scan the program's arguments. Some can be dealt with right away; others are
 simply recorded for checking and handling afterwards. Do a high-level switch
 on the second character (the one after '-'), to save some effort. */
@@ -1712,6 +1559,21 @@ for (i = 1; i < argc; i++)
     argrest++;
     }
 
+  /* deal with --option_aliases */
+  else if (switchchar == '-')
+    {
+    if (Ustrcmp(argrest, "help") == 0)
+      {
+      usage_wanted = TRUE;
+      break;
+      }
+    else if (Ustrcmp(argrest, "version") == 0)
+      {
+      switchchar = 'b';
+      argrest = US"V";
+      }
+    }
+
   /* High-level switch on active initial letter */
 
   switch(switchchar)
@@ -1986,6 +1848,7 @@ for (i = 1; i < argc; i++)
 
       config_main_filelist = argrest;
       config_changed = TRUE;
+      trusted_config = FALSE;
       }
     break;
 
@@ -2080,7 +1943,7 @@ for (i = 1; i < argc; i++)
         }
       if (*argrest != 0)
         decode_bits(&selector, NULL, D_memory, 0, argrest, debug_options,
-          debug_options_count, US"debug");
+          debug_options_count, US"debug", 0);
       debug_selector = selector;
       }
     break;
@@ -3184,7 +3047,7 @@ values (such as the path name). If running in the test harness, pretend that
 configuration file changes and macro definitions haven't happened. */
 
 if ((                                            /* EITHER */
-    (config_changed || macros != NULL) &&        /* Config changed, and */
+    (!trusted_config || macros != NULL) &&       /* Config changed, and */
     real_uid != root_uid &&                      /* Not root, and */
     #ifndef ALT_CONFIG_ROOT_ONLY                 /* (when not locked out) */
     real_uid != exim_uid &&                      /* Not exim, and */
@@ -3249,8 +3112,8 @@ readconf_main();
 
 /* Handle the decoding of logging options. */
 
-decode_bits(&log_write_selector, &log_extra_selector, 0, 0, log_selector_string,
-  log_options, log_options_count, US"log");
+decode_bits(&log_write_selector, &log_extra_selector, 0, 0,
+  log_selector_string, log_options, log_options_count, US"log", 0);
 
 DEBUG(D_any)
   {
@@ -3403,7 +3266,7 @@ If ALT_CONFIG_ROOT_ONLY is defined, we don't know whether we were called by the
 built-in exim user or one defined in the configuration. In either event,
 re-enable log processing, assuming the sysadmin knows what they are doing. */
 
-if (removed_privilege && (config_changed || macros != NULL) &&
+if (removed_privilege && (!trusted_config || macros != NULL) &&
     real_uid == exim_uid)
   {
   #ifdef ALT_CONFIG_ROOT_ONLY
@@ -3415,7 +3278,7 @@ if (removed_privilege && (config_changed || macros != NULL) &&
   else
     log_write(0, LOG_MAIN|LOG_PANIC,
       "exim user (uid=%d) is defined only at runtime; privilege lost for %s",
-      (int)exim_uid, config_changed? "-C" : "-D");
+      (int)exim_uid, trusted_config? "-D" : "-C");
   #endif
   }
 
@@ -3761,6 +3624,7 @@ else setgid(exim_gid);
 /* Handle a request to scan a file for malware */
 if (malware_test_file)
   {
+#ifdef WITH_CONTENT_SCAN
   int result;
   set_process_info("scanning file for malware");
   result = malware_in_file(malware_test_file);
@@ -3778,6 +3642,9 @@ if (malware_test_file)
     printf("Malware found: %s\n", malware_name);
   else
     printf("Malware scan detected malware of unknown name.\n");
+#else
+  printf("Malware scanning not enabled at compile time.\n");
+#endif
   exit(EXIT_FAILURE);
   }