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.
By default, the I<env_reset> option is enabled. This causes commands
to be executed with a minimal environment containing 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.
to be executed with a new, minimal environment. On AIX (and Linux
systems without PAM), the environment is initialized with the
contents of the F</etc/environment> file. On BSD systems, if the
I<use_loginclass> option is enabled, the environment is initialized
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
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
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>,
and I<LOGNAME> are set based on the target user. On Linux and AIX
systems the contents of F</etc/environment> are also included. All
other environment variables are removed.
and I<LOGNAME> are set based on the target user. On AIX (and Linux
systems without PAM), the contents of F</etc/environment> are also
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
in that file will be set to their specified values.
Finally, if the I<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.
=head1 SUDOERS FILE FORMAT
@@ -1776,7 +1784,7 @@ Directory containing time stamps for the I<sudoers> security policy
=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

View File

@@ -42,6 +42,12 @@
#ifdef HAVE_UNISTD_H
# include <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 <errno.h>
#include <pwd.h>
@@ -638,6 +644,43 @@ env_should_keep(const char *var)
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
* 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 *));
#ifdef ENV_DEBUG
memset(env.envp, 0, env.env_size * sizeof(char *));
#else
env.envp[0] = NULL;
#endif
/* 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 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. */
for (ep = old_envp; *ep; ep++) {
bool keepit;
@@ -697,39 +768,8 @@ rebuild_env(void)
if (keepit) {
/* 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);
env_update_didvar(*ep, &didvar);
}
}
didvar |= didvar << 8; /* convert DID_* to KEPT_* */