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:
272
env.c
272
env.c
@@ -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
13
sudo.c
@@ -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);
|
||||||
|
Reference in New Issue
Block a user