Fix CVE-2016-1531
[exim.git] / src / src / exim.c
index d7cb5d88b13e90bff71642b90cf257c747e352ba..d6f2d4aac601c3fde28b0167461785bad131543e 100644 (file)
@@ -230,7 +230,7 @@ to disrupt whatever is going on outside the signal handler. */
 
 if (fd < 0) return;
 
-{int dummy = write(fd, process_info, process_info_len); dummy = dummy; }
+(void)write(fd, process_info, process_info_len);
 (void)close(fd);
 }
 
@@ -814,21 +814,33 @@ fprintf(f, "Support for:");
 #ifdef WITH_CONTENT_SCAN
   fprintf(f, " Content_Scanning");
 #endif
-#ifndef DISABLE_DKIM
-  fprintf(f, " DKIM");
-#endif
 #ifdef WITH_OLD_DEMIME
   fprintf(f, " Old_Demime");
 #endif
+#ifndef DISABLE_DKIM
+  fprintf(f, " DKIM");
+#endif
 #ifndef DISABLE_DNSSEC
   fprintf(f, " DNSSEC");
 #endif
-#ifndef DISABLE_PRDR
-  fprintf(f, " PRDR");
+#ifndef DISABLE_EVENT
+  fprintf(f, " Event");
+#endif
+#ifdef SUPPORT_I18N
+  fprintf(f, " I18N");
 #endif
 #ifndef DISABLE_OCSP
   fprintf(f, " OCSP");
 #endif
+#ifndef DISABLE_PRDR
+  fprintf(f, " PRDR");
+#endif
+#ifdef SUPPORT_PROXY
+  fprintf(f, " PROXY");
+#endif
+#ifdef SUPPORT_SOCKS
+  fprintf(f, " SOCKS");
+#endif
 #ifdef EXPERIMENTAL_SPF
   fprintf(f, " Experimental_SPF");
 #endif
@@ -847,20 +859,8 @@ fprintf(f, "Support for:");
 #ifdef EXPERIMENTAL_DMARC
   fprintf(f, " Experimental_DMARC");
 #endif
-#ifdef EXPERIMENTAL_PROXY
-  fprintf(f, " Experimental_Proxy");
-#endif
-#ifdef EXPERIMENTAL_EVENT
-  fprintf(f, " Experimental_Event");
-#endif
-#ifdef EXPERIMENTAL_REDIS
-  fprintf(f, " Experimental_Redis");
-#endif
-#ifdef EXPERIMENTAL_SOCKS
-  fprintf(f, " Experimental_SOCKS");
-#endif
-#ifdef EXPERIMENTAL_INTERNATIONAL
-  fprintf(f, " Experimental_International");
+#ifdef EXPERIMENTAL_DSN_INFO
+  fprintf(f, " Experimental_DSN_info");
 #endif
 fprintf(f, "\n");
 
@@ -904,6 +904,9 @@ fprintf(f, "Lookups (built-in):");
 #if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
   fprintf(f, " pgsql");
 #endif
+#if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
+  fprintf(f, " redis");
+#endif
 #if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
   fprintf(f, " sqlite");
 #endif
@@ -1028,7 +1031,7 @@ DEBUG(D_any) do {
 #ifdef SUPPORT_TLS
   tls_version_report(f);
 #endif
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
   utf8_version_report(f);
 #endif
 
@@ -1489,6 +1492,7 @@ BOOL f_end_dot = FALSE;
 BOOL deliver_give_up = FALSE;
 BOOL list_queue = FALSE;
 BOOL list_options = FALSE;
+BOOL list_config = FALSE;
 BOOL local_queue_only;
 BOOL more = TRUE;
 BOOL one_msg_action = FALSE;
@@ -1605,8 +1609,9 @@ if (!route_findgroup(US CONFIGURE_GROUPNAME, &config_gid))
   }
 #endif
 
-/* In the Cygwin environment, some initialization needs doing. It is fudged
-in by means of this macro. */
+/* In the Cygwin environment, some initialization used to need doing.
+It was fudged in by means of this macro; now no longer but we'll leave
+it in case of others. */
 
 #ifdef OS_INIT
 OS_INIT
@@ -1753,6 +1758,7 @@ regex_whitelisted_macro =
   regex_must_compile(US"^[A-Za-z0-9_/.-]*$", FALSE, TRUE);
 #endif
 
+for (i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL;
 
 /* If the program is called as "mailq" treat it as equivalent to "exim -bp";
 this seems to be a generally accepted convention, since one finds symbolic
@@ -2150,9 +2156,19 @@ for (i = 1; i < argc; i++)
 
     else if (Ustrcmp(argrest, "P") == 0)
       {
-      list_options = TRUE;
-      debug_selector |= D_v;
-      debug_file = stderr;
+      /* -bP config: we need to setup here, because later,
+       * when list_options is checked, the config is read already */
+      if (argv[i+1] && Ustrcmp(argv[i+1], "config") == 0)
+        {
+        list_config = TRUE;
+        readconf_save_config(version_string);
+        }
+      else
+        {
+        list_options = TRUE;
+        debug_selector |= D_v;
+        debug_file = stderr;
+        }
       }
 
     /* -brt: Test retry configuration lookup */
