When initializing the environment for env_reset, start out with

the contents of /etc/environment on AIX and login.conf on BSD.
This commit is contained in:
Todd C. Miller
2012-03-27 18:57:11 -04:00
parent 2f30694b87
commit caf01d98c4
2 changed files with 91 additions and 43 deletions

View File

@@ -89,11 +89,16 @@ environment are inherited by the command to be run. There are two
distinct ways I<sudoers> can deal with environment variables. distinct ways I<sudoers> can deal with environment variables.
By default, the I<env_reset> option is enabled. This causes commands By default, the I<env_reset> option is enabled. This causes commands
to be executed with a minimal environment containing the C<TERM>, to be executed with a new, minimal environment. On AIX (and Linux
C<PATH>, C<HOME>, C<MAIL>, C<SHELL>, C<LOGNAME>, C<USER>, C<USERNAME> systems without PAM), the environment is initialized with the
and C<SUDO_*> variables in addition to variables from the contents of the F</etc/environment> file. On BSD systems, if the
invoking process permitted by the I<env_check> and I<env_keep> I<use_loginclass> option is enabled, the environment is initialized
options. This is effectively a whitelist for environment variables. based on the I<path> and I<setenv> settings in F</etc/login.conf>.
The new environment contains the C<TERM>, C<PATH>, C<HOME>, C<MAIL>,
C<SHELL>, C<LOGNAME>, C<USER>, C<USERNAME> and C<SUDO_*> variables
in addition to variables from the invoking process permitted by the
I<env_check> and I<env_keep> options. This is effectively a whitelist
for environment variables.
If, however, the I<env_reset> option is disabled, any variables not If, however, the I<env_reset> option is disabled, any variables not
explicitly denied by the I<env_check> and I<env_delete> options are explicitly denied by the I<env_check> and I<env_delete> options are
@@ -119,12 +124,15 @@ As a special case, if B<sudo>'s B<-i> option (initial login) is
specified, I<sudoers> will initialize the environment regardless specified, I<sudoers> will initialize the environment regardless
of the value of I<env_reset>. The I<DISPLAY>, I<PATH> and I<TERM> of the value of I<env_reset>. The I<DISPLAY>, I<PATH> and I<TERM>
variables remain unchanged; I<HOME>, I<MAIL>, I<SHELL>, I<USER>, variables remain unchanged; I<HOME>, I<MAIL>, I<SHELL>, I<USER>,
and I<LOGNAME> are set based on the target user. On Linux and AIX and I<LOGNAME> are set based on the target user. On AIX (and Linux
systems the contents of F</etc/environment> are also included. All systems without PAM), the contents of F</etc/environment> are also
other environment variables are removed. included. On BSD systems, if the I<use_loginclass> option is
enabled, the I<path> and I<setenv> variables in F</etc/login.conf>
are also applied. All other environment variables are removed.
Lastly, if the I<env_file> option is defined, any variables present Finally, if the I<env_file> option is defined, any variables present
in that file will be set to their specified values. in that file will be set to their specified values as long as they
would not conflict with an existing environment variable.
=head1 SUDOERS FILE FORMAT =head1 SUDOERS FILE FORMAT
@@ -1776,7 +1784,7 @@ Directory containing time stamps for the I<sudoers> security policy
=item F</etc/environment> =item F</etc/environment>
Initial environment for B<-i> mode on Linux and AIX Initial environment for B<-i> mode on AIX and Linux systems
=back =back

View File

