version 1.1.1.1, 2012/02/21 16:23:02
|
version 1.1.1.2, 2012/05/29 12:26:49
|
Line 42
|
Line 42
|
#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> |
Line 90
|
Line 96
|
#define KEPT_MAX 0xff00 |
#define KEPT_MAX 0xff00 |
|
|
struct environment { |
struct environment { |
|
char * const *old_envp; /* pointer the environment we passed back */ |
char **envp; /* pointer to the new environment */ |
char **envp; /* pointer to the new environment */ |
size_t env_size; /* size of new_environ in char **'s */ |
size_t env_size; /* size of new_environ in char **'s */ |
size_t env_len; /* number of slots used, not counting NULL */ |
size_t env_len; /* number of slots used, not counting NULL */ |
}; |
}; |
|
|
/* |
/* |
* Prototypes |
|
*/ |
|
static void sudo_setenv(const char *, const char *, int); |
|
static void sudo_putenv(char *, int, int); |
|
|
|
/* |
|
* Copy of the sudo-managed environment. |
* Copy of the sudo-managed environment. |
*/ |
*/ |
static struct environment env; |
static struct environment env; |
Line 131 static const char *initial_badenv_table[] = {
|
Line 132 static const char *initial_badenv_table[] = {
|
#ifdef __APPLE__ |
#ifdef __APPLE__ |
"DYLD_*", |
"DYLD_*", |
#endif |
#endif |
#ifdef HAVE_KERB4 |
|
"KRB_CONF*", |
|
"KRBCONFDIR", |
|
"KRBTKFILE", |
|
#endif /* HAVE_KERB4 */ |
|
#ifdef HAVE_KERB5 |
#ifdef HAVE_KERB5 |
"KRB5_CONFIG*", |
"KRB5_CONFIG*", |
"KRB5_KTNAME", |
"KRB5_KTNAME", |
Line 202 static const char *initial_keepenv_table[] = {
|
Line 198 static const char *initial_keepenv_table[] = {
|
"TZ", |
"TZ", |
"XAUTHORITY", |
"XAUTHORITY", |
"XAUTHORIZATION", |
"XAUTHORIZATION", |
#ifdef _AIX |
|
"ODMDIR", |
|
#endif |
|
NULL |
NULL |
}; |
}; |
|
|
Line 216 env_init(char * const envp[])
|
Line 209 env_init(char * const envp[])
|
{ |
{ |
char * const *ep; |
char * const *ep; |
size_t len; |
size_t len; |
|
debug_decl(env_init, SUDO_DEBUG_ENV) |
|
|
for (ep = envp; *ep != NULL; ep++) | if (envp == NULL) { |
continue; | /* Reset to initial state but keep a pointer to what we allocated. */ |
len = (size_t)(ep - envp); | envp = env.envp; |
| memset(&env, 0, sizeof(env)); |
| env.old_envp = envp; |
| } else { |
| /* Make private copy of envp. */ |
| for (ep = envp; *ep != NULL; ep++) |
| continue; |
| len = (size_t)(ep - envp); |
|
|
env.env_len = len; | env.env_len = len; |
env.env_size = len + 1 + 128; | env.env_size = len + 1 + 128; |
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 *)); |
#endif |
#endif |
memcpy(env.envp, envp, len * sizeof(char *)); | memcpy(env.envp, envp, len * sizeof(char *)); |
env.envp[len] = '\0'; | env.envp[len] = '\0'; |
| |
| /* Free the old envp we allocated, if any. */ |
| if (env.old_envp != NULL) |
| efree((void *)env.old_envp); |
| } |
| |
| debug_return; |
} |
} |
|
|
|
/* |
|
* Getter for private copy of the environment. |
|
*/ |
char ** |
char ** |
env_get(void) |
env_get(void) |
{ |
{ |
Line 238 env_get(void)
|
Line 249 env_get(void)
|
} |
} |
|
|
/* |
/* |
* Similar to setenv(3) but operates on sudo's private copy of the environment |
|
* (not environ) and it always overwrites. The dupcheck param determines |
|
* whether we need to verify that the variable is not already set. |
|
*/ |
|
static void |
|
sudo_setenv(const char *var, const char *val, int dupcheck) |
|
{ |
|
char *estring; |
|
size_t esize; |
|
|
|
esize = strlen(var) + 1 + strlen(val) + 1; |
|
estring = emalloc(esize); |
|
|
|
/* Build environment string and insert it. */ |
|
if (strlcpy(estring, var, esize) >= esize || |
|
strlcat(estring, "=", esize) >= esize || |
|
strlcat(estring, val, esize) >= esize) { |
|
|
|
errorx(1, _("internal error, sudo_setenv() overflow")); |
|
} |
|
sudo_putenv(estring, dupcheck, TRUE); |
|
} |
|
|
|
/* |
|
* Similar to putenv(3) but operates on sudo's private copy of the |
* Similar to putenv(3) but operates on sudo's private copy of the |
* environment (not environ) and it always overwrites. The dupcheck param |
* environment (not environ) and it always overwrites. The dupcheck param |
* determines whether we need to verify that the variable is not already set. |
* determines whether we need to verify that the variable is not already set. |
* Will only overwrite an existing variable if overwrite is set. |
* Will only overwrite an existing variable if overwrite is set. |
|
* Does not include warnings or debugging to avoid recursive calls. |
*/ |
*/ |
static void | static int |
sudo_putenv(char *str, int dupcheck, int overwrite) | sudo_putenv_nodebug(char *str, bool dupcheck, bool overwrite) |
{ |
{ |
char **ep; |
char **ep; |
size_t len; |
size_t len; |
int found = FALSE; | bool found = false; |
|
|
/* Make sure there is room for the new entry plus a NULL. */ |
/* Make sure there is room for the new entry plus a NULL. */ |
if (env.env_len + 2 > env.env_size) { |
if (env.env_len + 2 > env.env_size) { |
env.env_size += 128; | char **nenvp; |
env.envp = erealloc3(env.envp, env.env_size, sizeof(char *)); | size_t nsize = env.env_size + 128; |
| nenvp = env.envp ? realloc(env.envp, nsize * sizeof(char *)) : |
| malloc(nsize * sizeof(char *)); |
| if (nenvp == NULL) { |
| errno = ENOMEM; |
| return -1; |
| } |
| env.envp = nenvp; |
| env.env_size = nsize; |
#ifdef ENV_DEBUG |
#ifdef ENV_DEBUG |
memset(env.envp + env.env_len, 0, |
memset(env.envp + env.env_len, 0, |
(env.env_size - env.env_len) * sizeof(char *)); |
(env.env_size - env.env_len) * sizeof(char *)); |
Line 285 sudo_putenv(char *str, int dupcheck, int overwrite)
|
Line 281 sudo_putenv(char *str, int dupcheck, int overwrite)
|
} |
} |
|
|
#ifdef ENV_DEBUG |
#ifdef ENV_DEBUG |
if (env.envp[env.env_len] != NULL) | if (env.envp[env.env_len] != NULL) { |
errorx(1, _("sudo_putenv: corrupted envp, length mismatch")); | errno = EINVAL; |
| return -1; |
| } |
#endif |
#endif |
|
|
if (dupcheck) { |
if (dupcheck) { |
Line 295 sudo_putenv(char *str, int dupcheck, int overwrite)
|
Line 293 sudo_putenv(char *str, int dupcheck, int overwrite)
|
if (strncmp(str, *ep, len) == 0) { |
if (strncmp(str, *ep, len) == 0) { |
if (overwrite) |
if (overwrite) |
*ep = str; |
*ep = str; |
found = TRUE; | found = true; |
} |
} |
} |
} |
/* Prune out duplicate variables. */ |
/* Prune out duplicate variables. */ |
Line 319 sudo_putenv(char *str, int dupcheck, int overwrite)
|
Line 317 sudo_putenv(char *str, int dupcheck, int overwrite)
|
*ep++ = str; |
*ep++ = str; |
*ep = NULL; |
*ep = NULL; |
} |
} |
|
return 0; |
} |
} |
|
|
/* |
/* |
* Check the env_delete blacklist. | * Similar to putenv(3) but operates on sudo's private copy of the |
* Returns TRUE if the variable was found, else false. | * environment (not environ) and it always overwrites. The dupcheck param |
| * determines whether we need to verify that the variable is not already set. |
| * Will only overwrite an existing variable if overwrite is set. |
*/ |
*/ |
static int |
static int |
|
sudo_putenv(char *str, bool dupcheck, bool overwrite) |
|
{ |
|
int rval; |
|
debug_decl(sudo_putenv, SUDO_DEBUG_ENV) |
|
|
|
rval = sudo_putenv_nodebug(str, dupcheck, overwrite); |
|
if (rval == -1) { |
|
#ifdef ENV_DEBUG |
|
if (env.envp[env.env_len] != NULL) |
|
errorx(1, _("sudo_putenv: corrupted envp, length mismatch")); |
|
#endif |
|
errorx(1, _("unable to allocate memory")); |
|
} |
|
debug_return_int(rval); |
|
} |
|
|
|
/* |
|
* Similar to setenv(3) but operates on a private copy of the environment. |
|
* The dupcheck param determines whether we need to verify that the variable |
|
* is not already set. |
|
*/ |
|
static int |
|
sudo_setenv2(const char *var, const char *val, bool dupcheck, bool overwrite) |
|
{ |
|
char *estring; |
|
size_t esize; |
|
debug_decl(sudo_setenv2, SUDO_DEBUG_ENV) |
|
|
|
esize = strlen(var) + 1 + strlen(val) + 1; |
|
estring = emalloc(esize); |
|
|
|
/* Build environment string and insert it. */ |
|
if (strlcpy(estring, var, esize) >= esize || |
|
strlcat(estring, "=", esize) >= esize || |
|
strlcat(estring, val, esize) >= esize) { |
|
|
|
errorx(1, _("internal error, sudo_setenv2() overflow")); |
|
} |
|
debug_return_int(sudo_putenv(estring, dupcheck, overwrite)); |
|
} |
|
|
|
/* |
|
* Similar to setenv(3) but operates on a private copy of the environment. |
|
* Does not include warnings or debugging to avoid recursive calls. |
|
*/ |
|
static int |
|
sudo_setenv_nodebug(const char *var, const char *val, int overwrite) |
|
{ |
|
char *estring; |
|
size_t esize; |
|
|
|
esize = strlen(var) + 1 + strlen(val) + 1; |
|
if ((estring = malloc(esize)) == NULL) { |
|
errno = ENOMEM; |
|
return -1; |
|
} |
|
|
|
/* Build environment string and insert it. */ |
|
if (strlcpy(estring, var, esize) >= esize || |
|
strlcat(estring, "=", esize) >= esize || |
|
strlcat(estring, val, esize) >= esize) { |
|
|
|
errno = EINVAL; |
|
return -1; |
|
} |
|
return sudo_putenv_nodebug(estring, true, overwrite); |
|
} |
|
|
|
/* |
|
* Similar to setenv(3) but operates on a private copy of the environment. |
|
*/ |
|
int |
|
sudo_setenv(const char *var, const char *val, int overwrite) |
|
{ |
|
int rval; |
|
debug_decl(sudo_setenv, SUDO_DEBUG_ENV) |
|
|
|
rval = sudo_setenv_nodebug(var, val, overwrite); |
|
if (rval == -1) { |
|
if (errno == EINVAL) |
|
errorx(1, _("internal error, sudo_setenv() overflow")); |
|
errorx(1, _("unable to allocate memory")); |
|
} |
|
debug_return_int(rval); |
|
} |
|
|
|
/* |
|
* Similar to unsetenv(3) but operates on a private copy of the environment. |
|
* Does not include warnings or debugging to avoid recursive calls. |
|
*/ |
|
static int |
|
sudo_unsetenv_nodebug(const char *var) |
|
{ |
|
char **ep = env.envp; |
|
size_t len; |
|
|
|
if (ep == NULL || var == NULL || *var == '\0' || strchr(var, '=') != NULL) { |
|
errno = EINVAL; |
|
return -1; |
|
} |
|
|
|
len = strlen(var); |
|
while (*ep != NULL) { |
|
if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') { |
|
/* Found it; shift remainder + NULL over by one. */ |
|
char **cur = ep; |
|
while ((*cur = *(cur + 1)) != NULL) |
|
cur++; |
|
/* Keep going, could be multiple instances of the var. */ |
|
} else { |
|
ep++; |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
/* |
|
* Similar to unsetenv(3) but operates on a private copy of the environment. |
|
*/ |
|
int |
|
sudo_unsetenv(const char *name) |
|
{ |
|
int rval; |
|
debug_decl(sudo_unsetenv, SUDO_DEBUG_ENV) |
|
|
|
rval = sudo_unsetenv_nodebug(name); |
|
|
|
debug_return_int(rval); |
|
} |
|
|
|
/* |
|
* Similar to getenv(3) but operates on a private copy of the environment. |
|
* Does not include warnings or debugging to avoid recursive calls. |
|
*/ |
|
static char * |
|
sudo_getenv_nodebug(const char *name) |
|
{ |
|
char **ep, *val = NULL; |
|
size_t namelen = 0; |
|
|
|
if (env.env_len != 0) { |
|
/* For BSD compatibility, treat '=' in name like end of string. */ |
|
while (name[namelen] != '\0' && name[namelen] != '=') |
|
namelen++; |
|
for (ep = env.envp; *ep != NULL; ep++) { |
|
if (strncmp(*ep, name, namelen) == 0 && (*ep)[namelen] == '=') { |
|
val = *ep + namelen + 1; |
|
break; |
|
} |
|
} |
|
} |
|
return val; |
|
} |
|
|
|
/* |
|
* Similar to getenv(3) but operates on a private copy of the environment. |
|
*/ |
|
char * |
|
sudo_getenv(const char *name) |
|
{ |
|
char *val; |
|
debug_decl(sudo_getenv, SUDO_DEBUG_ENV) |
|
|
|
val = sudo_getenv_nodebug(name); |
|
|
|
debug_return_str(val); |
|
} |
|
|
|
/* |
|
* Merge another environment with our private copy. |
|
*/ |
|
void |
|
env_merge(char * const envp[], bool overwrite) |
|
{ |
|
char * const *ep; |
|
debug_decl(env_merge, SUDO_DEBUG_ENV) |
|
|
|
for (ep = envp; *ep != NULL; ep++) |
|
sudo_putenv(*ep, true, overwrite); |
|
|
|
debug_return; |
|
} |
|
|
|
/* |
|
* Check the env_delete blacklist. |
|
* Returns true if the variable was found, else false. |
|
*/ |
|
static bool |
matches_env_delete(const char *var) |
matches_env_delete(const char *var) |
{ |
{ |
struct list_member *cur; |
struct list_member *cur; |
size_t len; |
size_t len; |
int iswild, match = FALSE; | bool iswild; |
| bool match = false; |
| debug_decl(matches_env_delete, SUDO_DEBUG_ENV) |
|
|
/* Skip anything listed in env_delete. */ |
/* Skip anything listed in env_delete. */ |
for (cur = def_env_delete; cur; cur = cur->next) { |
for (cur = def_env_delete; cur; cur = cur->next) { |
Line 338 matches_env_delete(const char *var)
|
Line 529 matches_env_delete(const char *var)
|
/* Deal with '*' wildcard */ |
/* Deal with '*' wildcard */ |
if (cur->value[len - 1] == '*') { |
if (cur->value[len - 1] == '*') { |
len--; |
len--; |
iswild = TRUE; | iswild = true; |
} else |
} else |
iswild = FALSE; | iswild = false; |
if (strncmp(cur->value, var, len) == 0 && |
if (strncmp(cur->value, var, len) == 0 && |
(iswild || var[len] == '=')) { |
(iswild || var[len] == '=')) { |
match = TRUE; | match = true; |
break; |
break; |
} |
} |
} |
} |
return match; | debug_return_bool(match); |
} |
} |
|
|
/* |
/* |
* Apply the env_check list. |
* Apply the env_check list. |
* Returns TRUE if the variable is allowed, FALSE if denied | * Returns true if the variable is allowed, false if denied |
* or -1 if no match. |
* or -1 if no match. |
*/ |
*/ |
static int |
static int |
Line 360 matches_env_check(const char *var)
|
Line 551 matches_env_check(const char *var)
|
{ |
{ |
struct list_member *cur; |
struct list_member *cur; |
size_t len; |
size_t len; |
int iswild, keepit = -1; | bool iswild; |
| int keepit = -1; |
| debug_decl(matches_env_check, SUDO_DEBUG_ENV) |
|
|
for (cur = def_env_check; cur; cur = cur->next) { |
for (cur = def_env_check; cur; cur = cur->next) { |
len = strlen(cur->value); |
len = strlen(cur->value); |
/* Deal with '*' wildcard */ |
/* Deal with '*' wildcard */ |
if (cur->value[len - 1] == '*') { |
if (cur->value[len - 1] == '*') { |
len--; |
len--; |
iswild = TRUE; | iswild = true; |
} else |
} else |
iswild = FALSE; | iswild = false; |
if (strncmp(cur->value, var, len) == 0 && |
if (strncmp(cur->value, var, len) == 0 && |
(iswild || var[len] == '=')) { |
(iswild || var[len] == '=')) { |
keepit = !strpbrk(var, "/%"); |
keepit = !strpbrk(var, "/%"); |
break; |
break; |
} |
} |
} |
} |
return keepit; | debug_return_bool(keepit); |
} |
} |
|
|
/* |
/* |
* Check the env_keep list. |
* Check the env_keep list. |
* Returns TRUE if the variable is allowed else FALSE. | * Returns true if the variable is allowed else false. |
*/ |
*/ |
static int | static bool |
matches_env_keep(const char *var) |
matches_env_keep(const char *var) |
{ |
{ |
struct list_member *cur; |
struct list_member *cur; |
size_t len; |
size_t len; |
int iswild, keepit = FALSE; | bool iswild, keepit = false; |
| debug_decl(matches_env_keep, SUDO_DEBUG_ENV) |
|
|
/* Preserve SHELL variable for "sudo -s". */ |
/* Preserve SHELL variable for "sudo -s". */ |
if (ISSET(sudo_mode, MODE_SHELL) && strncmp(var, "SHELL=", 6) == 0) | if (ISSET(sudo_mode, MODE_SHELL) && strncmp(var, "SHELL=", 6) == 0) { |
return TRUE; | keepit = true; |
| goto done; |
| } |
|
|
for (cur = def_env_keep; cur; cur = cur->next) { |
for (cur = def_env_keep; cur; cur = cur->next) { |
len = strlen(cur->value); |
len = strlen(cur->value); |
/* Deal with '*' wildcard */ |
/* Deal with '*' wildcard */ |
if (cur->value[len - 1] == '*') { |
if (cur->value[len - 1] == '*') { |
len--; |
len--; |
iswild = TRUE; | iswild = true; |
} else |
} else |
iswild = FALSE; | iswild = false; |
if (strncmp(cur->value, var, len) == 0 && |
if (strncmp(cur->value, var, len) == 0 && |
(iswild || var[len] == '=')) { |
(iswild || var[len] == '=')) { |
keepit = TRUE; | keepit = true; |
break; |
break; |
} |
} |
} |
} |
return keepit; | done: |
| debug_return_bool(keepit); |
} |
} |
|
|
/* |
/* |
|
* Look up var in the env_delete and env_check. |
|
* Returns true if we should delete the variable, else false. |
|
*/ |
|
static bool |
|
env_should_delete(const char *var) |
|
{ |
|
int delete_it; |
|
debug_decl(env_should_delete, SUDO_DEBUG_ENV); |
|
|
|
delete_it = matches_env_delete(var); |
|
if (!delete_it) |
|
delete_it = matches_env_check(var) == false; |
|
debug_return_bool(delete_it); |
|
} |
|
|
|
/* |
|
* Lookup var in the env_check and env_keep lists. |
|
* Returns true if the variable is allowed else false. |
|
*/ |
|
static bool |
|
env_should_keep(const char *var) |
|
{ |
|
int keepit; |
|
debug_decl(env_should_keep, SUDO_DEBUG_ENV) |
|
|
|
keepit = matches_env_check(var); |
|
if (keepit == -1) |
|
keepit = matches_env_keep(var); |
|
|
|
debug_return_bool(keepit == true); |
|
} |
|
|
|
static void |
|
env_update_didvar(const char *ep, unsigned 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. |
* Also adds sudo-specific variables (SUDO_*). |
* Also adds sudo-specific variables (SUDO_*). |
Line 422 rebuild_env(void)
|
Line 689 rebuild_env(void)
|
char **old_envp, **ep, *cp, *ps1; |
char **old_envp, **ep, *cp, *ps1; |
char idbuf[MAX_UID_T_LEN]; |
char idbuf[MAX_UID_T_LEN]; |
unsigned int didvar; |
unsigned int didvar; |
int reset_home = FALSE; | bool reset_home = false; |
|
|
/* |
/* |
* Either clean out the environment or reset to a safe default. |
* Either clean out the environment or reset to a safe default. |
Line 435 rebuild_env(void)
|
Line 702 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. */ |
Line 442 rebuild_env(void)
|
Line 711 rebuild_env(void)
|
if (def_always_set_home || |
if (def_always_set_home || |
ISSET(sudo_mode, MODE_RESET_HOME | MODE_LOGIN_SHELL) || |
ISSET(sudo_mode, MODE_RESET_HOME | MODE_LOGIN_SHELL) || |
(ISSET(sudo_mode, MODE_SHELL) && def_set_home)) |
(ISSET(sudo_mode, MODE_SHELL) && def_set_home)) |
reset_home = TRUE; | reset_home = true; |
} |
} |
|
|
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++) { |
int keepit; | bool keepit; |
|
|
/* Skip variables with values beginning with () (bash functions) */ |
/* Skip variables with values beginning with () (bash functions) */ |
if ((cp = strchr(*ep, '=')) != NULL) { |
if ((cp = strchr(*ep, '=')) != NULL) { |
Line 457 rebuild_env(void)
|
Line 752 rebuild_env(void)
|
} |
} |
|
|
/* |
/* |
* First check certain variables for '%' and '/' characters. | * Look up the variable in the env_check and env_keep lists. |
* If no match there, check the keep list. | |
* If nothing matched, we remove it from the environment. | |
*/ |
*/ |
keepit = matches_env_check(*ep); | keepit = env_should_keep(*ep); |
if (keepit == -1) | |
keepit = matches_env_keep(*ep); | |
|
|
/* For SUDO_PS1 -> PS1 conversion. */ | /* |
| * Do SUDO_PS1 -> PS1 conversion. |
| * This must happen *after* env_should_keep() is called. |
| */ |
if (strncmp(*ep, "SUDO_PS1=", 8) == 0) |
if (strncmp(*ep, "SUDO_PS1=", 8) == 0) |
ps1 = *ep + 5; |
ps1 = *ep + 5; |
|
|
if (keepit) { |
if (keepit) { |
/* Preserve variable. */ |
/* Preserve variable. */ |
switch (**ep) { | sudo_putenv(*ep, false, false); |
case 'H': | env_update_didvar(*ep, &didvar); |
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); | |
} |
} |
} |
} |
didvar |= didvar << 8; /* convert DID_* to KEPT_* */ |
didvar |= didvar << 8; /* convert DID_* to KEPT_* */ |
Line 514 rebuild_env(void)
|
Line 777 rebuild_env(void)
|
* on sudoers options). |
* on sudoers options). |
*/ |
*/ |
if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { |
if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { |
sudo_setenv("SHELL", runas_pw->pw_shell, ISSET(didvar, DID_SHELL)); | sudo_setenv2("SHELL", runas_pw->pw_shell, |
sudo_setenv("LOGNAME", runas_pw->pw_name, | ISSET(didvar, DID_SHELL), true); |
ISSET(didvar, DID_LOGNAME)); | sudo_setenv2("LOGNAME", runas_pw->pw_name, |
sudo_setenv("USER", runas_pw->pw_name, ISSET(didvar, DID_USER)); | ISSET(didvar, DID_LOGNAME), true); |
sudo_setenv("USERNAME", runas_pw->pw_name, | sudo_setenv2("USER", runas_pw->pw_name, |
ISSET(didvar, DID_USERNAME)); | ISSET(didvar, DID_USER), true); |
| sudo_setenv2("USERNAME", runas_pw->pw_name, |
| ISSET(didvar, DID_USERNAME), true); |
} else { |
} else { |
if (!ISSET(didvar, DID_SHELL)) |
if (!ISSET(didvar, DID_SHELL)) |
sudo_setenv("SHELL", sudo_user.pw->pw_shell, FALSE); | sudo_setenv2("SHELL", sudo_user.pw->pw_shell, false, true); |
if (!ISSET(didvar, DID_LOGNAME)) |
if (!ISSET(didvar, DID_LOGNAME)) |
sudo_setenv("LOGNAME", user_name, FALSE); | sudo_setenv2("LOGNAME", user_name, false, true); |
if (!ISSET(didvar, DID_USER)) |
if (!ISSET(didvar, DID_USER)) |
sudo_setenv("USER", user_name, FALSE); | sudo_setenv2("USER", user_name, false, true); |
if (!ISSET(didvar, DID_USERNAME)) |
if (!ISSET(didvar, DID_USERNAME)) |
sudo_setenv("USERNAME", user_name, FALSE); | sudo_setenv2("USERNAME", user_name, false, true); |
} |
} |
|
|
/* If we didn't keep HOME, reset it based on target user. */ |
/* If we didn't keep HOME, reset it based on target user. */ |
if (!ISSET(didvar, KEPT_HOME)) |
if (!ISSET(didvar, KEPT_HOME)) |
reset_home = TRUE; | reset_home = true; |
|
|
/* |
/* |
* Set MAIL to target user in -i mode or if MAIL is not preserved |
* Set MAIL to target user in -i mode or if MAIL is not preserved |
Line 545 rebuild_env(void)
|
Line 810 rebuild_env(void)
|
easprintf(&cp, "MAIL=%s%s", _PATH_MAILDIR, runas_pw->pw_name); |
easprintf(&cp, "MAIL=%s%s", _PATH_MAILDIR, runas_pw->pw_name); |
else |
else |
easprintf(&cp, "MAIL=%s/%s", _PATH_MAILDIR, runas_pw->pw_name); |
easprintf(&cp, "MAIL=%s/%s", _PATH_MAILDIR, runas_pw->pw_name); |
sudo_putenv(cp, ISSET(didvar, DID_MAIL), TRUE); | sudo_putenv(cp, ISSET(didvar, DID_MAIL), true); |
} |
} |
} else { |
} else { |
/* |
/* |
Line 553 rebuild_env(void)
|
Line 818 rebuild_env(void)
|
* env_check. |
* env_check. |
*/ |
*/ |
for (ep = old_envp; *ep; ep++) { |
for (ep = old_envp; *ep; ep++) { |
int okvar; |
|
|
|
/* Skip variables with values beginning with () (bash functions) */ |
/* Skip variables with values beginning with () (bash functions) */ |
if ((cp = strchr(*ep, '=')) != NULL) { |
if ((cp = strchr(*ep, '=')) != NULL) { |
if (strncmp(cp, "=() ", 3) == 0) |
if (strncmp(cp, "=() ", 3) == 0) |
continue; |
continue; |
} |
} |
|
|
/* | /* Add variable unless it matches a black list. */ |
* First check variables against the blacklist in env_delete. | if (!env_should_delete(*ep)) { |
* If no match there check for '%' and '/' characters. | |
*/ | |
okvar = matches_env_delete(*ep) != TRUE; | |
if (okvar) | |
okvar = matches_env_check(*ep) != FALSE; | |
| |
if (okvar) { | |
if (strncmp(*ep, "SUDO_PS1=", 9) == 0) |
if (strncmp(*ep, "SUDO_PS1=", 9) == 0) |
ps1 = *ep + 5; |
ps1 = *ep + 5; |
else if (strncmp(*ep, "PATH=", 5) == 0) |
else if (strncmp(*ep, "PATH=", 5) == 0) |
SET(didvar, DID_PATH); |
SET(didvar, DID_PATH); |
else if (strncmp(*ep, "TERM=", 5) == 0) |
else if (strncmp(*ep, "TERM=", 5) == 0) |
SET(didvar, DID_TERM); |
SET(didvar, DID_TERM); |
sudo_putenv(*ep, FALSE, FALSE); | sudo_putenv(*ep, false, false); |
} |
} |
} |
} |
} |
} |
/* Replace the PATH envariable with a secure one? */ |
/* Replace the PATH envariable with a secure one? */ |
if (def_secure_path && !user_is_exempt()) { |
if (def_secure_path && !user_is_exempt()) { |
sudo_setenv("PATH", def_secure_path, TRUE); | sudo_setenv2("PATH", def_secure_path, true, true); |
SET(didvar, DID_PATH); |
SET(didvar, DID_PATH); |
} |
} |
|
|
Line 594 rebuild_env(void)
|
Line 850 rebuild_env(void)
|
*/ |
*/ |
if (def_set_logname && !ISSET(sudo_mode, MODE_LOGIN_SHELL|MODE_EDIT)) { |
if (def_set_logname && !ISSET(sudo_mode, MODE_LOGIN_SHELL|MODE_EDIT)) { |
if (!ISSET(didvar, KEPT_LOGNAME)) |
if (!ISSET(didvar, KEPT_LOGNAME)) |
sudo_setenv("LOGNAME", runas_pw->pw_name, TRUE); | sudo_setenv2("LOGNAME", runas_pw->pw_name, true, true); |
if (!ISSET(didvar, KEPT_USER)) |
if (!ISSET(didvar, KEPT_USER)) |
sudo_setenv("USER", runas_pw->pw_name, TRUE); | sudo_setenv2("USER", runas_pw->pw_name, true, true); |
if (!ISSET(didvar, KEPT_USERNAME)) |
if (!ISSET(didvar, KEPT_USERNAME)) |
sudo_setenv("USERNAME", runas_pw->pw_name, TRUE); | sudo_setenv2("USERNAME", runas_pw->pw_name, true, true); |
} |
} |
|
|
/* Set $HOME to target user if not preserving user's value. */ |
/* Set $HOME to target user if not preserving user's value. */ |
if (reset_home) |
if (reset_home) |
sudo_setenv("HOME", runas_pw->pw_dir, TRUE); | sudo_setenv2("HOME", runas_pw->pw_dir, true, true); |
|
|
/* Provide default values for $TERM and $PATH if they are not set. */ |
/* Provide default values for $TERM and $PATH if they are not set. */ |
if (!ISSET(didvar, DID_TERM)) |
if (!ISSET(didvar, DID_TERM)) |
sudo_putenv("TERM=unknown", FALSE, FALSE); | sudo_putenv("TERM=unknown", false, false); |
if (!ISSET(didvar, DID_PATH)) |
if (!ISSET(didvar, DID_PATH)) |
sudo_setenv("PATH", _PATH_STDPATH, FALSE); | sudo_setenv2("PATH", _PATH_STDPATH, false, true); |
|
|
/* Set PS1 if SUDO_PS1 is set. */ |
/* Set PS1 if SUDO_PS1 is set. */ |
if (ps1 != NULL) |
if (ps1 != NULL) |
sudo_putenv(ps1, TRUE, TRUE); | sudo_putenv(ps1, true, true); |
|
|
/* Add the SUDO_COMMAND envariable (cmnd + args). */ |
/* Add the SUDO_COMMAND envariable (cmnd + args). */ |
if (user_args) { |
if (user_args) { |
easprintf(&cp, "%s %s", user_cmnd, user_args); |
easprintf(&cp, "%s %s", user_cmnd, user_args); |
sudo_setenv("SUDO_COMMAND", cp, TRUE); | sudo_setenv2("SUDO_COMMAND", cp, true, true); |
efree(cp); |
efree(cp); |
} else { |
} else { |
sudo_setenv("SUDO_COMMAND", user_cmnd, TRUE); | sudo_setenv2("SUDO_COMMAND", user_cmnd, true, true); |
} |
} |
|
|
/* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */ |
/* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */ |
sudo_setenv("SUDO_USER", user_name, TRUE); | sudo_setenv2("SUDO_USER", user_name, true, true); |
snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_uid); |
snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_uid); |
sudo_setenv("SUDO_UID", idbuf, TRUE); | sudo_setenv2("SUDO_UID", idbuf, true, true); |
snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_gid); |
snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_gid); |
sudo_setenv("SUDO_GID", idbuf, TRUE); | sudo_setenv2("SUDO_GID", idbuf, true, true); |
|
|
/* Free old environment. */ |
/* Free old environment. */ |
efree(old_envp); |
efree(old_envp); |
Line 645 insert_env_vars(char * const envp[])
|
Line 901 insert_env_vars(char * const envp[])
|
|
|
/* Add user-specified environment variables. */ |
/* Add user-specified environment variables. */ |
for (ep = envp; *ep != NULL; ep++) |
for (ep = envp; *ep != NULL; ep++) |
sudo_putenv(*ep, TRUE, TRUE); | sudo_putenv(*ep, true, true); |
} |
} |
|
|
/* |
/* |
* Validate the list of environment variables passed in on the command |
* Validate the list of environment variables passed in on the command |
* line against env_delete, env_check, and env_keep. |
* line against env_delete, env_check, and env_keep. |
* Calls log_error() if any specified variables are not allowed. | * Calls log_fatal() if any specified variables are not allowed. |
*/ |
*/ |
void |
void |
validate_env_vars(char * const env_vars[]) |
validate_env_vars(char * const env_vars[]) |
Line 659 validate_env_vars(char * const env_vars[])
|
Line 915 validate_env_vars(char * const env_vars[])
|
char * const *ep; |
char * const *ep; |
char *eq, *bad = NULL; |
char *eq, *bad = NULL; |
size_t len, blen = 0, bsize = 0; |
size_t len, blen = 0, bsize = 0; |
int okvar; | bool okvar; |
|
|
if (env_vars == NULL) |
if (env_vars == NULL) |
return; |
return; |
Line 668 validate_env_vars(char * const env_vars[])
|
Line 924 validate_env_vars(char * const env_vars[])
|
for (ep = env_vars; *ep != NULL; ep++) { |
for (ep = env_vars; *ep != NULL; ep++) { |
if (def_secure_path && !user_is_exempt() && |
if (def_secure_path && !user_is_exempt() && |
strncmp(*ep, "PATH=", 5) == 0) { |
strncmp(*ep, "PATH=", 5) == 0) { |
okvar = FALSE; | okvar = false; |
} else if (def_env_reset) { |
} else if (def_env_reset) { |
okvar = matches_env_check(*ep); | okvar = env_should_keep(*ep); |
if (okvar == -1) | |
okvar = matches_env_keep(*ep); | |
} else { |
} else { |
okvar = matches_env_delete(*ep) == FALSE; | okvar = !env_should_delete(*ep); |
if (okvar == FALSE) | |
okvar = matches_env_check(*ep) != FALSE; | |
} |
} |
if (okvar == FALSE) { | if (okvar == false) { |
/* Not allowed, add to error string, allocating as needed. */ |
/* Not allowed, add to error string, allocating as needed. */ |
if ((eq = strchr(*ep, '=')) != NULL) |
if ((eq = strchr(*ep, '=')) != NULL) |
*eq = '\0'; |
*eq = '\0'; |
Line 699 validate_env_vars(char * const env_vars[])
|
Line 951 validate_env_vars(char * const env_vars[])
|
} |
} |
if (bad != NULL) { |
if (bad != NULL) { |
bad[blen - 2] = '\0'; /* remove trailing ", " */ |
bad[blen - 2] = '\0'; /* remove trailing ", " */ |
log_error(NO_MAIL, | log_fatal(NO_MAIL, |
_("sorry, you are not allowed to set the following environment variables: %s"), bad); |
_("sorry, you are not allowed to set the following environment variables: %s"), bad); |
/* NOTREACHED */ |
/* NOTREACHED */ |
efree(bad); |
efree(bad); |
Line 758 read_env_file(const char *path, int overwrite)
|
Line 1010 read_env_file(const char *path, int overwrite)
|
memcpy(cp, var, var_len + 1); /* includes '=' */ |
memcpy(cp, var, var_len + 1); /* includes '=' */ |
memcpy(cp + var_len + 1, val, val_len + 1); /* includes NUL */ |
memcpy(cp + var_len + 1, val, val_len + 1); /* includes NUL */ |
|
|
sudo_putenv(cp, TRUE, overwrite); | sudo_putenv(cp, true, overwrite); |
} |
} |
fclose(fp); |
fclose(fp); |
} |
} |
Line 771 init_envtables(void)
|
Line 1023 init_envtables(void)
|
|
|
/* Fill in the "env_delete" list. */ |
/* Fill in the "env_delete" list. */ |
for (p = initial_badenv_table; *p; p++) { |
for (p = initial_badenv_table; *p; p++) { |
cur = emalloc(sizeof(struct list_member)); | cur = ecalloc(1, sizeof(struct list_member)); |
cur->value = estrdup(*p); |
cur->value = estrdup(*p); |
cur->next = def_env_delete; |
cur->next = def_env_delete; |
def_env_delete = cur; |
def_env_delete = cur; |
Line 779 init_envtables(void)
|
Line 1031 init_envtables(void)
|
|
|
/* Fill in the "env_check" list. */ |
/* Fill in the "env_check" list. */ |
for (p = initial_checkenv_table; *p; p++) { |
for (p = initial_checkenv_table; *p; p++) { |
cur = emalloc(sizeof(struct list_member)); | cur = ecalloc(1, sizeof(struct list_member)); |
cur->value = estrdup(*p); |
cur->value = estrdup(*p); |
cur->next = def_env_check; |
cur->next = def_env_check; |
def_env_check = cur; |
def_env_check = cur; |
Line 787 init_envtables(void)
|
Line 1039 init_envtables(void)
|
|
|
/* Fill in the "env_keep" list. */ |
/* Fill in the "env_keep" list. */ |
for (p = initial_keepenv_table; *p; p++) { |
for (p = initial_keepenv_table; *p; p++) { |
cur = emalloc(sizeof(struct list_member)); | cur = ecalloc(1, sizeof(struct list_member)); |
cur->value = estrdup(*p); |
cur->value = estrdup(*p); |
cur->next = def_env_keep; |
cur->next = def_env_keep; |
def_env_keep = cur; |
def_env_keep = cur; |
} |
} |
|
} |
|
|
|
int |
|
sudoers_hook_getenv(const char *name, char **value, void *closure) |
|
{ |
|
static bool in_progress = false; /* avoid recursion */ |
|
|
|
if (in_progress || env.envp == NULL) |
|
return SUDO_HOOK_RET_NEXT; |
|
|
|
in_progress = true; |
|
*value = sudo_getenv_nodebug(name); |
|
in_progress = false; |
|
return SUDO_HOOK_RET_STOP; |
|
} |
|
|
|
int |
|
sudoers_hook_putenv(char *string, void *closure) |
|
{ |
|
static bool in_progress = false; /* avoid recursion */ |
|
|
|
if (in_progress || env.envp == NULL) |
|
return SUDO_HOOK_RET_NEXT; |
|
|
|
in_progress = true; |
|
sudo_putenv_nodebug(string, true, true); |
|
in_progress = false; |
|
return SUDO_HOOK_RET_STOP; |
|
} |
|
|
|
int |
|
sudoers_hook_setenv(const char *name, const char *value, int overwrite, void *closure) |
|
{ |
|
static bool in_progress = false; /* avoid recursion */ |
|
|
|
if (in_progress || env.envp == NULL) |
|
return SUDO_HOOK_RET_NEXT; |
|
|
|
in_progress = true; |
|
sudo_setenv_nodebug(name, value, overwrite); |
|
in_progress = false; |
|
return SUDO_HOOK_RET_STOP; |
|
} |
|
|
|
int |
|
sudoers_hook_unsetenv(const char *name, void *closure) |
|
{ |
|
static bool in_progress = false; /* avoid recursion */ |
|
|
|
if (in_progress || env.envp == NULL) |
|
return SUDO_HOOK_RET_NEXT; |
|
|
|
in_progress = true; |
|
sudo_unsetenv_nodebug(name); |
|
in_progress = false; |
|
return SUDO_HOOK_RET_STOP; |
} |
} |