Add acl_not_smtp_start ACL (mostly Johannes Berg's patch).
[exim.git] / src / src / exim.c
index 5cc0cb47c8ebbd3c9d4de4fb09ae1209955561d3..a40ded77e7ea2af2bae92662347cc8e48c911ce6 100644 (file)
@@ -1,10 +1,10 @@
-/* $Cambridge: exim/src/src/exim.c,v 1.22 2005/06/28 10:23:35 ph10 Exp $ */
+/* $Cambridge: exim/src/src/exim.c,v 1.40 2006/06/28 16:00:24 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* Copyright (c) University of Cambridge 1995 - 2006 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 
@@ -375,6 +375,38 @@ va_end(ap);
 
 
 
+/*************************************************
+*   Call fopen() with umask 777 and adjust mode  *
+*************************************************/
+
+/* Exim runs with umask(0) so that files created with open() have the mode that
+is specified in the open() call. However, there are some files, typically in
+the spool directory, that are created with fopen(). They end up world-writeable
+if no precautions are taken. Although the spool directory is not accessible to
+the world, this is an untidiness. So this is a wrapper function for fopen()
+that sorts out the mode of the created file.
+
+Arguments:
+   filename       the file name
+   options        the fopen() options
+   mode           the required mode
+
+Returns:          the fopened FILE or NULL
+*/
+
+FILE *
+modefopen(uschar *filename, char *options, mode_t mode)
+{
+mode_t saved_umask = umask(0777);
+FILE *f = Ufopen(filename, options);
+(void)umask(saved_umask);
+if (f != NULL) (void)fchmod(fileno(f), mode);
+return f;
+}
+
+
+
+
 /*************************************************
 *   Ensure stdin, stdout, and stderr exist       *
 *************************************************/
@@ -599,7 +631,7 @@ Returns:    the port, or zero if there isn't one
 static int
 check_port(uschar *address)
 {
-int port = host_extract_port(address);
+int port = host_address_extract_port(address);
 if (string_is_ip_address(address, NULL) == 0)
   {
   fprintf(stderr, "exim abandoned: \"%s\" is not an IP address\n", address);
@@ -833,12 +865,18 @@ fprintf(f, "Using tdb\n");
 #endif
 
 fprintf(f, "Support for:");
+#ifdef SUPPORT_CRYPTEQ
+  fprintf(f, " crypteq");
+#endif
 #if HAVE_ICONV
   fprintf(f, " iconv()");
 #endif
 #if HAVE_IPV6
   fprintf(f, " IPv6");
 #endif
+#ifdef HAVE_SETCLASSRESOURCES
+  fprintf(f, " use_setclassresources");
+#endif
 #ifdef SUPPORT_PAM
   fprintf(f, " PAM");
 #endif
@@ -858,6 +896,12 @@ fprintf(f, "Support for:");
   fprintf(f, " OpenSSL");
   #endif
 #endif
+#ifdef SUPPORT_TRANSLATE_IP_ADDRESS
+  fprintf(f, " translate_ip_address");
+#endif
+#ifdef SUPPORT_MOVE_FROZEN_MESSAGES
+  fprintf(f, " move_frozen_messages");
+#endif
 #ifdef WITH_CONTENT_SCAN
   fprintf(f, " Content_Scanning");
 #endif
@@ -918,6 +962,9 @@ fprintf(f, "Lookups:");
 #ifdef LOOKUP_PGSQL
   fprintf(f, " pgsql");
 #endif
+#ifdef LOOKUP_SQLITE
+  fprintf(f, " sqlite");
+#endif
 #ifdef LOOKUP_TESTDB
   fprintf(f, " testdb");
 #endif
@@ -1000,6 +1047,8 @@ if (fixed_never_users[0] > 0)
     fprintf(f, "%d:", (unsigned int)fixed_never_users[i]);
   fprintf(f, "%d\n", (unsigned int)fixed_never_users[i]);
   }
+
+fprintf(f, "Size of off_t: %d\n", sizeof(off_t));
 }
 
 
@@ -1423,10 +1472,17 @@ message_id_external[0] = 'E';
 message_id = message_id_external + 1;
 message_id[0] = 0;
 
-/* Set the umask to zero so that any files that Exim creates are created
-with the modes that it specifies. */
+/* Set the umask to zero so that any files Exim creates using open() are
+created with the modes that it specifies. NOTE: Files created with fopen() have
+a problem, which was not recognized till rather late (February 2006). With this
+umask, such files will be world writeable. (They are all content scanning files
+in the spool directory, which isn't world-accessible, so this is not a
+disaster, but it's untidy.) I don't want to change this overall setting,
+however, because it will interact badly with the open() calls. Instead, there's
+now a function called modefopen() that fiddles with the umask while calling
+fopen(). */
 
-umask(0);
+(void)umask(0);
 
 /* Precompile the regular expression for matching a message id. Keep this in
 step with the code that generates ids in the accept.c module. We need to do
@@ -1987,6 +2043,7 @@ for (i = 1; i < argc; i++)
         { badarg = TRUE; break; }
       }
     originator_name = argrest;
+    sender_name_forced = TRUE;
     break;
 
 
@@ -3297,11 +3354,12 @@ if (((debug_selector & D_any) != 0 || (log_extra_selector & LX_arguments) != 0)
 on this in the code, which always uses fully qualified names, but it's useful
 for core dumps etc. Don't complain if it fails - the spool directory might not
 be generally accessible and calls with the -C option (and others) have lost
-privilege by now. */
+privilege by now. Before the chdir, we try to ensure that the directory exists.
+*/
 
 if (Uchdir(spool_directory) != 0)
   {
-  (void)directory_make(spool_directory, US"", SPOOL_DIRECTORY_MODE, TRUE);
+  (void)directory_make(spool_directory, US"", SPOOL_DIRECTORY_MODE, FALSE);
   (void)Uchdir(spool_directory);
   }
 
@@ -3539,7 +3597,9 @@ root privilege above as a result of -C, -D, -be, -bf or -bF, remove it now
 except when starting the daemon or doing some kind of delivery or address
 testing (-bt). These are the only cases when root need to be retained. We run
 as exim for -bv and -bh. However, if deliver_drop_privilege is set, root is
-retained only for starting the daemon. */
+retained only for starting the daemon. We always do the initgroups() in this
+situation (controlled by the TRUE below), in order to be as close as possible
+to the state Exim usually runs in. */
 
 if (!unprivileged &&                      /* originally had root AND */
     !removed_privilege &&                 /* still got root AND      */
@@ -3555,7 +3615,7 @@ if (!unprivileged &&                      /* originally had root AND */
         )
       ))
   {
-  exim_setugid(exim_uid, exim_gid, FALSE, US"privilege not needed");
+  exim_setugid(exim_uid, exim_gid, TRUE, US"privilege not needed");
   }
 
 /* When we are retaining a privileged uid, we still change to the exim gid. */
