diff --git a/gmid.c b/gmid.c index 0949e7f..463b7ae 100644 --- a/gmid.c +++ b/gmid.c @@ -51,7 +51,7 @@ static struct privsep_proc procs[] = { { "logger", PROC_LOGGER, main_dispatch_logger, logger }, }; -static const char *opts = "c:D:fI:hnP:T:Vv"; +static const char *opts = "c:D:fI:hnP:T:U:VvX:"; static const struct option longopts[] = { {"help", no_argument, NULL, 'h'}, @@ -169,6 +169,7 @@ main(int argc, char **argv) struct conf *conf; struct privsep *ps; const char *errstr, *title = NULL; + const char *user = NULL, *chroot = NULL; size_t i; int ch, conftest = 0; int proc_instance = 0; @@ -214,12 +215,18 @@ main(int argc, char **argv) if (proc_id == PROC_MAX) fatalx("invalid process name"); break; + case 'U': + user = optarg; + break; case 'V': puts("Version: " GMID_STRING); return 0; case 'v': verbose = 1; break; + case 'X': + chroot = optarg; + break; default: usage(); return 1; @@ -231,10 +238,21 @@ main(int argc, char **argv) conf = config_new(); - if (parse_conf(conf, config_path) == -1) - fatalx("failed to load configuration file"); - if (*conf->chroot != '\0' && *conf->user == '\0') - fatalx("can't chroot without a user to switch to after."); + /* + * Only the parent loads the config, the others get user and + * chroot via flags and the rest via imsg. + */ + if (proc_id == PROC_PARENT) { + if (parse_conf(conf, config_path) == -1) + fatalx("failed to load configuration file"); + if (*conf->chroot != '\0' && *conf->user == '\0') + fatalx("can't chroot without a user to switch to."); + } else { + if (user) + strlcpy(conf->user, user, sizeof(conf->user)); + if (chroot) + strlcpy(conf->chroot, chroot, sizeof(conf->chroot)); + } if (conftest) { fprintf(stderr, "config OK\n"); diff --git a/proc.c b/proc.c index 62d3b87..3060e65 100644 --- a/proc.c +++ b/proc.c @@ -89,14 +89,14 @@ void proc_exec(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc, int debug, int argc, char **argv) { - unsigned int proc, nargc, i, proc_i; + unsigned int proc, nargc, i, proc_i, proc_X = 0; const char **nargv; struct privsep_proc *p; char num[32]; int fd; /* Prepare the new process argv. */ - nargv = calloc(argc + 5, sizeof(char *)); + nargv = calloc(argc + 9, sizeof(char *)); if (nargv == NULL) fatal("%s: calloc", __func__); @@ -109,6 +109,16 @@ proc_exec(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc, proc_i = nargc; nargc++; + /* Set user and chroot */ + if (ps->ps_pw != NULL) { + nargv[nargc++] = "-U"; + nargv[nargc++] = ps->ps_pw->pw_name; + + nargv[nargc++] = "-X"; + proc_X = nargc; + nargc++; + } + /* Point process instance arg to stack and copy the original args. */ nargv[nargc++] = "-I"; nargv[nargc++] = num; @@ -120,8 +130,10 @@ proc_exec(struct privsep *ps, struct privsep_proc *procs, unsigned int nproc, for (proc = 0; proc < nproc; proc++) { p = &procs[proc]; - /* Update args with process title. */ + /* Update args with process title and chroot. */ nargv[proc_i] = (char *)(uintptr_t)p->p_title; + if (proc_X && p->p_chroot != NULL) + nargv[proc_X] = p->p_chroot; /* Fire children processes. */ for (i = 0; i < ps->ps_instances[p->p_id]; i++) {