2
0
mirror of https://github.com/sudo-project/sudo.git synced 2025-09-01 06:45:10 +00:00

Just clean the environment once. This assumes that any further

setenv/putenv will be able to handle the fact that we replaced environ
with our own malloc'd copy but all the implementations I've checked do.
This commit is contained in:
Todd C. Miller
2005-02-20 16:48:05 +00:00
parent 87a8b5b48b
commit 6bee8e3770
2 changed files with 111 additions and 174 deletions

272
env.c
View File

@@ -78,11 +78,10 @@ struct environment {
/* /*
* Prototypes * Prototypes
*/ */
char **rebuild_env __P((char **, char **, int, int)); char **rebuild_env __P((char **, int, int));
char **zero_env __P((char **)); char **zero_env __P((char **));
static void insert_env __P((char *, struct environment *, int)); static void insert_env __P((char *, struct environment *, int));
static char *format_env __P((char *, ...)); static char *format_env __P((char *, ...));
static int var_ok __P((char *));
/* /*
* Default table of "bad" variables to remove from the environment. * Default table of "bad" variables to remove from the environment.
@@ -150,38 +149,6 @@ static const char *initial_keepenv_table[] = {
NULL NULL
}; };
/*
* Remove potentially dangerous variables from the environment
* and returns a vector of what was pruned out.
*/
char **
clean_env(envp)
char **envp;
{
char **ep, **end;
struct environment pruned_env;
/* Find the end of the environment. */
for (end = envp; *end; end++)
continue;
/*
* Prune out any bad environment variables and set user_path, user_prompt
* and prev_user.
*/
memset(&pruned_env, 0, sizeof(pruned_env));
for (ep = envp; *ep; ) {
if (var_ok(*ep)) {
ep++;
} else {
insert_env(*ep, &pruned_env, 0);
memmove(ep, ep + 1, end - ep);
}
}
return (pruned_env.envp);
}
/* /*
* Given a variable and value, allocate and format an environment string. * Given a variable and value, allocate and format an environment string.
*/ */
@@ -267,150 +234,90 @@ insert_env(str, e, dupcheck)
*nep = NULL; *nep = NULL;
} }
/*
* Check an environment variable against the env_delete
* and env_chec lists. Returns TRUE if allowed, else FALSE.
*/
static int
var_ok(var)
char *var;
{
struct list_member *cur;
size_t len;
char *cp;
int iswild, okvar = TRUE;
/* Skip variables with values beginning with () (bash functions) */
if ((cp = strchr(var, '=')) != NULL) {
if (strncmp(cp, "=() ", 3) == 0)
return (FALSE);
}
/* Skip anything listed in env_delete. */
for (cur = def_env_delete; cur && okvar; cur = cur->next) {
len = strlen(cur->value);
/* Deal with '*' wildcard */
if (cur->value[len - 1] == '*') {
len--;
iswild = TRUE;
} else
iswild = FALSE;
if (strncmp(cur->value, var, len) == 0 &&
(iswild || var[len] == '=')) {
okvar = FALSE;
}
}
/* Check certain variables for '%' and '/' characters. */
for (cur = def_env_check; cur && okvar; cur = cur->next) {
len = strlen(cur->value);
/* Deal with '*' wildcard */
if (cur->value[len - 1] == '*') {
len--;
iswild = TRUE;
} else
iswild = FALSE;
if (strncmp(cur->value, var, len) == 0 &&
(iswild || var[len] == '=') &&
strpbrk(var, "/%")) {
okvar = FALSE;
}
}
return (okvar);
}
/* /*
* 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_*).
*/ */
char ** char **
rebuild_env(envp1, envp2, sudo_mode, noexec) rebuild_env(envp, sudo_mode, noexec)
char **envp1; char **envp;
char **envp2;
int sudo_mode; int sudo_mode;
int noexec; int noexec;
{ {
struct list_member *cur;
struct environment env; struct environment env;
char **envpv[2], **ep, *cp, *ps1; size_t len;
int didvar, i; char **ep, *cp, *ps1;
int okvar, iswild, didvar;
/* /*
* Either clean out the environment or reset to a safe default. * Either clean out the environment or reset to a safe default.
*/ */
ps1 = NULL; ps1 = NULL;
didvar = 0; didvar = 0;
envpv[0] = envp1;
envpv[1] = envp2;
memset(&env, 0, sizeof(env)); memset(&env, 0, sizeof(env));
if (def_env_reset) { if (def_env_reset) {
struct list_member *cur; int keepit;
size_t len;
int iswild, keepit;
/* Pull in vars we want to keep from the old environment. */ /* Pull in vars we want to keep from the old environment. */
for (i = 0; i < 2; i++) { for (ep = envp; *ep; ep++) {
if ((ep = envpv[i]) == NULL) keepit = FALSE;
continue;
for (; *ep; ep++) {
keepit = 0;
/* 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;
}
for (cur = def_env_keep; cur; cur = cur->next) {
len = strlen(cur->value);
/* Deal with '*' wildcard */
if (cur->value[len - 1] == '*') {
len--;
iswild = TRUE;
} else
iswild = FALSE;
if (strncmp(cur->value, *ep, len) == 0 &&
(iswild || (*ep)[len] == '=')) {
keepit = TRUE;
break;
} }
}
for (cur = def_env_keep; cur; cur = cur->next) { /* For SUDO_PS1 -> PS1 conversion. */
len = strlen(cur->value); if (strncmp(*ep, "SUDO_PS1=", 8) == 0)
/* Deal with '*' wildcard */ ps1 = *ep + 5;
if (cur->value[len - 1] == '*') {
len--; if (keepit) {
iswild = 1; /* Preserve variable. */
} else switch (**ep) {
iswild = 0; case 'H':
if (strncmp(cur->value, *ep, len) == 0 && if (strncmp(*ep, "HOME=", 5) == 0)
(iswild || (*ep)[len] == '=')) { SET(didvar, DID_HOME);
keepit = 1; break;
case 'L':
if (strncmp(*ep, "LOGNAME=", 8) == 0)
SET(didvar, DID_LOGNAME);
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);
break; break;
}
}
/* For SUDO_PS1 -> PS1 conversion. */
if (strncmp(*ep, "SUDO_PS1=", 8) == 0)
ps1 = *ep + 5;
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 '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);
break;
}
insert_env(*ep, &env, 0);
} }
insert_env(*ep, &env, 0);
} }
} }
@@ -444,20 +351,55 @@ rebuild_env(envp1, envp2, sudo_mode, noexec)
* Copy envp entries as long as they don't match env_delete or * Copy envp entries as long as they don't match env_delete or
* env_check. * env_check.
*/ */
for (i = 0; i < 2; i++) { for (ep = envp; *ep; ep++) {
if ((ep = envpv[i]) == NULL) okvar = TRUE;
continue;
for (; *ep; ep++) { /* Skip variables with values beginning with () (bash functions) */
if (var_ok(*ep)) { if ((cp = strchr(*ep, '=')) != NULL) {
if (strncmp(*ep, "SUDO_PS1=", 9) == 0) if (strncmp(cp, "=() ", 3) == 0)
ps1 = *ep + 5; continue;
else if (strncmp(*ep, "PATH=", 5) == 0) }
SET(didvar, DID_PATH);
else if (strncmp(*ep, "TERM=", 5) == 0) /* Skip anything listed in env_delete. */
SET(didvar, DID_TERM); for (cur = def_env_delete; cur && okvar; cur = cur->next) {
insert_env(*ep, &env, 0); len = strlen(cur->value);
/* Deal with '*' wildcard */
if (cur->value[len - 1] == '*') {
len--;
iswild = TRUE;
} else
iswild = FALSE;
if (strncmp(cur->value, *ep, len) == 0 &&
(iswild || (*ep)[len] == '=')) {
okvar = FALSE;
} }
} }
/* Check certain variables for '%' and '/' characters. */
for (cur = def_env_check; cur && okvar; cur = cur->next) {
len = strlen(cur->value);
/* Deal with '*' wildcard */
if (cur->value[len - 1] == '*') {
len--;
iswild = TRUE;
} else
iswild = FALSE;
if (strncmp(cur->value, *ep, len) == 0 &&
(iswild || (*ep)[len] == '=') &&
strpbrk(*ep, "/%")) {
okvar = FALSE;
}
}
if (okvar) {
if (strncmp(*ep, "SUDO_PS1=", 9) == 0)
ps1 = *ep + 5;
else if (strncmp(*ep, "PATH=", 5) == 0)
SET(didvar, DID_PATH);
else if (strncmp(*ep, "TERM=", 5) == 0)
SET(didvar, DID_TERM);
insert_env(*ep, &env, 0);
}
} }
} }
/* Replace the PATH envariable with a secure one? */ /* Replace the PATH envariable with a secure one? */

