Diff for /embedaddon/sudo/plugins/sudoers/env.c between versions 1.1.1.2 and 1.1.1.5

version 1.1.1.2, 2012/05/29 12:26:49 version 1.1.1.5, 2013/10/14 07:56:34
Line 1 Line 1
 /*  /*
 * Copyright (c) 2000-2005, 2007-2011 * Copyright (c) 2000-2005, 2007-2013
  *      Todd C. Miller <Todd.Miller@courtesan.com>   *      Todd C. Miller <Todd.Miller@courtesan.com>
  *   *
  * Permission to use, copy, modify, and distribute this software for any   * Permission to use, copy, modify, and distribute this software for any
Line 22 Line 22
 #include <config.h>  #include <config.h>
   
 #include <sys/types.h>  #include <sys/types.h>
 #include <sys/param.h>  
 #include <sys/stat.h>  #include <sys/stat.h>
 #include <stdio.h>  #include <stdio.h>
 #ifdef STDC_HEADERS  #ifdef STDC_HEADERS
Line 42 Line 41
 #ifdef HAVE_UNISTD_H  #ifdef HAVE_UNISTD_H
 # include <unistd.h>  # include <unistd.h>
 #endif /* HAVE_UNISTD_H */  #endif /* HAVE_UNISTD_H */
   #ifdef HAVE_INTTYPES_H
   # include <inttypes.h>
   #endif
 #ifdef HAVE_LOGIN_CAP_H  #ifdef HAVE_LOGIN_CAP_H
 # include <login_cap.h>  # include <login_cap.h>
 # ifndef LOGIN_SETENV  # ifndef LOGIN_SETENV
Line 50 Line 52
 #endif /* HAVE_LOGIN_CAP_H */  #endif /* HAVE_LOGIN_CAP_H */
 #include <ctype.h>  #include <ctype.h>
 #include <errno.h>  #include <errno.h>
   #include <limits.h>
 #include <pwd.h>  #include <pwd.h>
   
 #include "sudoers.h"  #include "sudoers.h"
   
 /*  /*
    * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t
    * could be signed (as it is on SunOS 4.x).  This just means that
    * emalloc2() and erealloc3() cannot allocate huge amounts on such a
    * platform but that is OK since sudo doesn't need to do so anyway.
    */
   #ifndef SIZE_MAX
   # ifdef SIZE_T_MAX
   #  define SIZE_MAX      SIZE_T_MAX
   # else
   #  define SIZE_MAX      INT_MAX
   # endif /* SIZE_T_MAX */
   #endif /* SIZE_MAX */
           
   /*
  * Flags used in rebuild_env()   * Flags used in rebuild_env()
  */   */
 #undef DID_TERM  #undef DID_TERM
Line 229  env_init(char * const envp[]) Line 246  env_init(char * const envp[])
         memset(env.envp, 0, env.env_size * sizeof(char *));          memset(env.envp, 0, env.env_size * sizeof(char *));
 #endif  #endif
         memcpy(env.envp, envp, len * sizeof(char *));          memcpy(env.envp, envp, len * sizeof(char *));
        env.envp[len] = '\0';        env.envp[len] = NULL;
   
         /* Free the old envp we allocated, if any. */          /* Free the old envp we allocated, if any. */
         if (env.old_envp != NULL)          if (env.old_envp != NULL)