@@ -2544,12 +2560,12 @@ for (i = 1; i < argc; i++)
         if (temp >= argrest && *temp == '.') f_end_dot = TRUE;
         allow_domain_literals = TRUE;
         strip_trailing_dot = TRUE;
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
        allow_utf8_domains = TRUE;
 #endif
         sender_address = parse_extract_address(argrest, &errmess,
           &dummy_start, &dummy_end, &sender_address_domain, TRUE);
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
        message_smtputf8 =  string_is_utf8(sender_address);
        allow_utf8_domains = FALSE;
 #endif
@@ -3719,7 +3735,7 @@ is equivalent to the ability to modify a setuid binary!
 This needs to happen before we read the main configuration. */
 init_lookup_list();
 
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
 if (running_in_test_harness) smtputf8_advertise_hosts = NULL;
 #endif
 
@@ -3727,8 +3743,19 @@ if (running_in_test_harness) smtputf8_advertise_hosts = NULL;
 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);
+  }
+
 readconf_main();
 
+if (cleanup_environment() == FALSE)
+  log_write(0, LOG_PANIC_DIE, "Can't cleanup environment");
+
+
 /* If an action on specific messages is requested, or if a daemon or queue
 runner is being started, we need to know if Exim was called by an admin user.
 This is the case if the real user is root or exim, or if the real group is
@@ -3883,20 +3910,23 @@ if (log_oneline)
 temporary files are created; Exim doesn't use these (apart from when delivering
 to MBX mailboxes), but called libraries such as DBM libraries may require them.
 If TMPDIR is found in the environment, reset it to the value defined in the
-TMPDIR macro, if this macro is defined. */
+EXIM_TMPDIR macro, if this macro is defined.  For backward compatibility this
+macro may be called TMPDIR in old "Local/Makefile"s. It's converted to
+EXIM_TMPDIR by the build scripts.
+*/
 
-#ifdef TMPDIR
+#ifdef EXIM_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)
+        Ustrcmp(*p+7, EXIM_TMPDIR) != 0)
       {
-      uschar *newp = malloc(Ustrlen(TMPDIR) + 8);
-      sprintf(CS newp, "TMPDIR=%s", TMPDIR);
+      uschar *newp = malloc(Ustrlen(EXIM_TMPDIR) + 8);
+      sprintf(CS newp, "TMPDIR=%s", EXIM_TMPDIR);
       *p = newp;
-      DEBUG(D_any) debug_printf("reset TMPDIR=%s in environment\n", TMPDIR);
+      DEBUG(D_any) debug_printf("reset TMPDIR=%s in environment\n", EXIM_TMPDIR);
       }
     }
   }
@@ -3928,10 +3958,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;
@@ -4521,7 +4551,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], flag_n);
         i++;
@@ -4531,6 +4562,19 @@ if (list_options)
   exim_exit(EXIT_SUCCESS);
   }
 
+if (list_config)
+  {
+  set_process_info("listing config");
+  readconf_print(US"config", NULL, FALSE);
+  exim_exit(EXIT_SUCCESS);
+  }
+
+
+/* Initialise subsystems as required */
+#ifndef DISABLE_DKIM
+dkim_exim_init();
+#endif
+
 
 /* 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
@@ -5027,6 +5071,7 @@ if (host_checking)
     "**** This is not for real!\n\n",
       sender_host_address);
 
+  memset(sender_host_cache, 0, sizeof(sender_host_cache));
   if (verify_check_host(&hosts_connection_nolog) == OK)
     BIT_CLEAR(log_selector, log_selector_size, Li_smtp_connection);
   log_write(L_smtp_connection, LOG_MAIN, "%s", smtp_get_connection_info());
@@ -5097,7 +5142,7 @@ if (mua_wrapper)
   deliver_drop_privilege = TRUE;
   queue_smtp = FALSE;
   queue_smtp_domains = NULL;
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
   message_utf8_downconvert = -1;       /* convert-if-needed */
 #endif
   }
@@ -5201,6 +5246,7 @@ if (smtp_input)
   {
   smtp_in = stdin;
   smtp_out = stdout;
+  memset(sender_host_cache, 0, sizeof(sender_host_cache));
   if (verify_check_host(&hosts_connection_nolog) == OK)
     BIT_CLEAR(log_selector, log_selector_size, Li_smtp_connection);
   log_write(L_smtp_connection, LOG_MAIN, "%s", smtp_get_connection_info());
@@ -5390,7 +5436,7 @@ while (more)
                 errors_sender_rc : EXIT_FAILURE;
             }
 
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
        {
        BOOL b = allow_utf8_domains;
        allow_utf8_domains = TRUE;
@@ -5398,7 +5444,7 @@ while (more)
         recipient =
           parse_extract_address(s, &errmess, &start, &end, &domain, FALSE);
 
-#ifdef EXPERIMENTAL_INTERNATIONAL
+#ifdef SUPPORT_I18N
        if (string_is_utf8(recipient))
          message_smtputf8 = TRUE;
        else