From: Todd C. Miller Date: Tue, 8 Jun 2010 14:26:15 +0000 (-0400) Subject: Instead of trying to keep the global environment in sync with our X-Git-Tag: SUDO_1_7_3~103 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f1cd89bd429329073362b1966a0058b54528484c;p=sudo Instead of trying to keep the global environment in sync with our private copy, provide our own getenv() that returns values from the private environment and use env_get() to pass the environment in to run_command(). --HG-- branch : 1.7 --- diff --git a/env.c b/env.c index 115d7fc14..14cbf44fd 100644 --- a/env.c +++ b/env.c @@ -86,9 +86,6 @@ #undef KEPT_MAX #define KEPT_MAX 0xff00 -#undef VNULL -#define VNULL (void *)NULL - struct environment { char **envp; /* pointer to the new environment */ size_t env_size; /* size of new_environ in char **'s */ @@ -98,7 +95,6 @@ struct environment { /* * Prototypes */ -void rebuild_env __P((int, int)); static void sudo_setenv __P((const char *, const char *, int)); static void sudo_putenv __P((char *, int, int)); @@ -209,6 +205,39 @@ static const char *initial_keepenv_table[] = { NULL }; +/* + * Initialize env based on envp. + */ +void +env_init(envp) + char * const envp[]; +{ + /* May have gotten initialized lazily. */ + if (env.envp == NULL) { + char * const *ep; + size_t len; + + for (ep = envp; *ep != NULL; ep++) + continue; + len = (size_t)(ep - envp); + + env.env_len = len; + env.env_size = len + 1 + 128; + env.envp = emalloc2(env.env_size, sizeof(char *)); +#ifdef ENV_DEBUG + memset(env.envp, 0, env.env_size * sizeof(char *)); +#endif + memcpy(env.envp, envp, len * sizeof(char *)); + env.envp[len] = '\0'; + } +} + +char ** +env_get() +{ + return env.envp; +} + /* * Similar to setenv(3) but operates on sudo's private copy of the environment * (not environ) and it always overwrites. The dupcheck param determines @@ -236,9 +265,27 @@ sudo_setenv(var, val, dupcheck) sudo_putenv(estring, dupcheck, TRUE); } +/* + * Version of getenv(3) that uses our own environ pointer. + */ +char * +getenv(const char *var) +{ + char *cp, **ev; + size_t vlen = strlen(var); + + if (env.envp == NULL) + env_init(environ); + + for (ev = env.envp; (cp = *ev) != NULL; ev++) { + if (strncmp(var, cp, vlen) == 0 && cp[vlen] == '=') + return cp + vlen + 1; + } + return NULL; +} + /* * Version of setenv(3) that uses our own environ pointer. - * Will sync with environ as needed. */ int setenv(var, val, overwrite) @@ -250,6 +297,9 @@ setenv(var, val, overwrite) const char *cp; size_t esize; + if (env.envp == NULL) + env_init(environ); + if (!var || *var == '\0') { errno = EINVAL; return(-1); @@ -277,39 +327,16 @@ setenv(var, val, overwrite) } *ep = '\0'; - /* Sync env.envp with environ as needed. */ - if (env.envp != environ) { - char **ep; - size_t len; - - for (ep = environ; *ep != NULL; ep++) - continue; - len = ep - environ; - if (len + 2 > env.env_size) { - efree(env.envp); - env.env_size = len + 2 + 128; - env.envp = emalloc2(env.env_size, sizeof(char *)); -#ifdef ENV_DEBUG - memset(env.envp, 0, env.env_size * sizeof(char *)); -#endif - } - memcpy(env.envp, environ, len * sizeof(char *)); - env.envp[len] = NULL; - env.env_len = len; - environ = env.envp; #ifdef ENV_DEBUG - } else { - if (env.envp[env.env_len] != NULL) - errorx(1, "setenv: corrupted envp, len mismatch"); + if (env.envp[env.env_len] != NULL) + errorx(1, "setenv: corrupted envp, len mismatch"); #endif - } sudo_putenv(estring, TRUE, overwrite); return(0); } /* * Version of unsetenv(3) that uses our own environ pointer. - * Will sync with environ as needed. */ #ifdef UNSETENV_VOID void @@ -322,6 +349,9 @@ unsetenv(var) char **ep = env.envp; size_t len; + if (env.envp == NULL) + env_init(environ); + if (strchr(var, '=') != NULL) { errno = EINVAL; #ifdef UNSETENV_VOID @@ -331,30 +361,10 @@ unsetenv(var) #endif } - /* Make sure we are operating on the current environment. */ - /* XXX - this could be optimized to include the search */ - if (env.envp != environ) { - for (ep = environ; *ep != NULL; ep++) - continue; - len = ep - environ; - if (len + 1 > env.env_size) { - efree(env.envp); - env.env_size = len + 1 + 128; - env.envp = emalloc2(env.env_size, sizeof(char *)); #ifdef ENV_DEBUG - memset(env.envp, 0, env.env_size * sizeof(char *)); -#endif - } - memcpy(env.envp, environ, len * sizeof(char *)); - env.envp[len] = NULL; - env.env_len = len; - environ = env.envp; -#ifdef ENV_DEBUG - } else { - if (env.envp[env.env_len] != NULL) - errorx(1, "unsetenv: corrupted envp, len mismatch"); + if (env.envp[env.env_len] != NULL) + errorx(1, "unsetenv: corrupted envp, len mismatch"); #endif - } len = strlen(var); while (*ep != NULL) { @@ -375,7 +385,6 @@ unsetenv(var) /* * Version of putenv(3) that uses our own environ pointer. - * Will sync with environ as needed. */ int #ifdef PUTENV_CONST @@ -385,36 +394,17 @@ putenv(string) char *string; #endif { + if (env.envp == NULL) + env_init(environ); + if (strchr(string, '=') == NULL) { errno = EINVAL; return(-1); } - /* Sync env.envp with environ as needed. */ - if (env.envp != environ) { - char **ep; - size_t len; - - for (ep = environ; *ep != NULL; ep++) - continue; - len = ep - environ; - if (len + 2 > env.env_size) { - efree(env.envp); - env.env_size = len + 2 + 128; - env.envp = emalloc2(env.env_size, sizeof(char *)); -#ifdef ENV_DEBUG - memset(env.envp, 0, env.env_size * sizeof(char *)); -#endif - } - memcpy(env.envp, environ, len * sizeof(char *)); - env.envp[len] = NULL; - env.env_len = len; - environ = env.envp; #ifdef ENV_DEBUG - } else { - if (env.envp[env.env_len] != NULL) - errorx(1, "putenv: corrupted envp, len mismatch"); + if (env.envp[env.env_len] != NULL) + errorx(1, "putenv: corrupted envp, len mismatch"); #endif - } sudo_putenv((char *)string, TRUE, TRUE); return(0); } @@ -443,7 +433,6 @@ sudo_putenv(str, dupcheck, overwrite) memset(env.envp + env.env_len, 0, (env.env_size - env.env_len) * sizeof(char *)); #endif - environ = env.envp; } #ifdef ENV_DEBUG @@ -599,7 +588,7 @@ rebuild_env(sudo_mode, noexec) #endif if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) { /* Pull in vars we want to keep from the old environment. */ - for (ep = environ; *ep; ep++) { + for (ep = old_envp; *ep; ep++) { int keepit; /* Skip variables with values beginning with () (bash functions) */ @@ -686,7 +675,7 @@ rebuild_env(sudo_mode, noexec) * Copy environ entries as long as they don't match env_delete or * env_check. */ - for (ep = environ; *ep; ep++) { + for (ep = old_envp; *ep; ep++) { int okvar; /* Skip variables with values beginning with () (bash functions) */ @@ -779,8 +768,9 @@ rebuild_env(sudo_mode, noexec) easprintf(&cp, "%s %s", user_cmnd, user_args); sudo_setenv("SUDO_COMMAND", cp, TRUE); efree(cp); - } else + } else { sudo_setenv("SUDO_COMMAND", user_cmnd, TRUE); + } /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */ sudo_setenv("SUDO_USER", user_name, TRUE); @@ -789,8 +779,7 @@ rebuild_env(sudo_mode, noexec) snprintf(idbuf, sizeof(idbuf), "%lu", (unsigned long) user_gid); sudo_setenv("SUDO_GID", idbuf, TRUE); - /* Install new environment. */ - environ = env.envp; + /* Free old environment. */ efree(old_envp); } @@ -800,9 +789,6 @@ insert_env_vars(env_vars) { struct list_member *cur; - if (env_vars == NULL) - return; - /* Add user-specified environment variables. */ for (cur = env_vars; cur != NULL; cur = cur->next) putenv(cur->value); @@ -822,6 +808,7 @@ validate_env_vars(env_vars) size_t len, blen = 0, bsize = 0; int okvar; + /* Add user-specified environment variables. */ for (var = env_vars; var != NULL; var = var->next) { if (def_secure_path && !user_is_exempt() && strncmp(var->value, "PATH=", 5) == 0) { diff --git a/sudo.c b/sudo.c index 3e883f4a6..eaa388f5f 100644 --- a/sudo.c +++ b/sudo.c @@ -121,9 +121,6 @@ static void set_runaspw __P((char *)); static void show_version __P((void)); static struct passwd *get_authpw __P((void)); extern int sudo_edit __P((int, char **, char **)); -extern void rebuild_env __P((int, int)); -void validate_env_vars __P((struct list_member *)); -void insert_env_vars __P((struct list_member *)); int run_command __P((const char *path, char *argv[], char *envp[], uid_t uid, int dowait)); /* XXX should be in sudo.h */ /* @@ -162,8 +159,8 @@ extern int optind; int main(argc, argv, envp) int argc; - char **argv; - char **envp; + char *argv[]; + char *envp[]; { int sources = 0, validated; int fd, cmnd_status, pwflag, rc = 0; @@ -207,6 +204,9 @@ main(argc, argv, envp) (void) sigaction(SIGQUIT, &sa, &saved_sa_quit); (void) sigaction(SIGTSTP, &sa, &saved_sa_tstp); + /* Initialize environment functions (including replacements). */ + env_init(envp); + /* * Turn off core dumps and make sure fds 0-2 are open. */ @@ -516,7 +516,7 @@ main(argc, argv, envp) if (ISSET(sudo_mode, MODE_EDIT)) exit(sudo_edit(NewArgc, NewArgv, envp)); else - exit(run_command(safe_cmnd, NewArgv, environ, runas_pw->pw_uid, FALSE)); + exit(run_command(safe_cmnd, NewArgv, env_get(), runas_pw->pw_uid, FALSE)); } else if (ISSET(validated, FLAG_NO_USER | FLAG_NO_HOST)) { audit_failure(NewArgv, "No user or host"); log_denial(validated, 1); diff --git a/sudo.h b/sudo.h index 8b47bff26..e07876ef3 100644 --- a/sudo.h +++ b/sudo.h @@ -221,8 +221,13 @@ void check_user __P((int, int)); void remove_timestamp __P((int)); /* env.c */ +char **env_get __P((void)); +void env_init __P((char * const envp[])); void init_envtables __P((void)); +void insert_env_vars __P((struct list_member *)); void read_env_file __P((const char *, int)); +void rebuild_env __P((int, int)); +void validate_env_vars __P((struct list_member *)); /* exec.c */ int sudo_execve __P((const char *path, char *argv[], char *envp[], uid_t uid, @@ -373,6 +378,5 @@ int run_command __P((const char *path, char *argv[], char *envp[], uid_t uid, in #ifndef errno extern int errno; #endif -extern char **environ; /* XXX */ #endif /* _SUDO_SUDO_H */