Line 263  sudo_putenv_nodebug(char *str, bool dupcheck, bool ove Line 280  sudo_putenv_nodebug(char *str, bool dupcheck, bool ove
     bool found = false;      bool found = false;
   
     /* Make sure there is room for the new entry plus a NULL. */      /* Make sure there is room for the new entry plus a NULL. */
    if (env.env_len + 2 > env.env_size) {    if (env.env_size > 2 && env.env_len > env.env_size - 2) {
         char **nenvp;          char **nenvp;
        size_t nsize = env.env_size + 128;        size_t nsize;
        nenvp = env.envp ? realloc(env.envp, nsize * sizeof(char *)) :
            malloc(nsize * sizeof(char *));        if (env.env_size > SIZE_MAX - 128) {
             fatalx_nodebug(_("internal error, %s overflow"),
                 "sudo_putenv_nodebug()");
         }
         nsize = env.env_size + 128;
         if (nsize > SIZE_MAX / sizeof(char *)) {
             fatalx_nodebug(_("internal error, %s overflow"),
                 "sudo_putenv_nodebug()");
         }
         nenvp = realloc(env.envp, nsize * sizeof(char *));
         if (nenvp == NULL) {          if (nenvp == NULL) {
             errno = ENOMEM;              errno = ENOMEM;
             return -1;              return -1;
Line 289  sudo_putenv_nodebug(char *str, bool dupcheck, bool ove Line 315  sudo_putenv_nodebug(char *str, bool dupcheck, bool ove
   
     if (dupcheck) {      if (dupcheck) {
         len = (strchr(str, '=') - str) + 1;          len = (strchr(str, '=') - str) + 1;
        for (ep = env.envp; !found && *ep != NULL; ep++) {        for (ep = env.envp; *ep != NULL; ep++) {
             if (strncmp(str, *ep, len) == 0) {              if (strncmp(str, *ep, len) == 0) {
                 if (overwrite)                  if (overwrite)
                     *ep = str;                      *ep = str;
                 found = true;                  found = true;
                   break;
             }              }
         }          }
        /* Prune out duplicate variables. */        /* Prune out extra instances of the variable we just overwrote. */
         if (found && overwrite) {          if (found && overwrite) {
            while (*ep != NULL) {            while (*++ep != NULL) {
                 if (strncmp(str, *ep, len) == 0) {                  if (strncmp(str, *ep, len) == 0) {
                     char **cur = ep;                      char **cur = ep;
                     while ((*cur = *(cur + 1)) != NULL)                      while ((*cur = *(cur + 1)) != NULL)
                         cur++;                          cur++;
                } else {                    ep--;
                    ep++; 
                 }                  }
             }              }
             env.env_len = ep - env.envp;              env.env_len = ep - env.envp;
Line 332  sudo_putenv(char *str, bool dupcheck, bool overwrite) Line 358  sudo_putenv(char *str, bool dupcheck, bool overwrite)
     int rval;      int rval;
     debug_decl(sudo_putenv, SUDO_DEBUG_ENV)      debug_decl(sudo_putenv, SUDO_DEBUG_ENV)
   
       sudo_debug_printf(SUDO_DEBUG_INFO, "sudo_putenv: %s", str);
   
     rval = sudo_putenv_nodebug(str, dupcheck, overwrite);      rval = sudo_putenv_nodebug(str, dupcheck, overwrite);
     if (rval == -1) {      if (rval == -1) {
 #ifdef ENV_DEBUG  #ifdef ENV_DEBUG
         if (env.envp[env.env_len] != NULL)          if (env.envp[env.env_len] != NULL)
            errorx(1, _("sudo_putenv: corrupted envp, length mismatch"));            fatalx(_("sudo_putenv: corrupted envp, length mismatch"));
 #endif  #endif
        errorx(1, _("unable to allocate memory"));        fatal(NULL);
     }      }
     debug_return_int(rval);      debug_return_int(rval);
 }  }
Line 353  sudo_setenv2(const char *var, const char *val, bool du Line 381  sudo_setenv2(const char *var, const char *val, bool du
 {  {
     char *estring;      char *estring;
     size_t esize;      size_t esize;
       int rval;
     debug_decl(sudo_setenv2, SUDO_DEBUG_ENV)      debug_decl(sudo_setenv2, SUDO_DEBUG_ENV)
   
     esize = strlen(var) + 1 + strlen(val) + 1;      esize = strlen(var) + 1 + strlen(val) + 1;
Line 363  sudo_setenv2(const char *var, const char *val, bool du Line 392  sudo_setenv2(const char *var, const char *val, bool du
         strlcat(estring, "=", esize) >= esize ||          strlcat(estring, "=", esize) >= esize ||
         strlcat(estring, val, esize) >= esize) {          strlcat(estring, val, esize) >= esize) {
   
        errorx(1, _("internal error, sudo_setenv2() overflow"));        fatalx(_("internal error, %s overflow"), "sudo_setenv2()");
     }      }
    debug_return_int(sudo_putenv(estring, dupcheck, overwrite));    rval = sudo_putenv(estring, dupcheck, overwrite);
     if (rval == -1)
         efree(estring);
     debug_return_int(rval);
 }  }
   
 /*  /*
  * Similar to setenv(3) but operates on a private copy of the environment.   * Similar to setenv(3) but operates on a private copy of the environment.
    */
   int
   sudo_setenv(const char *var, const char *val, int overwrite)
   {
       return sudo_setenv2(var, val, true, (bool)overwrite);
   }
   
   /*
    * Similar to setenv(3) but operates on a private copy of the environment.
  * Does not include warnings or debugging to avoid recursive calls.   * Does not include warnings or debugging to avoid recursive calls.
  */   */
 static int  static int
 sudo_setenv_nodebug(const char *var, const char *val, int overwrite)  sudo_setenv_nodebug(const char *var, const char *val, int overwrite)
 {  {
    char *estring;    char *ep, *estring = NULL;
     const char *cp;
     size_t esize;      size_t esize;
       int rval = -1;
   
    esize = strlen(var) + 1 + strlen(val) + 1;    if (var == NULL || *var == '\0') {
    if ((estring = malloc(esize)) == NULL) {        errno = EINVAL;
        errno = ENOMEM;        goto done;
        return -1; 
     }      }
   
    /* Build environment string and insert it. */    /*
    if (strlcpy(estring, var, esize) >= esize ||     * POSIX says a var name with '=' is an error but BSD
        strlcat(estring, "=", esize) >= esize ||     * just ignores the '=' and anything after it.
        strlcat(estring, val, esize) >= esize) {     */
    for (cp = var; *cp && *cp != '='; cp++)
        errno = EINVAL;        ;
        return -1;    esize = (size_t)(cp - var) + 2;
     if (val) {
         esize += strlen(val);        /* glibc treats a NULL val as "" */
     }      }
     return sudo_putenv_nodebug(estring, true, overwrite);  
 }  
   
/*    /* Allocate and fill in estring. */
 * Similar to setenv(3) but operates on a private copy of the environment.    if ((estring = ep = malloc(esize)) == NULL) {
 */        errno = ENOMEM;
int        goto done;
sudo_setenv(const char *var, const char *val, int overwrite) 
{ 
    int rval; 
    debug_decl(sudo_setenv, SUDO_DEBUG_ENV) 
 
    rval = sudo_setenv_nodebug(var, val, overwrite); 
    if (rval == -1) { 
        if (errno == EINVAL) 
            errorx(1, _("internal error, sudo_setenv() overflow")); 
        errorx(1, _("unable to allocate memory")); 
     }      }
    debug_return_int(rval);    for (cp = var; *cp && *cp != '='; cp++)
         *ep++ = *cp;
     *ep++ = '=';
     if (val) {
         for (cp = val; *cp; cp++)
             *ep++ = *cp;
     }
     *ep = '\0';
 
     rval = sudo_putenv_nodebug(estring, true, overwrite);
 done:
     if (rval == -1)
         free(estring);
     return rval;
 }  }
   
 /*  /*
Line 452  sudo_unsetenv(const char *name) Line 497  sudo_unsetenv(const char *name)
     int rval;      int rval;
     debug_decl(sudo_unsetenv, SUDO_DEBUG_ENV)      debug_decl(sudo_unsetenv, SUDO_DEBUG_ENV)
   
       sudo_debug_printf(SUDO_DEBUG_INFO, "sudo_unsetenv: %s", name);
   
     rval = sudo_unsetenv_nodebug(name);      rval = sudo_unsetenv_nodebug(name);
   
     debug_return_int(rval);      debug_return_int(rval);
Line 490  sudo_getenv(const char *name) Line 537  sudo_getenv(const char *name)
     char *val;      char *val;
     debug_decl(sudo_getenv, SUDO_DEBUG_ENV)      debug_decl(sudo_getenv, SUDO_DEBUG_ENV)
   
       sudo_debug_printf(SUDO_DEBUG_INFO, "sudo_getenv: %s", name);
   
     val = sudo_getenv_nodebug(name);      val = sudo_getenv_nodebug(name);
   
     debug_return_str(val);      debug_return_str(val);
 }  }
   
 /*  /*
  * Merge another environment with our private copy.  
  */  
 void  
 env_merge(char * const envp[], bool overwrite)  
 {  
     char * const *ep;  
     debug_decl(env_merge, SUDO_DEBUG_ENV)  
   
     for (ep = envp; *ep != NULL; ep++)  
         sudo_putenv(*ep, true, overwrite);  
   
     debug_return;  
 }  
   
 /*  
  * Check the env_delete blacklist.   * Check the env_delete blacklist.
  * Returns true if the variable was found, else false.   * Returns true if the variable was found, else false.
  */   */
Line 621  env_should_delete(const char *var) Line 655  env_should_delete(const char *var)
     delete_it = matches_env_delete(var);      delete_it = matches_env_delete(var);
     if (!delete_it)      if (!delete_it)
         delete_it = matches_env_check(var) == false;          delete_it = matches_env_check(var) == false;
   
       sudo_debug_printf(SUDO_DEBUG_INFO, "delete %s: %s",
           var, delete_it ? "YES" : "NO");
     debug_return_bool(delete_it);      debug_return_bool(delete_it);
 }  }
   
Line 638  env_should_keep(const char *var) Line 675  env_should_keep(const char *var)
     if (keepit == -1)      if (keepit == -1)
         keepit = matches_env_keep(var);          keepit = matches_env_keep(var);
   
       sudo_debug_printf(SUDO_DEBUG_INFO, "keep %s: %s",
           var, keepit ? "YES" : "NO");
     debug_return_bool(keepit == true);      debug_return_bool(keepit == true);
 }  }
   
   /*
    * Merge another environment with our private copy.
    * Only overwrite an existing variable if it is not
    * being preserved from the user's environment.
    */
   void
   env_merge(char * const envp[])
   {
       char * const *ep;
       debug_decl(env_merge, SUDO_DEBUG_ENV)
   
       for (ep = envp; *ep != NULL; ep++)
           sudo_putenv(*ep, true, !env_should_keep(*ep));
   
       debug_return;
   }
   
 static void  static void
 env_update_didvar(const char *ep, unsigned int *didvar)  env_update_didvar(const char *ep, unsigned int *didvar)
 {  {
Line 687  void Line 743  void
 rebuild_env(void)  rebuild_env(void)
 {  {
     char **old_envp, **ep, *cp, *ps1;      char **old_envp, **ep, *cp, *ps1;
    char idbuf[MAX_UID_T_LEN];    char idbuf[MAX_UID_T_LEN + 1];
     unsigned int didvar;      unsigned int didvar;
     bool reset_home = false;      bool reset_home = false;
   
Line 788  rebuild_env(void) Line 844  rebuild_env(void)
         } else {          } else {
             if (!ISSET(didvar, DID_SHELL))              if (!ISSET(didvar, DID_SHELL))
                 sudo_setenv2("SHELL", sudo_user.pw->pw_shell, false, true);                  sudo_setenv2("SHELL", sudo_user.pw->pw_shell, false, true);
            if (!ISSET(didvar, DID_LOGNAME))            /* We will set LOGNAME later in the !def_set_logname case. */
                sudo_setenv2("LOGNAME", user_name, false, true);            if (!def_set_logname) {
            if (!ISSET(didvar, DID_USER))                if (!ISSET(didvar, DID_LOGNAME))
                sudo_setenv2("USER", user_name, false, true);                    sudo_setenv2("LOGNAME", user_name, false, true);
            if (!ISSET(didvar, DID_USERNAME))                if (!ISSET(didvar, DID_USER))
                sudo_setenv2("USERNAME", user_name, false, true);                    sudo_setenv2("USER", user_name, false, true);
                 if (!ISSET(didvar, DID_USERNAME))
                     sudo_setenv2("USERNAME", user_name, false, true);
             }
         }          }
   
         /* If we didn't keep HOME, reset it based on target user. */          /* If we didn't keep HOME, reset it based on target user. */
Line 845  rebuild_env(void) Line 904  rebuild_env(void)
     /*      /*
      * Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is not       * Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is not
      * disabled.  We skip this if we are running a login shell (because       * disabled.  We skip this if we are running a login shell (because
     * they have already been set them) or sudoedit (because we want the     * they have already been set) or sudoedit (because we want the editor
     * editor to find the user's startup files).     * to find the invoking user's startup files).
      */       */
     if (def_set_logname && !ISSET(sudo_mode, MODE_LOGIN_SHELL|MODE_EDIT)) {      if (def_set_logname && !ISSET(sudo_mode, MODE_LOGIN_SHELL|MODE_EDIT)) {
         if (!ISSET(didvar, KEPT_LOGNAME))          if (!ISSET(didvar, KEPT_LOGNAME))
Line 952  validate_env_vars(char * const env_vars[]) Line 1011  validate_env_vars(char * const env_vars[])
     if (bad != NULL) {      if (bad != NULL) {
         bad[blen - 2] = '\0';           /* remove trailing ", " */          bad[blen - 2] = '\0';           /* remove trailing ", " */
         log_fatal(NO_MAIL,          log_fatal(NO_MAIL,
            _("sorry, you are not allowed to set the following environment variables: %s"), bad);            N_("sorry, you are not allowed to set the following environment variables: %s"), bad);
         /* NOTREACHED */          /* NOTREACHED */
         efree(bad);          efree(bad);
     }      }
Line 972  void Line 1031  void
 read_env_file(const char *path, int overwrite)  read_env_file(const char *path, int overwrite)
 {  {
     FILE *fp;      FILE *fp;
    char *cp, *var, *val;    char *cp, *var, *val, *line = NULL;
    size_t var_len, val_len;    size_t var_len, val_len, linesize = 0;
   
     if ((fp = fopen(path, "r")) == NULL)      if ((fp = fopen(path, "r")) == NULL)
         return;          return;
   
    while ((var = sudo_parseln(fp)) != NULL) {    while (sudo_parseln(&line, &linesize, NULL, fp) != -1) {
         /* Skip blank or comment lines */          /* Skip blank or comment lines */
        if (*var == '\0')        if (*(var = line) == '\0')
             continue;              continue;
   
         /* Skip optional "export " */          /* Skip optional "export " */
Line 1012  read_env_file(const char *path, int overwrite) Line 1071  read_env_file(const char *path, int overwrite)
   
         sudo_putenv(cp, true, overwrite);          sudo_putenv(cp, true, overwrite);
     }      }
       free(line);
     fclose(fp);      fclose(fp);
 }  }
   
Line 1055  sudoers_hook_getenv(const char *name, char **value, vo Line 1115  sudoers_hook_getenv(const char *name, char **value, vo
         return SUDO_HOOK_RET_NEXT;          return SUDO_HOOK_RET_NEXT;
   
     in_progress = true;      in_progress = true;
   
       /* Hack to make GNU gettext() find the sudoers locale when needed. */
       if (*name == 'L' && sudoers_getlocale() == SUDOERS_LOCALE_SUDOERS) {
           if (strcmp(name, "LANGUAGE") == 0 || strcmp(name, "LANG") == 0) {
               *value = NULL;
               goto done;
           }
           if (strcmp(name, "LC_ALL") == 0 || strcmp(name, "LC_MESSAGES") == 0) {
               *value = def_sudoers_locale;
               goto done;
           }
       }
   
     *value = sudo_getenv_nodebug(name);      *value = sudo_getenv_nodebug(name);
   done:
     in_progress = false;      in_progress = false;
     return SUDO_HOOK_RET_STOP;      return SUDO_HOOK_RET_STOP;
 }  }

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.5


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>