Store the initial working directory, expand $initial_cwd. Bug 1805
[exim.git] / src / src / exim.c
index b4ea01dcd35fa64cd6adfb4a8ddabc9848bc12e6..453165f830d629dd37166118beee003c8a93cd29 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 - 2012 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 
@@ -816,7 +816,7 @@ fprintf(f, "Lookups (built-in):");
   fprintf(f, " cdb");
 #endif
 #if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
-  fprintf(f, " dbm dbmnz");
+  fprintf(f, " dbm dbmjz dbmnz");
 #endif
 #if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
   fprintf(f, " dnsdb");
@@ -872,6 +872,9 @@ fprintf(f, "Authenticators:");
 #ifdef AUTH_GSASL
   fprintf(f, " gsasl");
 #endif
+#ifdef AUTH_HEIMDAL_GSSAPI
+  fprintf(f, " heimdal_gssapi");
+#endif
 #ifdef AUTH_PLAINTEXT
   fprintf(f, " plaintext");
 #endif
@@ -973,20 +976,21 @@ DEBUG(D_any) do {
     }
   }
 
+  /* PCRE_PRERELEASE is either defined and empty or a bare sequence of
+  characters; unless it's an ancient version of PCRE in which case it
+  is not defined. */
+#ifndef PCRE_PRERELEASE
+#define PCRE_PRERELEASE
+#endif
+#define QUOTE(X) #X
+#define EXPAND_AND_QUOTE(X) QUOTE(X)
   fprintf(f, "Library version: PCRE: Compile: %d.%d%s\n"
              "                       Runtime: %s\n",
           PCRE_MAJOR, PCRE_MINOR,
-          /* PRE_PRERELEASE is either defined and empty or a string.
-           * unless its an ancient version of PCRE in which case it
-           * is not defined */
-#ifdef PCRE_PRERELEASE
-# define STRINGIFY(x) #x
-          STRINGIFY(PCRE_PRERELEASE) "",
-# undef STRINGIFY
-#else
-          "",
-#endif
+          EXPAND_AND_QUOTE(PCRE_PRERELEASE) "",
           pcre_version());
+#undef QUOTE
+#undef EXPAND_AND_QUOTE
 
   init_lookup_list();
   for (i = 0; i < lookup_list_count; i++)
@@ -2057,6 +2061,24 @@ for (i = 1; i < argc; i++)
       show_whats_supported(stdout);
       }
 
+    /* -bw: inetd wait mode, accept a listening socket as stdin */
+
+    else if (*argrest == 'w')
+      {
+      inetd_wait_mode = TRUE;
+      background_daemon = FALSE;
+      daemon_listen = TRUE;
+      if (*(++argrest) != '\0')
+        {
+        inetd_wait_timeout = readconf_readtime(argrest, 0, FALSE);
+        if (inetd_wait_timeout <= 0)
+          {
+          fprintf(stderr, "exim: bad time value %s: abandoned\n", argv[i]);
+          exit(EXIT_FAILURE);
+          }
+        }
+      }
+
     else badarg = TRUE;
     break;
 
@@ -3219,6 +3241,9 @@ if ((
     daemon_listen && queue_interval == 0
     ) ||
     (
+    inetd_wait_mode && queue_interval >= 0
+    ) ||
+    (
     list_options &&
     (checking || smtp_input || extract_recipients ||
       filter_test != FTEST_NONE || bi_option)
@@ -3453,12 +3478,41 @@ if ((filter_test & FTEST_USER) != 0)
     }
   }
 
+/* Initialise lookup_list
+If debugging, already called above via version reporting.
+In either case, we initialise the list of available lookups while running
+as root.  All dynamically modules are loaded from a directory which is
+hard-coded into the binary and is code which, if not a module, would be
+part of Exim already.  Ability to modify the content of the directory
+is equivalent to the ability to modify a setuid binary!
+
+This needs to happen before we read the main configuration. */
+init_lookup_list();
+
 /* Read the main runtime configuration data; this gives up if there
 is a failure. It leaves the configuration file open so that the subsequent
 configuration data for delivery can be read if needed. */
 
