From: Todd C. Miller Date: Thu, 2 May 2002 19:40:25 +0000 (+0000) Subject: Don't try to pre-compute the size of the new envp, just allocate X-Git-Tag: SUDO_1_6_7~133 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3f7d80188096e438b54e3a835c69123a6ea40d11;p=sudo Don't try to pre-compute the size of the new envp, just allocate space up front and realloc as needed. Changes to the new env pointer must all be made through insert_env() which now keeps track of spaced used and allocates as needed. --- diff --git a/env.c b/env.c index 661a1d44a..59c36cd58 100644 --- a/env.c +++ b/env.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001 Todd C. Miller + * Copyright (c) 2000-2002 Todd C. Miller * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -86,14 +86,14 @@ static const char rcsid[] = "$Sudo$"; */ char **rebuild_env __P((int, char **)); char **zero_env __P((char **)); -static void insert_env __P((char **, char *)); +static void insert_env __P((char *, int)); static char *format_env __P((char *, char *)); /* * Default table of "bad" variables to remove from the environment. * XXX - how to omit TERMCAP if it starts with '/'? */ -char *initial_badenv_table[] = { +static const char *initial_badenv_table[] = { "IFS", "LOCALDOMAIN", "RES_OPTIONS", @@ -133,13 +133,17 @@ char *initial_badenv_table[] = { /* * Default table of variables to check for '%' and '/' characters. */ -char *initial_checkenv_table[] = { +static const char *initial_checkenv_table[] = { "LC_*", "LANG", "LANGUAGE", NULL }; +static char **new_environ; /* Modified copy of the environment */ +static size_t env_size; /* size of new_environ in char **'s */ +static size_t env_len; /* number of slots used, not counting NULL */ + /* * Zero out environment and replace with a minimal set of * USER, LOGNAME, HOME, TZ, PATH (XXX - should just set path to default) @@ -221,29 +225,38 @@ format_env(var, val) } /* - * Insert str into envp. - * Assumes str has an '=' in it and does not check for available space! + * Insert str into new_environ, assumes str has an '=' in it. + * NOTE: no other routines may modify new_environ, env_size, or env_len. */ static void -insert_env(envp, str) - char **envp; +insert_env(str, dupcheck) char *str; + int dupcheck; { - char **ep; + char **nep; size_t varlen; - varlen = (strchr(str, '=') - str) + 1; - - for (ep = envp; *ep; ep++) { - if (strncmp(str, *ep, varlen) == 0) { - *ep = str; - break; - } - } - if (*ep == NULL) { - *ep++ = str; - *ep = NULL; + /* Make sure there is room for the new entry. */ + if (env_len + 1 > env_size) { + env_size += 128; + new_environ = erealloc(new_environ, env_size * sizeof(char *)); } + + if (dupcheck) { + varlen = (strchr(str, '=') - str) + 1; + + for (nep = new_environ; *nep; nep++) { + if (strncmp(str, *nep, varlen) == 0) { + *nep = str; + return; + } + } + } else + nep = &new_environ[env_len]; + + env_len++; + *nep++ = str; + *nep = NULL; } /* @@ -256,15 +269,11 @@ rebuild_env(sudo_mode, envp) int sudo_mode; char **envp; { - char **newenvp, **ep, **nep, *cp, *ps1; + char **ep, *cp, *ps1; int okvar, iswild, didvar; - size_t env_size, len; + size_t len; struct list_member *cur; - /* Count number of items in "env_keep" list (if any) */ - for (len = 0, cur = def_list(I_ENV_KEEP); cur; cur = cur->next) - len++; - /* * Either clean out the environment or reset to a safe default. */ @@ -273,10 +282,6 @@ rebuild_env(sudo_mode, envp) if (def_flag(I_ENV_RESET)) { int keepit; - /* Alloc space for new environment. */ - env_size = 32 + len; - nep = newenvp = (char **) emalloc(env_size * sizeof(char *)); - /* Pull in vars we want to keep from the old environment. */ for (ep = envp; *ep; ep++) { keepit = 0; @@ -321,14 +326,14 @@ rebuild_env(sudo_mode, envp) didvar |= DID_USER; break; } - *nep++ = *ep; + insert_env(*ep, 0); } else { /* Preserve TERM and PATH, ignore anything else. */ if (!(didvar & DID_TERM) && !strncmp(*ep, "TERM=", 5)) { - *nep++ = *ep; + insert_env(*ep, 0); didvar |= DID_TERM; } else if (!(didvar & DID_PATH) && !strncmp(*ep, "PATH=", 5)) { - *nep++ = *ep; + insert_env(*ep, 0); didvar |= DID_PATH; } } @@ -339,19 +344,14 @@ rebuild_env(sudo_mode, envp) * user's environment. */ if (!(didvar & DID_HOME)) - *nep++ = format_env("HOME", user_dir); + insert_env(format_env("HOME", user_dir), 0); if (!(didvar & DID_SHELL)) - *nep++ = format_env("SHELL", sudo_user.pw->pw_shell); + insert_env(format_env("SHELL", sudo_user.pw->pw_shell), 0); if (!(didvar & DID_LOGNAME)) - *nep++ = format_env("LOGNAME", user_name); + insert_env(format_env("LOGNAME", user_name), 0); if (!(didvar & DID_USER)) - *nep++ = format_env("USER", user_name); + insert_env(format_env("USER", user_name), 0); } else { - /* Alloc space for new environment. */ - for (env_size = 16 + len, ep = envp; *ep; ep++, env_size++) - ; - nep = newenvp = (char **) emalloc(env_size * sizeof(char *)); - /* * Copy envp entries as long as they don't match env_delete or * env_check. @@ -397,56 +397,50 @@ rebuild_env(sudo_mode, envp) didvar |= DID_PATH; else if (strncmp(*ep, "TERM=", 5) == 0) didvar |= DID_TERM; - *nep++ = *ep; + insert_env(*ep, 0); } } } /* Provide default values for $TERM and $PATH if they are not set. */ if (!(didvar & DID_TERM)) - *nep++ = "TERM=unknown"; + insert_env("TERM=unknown", 0); if (!(didvar & DID_PATH)) - *nep++ = format_env("PATH", _PATH_DEFPATH); - *nep = NULL; - - /* - * At this point we must use insert_env() to modify newenvp. - * Access via 'nep' is not allowed (since we must check for dupes). - */ + insert_env(format_env("PATH", _PATH_DEFPATH), 0); #ifdef SECURE_PATH /* Replace the PATH envariable with a secure one. */ - insert_env(newenvp, format_env("PATH", SECURE_PATH)); + insert_env(format_env("PATH", SECURE_PATH), 1); #endif /* Set $USER and $LOGNAME to target if "set_logname" is true. */ if (def_flag(I_SET_LOGNAME) && runas_pw->pw_name) { - insert_env(newenvp, format_env("LOGNAME", runas_pw->pw_name)); - insert_env(newenvp, format_env("USER", runas_pw->pw_name)); + insert_env(format_env("LOGNAME", runas_pw->pw_name), 1); + insert_env(format_env("USER", runas_pw->pw_name), 1); } /* Set $HOME for `sudo -H'. Only valid at PERM_RUNAS. */ if ((sudo_mode & MODE_RESET_HOME) && runas_pw->pw_dir) - insert_env(newenvp, format_env("HOME", runas_pw->pw_dir)); + insert_env(format_env("HOME", runas_pw->pw_dir), 1); /* Set PS1 if SUDO_PS1 is set. */ if (ps1) - insert_env(newenvp, ps1); + insert_env(ps1, 1); /* Add the SUDO_COMMAND envariable (cmnd + args). */ if (user_args) { easprintf(&cp, "SUDO_COMMAND=%s %s", user_cmnd, user_args); - insert_env(newenvp, cp); + insert_env(cp, 1); } else - insert_env(newenvp, format_env("SUDO_COMMAND", user_cmnd)); + insert_env(format_env("SUDO_COMMAND", user_cmnd), 1); /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */ - insert_env(newenvp, format_env("SUDO_USER", user_name)); + insert_env(format_env("SUDO_USER", user_name), 1); easprintf(&cp, "SUDO_UID=%ld", (long) user_uid); - insert_env(newenvp, cp); + insert_env(cp, 1); easprintf(&cp, "SUDO_GID=%ld", (long) user_gid); - insert_env(newenvp, cp); + insert_env(cp, 1); - return(newenvp); + return(new_environ); } void @@ -467,7 +461,7 @@ void init_envtables() { struct list_member *cur; - char **p; + const char **p; /* Fill in "env_delete" variable. */ for (p = initial_badenv_table; *p; p++) {