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
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
=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
#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>
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.
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. */
}
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;
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_* */