From c18dde2350403727caa96a3e6dbb637cec5282b5 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Thu, 3 Aug 2017 07:32:24 -0600 Subject: [PATCH] Allow the user to specify a list of environment variables to preserve. This adds an option paramter to the --preserve-env option, a comma-separated list of variable names. --- NEWS | 3 ++ doc/sudo.cat | 9 +++- doc/sudo.man.in | 9 +++- doc/sudo.mdoc.in | 8 +++- src/parse_args.c | 120 +++++++++++++++++++++++++++++++++++++---------- 5 files changed, 121 insertions(+), 28 deletions(-) diff --git a/NEWS b/NEWS index 6d7d7dab4..60f747922 100644 --- a/NEWS +++ b/NEWS @@ -56,6 +56,9 @@ What's new in Sudo 1.8.21 the time stamp to commands run by the same process, usually the shell. Bug #793 + * The --preserve-env command line option has been extended to accept + a comma-separated list of environment variables to preserve. + What's new in Sudo 1.8.20p2 * Fixed a bug parsing /proc/pid/stat on Linux when the process diff --git a/doc/sudo.cat b/doc/sudo.cat index a689a951c..527f528c4 100644 --- a/doc/sudo.cat +++ b/doc/sudo.cat @@ -107,6 +107,13 @@ DDEESSCCRRIIPPTTIIOONN policy may return an error if the user does not have permission to preserve the environment. + ----pprreesseerrvvee--eennvv==lliisstt + Indicates to the security policy that the user wishes to add + the comma-separated list of environment variables to those + preserved from the user's environment. The security policy + may return an error if the user does not have permission to + preserve the environment. + --ee, ----eeddiitt Edit one or more files instead of running a command. In lieu of a path name, the string "sudoedit" is used when consulting the security policy. If the user is authorized by the @@ -631,4 +638,4 @@ DDIISSCCLLAAIIMMEERR file distributed with ssuuddoo or https://www.sudo.ws/license.html for complete details. -Sudo 1.8.21 July 21, 2017 Sudo 1.8.21 +Sudo 1.8.21 Auguest 2, 2017 Sudo 1.8.21 diff --git a/doc/sudo.man.in b/doc/sudo.man.in index 699aa3508..a00ee3573 100644 --- a/doc/sudo.man.in +++ b/doc/sudo.man.in @@ -21,7 +21,7 @@ .\" Agency (DARPA) and Air Force Research Laboratory, Air Force .\" Materiel Command, USAF, under agreement number F39502-99-1-0512. .\" -.TH "SUDO" "8" "July 21, 2017" "Sudo @PACKAGE_VERSION@" "System Manager's Manual" +.TH "SUDO" "8" "Auguest 2, 2017" "Sudo @PACKAGE_VERSION@" "System Manager's Manual" .nh .if n .ad l .SH "NAME" @@ -260,6 +260,13 @@ preserve their existing environment variables. The security policy may return an error if the user does not have permission to preserve the environment. .TP 12n +\fB\--preserve-env=list\fR +Indicates to the security policy that the user wishes to add the +comma-separated list of environment variables to those preserved +from the user's environment. +The security policy may return an error if the user does not have +permission to preserve the environment. +.TP 12n \fB\-e\fR, \fB\--edit\fR Edit one or more files instead of running a command. In lieu of a path name, the string "sudoedit" is used when consulting diff --git a/doc/sudo.mdoc.in b/doc/sudo.mdoc.in index e995264d6..bf1e18cf7 100644 --- a/doc/sudo.mdoc.in +++ b/doc/sudo.mdoc.in @@ -19,7 +19,7 @@ .\" Agency (DARPA) and Air Force Research Laboratory, Air Force .\" Materiel Command, USAF, under agreement number F39502-99-1-0512. .\" -.Dd July 21, 2017 +.Dd Auguest 2, 2017 .Dt SUDO @mansectsu@ .Os Sudo @PACKAGE_VERSION@ .Sh NAME @@ -236,6 +236,12 @@ Indicates to the security policy that the user wishes to preserve their existing environment variables. The security policy may return an error if the user does not have permission to preserve the environment. +.It Fl -preserve-env=list +Indicates to the security policy that the user wishes to add the +comma-separated list of environment variables to those preserved +from the user's environment. +The security policy may return an error if the user does not have +permission to preserve the environment. .It Fl e , -edit Edit one or more files instead of running a command. In lieu of a path name, the string "sudoedit" is used when consulting diff --git a/src/parse_args.c b/src/parse_args.c index 1f774e677..4b6abd1aa 100644 --- a/src/parse_args.c +++ b/src/parse_args.c @@ -107,6 +107,12 @@ static struct sudo_settings sudo_settings[] = { { NULL } }; +struct environment { + char **envp; /* pointer to the new environment */ + size_t env_size; /* size of new_environ in char **'s */ + size_t env_len; /* number of slots used, not counting NULL */ +}; + /* * Default flags allowed when running a command. */ @@ -127,7 +133,7 @@ static struct option long_opts[] = { { "background", no_argument, NULL, 'b' }, { "close-from", required_argument, NULL, 'C' }, { "login-class", required_argument, NULL, 'c' }, - { "preserve-env", no_argument, NULL, 'E' }, + { "preserve-env", optional_argument, NULL, 'E' }, { "edit", no_argument, NULL, 'e' }, { "group", required_argument, NULL, 'g' }, { "set-home", no_argument, NULL, 'H' }, @@ -152,6 +158,73 @@ static struct option long_opts[] = { { NULL, no_argument, NULL, '\0' }, }; +/* + * Insert a key=value pair into the specified environment. + */ +static void +env_insert(struct environment *e, char *pair) +{ + debug_decl(env_insert, SUDO_DEBUG_ARGS) + + /* Make sure we have at least two slots free (one for NULL). */ + if (e->env_len + 1 >= e->env_size) { + char **tmp; + + if (e->env_size == 0) + e->env_size = 16; + tmp = reallocarray(e->envp, e->env_size, 2 * sizeof(char *)); + if (tmp == NULL) + sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + e->envp = tmp; + e->env_size *= 2; + } + e->envp[e->env_len++] = pair; + e->envp[e->env_len] = NULL; + + debug_return; +} + +/* + * Format as var=val and insert into the specified environment. + */ +static void +env_set(struct environment *e, char *var, char *val) +{ + char *pair; + debug_decl(env_set, SUDO_DEBUG_ARGS) + + pair = sudo_new_key_val(var, val); + if (pair == NULL) { + sudo_fatalx(U_("%s: %s"), + __func__, U_("unable to allocate memory")); + } + env_insert(e, pair); + + debug_return; +} + +/* + * Parse a comma-separated list of env vars and add to the + * specified environment. + */ +static void +parse_env_list(struct environment *e, char *list) +{ + char *cp, *last, *val; + debug_decl(parse_env_list, SUDO_DEBUG_ARGS) + + for ((cp = strtok_r(list, ",", &last)); cp != NULL; + (cp = strtok_r(NULL, ",", &last))) { + if (strchr(cp, '=') != NULL) { + sudo_warnx(U_("invalid environment variable name: %s"), cp); + usage(1); + } + if ((val = getenv(cp)) != NULL) + env_set(e, cp, val); + } + debug_return; +} + /* * Command line argument parsing. * Sets nargc and nargv which corresponds to the argc/argv we'll use @@ -161,27 +234,22 @@ int parse_args(int argc, char **argv, int *nargc, char ***nargv, struct sudo_settings **settingsp, char ***env_addp) { + struct environment extra_env; int mode = 0; /* what mode is sudo to be run in? */ int flags = 0; /* mode flags */ int valid_flags = DEFAULT_VALID_FLAGS; int ch, i; - char *cp, **env_add; + char *cp; const char *runas_user = NULL; const char *runas_group = NULL; const char *progname; int proglen; - int nenv = 0; - int env_size = 32; debug_decl(parse_args, SUDO_DEBUG_ARGS) /* Is someone trying something funny? */ if (argc <= 0) usage(1); - env_add = reallocarray(NULL, env_size, sizeof(char *)); - if (env_add == NULL) - sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - /* Pass progname to plugin so it can call initprogname() */ progname = getprogname(); sudo_settings[ARG_PROGNAME].value = progname; @@ -218,6 +286,9 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, #define is_envar (optind < argc && argv[optind][0] != '/' && \ strchr(argv[optind], '=') != NULL) + /* Space for environment variables is lazy allocated. */ + memset(&extra_env, 0, sizeof(extra_env)); + /* XXX - should fill in settings at the end to avoid dupes */ for (;;) { /* @@ -253,7 +324,15 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, /* Ignored for backwards compatibility. */ break; case 'E': - sudo_settings[ARG_PRESERVE_ENVIRONMENT].value = "true"; + /* + * Optional argument is a comma-separated list of + * environment variables to preserve. If not present, + * preserve everything. + */ + if (optarg == NULL) + sudo_settings[ARG_PRESERVE_ENVIRONMENT].value = "true"; + else + parse_env_list(&extra_env, optarg); break; case 'e': if (mode && mode != MODE_EDIT) @@ -368,25 +447,14 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, usage(1); } } else if (!got_end_of_args && is_envar) { - if (nenv == env_size - 2) { - char **tmp; - - tmp = reallocarray(env_add, env_size, 2 * sizeof(char *)); - if (tmp == NULL) - sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - env_add = tmp; - env_size *= 2; - } - env_add[nenv++] = argv[optind]; - - /* Crank optind and resume getopt. */ + /* Insert key=value pair, crank optind and resume getopt. */ + env_insert(&extra_env, argv[optind]); optind++; } else { /* Not an option or an environment variable -- we're done. */ break; } } - env_add[nenv] = NULL; argc -= optind; argv += optind; @@ -421,10 +489,10 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, if ((flags & valid_flags) != flags) usage(1); if (mode == MODE_EDIT && - (ISSET(flags, MODE_PRESERVE_ENV) || env_add[0] != NULL)) { + (ISSET(flags, MODE_PRESERVE_ENV) || extra_env.env_len != 0)) { if (ISSET(mode, MODE_PRESERVE_ENV)) sudo_warnx(U_("the `-E' option is not valid in edit mode")); - if (env_add[0] != NULL) + if (extra_env.env_len != 0) sudo_warnx(U_("you may not specify environment variables in edit mode")); usage(1); } @@ -518,7 +586,7 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, } *settingsp = sudo_settings; - *env_addp = env_add; + *env_addp = extra_env.envp; *nargc = argc; *nargv = argv; debug_return_int(mode | flags); @@ -624,6 +692,8 @@ help(void) #endif sudo_lbuf_append(&lbuf, " -E, --preserve-env %s\n", _("preserve user environment when running command")); + sudo_lbuf_append(&lbuf, " --preserve-env=list %s\n", + _("preserve specific environment variables")); sudo_lbuf_append(&lbuf, " -e, --edit %s\n", _("edit files instead of running a command")); sudo_lbuf_append(&lbuf, " -g, --group=group %s\n", -- 2.40.0