]> granicus.if.org Git - sudo/commitdiff
Don't try to pre-compute the size of the new envp, just allocate
authorTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 2 May 2002 19:40:25 +0000 (19:40 +0000)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 2 May 2002 19:40:25 +0000 (19:40 +0000)
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.

env.c

diff --git a/env.c b/env.c
index 661a1d44a113a299df93ba1d87996f6cb4d9ca74..59c36cd58ba2373a07c575b895c3908f5a0ecd0e 100644 (file)
--- a/env.c
+++ b/env.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2000-2002 Todd C. Miller <Todd.Miller@courtesan.com>
  * 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++) {