13
sudo.c
View File

@@ -110,7 +110,7 @@ static void usage_excl __P((int))
__attribute__((__noreturn__)); __attribute__((__noreturn__));
static struct passwd *get_authpw __P((void)); static struct passwd *get_authpw __P((void));
extern int sudo_edit __P((int, char **)); extern int sudo_edit __P((int, char **));
extern char **rebuild_env __P((char **, char **, int, int)); extern char **rebuild_env __P((char **, int, int));
extern char **clean_env __P((char **)); extern char **clean_env __P((char **));
/* /*
@@ -151,7 +151,6 @@ main(argc, argv)
int cmnd_status; int cmnd_status;
int sudo_mode; int sudo_mode;
int pwflag; int pwflag;
char **new_environ, **pruned_environ;
sigaction_t sa; sigaction_t sa;
#ifdef HAVE_LDAP #ifdef HAVE_LDAP
VOID *ld; VOID *ld;
@@ -292,8 +291,6 @@ main(argc, argv)
def_closefrom = user_closefrom; def_closefrom = user_closefrom;
} }
pruned_environ = clean_env(environ);
cmnd_status = set_cmnd(sudo_mode); cmnd_status = set_cmnd(sudo_mode);
#ifdef HAVE_LDAP #ifdef HAVE_LDAP
@@ -360,9 +357,7 @@ main(argc, argv)
/* Build a new environment based on the rules in sudoers. */ /* Build a new environment based on the rules in sudoers. */
if (ISSET(sudo_mode, MODE_RUN)) if (ISSET(sudo_mode, MODE_RUN))
new_environ = rebuild_env(pruned_environ, environ, sudo_mode, def_noexec); environ = rebuild_env(environ, sudo_mode, def_noexec);
else
new_environ = environ;
if (ISSET(validated, VALIDATE_OK)) { if (ISSET(validated, VALIDATE_OK)) {
/* Finally tell the user if the command did not exist. */ /* Finally tell the user if the command did not exist. */
@@ -438,7 +433,7 @@ main(argc, argv)
if (ISSET(sudo_mode, MODE_BACKGROUND) && fork() > 0) if (ISSET(sudo_mode, MODE_BACKGROUND) && fork() > 0)
exit(0); exit(0);
else else
execve(safe_cmnd, NewArgv, new_environ); execve(safe_cmnd, NewArgv, environ);
#else #else
exit(0); exit(0);
#endif /* PROFILING */ #endif /* PROFILING */
@@ -449,7 +444,7 @@ main(argc, argv)
NewArgv--; /* at least one extra slot... */ NewArgv--; /* at least one extra slot... */
NewArgv[0] = "sh"; NewArgv[0] = "sh";
NewArgv[1] = safe_cmnd; NewArgv[1] = safe_cmnd;
execve(_PATH_BSHELL, NewArgv, new_environ); execve(_PATH_BSHELL, NewArgv, environ);
} }
warning("unable to execute %s", safe_cmnd); warning("unable to execute %s", safe_cmnd);
exit(127); exit(127);