diff options
author | Andrew Mortensen <admorten@isc.upenn.edu> | 2012-02-22 15:41:26 -0800 |
---|---|---|
committer | Russ Allbery <rra@stanford.edu> | 2012-02-22 15:41:26 -0800 |
commit | 42985658676f24a38205f94e21f398a5cd09a166 (patch) | |
tree | baa971184c0b80e3b1354321bf0f969d6c797133 /server | |
parent | 02b54ff4cfd2299b32cc2dc88d68da2e3de0370d (diff) |
Add server configuration option to run as a different user
Add a new server configuration option for remctl commands, user,
which sets the user as which to run the command. If this option is
set, remctld changes to the given user and that user's groups before
running the command. The groups are set via initgroups and the
primary group is looked up via getpwuid. The user may be either a UID
or a username.
Diffstat (limited to 'server')
-rw-r--r-- | server/commands.c | 16 | ||||
-rw-r--r-- | server/config.c | 31 | ||||
-rw-r--r-- | server/internal.h | 3 |
3 files changed, 50 insertions, 0 deletions
diff --git a/server/commands.c b/server/commands.c index 07fd91d..b237129 100644 --- a/server/commands.c +++ b/server/commands.c @@ -511,6 +511,22 @@ server_run_command(struct client *client, struct config *config, exit(-1); } + /* drop privileges, if requested */ + if (cline->user && cline->uid > 0) { + if (initgroups(cline->user, cline->gid) != 0) { + syswarn("cannot initgroups for %s\n", cline->user); + exit(-1); + } + if (setgid(cline->gid) != 0) { + syswarn("cannot setgid to %d\n", cline->gid); + exit(-1); + } + if (setuid(cline->uid) != 0) { + syswarn("cannot setuid to %d\n", cline->uid); + exit(-1); + } + } + /* Run the command. */ execv(path, req_argv); diff --git a/server/config.c b/server/config.c index 239084a..b6ae18c 100644 --- a/server/config.c +++ b/server/config.c @@ -22,6 +22,7 @@ #ifdef HAVE_PCRE # include <pcre.h> #endif +#include <pwd.h> #ifdef HAVE_REGCOMP # include <regex.h> #endif @@ -260,6 +261,33 @@ option_stdin(struct confline *confline, char *value, const char *name, return CONFIG_SUCCESS; } +static enum config_status +option_user(struct confline *confline, char *value, const char *name, + size_t lineno) +{ + struct passwd *pw; + char *end; + + errno = 0; + confline->uid = (uid_t)strtol(value, &end, 10); + if (errno == 0 && *end == '\0') { + pw = getpwuid( confline->uid ); + } else { + pw = getpwnam( value ); + } + if (pw) { + confline->user = xstrdup(pw->pw_name); + confline->uid = pw->pw_uid; + confline->gid = pw->pw_gid; + } else { + warn("%s:%lu: invalid user value %s", name, + (unsigned long) lineno, value); + return CONFIG_ERROR; + } + + return CONFIG_SUCCESS; +} + /* * The table relating configuration option names to functions. @@ -267,6 +295,7 @@ option_stdin(struct confline *confline, char *value, const char *name, static const struct config_option options[] = { { "logmask", option_logmask }, { "stdin", option_stdin }, + { "user", option_user }, { NULL, NULL } }; @@ -923,6 +952,8 @@ server_config_free(struct config *config) rule = config->rules[i]; if (rule->logmask != NULL) free(rule->logmask); + if (rule->user != NULL) + free(rule->user); if (rule->acls != NULL) free(rule->acls); if (rule->line != NULL) diff --git a/server/internal.h b/server/internal.h index 8a48fb4..4dd4cd2 100644 --- a/server/internal.h +++ b/server/internal.h @@ -64,6 +64,9 @@ struct confline { char *program; /* Full file name of executable. */ unsigned int *logmask; /* Zero-terminated list of args to mask. */ long stdin_arg; /* Arg to pass on stdin, -1 for last. */ + char *user; /* Run executable as user. */ + uid_t uid; /* Run executable as uid. */ + gid_t gid; /* Primary gid for executable. */ char **acls; /* Full file names of ACL files. */ }; |