summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authorAndrew Mortensen <admorten@isc.upenn.edu>2012-02-22 15:41:26 -0800
committerRuss Allbery <rra@stanford.edu>2012-02-22 15:41:26 -0800
commit42985658676f24a38205f94e21f398a5cd09a166 (patch)
treebaa971184c0b80e3b1354321bf0f969d6c797133 /server
parent02b54ff4cfd2299b32cc2dc88d68da2e3de0370d (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.c16
-rw-r--r--server/config.c31
-rw-r--r--server/internal.h3
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. */
};