Fix CVE-2016-1531
[exim.git] / src / src / exim.c
index 91a3f7a4c676e2b831a859b453d3befe505b80dd..3dc5214f10d29c2169cdfc19405866f275843348 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2012 */
+/* Copyright (c) University of Cambridge 1995 - 2014 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 
@@ -399,9 +399,10 @@ if (exim_tvcmp(&now_tv, then_tv) <= 0)
     if (!running_in_test_harness)
       {
       debug_printf("tick check: %lu.%06lu %lu.%06lu\n",
-        then_tv->tv_sec, then_tv->tv_usec, now_tv.tv_sec, now_tv.tv_usec);
+        then_tv->tv_sec, (long) then_tv->tv_usec,
+               now_tv.tv_sec, (long) now_tv.tv_usec);
       debug_printf("waiting %lu.%06lu\n", itval.it_value.tv_sec,
-        itval.it_value.tv_usec);
+        (long) itval.it_value.tv_usec);
       }
     }
 
@@ -526,7 +527,7 @@ close_unwanted(void)
 if (smtp_input)
   {
   #ifdef SUPPORT_TLS
-  tls_close(FALSE, FALSE);      /* Shut down the TLS library */
+  tls_close(TRUE, FALSE);      /* Shut down the TLS library */
   #endif
   (void)close(fileno(smtp_in));
   (void)close(fileno(smtp_out));
@@ -804,6 +805,12 @@ fprintf(f, "Support for:");
 #ifdef WITH_OLD_DEMIME
   fprintf(f, " Old_Demime");
 #endif
+#ifndef DISABLE_PRDR
+  fprintf(f, " PRDR");
+#endif
+#ifndef DISABLE_OCSP
+  fprintf(f, " OCSP");
+#endif
 #ifdef EXPERIMENTAL_SPF
   fprintf(f, " Experimental_SPF");
 #endif
@@ -816,8 +823,23 @@ fprintf(f, "Support for:");
 #ifdef EXPERIMENTAL_DCC
   fprintf(f, " Experimental_DCC");
 #endif
-#ifdef EXPERIMENTAL_OCSP
-  fprintf(f, " Experimental_OCSP");
+#ifdef EXPERIMENTAL_DMARC
+  fprintf(f, " Experimental_DMARC");
+#endif
+#ifdef EXPERIMENTAL_PROXY
+  fprintf(f, " Experimental_Proxy");
+#endif
+#ifdef EXPERIMENTAL_TPDA
+  fprintf(f, " Experimental_TPDA");
+#endif
+#ifdef EXPERIMENTAL_REDIS
+  fprintf(f, " Experimental_Redis");
+#endif
+#ifdef EXPERIMENTAL_CERTNAMES
+  fprintf(f, " Experimental_Certnames");
+#endif
+#ifdef EXPERIMENTAL_DSN
+  fprintf(f, " Experimental_DSN");
 #endif
 fprintf(f, "\n");
 
@@ -2641,6 +2663,16 @@ for (i = 1; i < argc; i++)
       break;
       }
 
+    #ifdef EXPERIMENTAL_DSN
+    /* -MCD: set the smtp_use_dsn flag; this indicates that the host
+       that exim is connected to supports the esmtp extension DSN */
+    else if (strcmp(argrest, "CD") == 0)
+      {
+      smtp_use_dsn = TRUE;
+      break;
+      }
+    #endif
+
     /* -MCP: set the smtp_use_pipelining flag; this is useful only when
     it preceded -MC (see above) */
 
@@ -2974,6 +3006,23 @@ for (i = 1; i < argc; i++)
 
       else if (Ustrcmp(argrest, "Mi") == 0) interface_address = argv[++i];
 
+      /* -oMm: Message reference */
+
+      else if (Ustrcmp(argrest, "Mm") == 0)
+        {
+        if (!mac_ismsgid(argv[i+1]))
+          {
+            fprintf(stderr,"-oMm must be a valid message ID\n");
+            exit(EXIT_FAILURE);
+          }
+        if (!trusted_config)
+          {
+            fprintf(stderr,"-oMm must be called by a trusted user/config\n");
+            exit(EXIT_FAILURE);
+          }
+          message_reference = argv[++i];
+        }
+
       /* -oMr: Received protocol */
 
       else if (Ustrcmp(argrest, "Mr") == 0) received_protocol = argv[++i];
@@ -3636,8 +3685,19 @@ init_lookup_list();
 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
@@ -3783,7 +3843,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)
@@ -3823,10 +3883,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;
@@ -4264,13 +4324,12 @@ if (msg_action_arg > 0 && msg_action != MSG_DELIVER && msg_action != MSG_LOAD)
   exit(yield);
   }
 
-/* All the modes below here require the remaining configuration sections
-to be read, except that we can skip over the ACL setting when delivering
-specific messages, or doing a queue run. (For various testing cases we could
-skip too, but as they are rare, it doesn't really matter.) The argument is TRUE
-for skipping. */
+/* We used to set up here to skip reading the ACL section, on
+ (msg_action_arg > 0 || (queue_interval == 0 && !daemon_listen)
+Now, since the intro of the ${acl } expansion, ACL definitions may be
+needed in transports so we lost the optimisation. */
 
-readconf_rest(msg_action_arg > 0 || (queue_interval == 0 && !daemon_listen));
+readconf_rest();
 
 /* The configuration data will have been read into POOL_PERM because we won't
 ever want to reset back past it. Change the current pool to POOL_MAIN. In fact,
@@ -4417,7 +4476,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++;