Panic-die if a system filter or router generates more then 32767 child
[exim.git] / src / src / routers / queryprogram.c
index 5282a1fa6bdce12cedf75d20808fc487fa6c649e..ef3ae8e28ac9b1a0ae7a3431489f35ea43a246a4 100644 (file)
@@ -1,10 +1,10 @@
-/* $Cambridge: exim/src/src/routers/queryprogram.c,v 1.4 2005/04/28 13:06:32 ph10 Exp $ */
+/* $Cambridge: exim/src/src/routers/queryprogram.c,v 1.9 2007/01/02 11:25:00 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. */
 
 #include "../exim.h"
@@ -122,6 +122,9 @@ while (generated != NULL)
   next->next = *addr_new;
   *addr_new = next;
 
+  if (addr->child_count == SHRT_MAX)
+    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s router generated more than %d "
+      "child addresses for <%s>", rblock->name, SHRT_MAX, addr->address);
   addr->child_count++;
 
   DEBUG(D_route)
@@ -181,7 +184,7 @@ queryprogram_router_entry(
   router_instance *rblock,        /* data for this instantiation */
   address_item *addr,             /* address we are working on */
   struct passwd *pw,              /* passwd entry after check_local_user */
-  BOOL verify,                    /* TRUE when verifying */
+  int verify,                     /* v_none/v_recipient/v_sender/v_expn */
   address_item **addr_local,      /* add it to this if it's local */
   address_item **addr_remote,     /* add it to this if it's remote */
   address_item **addr_new,        /* put new addresses on here */
@@ -198,8 +201,12 @@ queryprogram_router_options_block *ob =
   (queryprogram_router_options_block *)(rblock->options_block);
 uschar *current_directory = ob->current_directory;
 ugid_block ugid;
+uid_t curr_uid = getuid();
+gid_t curr_gid = getgid();
 uid_t uid = ob->cmd_uid;
 gid_t gid = ob->cmd_gid;
+uid_t *puid = &uid;
+gid_t *pgid = &gid;
 
 DEBUG(D_route) debug_printf("%s router called for %s: domain = %s\n",
   rblock->name, addr->address, addr->domain);
@@ -250,9 +257,24 @@ if (!ob->cmd_gid_set)
     }
   }
 
-DEBUG(D_route) debug_printf("uid=%ld gid=%ld current_directory=%s\n",
+DEBUG(D_route) debug_printf("requires uid=%ld gid=%ld current_directory=%s\n",
   (long int)uid, (long int)gid, current_directory);
 
+/* If we are not running as root, we will not be able to change uid/gid. */
+
+if (curr_uid != root_uid && (uid != curr_uid || gid != curr_gid))
+  {
+  DEBUG(D_route)
+    {
+    debug_printf("not running as root: cannot change uid/gid\n");
+    debug_printf("subprocess will run with uid=%ld gid=%ld\n",
+      (long int)curr_uid, (long int)curr_gid);
+    }
+  puid = pgid = NULL;
+  }
+
+/* Set up the command to run */
+
 if (!transport_set_up_command(&argvptr, /* anchor for arg list */
     ob->command,                        /* raw command */
     TRUE,                               /* expand the arguments */
@@ -266,7 +288,7 @@ if (!transport_set_up_command(&argvptr, /* anchor for arg list */
 
 /* Create the child process, making it a group leader. */
 
-pid = child_open_uid(argvptr, NULL, 0077, &uid, &gid, &fd_in, &fd_out,
+pid = child_open_uid(argvptr, NULL, 0077, puid, pgid, &fd_in, &fd_out,
   current_directory, TRUE);
 
 if (pid < 0)
@@ -278,7 +300,7 @@ if (pid < 0)
 
 /* Nothing is written to the standard input. */
 
-close(fd_in);
+(void)close(fd_in);
 
 /* Wait for the process to finish, applying the timeout, and inspect its return
 code. */
@@ -310,7 +332,7 @@ if ((rc = child_close(pid, ob->timeout)) != 0)
 /* Read the pipe to get the command's output, and then close it. */
 
 len = read(fd_out, buffer, sizeof(buffer) - 1);
-close(fd_out);
+(void)close(fd_out);
 
 /* Failure to return any data is an error. */