diff options
author | Philip Hazel <ph10@hermes.cam.ac.uk> | 2006-02-07 14:05:17 +0000 |
---|---|---|
committer | Philip Hazel <ph10@hermes.cam.ac.uk> | 2006-02-07 14:05:17 +0000 |
commit | 59e82a2a0e97f55f0e27323112116e01a06cb198 (patch) | |
tree | 945e9bc068b5c4dded91c9404f6ac1df785f1a78 /src | |
parent | 312fd9e929e73d6c0d5ca7414431d2b87fa0ea21 (diff) |
Improve queryprogram behaviour when not running as root.
Diffstat (limited to 'src')
-rw-r--r-- | src/src/child.c | 59 | ||||
-rw-r--r-- | src/src/routers/queryprogram.c | 25 |
2 files changed, 63 insertions, 21 deletions
diff --git a/src/src/child.c b/src/src/child.c index 8f2f9d78c..4a1a89887 100644 --- a/src/src/child.c +++ b/src/src/child.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/child.c,v 1.7 2006/02/07 11:19:00 ph10 Exp $ */ +/* $Cambridge: exim/src/src/child.c,v 1.8 2006/02/07 14:05:17 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -292,14 +292,48 @@ otherwise. Save the old state for resetting on the wait. */ oldsignal = signal(SIGCHLD, SIG_DFL); pid = fork(); -/* The child process becomes a process group leader if requested, and then -organizes the pipes. Any unexpected failure is signalled with EX_EXECFAILED; -these are all "should never occur" failures, except perhaps for exec failing -because the command doesn't exist. */ +/* Handle the child process. First, set the required environment. We must do +this before messing with the pipes, in order to be able to write debugging +output when things go wrong. */ if (pid == 0) { - if (make_leader && setpgid(0,0) < 0) goto CHILD_FAILED; + signal(SIGUSR1, SIG_IGN); + + if (newgid != NULL && setgid(*newgid) < 0) + { + DEBUG(D_any) debug_printf("failed to set gid=%ld in subprocess: %s\n", + (long int)(*newgid), strerror(errno)); + goto CHILD_FAILED; + } + + if (newuid != NULL && setuid(*newuid) < 0) + { + DEBUG(D_any) debug_printf("failed to set uid=%ld in subprocess: %s\n", + (long int)(*newuid), strerror(errno)); + goto CHILD_FAILED; + } + + (void)umask(newumask); + + if (wd != NULL && Uchdir(wd) < 0) + { + DEBUG(D_any) debug_printf("failed to chdir to %s: %s\n", wd, + strerror(errno)); + goto CHILD_FAILED; + } + + /* Becomes a process group leader if requested, and then organize the pipes. + Any unexpected failure is signalled with EX_EXECFAILED; these are all "should + never occur" failures, except for exec failing because the command doesn't + exist. */ + + if (make_leader && setpgid(0,0) < 0) + { + DEBUG(D_any) debug_printf("failed to set group leader in subprocess: %s\n", + strerror(errno)); + goto CHILD_FAILED; + } (void)close(inpfd[pipe_write]); force_fd(inpfd[pipe_read], 0); @@ -310,17 +344,6 @@ if (pid == 0) (void)close(2); (void)dup2(1, 2); - /* Set the required environment. */ - - signal(SIGUSR1, SIG_IGN); - if (newgid != NULL && setgid(*newgid) < 0) goto CHILD_FAILED; - if (newuid != NULL && setuid(*newuid) < 0) goto CHILD_FAILED; - (void)umask(newumask); - - /* Set the working directory if required */ - - if (wd != NULL && Uchdir(wd) < 0) goto CHILD_FAILED; - /* Now do the exec */ if (envp == NULL) execv(CS argv[0], (char *const *)argv); @@ -328,7 +351,7 @@ if (pid == 0) /* Failed to execv. Signal this failure using EX_EXECFAILED. We are losing the actual errno we got back, because there is no way to return - this. */ + this information. */ CHILD_FAILED: _exit(EX_EXECFAILED); /* Note: must be _exit(), NOT exit() */ diff --git a/src/src/routers/queryprogram.c b/src/src/routers/queryprogram.c index c9b409e78..1b974fc4e 100644 --- a/src/src/routers/queryprogram.c +++ b/src/src/routers/queryprogram.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/routers/queryprogram.c,v 1.7 2006/02/07 11:19:02 ph10 Exp $ */ +/* $Cambridge: exim/src/src/routers/queryprogram.c,v 1.8 2006/02/07 14:05:17 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -198,8 +198,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 +254,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 +285,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) |