Annotation of embedaddon/sudo/plugins/sudoers/env.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (c) 2000-2005, 2007-2011
        !             3:  *     Todd C. Miller <Todd.Miller@courtesan.com>
        !             4:  *
        !             5:  * Permission to use, copy, modify, and distribute this software for any
        !             6:  * purpose with or without fee is hereby granted, provided that the above
        !             7:  * copyright notice and this permission notice appear in all copies.
        !             8:  *
        !             9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            16:  *
        !            17:  * Sponsored in part by the Defense Advanced Research Projects
        !            18:  * Agency (DARPA) and Air Force Research Laboratory, Air Force
        !            19:  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
        !            20:  */
        !            21: 
        !            22: #include <config.h>
        !            23: 
        !            24: #include <sys/types.h>
        !            25: #include <sys/param.h>
        !            26: #include <sys/stat.h>
        !            27: #include <stdio.h>
        !            28: #ifdef STDC_HEADERS
        !            29: # include <stdlib.h>
        !            30: # include <stddef.h>
        !            31: #else
        !            32: # ifdef HAVE_STDLIB_H
        !            33: #  include <stdlib.h>
        !            34: # endif
        !            35: #endif /* STDC_HEADERS */
        !            36: #ifdef HAVE_STRING_H
        !            37: # include <string.h>
        !            38: #endif /* HAVE_STRING_H */
        !            39: #ifdef HAVE_STRINGS_H
        !            40: # include <strings.h>
        !            41: #endif /* HAVE_STRINGS_H */
        !            42: #ifdef HAVE_UNISTD_H
        !            43: # include <unistd.h>
        !            44: #endif /* HAVE_UNISTD_H */
        !            45: #include <ctype.h>
        !            46: #include <errno.h>
        !            47: #include <pwd.h>
        !            48: 
        !            49: #include "sudoers.h"
        !            50: 
        !            51: /*
        !            52:  * Flags used in rebuild_env()
        !            53:  */
        !            54: #undef DID_TERM
        !            55: #define DID_TERM       0x0001
        !            56: #undef DID_PATH
        !            57: #define DID_PATH       0x0002
        !            58: #undef DID_HOME
        !            59: #define DID_HOME       0x0004
        !            60: #undef DID_SHELL
        !            61: #define DID_SHELL      0x0008
        !            62: #undef DID_LOGNAME
        !            63: #define DID_LOGNAME    0x0010
        !            64: #undef DID_USER
        !            65: #define DID_USER       0x0020
        !            66: #undef DID_USERNAME
        !            67: #define DID_USERNAME           0x0040
        !            68: #undef DID_MAIL
        !            69: #define DID_MAIL       0x0080
        !            70: #undef DID_MAX
        !            71: #define DID_MAX        0x00ff
        !            72: 
        !            73: #undef KEPT_TERM
        !            74: #define KEPT_TERM      0x0100
        !            75: #undef KEPT_PATH
        !            76: #define KEPT_PATH      0x0200
        !            77: #undef KEPT_HOME
        !            78: #define KEPT_HOME      0x0400
        !            79: #undef KEPT_SHELL
        !            80: #define KEPT_SHELL     0x0800
        !            81: #undef KEPT_LOGNAME
        !            82: #define KEPT_LOGNAME   0x1000
        !            83: #undef KEPT_USER
        !            84: #define KEPT_USER      0x2000
        !            85: #undef KEPT_USERNAME
        !            86: #define KEPT_USERNAME  0x4000
        !            87: #undef KEPT_MAIL
        !            88: #define KEPT_MAIL      0x8000
        !            89: #undef KEPT_MAX
        !            90: #define KEPT_MAX       0xff00
        !            91: 
        !            92: struct environment {
        !            93:     char **envp;               /* pointer to the new environment */
        !            94:     size_t env_size;           /* size of new_environ in char **'s */
        !            95:     size_t env_len;            /* number of slots used, not counting NULL */
        !            96: };
        !            97: 
        !            98: /*
        !            99:  * Prototypes
        !           100:  */
        !           101: static void sudo_setenv(const char *, const char *, int);
        !           102: static void sudo_putenv(char *, int, int);
        !           103: 
        !           104: /*
        !           105:  * Copy of the sudo-managed environment.
        !           106:  */
        !           107: static struct environment env;
        !           108: 
        !           109: /*
        !           110:  * Default table of "bad" variables to remove from the environment.
        !           111:  * XXX - how to omit TERMCAP if it starts with '/'?
        !           112:  */
        !           113: static const char *initial_badenv_table[] = {
        !           114:     "IFS",
        !           115:     "CDPATH",
        !           116:     "LOCALDOMAIN",
        !           117:     "RES_OPTIONS",
        !           118:     "HOSTALIASES",
        !           119:     "NLSPATH",
        !           120:     "PATH_LOCALE",
        !           121:     "LD_*",
        !           122:     "_RLD*",
        !           123: #ifdef __hpux
        !           124:     "SHLIB_PATH",
        !           125: #endif /* __hpux */
        !           126: #ifdef _AIX
        !           127:     "LDR_*",
        !           128:     "LIBPATH",
        !           129:     "AUTHSTATE",
        !           130: #endif
        !           131: #ifdef __APPLE__
        !           132:     "DYLD_*",
        !           133: #endif
        !           134: #ifdef HAVE_KERB4
        !           135:     "KRB_CONF*",
        !           136:     "KRBCONFDIR",
        !           137:     "KRBTKFILE",
        !           138: #endif /* HAVE_KERB4 */
        !           139: #ifdef HAVE_KERB5
        !           140:     "KRB5_CONFIG*",
        !           141:     "KRB5_KTNAME",
        !           142: #endif /* HAVE_KERB5 */
        !           143: #ifdef HAVE_SECURID
        !           144:     "VAR_ACE",
        !           145:     "USR_ACE",
        !           146:     "DLC_ACE",
        !           147: #endif /* HAVE_SECURID */
        !           148:     "TERMINFO",                        /* terminfo, exclusive path to terminfo files */
        !           149:     "TERMINFO_DIRS",           /* terminfo, path(s) to terminfo files */
        !           150:     "TERMPATH",                        /* termcap, path(s) to termcap files */
        !           151:     "TERMCAP",                 /* XXX - only if it starts with '/' */
        !           152:     "ENV",                     /* ksh, file to source before script runs */
        !           153:     "BASH_ENV",                        /* bash, file to source before script runs */
        !           154:     "PS4",                     /* bash, prefix for lines in xtrace mode */
        !           155:     "GLOBIGNORE",              /* bash, globbing patterns to ignore */
        !           156:     "SHELLOPTS",               /* bash, extra command line options */
        !           157:     "JAVA_TOOL_OPTIONS",       /* java, extra command line options */
        !           158:     "PERLIO_DEBUG ",           /* perl, debugging output file */
        !           159:     "PERLLIB",                 /* perl, search path for modules/includes */
        !           160:     "PERL5LIB",                        /* perl 5, search path for modules/includes */
        !           161:     "PERL5OPT",                        /* perl 5, extra command line options */
        !           162:     "PERL5DB",                 /* perl 5, command used to load debugger */
        !           163:     "FPATH",                   /* ksh, search path for functions */
        !           164:     "NULLCMD",                 /* zsh, command for null file redirection */
        !           165:     "READNULLCMD",             /* zsh, command for null file redirection */
        !           166:     "ZDOTDIR",                 /* zsh, search path for dot files */
        !           167:     "TMPPREFIX",               /* zsh, prefix for temporary files */
        !           168:     "PYTHONHOME",              /* python, module search path */
        !           169:     "PYTHONPATH",              /* python, search path */
        !           170:     "PYTHONINSPECT",           /* python, allow inspection */
        !           171:     "PYTHONUSERBASE",          /* python, per user site-packages directory */
        !           172:     "RUBYLIB",                 /* ruby, library load path */
        !           173:     "RUBYOPT",                 /* ruby, extra command line options */
        !           174:     NULL
        !           175: };
        !           176: 
        !           177: /*
        !           178:  * Default table of variables to check for '%' and '/' characters.
        !           179:  */
        !           180: static const char *initial_checkenv_table[] = {
        !           181:     "COLORTERM",
        !           182:     "LANG",
        !           183:     "LANGUAGE",
        !           184:     "LC_*",
        !           185:     "LINGUAS",
        !           186:     "TERM",
        !           187:     NULL
        !           188: };
        !           189: 
        !           190: /*
        !           191:  * Default table of variables to preserve in the environment.
        !           192:  */
        !           193: static const char *initial_keepenv_table[] = {
        !           194:     "COLORS",
        !           195:     "DISPLAY",
        !           196:     "HOSTNAME",
        !           197:     "KRB5CCNAME",
        !           198:     "LS_COLORS",
        !           199:     "PATH",
        !           200:     "PS1",
        !           201:     "PS2",
        !           202:     "TZ",
        !           203:     "XAUTHORITY",
        !           204:     "XAUTHORIZATION",
        !           205: #ifdef _AIX
        !           206:     "ODMDIR",
        !           207: #endif
        !           208:     NULL
        !           209: };
        !           210: 
        !           211: /*
        !           212:  * Initialize env based on envp.
        !           213:  */
        !           214: void
        !           215: env_init(char * const envp[])
        !           216: {
        !           217:     char * const *ep;
        !           218:     size_t len;
        !           219: 
        !           220:     for (ep = envp; *ep != NULL; ep++)
        !           221:        continue;
        !           222:     len = (size_t)(ep - envp);
        !           223: 
        !           224:     env.env_len = len;
        !           225:     env.env_size = len + 1 + 128;
        !           226:     env.envp = emalloc2(env.env_size, sizeof(char *));
        !           227: #ifdef ENV_DEBUG
        !           228:     memset(env.envp, 0, env.env_size * sizeof(char *));
        !           229: #endif
        !           230:     memcpy(env.envp, envp, len * sizeof(char *));
        !           231:     env.envp[len] = '\0';
        !           232: }
        !           233: 
        !           234: char **
        !           235: env_get(void)
        !           236: {
        !           237:     return env.envp;
        !           238: }
        !           239: 
        !           240: /*
        !           241:  * Similar to setenv(3) but operates on sudo's private copy of the environment
        !           242:  * (not environ) and it always overwrites.  The dupcheck param determines
        !           243:  * whether we need to verify that the variable is not already set.
        !           244:  */
        !           245: static void
        !           246: sudo_setenv(const char *var, const char *val, int dupcheck)
        !           247: {
        !           248:     char *estring;
        !           249:     size_t esize;
        !           250: 
        !           251:     esize = strlen(var) + 1 + strlen(val) + 1;
        !           252:     estring = emalloc(esize);
        !           253: 
        !           254:     /* Build environment string and insert it. */
        !           255:     if (strlcpy(estring, var, esize) >= esize ||
        !           256:        strlcat(estring, "=", esize) >= esize ||
        !           257:        strlcat(estring, val, esize) >= esize) {
        !           258: 
        !           259:        errorx(1, _("internal error, sudo_setenv() overflow"));
        !           260:     }
        !           261:     sudo_putenv(estring, dupcheck, TRUE);
        !           262: }
        !           263: 
        !           264: /*
        !           265:  * Similar to putenv(3) but operates on sudo's private copy of the
        !           266:  * environment (not environ) and it always overwrites.  The dupcheck param
        !           267:  * determines whether we need to verify that the variable is not already set.
        !           268:  * Will only overwrite an existing variable if overwrite is set.
        !           269:  */
        !           270: static void
        !           271: sudo_putenv(char *str, int dupcheck, int overwrite)
        !           272: {
        !           273:     char **ep;
        !           274:     size_t len;
        !           275:     int found = FALSE;
        !           276: 
        !           277:     /* Make sure there is room for the new entry plus a NULL. */
        !           278:     if (env.env_len + 2 > env.env_size) {
        !           279:        env.env_size += 128;
        !           280:        env.envp = erealloc3(env.envp, env.env_size, sizeof(char *));
        !           281: #ifdef ENV_DEBUG
        !           282:        memset(env.envp + env.env_len, 0,
        !           283:            (env.env_size - env.env_len) * sizeof(char *));
        !           284: #endif
        !           285:     }
        !           286: 
        !           287: #ifdef ENV_DEBUG
        !           288:     if (env.envp[env.env_len] != NULL)
        !           289:        errorx(1, _("sudo_putenv: corrupted envp, length mismatch"));
        !           290: #endif
        !           291: 
        !           292:     if (dupcheck) {
        !           293:        len = (strchr(str, '=') - str) + 1;
        !           294:        for (ep = env.envp; !found && *ep != NULL; ep++) {
        !           295:            if (strncmp(str, *ep, len) == 0) {
        !           296:                if (overwrite)
        !           297:                    *ep = str;
        !           298:                found = TRUE;
        !           299:            }
        !           300:        }
        !           301:        /* Prune out duplicate variables. */
        !           302:        if (found && overwrite) {
        !           303:            while (*ep != NULL) {
        !           304:                if (strncmp(str, *ep, len) == 0) {
        !           305:                    char **cur = ep;
        !           306:                    while ((*cur = *(cur + 1)) != NULL)
        !           307:                        cur++;
        !           308:                } else {
        !           309:                    ep++;
        !           310:                }
        !           311:            }
        !           312:            env.env_len = ep - env.envp;
        !           313:        }
        !           314:     }
        !           315: 
        !           316:     if (!found) {
        !           317:        ep = env.envp + env.env_len;
        !           318:        env.env_len++;
        !           319:        *ep++ = str;
        !           320:        *ep = NULL;
        !           321:     }
        !           322: }
        !           323: 
        !           324: /*
        !           325:  * Check the env_delete blacklist.
        !           326:  * Returns TRUE if the variable was found, else false.
        !           327:  */
        !           328: static int
        !           329: matches_env_delete(const char *var)
        !           330: {
        !           331:     struct list_member *cur;
        !           332:     size_t len;
        !           333:     int iswild, match = FALSE;
        !           334: 
        !           335:     /* Skip anything listed in env_delete. */
        !           336:     for (cur = def_env_delete; cur; cur = cur->next) {
        !           337:        len = strlen(cur->value);
        !           338:        /* Deal with '*' wildcard */
        !           339:        if (cur->value[len - 1] == '*') {
        !           340:            len--;
        !           341:            iswild = TRUE;
        !           342:        } else
        !           343:            iswild = FALSE;
        !           344:        if (strncmp(cur->value, var, len) == 0 &&
        !           345:            (iswild || var[len] == '=')) {
        !           346:            match = TRUE;
        !           347:            break;
        !           348:        }
        !           349:     }
        !           350:     return match;
        !           351: }
        !           352: 
        !           353: /*
        !           354:  * Apply the env_check list.
        !           355:  * Returns TRUE if the variable is allowed, FALSE if denied
        !           356:  * or -1 if no match.
        !           357:  */
        !           358: static int
        !           359: matches_env_check(const char *var)
        !           360: {
        !           361:     struct list_member *cur;
        !           362:     size_t len;
        !           363:     int iswild, keepit = -1;
        !           364: 
        !           365:     for (cur = def_env_check; cur; cur = cur->next) {
        !           366:        len = strlen(cur->value);
        !           367:        /* Deal with '*' wildcard */
        !           368:        if (cur->value[len - 1] == '*') {
        !           369:            len--;
        !           370:            iswild = TRUE;
        !           371:        } else
        !           372:            iswild = FALSE;
        !           373:        if (strncmp(cur->value, var, len) == 0 &&
        !           374:            (iswild || var[len] == '=')) {
        !           375:            keepit = !strpbrk(var, "/%");
        !           376:            break;
        !           377:        }
        !           378:     }
        !           379:     return keepit;
        !           380: }
        !           381: 
        !           382: /*
        !           383:  * Check the env_keep list.
        !           384:  * Returns TRUE if the variable is allowed else FALSE.
        !           385:  */
        !           386: static int
        !           387: matches_env_keep(const char *var)
        !           388: {
        !           389:     struct list_member *cur;
        !           390:     size_t len;
        !           391:     int iswild, keepit = FALSE;
        !           392: 
        !           393:     /* Preserve SHELL variable for "sudo -s". */
        !           394:     if (ISSET(sudo_mode, MODE_SHELL) && strncmp(var, "SHELL=", 6) == 0)
        !           395:        return TRUE;
        !           396: 
        !           397:     for (cur = def_env_keep; cur; cur = cur->next) {
        !           398:        len = strlen(cur->value);
        !           399:        /* Deal with '*' wildcard */
        !           400:        if (cur->value[len - 1] == '*') {
        !           401:            len--;
        !           402:            iswild = TRUE;
        !           403:        } else
        !           404:            iswild = FALSE;
        !           405:        if (strncmp(cur->value, var, len) == 0 &&
        !           406:            (iswild || var[len] == '=')) {
        !           407:            keepit = TRUE;
        !           408:            break;
        !           409:        }
        !           410:     }
        !           411:     return keepit;
        !           412: }
        !           413: 
        !           414: /*
        !           415:  * Build a new environment and ether clear potentially dangerous
        !           416:  * variables from the old one or start with a clean slate.
        !           417:  * Also adds sudo-specific variables (SUDO_*).
        !           418:  */
        !           419: void
        !           420: rebuild_env(void)
        !           421: {
        !           422:     char **old_envp, **ep, *cp, *ps1;
        !           423:     char idbuf[MAX_UID_T_LEN];
        !           424:     unsigned int didvar;
        !           425:     int reset_home = FALSE;
        !           426: 
        !           427:     /*
        !           428:      * Either clean out the environment or reset to a safe default.
        !           429:      */
        !           430:     ps1 = NULL;
        !           431:     didvar = 0;
        !           432:     env.env_len = 0;
        !           433:     env.env_size = 128;
        !           434:     old_envp = env.envp;
        !           435:     env.envp = emalloc2(env.env_size, sizeof(char *));
        !           436: #ifdef ENV_DEBUG
        !           437:     memset(env.envp, 0, env.env_size * sizeof(char *));
        !           438: #endif
        !           439: 
        !           440:     /* Reset HOME based on target user if configured to. */
        !           441:     if (ISSET(sudo_mode, MODE_RUN)) {
        !           442:        if (def_always_set_home ||
        !           443:            ISSET(sudo_mode, MODE_RESET_HOME | MODE_LOGIN_SHELL) || 
        !           444:            (ISSET(sudo_mode, MODE_SHELL) && def_set_home))
        !           445:            reset_home = TRUE;
        !           446:     }
        !           447: 
        !           448:     if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
        !           449:        /* Pull in vars we want to keep from the old environment. */
        !           450:        for (ep = old_envp; *ep; ep++) {
        !           451:            int keepit;
        !           452: 
        !           453:            /* Skip variables with values beginning with () (bash functions) */
        !           454:            if ((cp = strchr(*ep, '=')) != NULL) {
        !           455:                if (strncmp(cp, "=() ", 3) == 0)
        !           456:                    continue;
        !           457:            }
        !           458: 
        !           459:            /*
        !           460:             * First check certain variables for '%' and '/' characters.
        !           461:             * If no match there, check the keep list.
        !           462:             * If nothing matched, we remove it from the environment.
        !           463:             */
        !           464:            keepit = matches_env_check(*ep);
        !           465:            if (keepit == -1)
        !           466:                keepit = matches_env_keep(*ep);
        !           467: 
        !           468:            /* For SUDO_PS1 -> PS1 conversion. */
        !           469:            if (strncmp(*ep, "SUDO_PS1=", 8) == 0)
        !           470:                ps1 = *ep + 5;
        !           471: 
        !           472:            if (keepit) {
        !           473:                /* Preserve variable. */
        !           474:                switch (**ep) {
        !           475:                    case 'H':
        !           476:                        if (strncmp(*ep, "HOME=", 5) == 0)
        !           477:                            SET(didvar, DID_HOME);
        !           478:                        break;
        !           479:                    case 'L':
        !           480:                        if (strncmp(*ep, "LOGNAME=", 8) == 0)
        !           481:                            SET(didvar, DID_LOGNAME);
        !           482:                        break;
        !           483:                    case 'M':
        !           484:                        if (strncmp(*ep, "MAIL=", 5) == 0)
        !           485:                            SET(didvar, DID_MAIL);
        !           486:                        break;
        !           487:                    case 'P':
        !           488:                        if (strncmp(*ep, "PATH=", 5) == 0)
        !           489:                            SET(didvar, DID_PATH);
        !           490:                        break;
        !           491:                    case 'S':
        !           492:                        if (strncmp(*ep, "SHELL=", 6) == 0)
        !           493:                            SET(didvar, DID_SHELL);
        !           494:                        break;
        !           495:                    case 'T':
        !           496:                        if (strncmp(*ep, "TERM=", 5) == 0)
        !           497:                            SET(didvar, DID_TERM);
        !           498:                        break;
        !           499:                    case 'U':
        !           500:                        if (strncmp(*ep, "USER=", 5) == 0)
        !           501:                            SET(didvar, DID_USER);
        !           502:                        if (strncmp(*ep, "USERNAME=", 5) == 0)
        !           503:                            SET(didvar, DID_USERNAME);
        !           504:                        break;
        !           505:                }
        !           506:                sudo_putenv(*ep, FALSE, FALSE);
        !           507:            }
        !           508:        }
        !           509:        didvar |= didvar << 8;          /* convert DID_* to KEPT_* */
        !           510: 
        !           511:        /*
        !           512:         * Add in defaults.  In -i mode these come from the runas user,
        !           513:         * otherwise they may be from the user's environment (depends
        !           514:         * on sudoers options).
        !           515:         */
        !           516:        if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
        !           517:            sudo_setenv("SHELL", runas_pw->pw_shell, ISSET(didvar, DID_SHELL));
        !           518:            sudo_setenv("LOGNAME", runas_pw->pw_name,
        !           519:                ISSET(didvar, DID_LOGNAME));
        !           520:            sudo_setenv("USER", runas_pw->pw_name, ISSET(didvar, DID_USER));
        !           521:            sudo_setenv("USERNAME", runas_pw->pw_name,
        !           522:                ISSET(didvar, DID_USERNAME));
        !           523:        } else {
        !           524:            if (!ISSET(didvar, DID_SHELL))
        !           525:                sudo_setenv("SHELL", sudo_user.pw->pw_shell, FALSE);
        !           526:            if (!ISSET(didvar, DID_LOGNAME))
        !           527:                sudo_setenv("LOGNAME", user_name, FALSE);
        !           528:            if (!ISSET(didvar, DID_USER))
        !           529:                sudo_setenv("USER", user_name, FALSE);
        !           530:            if (!ISSET(didvar, DID_USERNAME))
        !           531:                sudo_setenv("USERNAME", user_name, FALSE);
        !           532:        }
        !           533: 
        !           534:        /* If we didn't keep HOME, reset it based on target user. */
        !           535:        if (!ISSET(didvar, KEPT_HOME))
        !           536:            reset_home = TRUE;
        !           537: 
        !           538:        /*
        !           539:         * Set MAIL to target user in -i mode or if MAIL is not preserved
        !           540:         * from user's environment.
        !           541:         */
        !           542:        if (ISSET(sudo_mode, MODE_LOGIN_SHELL) || !ISSET(didvar, KEPT_MAIL)) {
        !           543:            cp = _PATH_MAILDIR;
        !           544:            if (cp[sizeof(_PATH_MAILDIR) - 2] == '/')
        !           545:                easprintf(&cp, "MAIL=%s%s", _PATH_MAILDIR, runas_pw->pw_name);
        !           546:            else
        !           547:                easprintf(&cp, "MAIL=%s/%s", _PATH_MAILDIR, runas_pw->pw_name);
        !           548:            sudo_putenv(cp, ISSET(didvar, DID_MAIL), TRUE);
        !           549:        }
        !           550:     } else {
        !           551:        /*
        !           552:         * Copy environ entries as long as they don't match env_delete or
        !           553:         * env_check.
        !           554:         */
        !           555:        for (ep = old_envp; *ep; ep++) {
        !           556:            int okvar;
        !           557: 
        !           558:            /* Skip variables with values beginning with () (bash functions) */
        !           559:            if ((cp = strchr(*ep, '=')) != NULL) {
        !           560:                if (strncmp(cp, "=() ", 3) == 0)
        !           561:                    continue;
        !           562:            }
        !           563: 
        !           564:            /*
        !           565:             * First check variables against the blacklist in env_delete.
        !           566:             * If no match there check for '%' and '/' characters.
        !           567:             */
        !           568:            okvar = matches_env_delete(*ep) != TRUE;
        !           569:            if (okvar)
        !           570:                okvar = matches_env_check(*ep) != FALSE;
        !           571: 
        !           572:            if (okvar) {
        !           573:                if (strncmp(*ep, "SUDO_PS1=", 9) == 0)
        !           574:                    ps1 = *ep + 5;
        !           575:                else if (strncmp(*ep, "PATH=", 5) == 0)
        !           576:                    SET(didvar, DID_PATH);
        !           577:                else if (strncmp(*ep, "TERM=", 5) == 0)
        !           578:                    SET(didvar, DID_TERM);
        !           579:                sudo_putenv(*ep, FALSE, FALSE);
        !           580:            }
        !           581:        }
        !           582:     }
        !           583:     /* Replace the PATH envariable with a secure one? */
        !           584:     if (def_secure_path && !user_is_exempt()) {
        !           585:        sudo_setenv("PATH", def_secure_path, TRUE);
        !           586:        SET(didvar, DID_PATH);
        !           587:     }
        !           588: 
        !           589:     /*
        !           590:      * Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is not
        !           591:      * disabled.  We skip this if we are running a login shell (because
        !           592:      * they have already been set them) or sudoedit (because we want the
        !           593:      * editor to find the user's startup files).
        !           594:      */
        !           595:     if (def_set_logname && !ISSET(sudo_mode, MODE_LOGIN_SHELL|MODE_EDIT)) {
        !           596:        if (!ISSET(didvar, KEPT_LOGNAME))
        !           597:            sudo_setenv("LOGNAME", runas_pw->pw_name, TRUE);
        !           598:        if (!ISSET(didvar, KEPT_USER))
        !           599:            sudo_setenv("USER", runas_pw->pw_name, TRUE);
        !           600:        if (!ISSET(didvar, KEPT_USERNAME))
        !           601:            sudo_setenv("USERNAME", runas_pw->pw_name, TRUE);
        !           602:     }
        !           603: 
        !           604:     /* Set $HOME to target user if not preserving user's value. */
        !           605:     if (reset_home)
        !           606:        sudo_setenv("HOME", runas_pw->pw_dir, TRUE);
        !           607: 
        !           608:     /* Provide default values for $TERM and $PATH if they are not set. */
        !           609:     if (!ISSET(didvar, DID_TERM))
        !           610:        sudo_putenv("TERM=unknown", FALSE, FALSE);
        !           611:     if (!ISSET(didvar, DID_PATH))
        !           612:        sudo_setenv("PATH", _PATH_STDPATH, FALSE);
        !           613: 
        !           614:     /* Set PS1 if SUDO_PS1 is set. */
        !           615:     if (ps1 != NULL)
        !           616:        sudo_putenv(ps1, TRUE, TRUE);
        !           617: 
        !           618:     /* Add the SUDO_COMMAND envariable (cmnd + args). */
        !           619:     if (user_args) {
        !           620:        easprintf(&cp, "%s %s", user_cmnd, user_args);
        !           621:        sudo_setenv("SUDO_COMMAND", cp, TRUE);
        !           622:        efree(cp);
        !           623:     } else {
        !           624:        sudo_setenv("SUDO_COMMAND", user_cmnd, TRUE);
        !           625:     }
        !           626: 
        !           627:     /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */
        !           628:     sudo_setenv("SUDO_USER", user_name, TRUE);
        !           629:     snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_uid);
        !           630:     sudo_setenv("SUDO_UID", idbuf, TRUE);
        !           631:     snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_gid);
        !           632:     sudo_setenv("SUDO_GID", idbuf, TRUE);
        !           633: 
        !           634:     /* Free old environment. */
        !           635:     efree(old_envp);
        !           636: }
        !           637: 
        !           638: void
        !           639: insert_env_vars(char * const envp[])
        !           640: {
        !           641:     char * const *ep;
        !           642: 
        !           643:     if (envp == NULL)
        !           644:        return;
        !           645: 
        !           646:     /* Add user-specified environment variables. */
        !           647:     for (ep = envp; *ep != NULL; ep++)
        !           648:        sudo_putenv(*ep, TRUE, TRUE);
        !           649: }
        !           650: 
        !           651: /*
        !           652:  * Validate the list of environment variables passed in on the command
        !           653:  * line against env_delete, env_check, and env_keep.
        !           654:  * Calls log_error() if any specified variables are not allowed.
        !           655:  */
        !           656: void
        !           657: validate_env_vars(char * const env_vars[])
        !           658: {
        !           659:     char * const *ep;
        !           660:     char *eq, *bad = NULL;
        !           661:     size_t len, blen = 0, bsize = 0;
        !           662:     int okvar;
        !           663: 
        !           664:     if (env_vars == NULL)
        !           665:        return;
        !           666: 
        !           667:     /* Add user-specified environment variables. */
        !           668:     for (ep = env_vars; *ep != NULL; ep++) {
        !           669:        if (def_secure_path && !user_is_exempt() &&
        !           670:            strncmp(*ep, "PATH=", 5) == 0) {
        !           671:            okvar = FALSE;
        !           672:        } else if (def_env_reset) {
        !           673:            okvar = matches_env_check(*ep);
        !           674:            if (okvar == -1)
        !           675:                okvar = matches_env_keep(*ep);
        !           676:        } else {
        !           677:            okvar = matches_env_delete(*ep) == FALSE;
        !           678:            if (okvar == FALSE)
        !           679:                okvar = matches_env_check(*ep) != FALSE;
        !           680:        }
        !           681:        if (okvar == FALSE) {
        !           682:            /* Not allowed, add to error string, allocating as needed. */
        !           683:            if ((eq = strchr(*ep, '=')) != NULL)
        !           684:                *eq = '\0';
        !           685:            len = strlen(*ep) + 2;
        !           686:            if (blen + len >= bsize) {
        !           687:                do {
        !           688:                    bsize += 1024;
        !           689:                } while (blen + len >= bsize);
        !           690:                bad = erealloc(bad, bsize);
        !           691:                bad[blen] = '\0';
        !           692:            }
        !           693:            strlcat(bad, *ep, bsize);
        !           694:            strlcat(bad, ", ", bsize);
        !           695:            blen += len;
        !           696:            if (eq != NULL)
        !           697:                *eq = '=';
        !           698:        }
        !           699:     }
        !           700:     if (bad != NULL) {
        !           701:        bad[blen - 2] = '\0';           /* remove trailing ", " */
        !           702:        log_error(NO_MAIL,
        !           703:            _("sorry, you are not allowed to set the following environment variables: %s"), bad);
        !           704:        /* NOTREACHED */
        !           705:        efree(bad);
        !           706:     }
        !           707: }
        !           708: 
        !           709: /*
        !           710:  * Read in /etc/environment ala AIX and Linux.
        !           711:  * Lines may be in either of three formats:
        !           712:  *  NAME=VALUE
        !           713:  *  NAME="VALUE"
        !           714:  *  NAME='VALUE'
        !           715:  * with an optional "export" prefix so the shell can source the file.
        !           716:  * Invalid lines, blank lines, or lines consisting solely of a comment
        !           717:  * character are skipped.
        !           718:  */
        !           719: void
        !           720: read_env_file(const char *path, int overwrite)
        !           721: {
        !           722:     FILE *fp;
        !           723:     char *cp, *var, *val;
        !           724:     size_t var_len, val_len;
        !           725: 
        !           726:     if ((fp = fopen(path, "r")) == NULL)
        !           727:        return;
        !           728: 
        !           729:     while ((var = sudo_parseln(fp)) != NULL) {
        !           730:        /* Skip blank or comment lines */
        !           731:        if (*var == '\0')
        !           732:            continue;
        !           733: 
        !           734:        /* Skip optional "export " */
        !           735:        if (strncmp(var, "export", 6) == 0 && isspace((unsigned char) var[6])) {
        !           736:            var += 7;
        !           737:            while (isspace((unsigned char) *var)) {
        !           738:                var++;
        !           739:            }
        !           740:        }
        !           741: 
        !           742:        /* Must be of the form name=["']value['"] */
        !           743:        for (val = var; *val != '\0' && *val != '='; val++)
        !           744:            ;
        !           745:        if (var == val || *val != '=')
        !           746:            continue;
        !           747:        var_len = (size_t)(val - var);
        !           748:        val_len = strlen(++val);
        !           749: 
        !           750:        /* Strip leading and trailing single/double quotes */
        !           751:        if ((val[0] == '\'' || val[0] == '\"') && val[0] == val[val_len - 1]) {
        !           752:            val[val_len - 1] = '\0';
        !           753:            val++;
        !           754:            val_len -= 2;
        !           755:        }
        !           756: 
        !           757:        cp = emalloc(var_len + 1 + val_len + 1);
        !           758:        memcpy(cp, var, var_len + 1); /* includes '=' */
        !           759:        memcpy(cp + var_len + 1, val, val_len + 1); /* includes NUL */
        !           760: 
        !           761:        sudo_putenv(cp, TRUE, overwrite);
        !           762:     }
        !           763:     fclose(fp);
        !           764: }
        !           765: 
        !           766: void
        !           767: init_envtables(void)
        !           768: {
        !           769:     struct list_member *cur;
        !           770:     const char **p;
        !           771: 
        !           772:     /* Fill in the "env_delete" list. */
        !           773:     for (p = initial_badenv_table; *p; p++) {
        !           774:        cur = emalloc(sizeof(struct list_member));
        !           775:        cur->value = estrdup(*p);
        !           776:        cur->next = def_env_delete;
        !           777:        def_env_delete = cur;
        !           778:     }
        !           779: 
        !           780:     /* Fill in the "env_check" list. */
        !           781:     for (p = initial_checkenv_table; *p; p++) {
        !           782:        cur = emalloc(sizeof(struct list_member));
        !           783:        cur->value = estrdup(*p);
        !           784:        cur->next = def_env_check;
        !           785:        def_env_check = cur;
        !           786:     }
        !           787: 
        !           788:     /* Fill in the "env_keep" list. */
        !           789:     for (p = initial_keepenv_table; *p; p++) {
        !           790:        cur = emalloc(sizeof(struct list_member));
        !           791:        cur->value = estrdup(*p);
        !           792:        cur->next = def_env_keep;
        !           793:        def_env_keep = cur;
        !           794:     }
        !           795: }

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