]> granicus.if.org Git - sudo/commitdiff
Instead of trying to keep the global environment in sync with our
authorTodd C. Miller <Todd.Miller@courtesan.com>
Tue, 8 Jun 2010 14:26:15 +0000 (10:26 -0400)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Tue, 8 Jun 2010 14:26:15 +0000 (10:26 -0400)
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

env.c
sudo.c
sudo.h

diff --git a/env.c b/env.c
index 115d7fc140690acb32043d7c72a67d782e20fb53..14cbf44fd49af88988d6bc6f38502f1abdd4f24e 100644 (file)
--- 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 3e883f4a6fadba9463bf87ecff121450e9423148..eaa388f5fdd209fa8d2b01807492ecfa71eead5c 100644 (file)
--- 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 8b47bff26ab7d9543a89d770417ed02f43d4e3b1..e07876ef3e8b02931b22a782fc856000a8bef58f 100644 (file)
--- 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 */