From b3af85ddc83fe0043296671622bfb82001d75f9f Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Wed, 22 Mar 2017 13:39:25 -0600 Subject: [PATCH] Add restricted_env_file which is like env_file but subject to the same restrictions as the user's own environment. --- doc/sudoers.cat | 33 ++++++++++++--- doc/sudoers.man.in | 61 +++++++++++++++++++++++---- doc/sudoers.mdoc.in | 60 +++++++++++++++++++++++---- plugins/sudoers/def_data.c | 4 ++ plugins/sudoers/def_data.h | 82 +++++++++++++++++++------------------ plugins/sudoers/def_data.in | 3 ++ plugins/sudoers/env.c | 13 +++++- plugins/sudoers/sudoers.c | 8 +++- plugins/sudoers/sudoers.h | 2 +- 9 files changed, 202 insertions(+), 64 deletions(-) diff --git a/doc/sudoers.cat b/doc/sudoers.cat index 5c5c3c8db..ea10b7d20 100644 --- a/doc/sudoers.cat +++ b/doc/sudoers.cat @@ -184,8 +184,12 @@ DDEESSCCRRIIPPTTIIOONN the _p_a_t_h and _s_e_t_e_n_v variables in _/_e_t_c_/_l_o_g_i_n_._c_o_n_f are also applied. All other environment variables are removed. - Finally, if the _e_n_v___f_i_l_e option is defined, any variables present in that - file will be set to their specified values as long as they would not + Finally, the _r_e_s_t_r_i_c_t_e_d___e_n_v___f_i_l_e and _e_n_v___f_i_l_e files are applied, if + present. The variables in _r_e_s_t_r_i_c_t_e_d___e_n_v___f_i_l_e are applied first and are + subject to the same restrictions as the invoking user's environment, as + detailed above. The variables in _e_n_v___f_i_l_e are applied last and are not + subject to these restrictions. In both cases, variables present in the + files will only be set to their specified values if they would not conflict with an existing environment variable. SSUUDDOOEERRSS FFIILLEE FFOORRMMAATT @@ -1005,8 +1009,9 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS env_reset If set, ssuuddoo will run the command in a minimal environment containing the TERM, PATH, HOME, MAIL, SHELL, LOGNAME, USER, USERNAME and SUDO_* variables. - Any variables in the caller's environment that match - the env_keep and env_check lists are then added, + Any variables in the caller's environment or in the + file specified by the _r_e_s_t_r_i_c_t_e_d___e_n_v___f_i_l_e option that + match the env_keep and env_check lists are then added, followed by any variables present in the file specified by the _e_n_v___f_i_l_e option (if any). The contents of the env_keep and env_check lists, as modified by global @@ -1914,6 +1919,24 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS should be enclosed in double quotes ("") to protect against ssuuddoo interpreting the @ sign. Defaults to root. + restricted_env_file + The _r_e_s_t_r_i_c_t_e_d___e_n_v___f_i_l_e option specifies the fully + qualified path to a file containing variables to be set in + the environment of the program being run. Entries in this + file should either be of the form "VARIABLE=value" or + "export VARIABLE=value". The value may optionally be + surrounded by single or double quotes. Variables in this + file are only added if the variable does not already exist + in the environment. Unlike _e_n_v___f_i_l_e, the file's contents + are not trusted and are processed in a manner similar to + that of the invoking user's environment. If _e_n_v___r_e_s_e_t is + enabled, variables in the file will only be added if they + are matched by either the _e_n_v___c_h_e_c_k or _e_n_v___k_e_e_p list. If + _e_n_v___r_e_s_e_t is disabled, variables in the file are added as + long as they are not matched by the _e_n_v___d_e_l_e_t_e list. In + either case, the contents of _r_e_s_t_r_i_c_t_e_d___e_n_v___f_i_l_e are + processed before the contents of _e_n_v___f_i_l_e. + secure_path Path used for every command run from ssuuddoo. If you don't trust the people running ssuuddoo to have a sane PATH environment variable you may want to use this. Another use @@ -2763,4 +2786,4 @@ DDIISSCCLLAAIIMMEERR file distributed with ssuuddoo or https://www.sudo.ws/license.html for complete details. -Sudo 1.8.20 March 21, 2017 Sudo 1.8.20 +Sudo 1.8.20 March 22, 2017 Sudo 1.8.20 diff --git a/doc/sudoers.man.in b/doc/sudoers.man.in index a5bd2fe3b..ec1d3b381 100644 --- a/doc/sudoers.man.in +++ b/doc/sudoers.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 "SUDOERS" "5" "March 21, 2017" "Sudo @PACKAGE_VERSION@" "File Formats Manual" +.TH "SUDOERS" "5" "March 22, 2017" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .nh .if n .ad l .SH "NAME" @@ -466,11 +466,21 @@ variables in are also applied. All other environment variables are removed. .PP -Finally, if the +Finally, the +\fIrestricted_env_file\fR +and +\fIenv_file\fR +files are applied, if present. +The variables in +\fIrestricted_env_file\fR +are applied first and are subject to the same restrictions as the +invoking user's environment, as detailed above. +The variables in \fIenv_file\fR -option is defined, any variables present -in that file will be set to their specified values as long as they -would not conflict with an existing environment variable. +are applied last and are not subject to these restrictions. +In both cases, variables present in the files will only be set to +their specified values if they would not conflict with an existing +environment variable. .SH "SUDOERS FILE FORMAT" The \fIsudoers\fR @@ -2145,8 +2155,10 @@ will run the command in a minimal environment containing the and \fRSUDO_*\fR variables. -Any -variables in the caller's environment that match the +Any variables in the caller's environment or in the file specified +by the +\fIrestricted_env_file\fR +option that match the \fRenv_keep\fR and \fRenv_check\fR @@ -3832,6 +3844,41 @@ sign. Defaults to \fR@mailto@\fR. .TP 14n +restricted_env_file +The +\fIrestricted_env_file\fR +option specifies the fully qualified path to a file containing variables +to be set in the environment of the program being run. +Entries in this file should either be of the form +\(Lq\fRVARIABLE=value\fR\(Rq +or +\(Lq\fRexport VARIABLE=value\fR\(Rq. +The value may optionally be surrounded by single or double quotes. +Variables in this file are only added if the variable does not already +exist in the environment. +Unlike +\fIenv_file\fR, +the file's contents are not trusted and are processed in a manner +similar to that of the invoking user's environment. +If +\fIenv_reset\fR +is enabled, variables in the file will only be added if they are +matched by either the +\fIenv_check\fR +or +\fIenv_keep\fR +list. +If +\fIenv_reset\fR +is disabled, variables in the file are added as long as they +are not matched by the +\fIenv_delete\fR +list. +In either case, the contents of +\fIrestricted_env_file\fR +are processed before the contents of +\fIenv_file\fR. +.TP 14n secure_path Path used for every command run from \fBsudo\fR. diff --git a/doc/sudoers.mdoc.in b/doc/sudoers.mdoc.in index 44b05b0b5..5fe09c061 100644 --- a/doc/sudoers.mdoc.in +++ b/doc/sudoers.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 March 21, 2017 +.Dd March 22, 2017 .Dt SUDOERS @mansectform@ .Os Sudo @PACKAGE_VERSION@ .Sh NAME @@ -452,11 +452,21 @@ variables in are also applied. All other environment variables are removed. .Pp -Finally, if the +Finally, the +.Em restricted_env_file +and +.Em env_file +files are applied, if present. +The variables in +.Em restricted_env_file +are applied first and are subject to the same restrictions as the +invoking user's environment, as detailed above. +The variables in .Em env_file -option is defined, any variables present -in that file will be set to their specified values as long as they -would not conflict with an existing environment variable. +are applied last and are not subject to these restrictions. +In both cases, variables present in the files will only be set to +their specified values if they would not conflict with an existing +environment variable. .Sh SUDOERS FILE FORMAT The .Em sudoers @@ -2010,8 +2020,10 @@ will run the command in a minimal environment containing the and .Ev SUDO_* variables. -Any -variables in the caller's environment that match the +Any variables in the caller's environment or in the file specified +by the +.Em restricted_env_file +option that match the .Li env_keep and .Li env_check @@ -3565,6 +3577,40 @@ interpreting the sign. Defaults to .Li @mailto@ . +.It restricted_env_file +The +.Em restricted_env_file +option specifies the fully qualified path to a file containing variables +to be set in the environment of the program being run. +Entries in this file should either be of the form +.Dq Li VARIABLE=value +or +.Dq Li export VARIABLE=value . +The value may optionally be surrounded by single or double quotes. +Variables in this file are only added if the variable does not already +exist in the environment. +Unlike +.Em env_file , +the file's contents are not trusted and are processed in a manner +similar to that of the invoking user's environment. +If +.Em env_reset +is enabled, variables in the file will only be added if they are +matched by either the +.Em env_check +or +.Em env_keep +list. +If +.Em env_reset +is disabled, variables in the file are added as long as they +are not matched by the +.Em env_delete +list. +In either case, the contents of +.Em restricted_env_file +are processed before the contents of +.Em env_file . .It secure_path Path used for every command run from .Nm sudo . diff --git a/plugins/sudoers/def_data.c b/plugins/sudoers/def_data.c index 331a6b428..c3e841a60 100644 --- a/plugins/sudoers/def_data.c +++ b/plugins/sudoers/def_data.c @@ -301,6 +301,10 @@ struct sudo_defs_types sudo_defs_table[] = { "env_file", T_STR|T_PATH|T_BOOL, N_("Path to the sudo-specific environment file: %s"), NULL, + }, { + "restricted_env_file", T_STR|T_PATH|T_BOOL, + N_("Path to the restricted sudo-specific environment file: %s"), + NULL, }, { "sudoers_locale", T_STR, N_("Locale to use while parsing sudoers: %s"), diff --git a/plugins/sudoers/def_data.h b/plugins/sudoers/def_data.h index c52335236..8b06078fd 100644 --- a/plugins/sudoers/def_data.h +++ b/plugins/sudoers/def_data.h @@ -134,85 +134,87 @@ #define def_type (sudo_defs_table[I_TYPE].sd_un.str) #define I_ENV_FILE 67 #define def_env_file (sudo_defs_table[I_ENV_FILE].sd_un.str) -#define I_SUDOERS_LOCALE 68 +#define I_RESTRICTED_ENV_FILE 68 +#define def_restricted_env_file (sudo_defs_table[I_RESTRICTED_ENV_FILE].sd_un.str) +#define I_SUDOERS_LOCALE 69 #define def_sudoers_locale (sudo_defs_table[I_SUDOERS_LOCALE].sd_un.str) -#define I_VISIBLEPW 69 +#define I_VISIBLEPW 70 #define def_visiblepw (sudo_defs_table[I_VISIBLEPW].sd_un.flag) -#define I_PWFEEDBACK 70 +#define I_PWFEEDBACK 71 #define def_pwfeedback (sudo_defs_table[I_PWFEEDBACK].sd_un.flag) -#define I_FAST_GLOB 71 +#define I_FAST_GLOB 72 #define def_fast_glob (sudo_defs_table[I_FAST_GLOB].sd_un.flag) -#define I_UMASK_OVERRIDE 72 +#define I_UMASK_OVERRIDE 73 #define def_umask_override (sudo_defs_table[I_UMASK_OVERRIDE].sd_un.flag) -#define I_LOG_INPUT 73 +#define I_LOG_INPUT 74 #define def_log_input (sudo_defs_table[I_LOG_INPUT].sd_un.flag) -#define I_LOG_OUTPUT 74 +#define I_LOG_OUTPUT 75 #define def_log_output (sudo_defs_table[I_LOG_OUTPUT].sd_un.flag) -#define I_COMPRESS_IO 75 +#define I_COMPRESS_IO 76 #define def_compress_io (sudo_defs_table[I_COMPRESS_IO].sd_un.flag) -#define I_USE_PTY 76 +#define I_USE_PTY 77 #define def_use_pty (sudo_defs_table[I_USE_PTY].sd_un.flag) -#define I_GROUP_PLUGIN 77 +#define I_GROUP_PLUGIN 78 #define def_group_plugin (sudo_defs_table[I_GROUP_PLUGIN].sd_un.str) -#define I_IOLOG_DIR 78 +#define I_IOLOG_DIR 79 #define def_iolog_dir (sudo_defs_table[I_IOLOG_DIR].sd_un.str) -#define I_IOLOG_FILE 79 +#define I_IOLOG_FILE 80 #define def_iolog_file (sudo_defs_table[I_IOLOG_FILE].sd_un.str) -#define I_SET_UTMP 80 +#define I_SET_UTMP 81 #define def_set_utmp (sudo_defs_table[I_SET_UTMP].sd_un.flag) -#define I_UTMP_RUNAS 81 +#define I_UTMP_RUNAS 82 #define def_utmp_runas (sudo_defs_table[I_UTMP_RUNAS].sd_un.flag) -#define I_PRIVS 82 +#define I_PRIVS 83 #define def_privs (sudo_defs_table[I_PRIVS].sd_un.str) -#define I_LIMITPRIVS 83 +#define I_LIMITPRIVS 84 #define def_limitprivs (sudo_defs_table[I_LIMITPRIVS].sd_un.str) -#define I_EXEC_BACKGROUND 84 +#define I_EXEC_BACKGROUND 85 #define def_exec_background (sudo_defs_table[I_EXEC_BACKGROUND].sd_un.flag) -#define I_PAM_SERVICE 85 +#define I_PAM_SERVICE 86 #define def_pam_service (sudo_defs_table[I_PAM_SERVICE].sd_un.str) -#define I_PAM_LOGIN_SERVICE 86 +#define I_PAM_LOGIN_SERVICE 87 #define def_pam_login_service (sudo_defs_table[I_PAM_LOGIN_SERVICE].sd_un.str) -#define I_PAM_SETCRED 87 +#define I_PAM_SETCRED 88 #define def_pam_setcred (sudo_defs_table[I_PAM_SETCRED].sd_un.flag) -#define I_PAM_SESSION 88 +#define I_PAM_SESSION 89 #define def_pam_session (sudo_defs_table[I_PAM_SESSION].sd_un.flag) -#define I_MAXSEQ 89 +#define I_MAXSEQ 90 #define def_maxseq (sudo_defs_table[I_MAXSEQ].sd_un.uival) -#define I_USE_NETGROUPS 90 +#define I_USE_NETGROUPS 91 #define def_use_netgroups (sudo_defs_table[I_USE_NETGROUPS].sd_un.flag) -#define I_SUDOEDIT_CHECKDIR 91 +#define I_SUDOEDIT_CHECKDIR 92 #define def_sudoedit_checkdir (sudo_defs_table[I_SUDOEDIT_CHECKDIR].sd_un.flag) -#define I_SUDOEDIT_FOLLOW 92 +#define I_SUDOEDIT_FOLLOW 93 #define def_sudoedit_follow (sudo_defs_table[I_SUDOEDIT_FOLLOW].sd_un.flag) -#define I_ALWAYS_QUERY_GROUP_PLUGIN 93 +#define I_ALWAYS_QUERY_GROUP_PLUGIN 94 #define def_always_query_group_plugin (sudo_defs_table[I_ALWAYS_QUERY_GROUP_PLUGIN].sd_un.flag) -#define I_NETGROUP_TUPLE 94 +#define I_NETGROUP_TUPLE 95 #define def_netgroup_tuple (sudo_defs_table[I_NETGROUP_TUPLE].sd_un.flag) -#define I_IGNORE_AUDIT_ERRORS 95 +#define I_IGNORE_AUDIT_ERRORS 96 #define def_ignore_audit_errors (sudo_defs_table[I_IGNORE_AUDIT_ERRORS].sd_un.flag) -#define I_IGNORE_IOLOG_ERRORS 96 +#define I_IGNORE_IOLOG_ERRORS 97 #define def_ignore_iolog_errors (sudo_defs_table[I_IGNORE_IOLOG_ERRORS].sd_un.flag) -#define I_IGNORE_LOGFILE_ERRORS 97 +#define I_IGNORE_LOGFILE_ERRORS 98 #define def_ignore_logfile_errors (sudo_defs_table[I_IGNORE_LOGFILE_ERRORS].sd_un.flag) -#define I_MATCH_GROUP_BY_GID 98 +#define I_MATCH_GROUP_BY_GID 99 #define def_match_group_by_gid (sudo_defs_table[I_MATCH_GROUP_BY_GID].sd_un.flag) -#define I_SYSLOG_MAXLEN 99 +#define I_SYSLOG_MAXLEN 100 #define def_syslog_maxlen (sudo_defs_table[I_SYSLOG_MAXLEN].sd_un.uival) -#define I_IOLOG_USER 100 +#define I_IOLOG_USER 101 #define def_iolog_user (sudo_defs_table[I_IOLOG_USER].sd_un.str) -#define I_IOLOG_GROUP 101 +#define I_IOLOG_GROUP 102 #define def_iolog_group (sudo_defs_table[I_IOLOG_GROUP].sd_un.str) -#define I_IOLOG_MODE 102 +#define I_IOLOG_MODE 103 #define def_iolog_mode (sudo_defs_table[I_IOLOG_MODE].sd_un.mode) -#define I_FDEXEC 103 +#define I_FDEXEC 104 #define def_fdexec (sudo_defs_table[I_FDEXEC].sd_un.tuple) -#define I_IGNORE_UNKNOWN_DEFAULTS 104 +#define I_IGNORE_UNKNOWN_DEFAULTS 105 #define def_ignore_unknown_defaults (sudo_defs_table[I_IGNORE_UNKNOWN_DEFAULTS].sd_un.flag) -#define I_COMMAND_TIMEOUT 105 +#define I_COMMAND_TIMEOUT 106 #define def_command_timeout (sudo_defs_table[I_COMMAND_TIMEOUT].sd_un.ival) -#define I_USER_COMMAND_TIMEOUTS 106 +#define I_USER_COMMAND_TIMEOUTS 107 #define def_user_command_timeouts (sudo_defs_table[I_USER_COMMAND_TIMEOUTS].sd_un.flag) -#define I_IOLOG_FLUSH 107 +#define I_IOLOG_FLUSH 108 #define def_iolog_flush (sudo_defs_table[I_IOLOG_FLUSH].sd_un.flag) enum def_tuple { diff --git a/plugins/sudoers/def_data.in b/plugins/sudoers/def_data.in index a005a6c01..12cdce699 100644 --- a/plugins/sudoers/def_data.in +++ b/plugins/sudoers/def_data.in @@ -217,6 +217,9 @@ type env_file T_STR|T_PATH|T_BOOL "Path to the sudo-specific environment file: %s" +restricted_env_file + T_STR|T_PATH|T_BOOL + "Path to the restricted sudo-specific environment file: %s" sudoers_locale T_STR "Locale to use while parsing sudoers: %s" diff --git a/plugins/sudoers/env.c b/plugins/sudoers/env.c index 04b3749a3..2cf5e7787 100644 --- a/plugins/sudoers/env.c +++ b/plugins/sudoers/env.c @@ -900,7 +900,7 @@ rebuild_env(void) #endif /* HAVE_LOGIN_CAP_H */ #if defined(_AIX) || (defined(__linux__) && !defined(HAVE_PAM)) /* Insert system-wide environment variables. */ - read_env_file(_PATH_ENVIRONMENT, true); + read_env_file(_PATH_ENVIRONMENT, true, false); #endif for (ep = env.envp; *ep; ep++) env_update_didvar(*ep, &didvar); @@ -1171,7 +1171,7 @@ validate_env_vars(char * const env_vars[]) * character are skipped. */ bool -read_env_file(const char *path, int overwrite) +read_env_file(const char *path, bool overwrite, bool restricted) { FILE *fp; bool ret = true; @@ -1206,6 +1206,15 @@ read_env_file(const char *path, int overwrite) var_len = (size_t)(val - var); val_len = strlen(++val); + /* + * If the env file is restricted, apply env_check and env_keep + * when env_reset is set or env_delete when it is not. + */ + if (restricted) { + if (def_env_reset ? !env_should_keep(var) : env_should_delete(var)) + continue; + } + /* Strip leading and trailing single/double quotes */ if ((val[0] == '\'' || val[0] == '\"') && val[0] == val[val_len - 1]) { val[val_len - 1] = '\0'; diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index ac5427b9e..62fd8bd4c 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -588,7 +588,7 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], #if defined(_AIX) || (defined(__linux__) && !defined(HAVE_PAM)) /* Insert system-wide environment variables. */ - if (!read_env_file(_PATH_ENVIRONMENT, true)) + if (!read_env_file(_PATH_ENVIRONMENT, true, false)) sudo_warn("%s", _PATH_ENVIRONMENT); #endif #ifdef HAVE_LOGIN_CAP_H @@ -604,8 +604,12 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], } /* Insert system-wide environment variables. */ + if (def_restricted_env_file) { + if (!read_env_file(def_env_file, false, true)) + sudo_warn("%s", def_restricted_env_file); + } if (def_env_file) { - if (!read_env_file(def_env_file, false)) + if (!read_env_file(def_env_file, false, false)) sudo_warn("%s", def_env_file); } diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index 37b69a561..d4c01ddb0 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -348,7 +348,7 @@ bool env_swap_old(void); bool env_init(char * const envp[]); bool init_envtables(void); bool insert_env_vars(char * const envp[]); -bool read_env_file(const char *, int); +bool read_env_file(const char *path, bool overwrite, bool restricted); bool rebuild_env(void); bool validate_env_vars(char * const envp[]); int sudo_setenv(const char *var, const char *val, int overwrite); -- 2.40.0