+/* To be safe: change the working directory to /. */
+if (Uchdir("/") < 0)
+  {
+    perror("exim: chdir `/': ");
+    exit(EXIT_FAILURE);
+  }
+
+/* Store the initial cwd before we change directories */
+if ((initial_cwd = getcwd(NULL, 0)) == NULL)
+  {
+  perror("exim: can't get the current working directory");
+  exit(EXIT_FAILURE);
+  }
+
 readconf_main();
 
+if (cleanup_environment() == FALSE)
+  log_write(0, LOG_PANIC_DIE, "Can't cleanup environment");
+
+
 /* Handle the decoding of logging options. */
 
 decode_bits(&log_write_selector, &log_extra_selector, 0, 0,
@@ -3526,7 +3580,7 @@ TMPDIR macro, if this macro is defined. */
 #ifdef TMPDIR
   {
   uschar **p;
-  for (p = USS environ; *p != NULL; p++)
+  if (environ) for (p = USS environ; *p != NULL; p++)
     {
     if (Ustrncmp(*p, "TMPDIR=", 7) == 0 &&
         Ustrcmp(*p+7, TMPDIR) != 0)
@@ -3566,10 +3620,10 @@ else
     uschar **new;
     uschar **newp;
     int count = 0;
-    while (*p++ != NULL) count++;
+    if (environ) while (*p++ != NULL) count++;
     if (envtz == NULL) count++;
     newp = new = malloc(sizeof(uschar *) * (count + 1));
-    for (p = USS environ; *p != NULL; p++)
+    if (environ) for (p = USS environ; *p != NULL; p++)
       {
       if (Ustrncmp(*p, "TZ=", 3) == 0) continue;
       *newp++ = *p;
@@ -3641,13 +3695,6 @@ if (opt_perl_at_start && opt_perl_startup != NULL)
   }
 #endif /* EXIM_PERL */
 
-/* Initialise lookup_list
-If debugging, already called above via version reporting.
-This does mean that debugging causes the list to be initialised while root.
-This *should* be harmless -- all modules are loaded from a fixed dir and
-it's code that would, if not a module, be part of Exim already. */
-init_lookup_list();
-
 /* Log the arguments of the call if the configuration file said so. This is
 a debugging feature for finding out what arguments certain MUAs actually use.
 Don't attempt it if logging is disabled, or if listing variables or if
@@ -3658,8 +3705,10 @@ if (((debug_selector & D_any) != 0 || (log_extra_selector & LX_arguments) != 0)
   {
   int i;
   uschar *p = big_buffer;
-  Ustrcpy(p, "cwd=");
   (void)getcwd(CS p+4, big_buffer_size - 4);
+
+  Ustrncpy(p + 4, initial_cwd, big_buffer_size-5);
+
   while (*p) p++;
   (void)string_format(p, big_buffer_size - (p - big_buffer), " %d args:", argc);
   while (*p) p++;
@@ -4205,7 +4254,8 @@ if (list_options)
           (Ustrcmp(argv[i], "router") == 0 ||
            Ustrcmp(argv[i], "transport") == 0 ||
            Ustrcmp(argv[i], "authenticator") == 0 ||
-           Ustrcmp(argv[i], "macro") == 0))
+           Ustrcmp(argv[i], "macro") == 0 ||
+           Ustrcmp(argv[i], "environment") == 0))
         {
         readconf_print(argv[i+1], argv[i]);
         i++;
@@ -4399,7 +4449,7 @@ returns. We leave this till here so that the originator_ fields are available
 for incoming messages via the daemon. The daemon cannot be run in mua_wrapper
 mode. */
 
-if (daemon_listen || queue_interval > 0)
+if (daemon_listen || inetd_wait_mode || queue_interval > 0)
   {
   if (mua_wrapper)
     {