@@ -42,6 +42,12 @@
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
# include <unistd.h> # include <unistd.h>
#endif /* HAVE_UNISTD_H */ #endif /* HAVE_UNISTD_H */
#ifdef HAVE_LOGIN_CAP_H
# include <login_cap.h>
# ifndef LOGIN_SETENV
# define LOGIN_SETENV 0
# endif
#endif /* HAVE_LOGIN_CAP_H */
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <pwd.h> #include <pwd.h>
@@ -638,6 +644,43 @@ env_should_keep(const char *var)
debug_return_bool(keepit == true); debug_return_bool(keepit == true);
} }
static void
env_update_didvar(const char *ep, int *didvar)
{
switch (*ep) {
case 'H':
if (strncmp(ep, "HOME=", 5) == 0)
SET(*didvar, DID_HOME);
break;
case 'L':
if (strncmp(ep, "LOGNAME=", 8) == 0)
SET(*didvar, DID_LOGNAME);
break;
case 'M':
if (strncmp(ep, "MAIL=", 5) == 0)
SET(*didvar, DID_MAIL);
break;
case 'P':
if (strncmp(ep, "PATH=", 5) == 0)
SET(*didvar, DID_PATH);
break;
case 'S':
if (strncmp(ep, "SHELL=", 6) == 0)
SET(*didvar, DID_SHELL);
break;
case 'T':
if (strncmp(ep, "TERM=", 5) == 0)
SET(*didvar, DID_TERM);
break;
case 'U':
if (strncmp(ep, "USER=", 5) == 0)
SET(*didvar, DID_USER);
if (strncmp(ep, "USERNAME=", 5) == 0)
SET(*didvar, DID_USERNAME);
break;
}
}
/* /*
* Build a new environment and ether clear potentially dangerous * Build a new environment and ether clear potentially dangerous
* variables from the old one or start with a clean slate. * variables from the old one or start with a clean slate.
@@ -662,6 +705,8 @@ rebuild_env(void)
env.envp = emalloc2(env.env_size, sizeof(char *)); env.envp = emalloc2(env.env_size, sizeof(char *));
#ifdef ENV_DEBUG #ifdef ENV_DEBUG
memset(env.envp, 0, env.env_size * sizeof(char *)); memset(env.envp, 0, env.env_size * sizeof(char *));
#else
env.envp[0] = NULL;
#endif #endif
/* Reset HOME based on target user if configured to. */ /* Reset HOME based on target user if configured to. */
@@ -673,6 +718,32 @@ rebuild_env(void)
} }
if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) { if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
/*
* If starting with a fresh environment, initialize it based on
* /etc/environment or login.conf. For "sudo -i" we want those
* variables to override the invoking user's environment, so we
* defer reading them until later.
*/
if (!ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
#ifdef HAVE_LOGIN_CAP_H
/* Insert login class environment variables. */
if (login_class) {
login_cap_t *lc = login_getclass(login_class);
if (lc != NULL) {
setusercontext(lc, runas_pw, runas_pw->pw_uid,
LOGIN_SETPATH|LOGIN_SETENV);
login_close(lc);
}
}
#endif /* HAVE_LOGIN_CAP_H */
#if defined(_AIX) || (defined(__linux__) && !defined(HAVE_PAM))
/* Insert system-wide environment variables. */
read_env_file(_PATH_ENVIRONMENT, true);
#endif
for (ep = env.envp; *ep; ep++)
env_update_didvar(*ep, &didvar);
}
/* Pull in vars we want to keep from the old environment. */ /* Pull in vars we want to keep from the old environment. */
for (ep = old_envp; *ep; ep++) { for (ep = old_envp; *ep; ep++) {
bool keepit; bool keepit;
@@ -697,39 +768,8 @@ rebuild_env(void)
if (keepit) { if (keepit) {
/* Preserve variable. */ /* Preserve variable. */
switch (**ep) {
case 'H':
if (strncmp(*ep, "HOME=", 5) == 0)
SET(didvar, DID_HOME);
break;
case 'L':
if (strncmp(*ep, "LOGNAME=", 8) == 0)
SET(didvar, DID_LOGNAME);
break;
case 'M':
if (strncmp(*ep, "MAIL=", 5) == 0)
SET(didvar, DID_MAIL);
break;
case 'P':
if (strncmp(*ep, "PATH=", 5) == 0)
SET(didvar, DID_PATH);
break;
case 'S':
if (strncmp(*ep, "SHELL=", 6) == 0)
SET(didvar, DID_SHELL);
break;
case 'T':
if (strncmp(*ep, "TERM=", 5) == 0)
SET(didvar, DID_TERM);
break;
case 'U':
if (strncmp(*ep, "USER=", 5) == 0)
SET(didvar, DID_USER);
if (strncmp(*ep, "USERNAME=", 5) == 0)
SET(didvar, DID_USERNAME);
break;
}
sudo_putenv(*ep, false, false); sudo_putenv(*ep, false, false);
env_update_didvar(*ep, &didvar);
} }
} }
didvar |= didvar << 8; /* convert DID_* to KEPT_* */ didvar |= didvar << 8; /* convert DID_* to KEPT_* */