@@ -3667,11 +3727,13 @@ if (test_retry_arg >= 0)
       return EXIT_FAILURE;
       }
 
-    /* For the rcpt_4xx errors, a value of 255 means "any", and a code > 100 as
-    an error is for matching codes to the decade. Turn them into a real error
-    code, off the decade. */
+    /* For the {MAIL,RCPT,DATA}_4xx errors, a value of 255 means "any", and a
+    code > 100 as an error is for matching codes to the decade. Turn them into
+    a real error code, off the decade. */
 
-    if (basic_errno == ERRNO_RCPT4XX)
+    if (basic_errno == ERRNO_MAIL4XX ||
+        basic_errno == ERRNO_RCPT4XX ||
+        basic_errno == ERRNO_DATA4XX)
       {
       int code = (more_errno >> 8) & 255;
       if (code == 255)
@@ -3905,7 +3967,7 @@ for (i = 0;;)
 
 /* If we cannot get a user login, log the incident and give up, unless the
 configuration specifies something to use. When running in the test harness,
-any setting of unknown_login overrides the actual login name. */
+any setting of unknown_login overrides the actual name. */
 
 if (originator_login == NULL || running_in_test_harness)
   {
@@ -4360,7 +4422,7 @@ if (smtp_input)
     }
   }
 
-/* Otherwise, set up the input size limit here */
+/* Otherwise, set up the input size limit here. */
 
 else
   {
@@ -4576,6 +4638,19 @@ while (more)
         }
       }
 
+    /* Run the acl_not_smtp_start ACL if required. The result of the ACL is
+    ignored; rejecting here would just add complication, and it can just as
+    well be done later. Allow $recipients to be visible in the ACL. */
+
+    if (acl_not_smtp_start != NULL)
+      {
+      uschar *user_msg, *log_msg;
+      enable_dollar_recipients = TRUE;
+      (void)acl_check(ACL_WHERE_NOTSMTP_START, NULL, acl_not_smtp_start,
+        &user_msg, &log_msg);
+      enable_dollar_recipients = FALSE;
+      }
+
     /* Read the data for the message. If filter_test is not FTEST_NONE, this
     will just read the headers for the message, and not write anything onto the
     spool. */
@@ -4724,12 +4799,6 @@ while (more)
       close_unwanted();      /* Close unwanted file descriptors and TLS */
       exim_nullstd();        /* Ensure std{in,out,err} exist */
 
-      /* Occasionally in the test harness we don't have synchronous delivery
-      set (can happen with bounces). In that case, let the old process finish
-      before continuing, to keep the debug output the same. */
-
-      if (running_in_test_harness && !synchronous_delivery) millisleep(100);
-
       /* Re-exec Exim if we need to regain privilege (note: in mua_wrapper
       mode, deliver_drop_privilege is forced TRUE). */