[BACK]Return to env.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / sudo

Annotation of src/usr.bin/sudo/env.c, Revision 1.21

1.1       millert     1: /*
1.20      millert     2:  * Copyright (c) 2000-2005, 2007-2009
1.18      millert     3:  *     Todd C. Miller <Todd.Miller@courtesan.com>
1.1       millert     4:  *
1.9       millert     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.
1.1       millert     8:  *
1.9       millert     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.
1.7       millert    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.
1.1       millert    20:  */
                     21:
1.14      millert    22: #include <config.h>
1.1       millert    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: #else
                     39: # ifdef HAVE_STRINGS_H
                     40: #  include <strings.h>
                     41: # endif
                     42: #endif /* HAVE_STRING_H */
                     43: #ifdef HAVE_UNISTD_H
                     44: # include <unistd.h>
                     45: #endif /* HAVE_UNISTD_H */
1.21    ! millert    46: #include <ctype.h>
1.19      millert    47: #include <errno.h>
1.1       millert    48: #include <pwd.h>
                     49:
                     50: #include "sudo.h"
                     51:
                     52: #ifndef lint
1.21    ! millert    53: __unused static const char rcsid[] = "$Sudo: env.c,v 1.106 2009/06/23 18:24:42 millert Exp $";
1.1       millert    54: #endif /* lint */
                     55:
                     56: /*
1.5       millert    57:  * Flags used in rebuild_env()
1.1       millert    58:  */
                     59: #undef DID_TERM
1.14      millert    60: #define DID_TERM       0x0001
1.1       millert    61: #undef DID_PATH
1.14      millert    62: #define DID_PATH       0x0002
1.1       millert    63: #undef DID_HOME
1.14      millert    64: #define DID_HOME       0x0004
1.1       millert    65: #undef DID_SHELL
1.14      millert    66: #define DID_SHELL      0x0008
1.1       millert    67: #undef DID_LOGNAME
1.14      millert    68: #define DID_LOGNAME    0x0010
1.9       millert    69: #undef DID_USER
1.14      millert    70: #define DID_USER       0x0020
                     71: #undef DID_USERNAME
                     72: #define DID_USERNAME           0x0040
                     73: #undef DID_MAX
                     74: #define DID_MAX        0x00ff
                     75:
                     76: #undef KEPT_TERM
                     77: #define KEPT_TERM      0x0100
                     78: #undef KEPT_PATH
                     79: #define KEPT_PATH      0x0200
                     80: #undef KEPT_HOME
                     81: #define KEPT_HOME      0x0400
                     82: #undef KEPT_SHELL
                     83: #define KEPT_SHELL     0x0800
                     84: #undef KEPT_LOGNAME
                     85: #define KEPT_LOGNAME   0x1000
                     86: #undef KEPT_USER
                     87: #define KEPT_USER      0x2000
                     88: #undef KEPT_USERNAME
                     89: #define KEPT_USERNAME  0x4000
                     90: #undef KEPT_MAX
                     91: #define KEPT_MAX       0xff00
1.1       millert    92:
1.9       millert    93: #undef VNULL
1.18      millert    94: #define        VNULL   (void *)NULL
1.9       millert    95:
1.14      millert    96: struct environment {
                     97:     char **envp;               /* pointer to the new environment */
                     98:     size_t env_size;           /* size of new_environ in char **'s */
                     99:     size_t env_len;            /* number of slots used, not counting NULL */
                    100: };
                    101:
1.1       millert   102: /*
                    103:  * Prototypes
                    104:  */
1.18      millert   105: void rebuild_env               __P((int, int));
1.19      millert   106: static void sudo_setenv                __P((const char *, const char *, int));
                    107: static void sudo_putenv                __P((char *, int, int));
1.18      millert   108:
                    109: extern char **environ;         /* global environment */
1.1       millert   110:
                    111: /*
1.14      millert   112:  * Copy of the sudo-managed environment.
                    113:  */
                    114: static struct environment env;
                    115:
                    116: /*
1.1       millert   117:  * Default table of "bad" variables to remove from the environment.
                    118:  * XXX - how to omit TERMCAP if it starts with '/'?
                    119:  */
1.5       millert   120: static const char *initial_badenv_table[] = {
1.1       millert   121:     "IFS",
1.11      millert   122:     "CDPATH",
1.1       millert   123:     "LOCALDOMAIN",
                    124:     "RES_OPTIONS",
                    125:     "HOSTALIASES",
                    126:     "NLSPATH",
                    127:     "PATH_LOCALE",
                    128:     "LD_*",
                    129:     "_RLD*",
                    130: #ifdef __hpux
                    131:     "SHLIB_PATH",
                    132: #endif /* __hpux */
                    133: #ifdef _AIX
1.14      millert   134:     "LDR_*",
1.1       millert   135:     "LIBPATH",
1.18      millert   136:     "AUTHSTATE",
1.14      millert   137: #endif
1.5       millert   138: #ifdef __APPLE__
                    139:     "DYLD_*",
                    140: #endif
1.1       millert   141: #ifdef HAVE_KERB4
                    142:     "KRB_CONF*",
1.6       millert   143:     "KRBCONFDIR",
1.1       millert   144:     "KRBTKFILE",
                    145: #endif /* HAVE_KERB4 */
                    146: #ifdef HAVE_KERB5
                    147:     "KRB5_CONFIG*",
1.14      millert   148:     "KRB5_KTNAME",
1.1       millert   149: #endif /* HAVE_KERB5 */
                    150: #ifdef HAVE_SECURID
                    151:     "VAR_ACE",
                    152:     "USR_ACE",
                    153:     "DLC_ACE",
                    154: #endif /* HAVE_SECURID */
1.14      millert   155:     "TERMINFO",                        /* terminfo, exclusive path to terminfo files */
                    156:     "TERMINFO_DIRS",           /* terminfo, path(s) to terminfo files */
                    157:     "TERMPATH",                        /* termcap, path(s) to termcap files */
1.1       millert   158:     "TERMCAP",                 /* XXX - only if it starts with '/' */
1.14      millert   159:     "ENV",                     /* ksh, file to source before script runs */
                    160:     "BASH_ENV",                        /* bash, file to source before script runs */
                    161:     "PS4",                     /* bash, prefix for lines in xtrace mode */
                    162:     "GLOBIGNORE",              /* bash, globbing patterns to ignore */
                    163:     "SHELLOPTS",               /* bash, extra command line options */
                    164:     "JAVA_TOOL_OPTIONS",       /* java, extra command line options */
                    165:     "PERLIO_DEBUG ",           /* perl, debugging output file */
                    166:     "PERLLIB",                 /* perl, search path for modules/includes */
                    167:     "PERL5LIB",                        /* perl 5, search path for modules/includes */
                    168:     "PERL5OPT",                        /* perl 5, extra command line options */
                    169:     "PERL5DB",                 /* perl 5, command used to load debugger */
                    170:     "FPATH",                   /* ksh, search path for functions */
                    171:     "NULLCMD",                 /* zsh, command for null file redirection */
                    172:     "READNULLCMD",             /* zsh, command for null file redirection */
                    173:     "ZDOTDIR",                 /* zsh, search path for dot files */
                    174:     "TMPPREFIX",               /* zsh, prefix for temporary files */
                    175:     "PYTHONHOME",              /* python, module search path */
                    176:     "PYTHONPATH",              /* python, search path */
1.16      millert   177:     "PYTHONINSPECT",           /* python, allow inspection */
1.14      millert   178:     "RUBYLIB",                 /* ruby, library load path */
                    179:     "RUBYOPT",                 /* ruby, extra command line options */
1.1       millert   180:     NULL
                    181: };
                    182:
                    183: /*
                    184:  * Default table of variables to check for '%' and '/' characters.
                    185:  */
1.5       millert   186: static const char *initial_checkenv_table[] = {
1.14      millert   187:     "COLORTERM",
1.1       millert   188:     "LANG",
                    189:     "LANGUAGE",
1.14      millert   190:     "LC_*",
                    191:     "LINGUAS",
                    192:     "TERM",
1.1       millert   193:     NULL
                    194: };
                    195:
                    196: /*
1.14      millert   197:  * Default table of variables to preserve in the environment.
1.1       millert   198:  */
1.14      millert   199: static const char *initial_keepenv_table[] = {
                    200:     "COLORS",
                    201:     "DISPLAY",
1.17      millert   202:     "HOME",
1.14      millert   203:     "HOSTNAME",
                    204:     "KRB5CCNAME",
                    205:     "LS_COLORS",
                    206:     "MAIL",
                    207:     "PATH",
                    208:     "PS1",
                    209:     "PS2",
                    210:     "TZ",
                    211:     "XAUTHORITY",
                    212:     "XAUTHORIZATION",
                    213:     NULL
                    214: };
1.1       millert   215:
                    216: /*
1.18      millert   217:  * Similar to setenv(3) but operates on sudo's private copy of the environment
1.19      millert   218:  * (not environ) and it always overwrites.  The dupcheck param determines
                    219:  * whether we need to verify that the variable is not already set.
1.1       millert   220:  */
1.18      millert   221: static void
1.19      millert   222: sudo_setenv(var, val, dupcheck)
1.18      millert   223:     const char *var;
                    224:     const char *val;
                    225:     int dupcheck;
1.1       millert   226: {
1.5       millert   227:     char *estring;
                    228:     size_t esize;
1.1       millert   229:
1.18      millert   230:     esize = strlen(var) + 1 + strlen(val) + 1;
                    231:     estring = emalloc(esize);
1.5       millert   232:
1.18      millert   233:     /* Build environment string and insert it. */
1.5       millert   234:     if (strlcpy(estring, var, esize) >= esize ||
1.18      millert   235:        strlcat(estring, "=", esize) >= esize ||
                    236:        strlcat(estring, val, esize) >= esize) {
1.6       millert   237:
1.18      millert   238:        errorx(1, "internal error, sudo_setenv() overflow");
1.5       millert   239:     }
1.19      millert   240:     sudo_putenv(estring, dupcheck, TRUE);
1.18      millert   241: }
1.1       millert   242:
1.18      millert   243: /*
1.19      millert   244:  * Version of setenv(3) that uses our own environ pointer.
                    245:  * Will sync with environ as needed.
1.18      millert   246:  */
1.19      millert   247: int
                    248: setenv(var, val, overwrite)
1.18      millert   249:     const char *var;
                    250:     const char *val;
1.19      millert   251:     int overwrite;
1.18      millert   252: {
1.20      millert   253:     char *estring, *ep;
                    254:     const char *cp;
1.18      millert   255:     size_t esize;
                    256:
1.20      millert   257:     if (!var || *var == '\0')
                    258:        return(EINVAL);
                    259:
                    260:     /*
                    261:      * POSIX says a var name with '=' is an error but BSD
                    262:      * just ignores the '=' and anything after it.
                    263:      */
                    264:     for (cp = var; *cp && *cp != '='; cp++)
                    265:        ;
                    266:     esize = (size_t)(cp - var) + 2;
                    267:     if (val) {
                    268:        esize += strlen(val);   /* glibc treats a NULL val as "" */
1.19      millert   269:     }
1.18      millert   270:
1.20      millert   271:     /* Allocate and fill in estring. */
                    272:     estring = ep = emalloc(esize);
                    273:     for (cp = var; *cp && *cp != '='; cp++)
                    274:        *ep++ = *cp;
                    275:     *ep++ = '=';
                    276:     if (val) {
                    277:        for (cp = val; *cp; cp++)
                    278:            *ep++ = *cp;
                    279:     }
                    280:     *ep = '\0';
1.18      millert   281:
1.19      millert   282:     /* Sync env.envp with environ as needed. */
                    283:     if (env.envp != environ) {
                    284:        char **ep;
                    285:        size_t len;
                    286:
                    287:        for (ep = environ; *ep != NULL; ep++)
                    288:            continue;
                    289:        len = ep - environ;
                    290:        if (len + 2 > env.env_size) {
                    291:            efree(env.envp);
                    292:            env.env_size = len + 2 + 128;
                    293:            env.envp = emalloc2(env.env_size, sizeof(char *));
                    294: #ifdef ENV_DEBUG
                    295:            memset(env.envp, 0, env.env_size * sizeof(char *));
                    296: #endif
                    297:        }
                    298:        memcpy(env.envp, environ, len * sizeof(char *));
                    299:        env.envp[len] = NULL;
                    300:        env.env_len = len;
                    301:        environ = env.envp;
                    302: #ifdef ENV_DEBUG
                    303:     } else {
                    304:        if (env.envp[env.env_len] != NULL)
                    305:            errorx(1, "setenv: corrupted envp, len mismatch");
                    306: #endif
1.9       millert   307:     }
1.19      millert   308:     sudo_putenv(estring, TRUE, overwrite);
                    309:     return(0);
1.18      millert   310: }
                    311:
                    312: /*
1.19      millert   313:  * Version of unsetenv(3) that uses our own environ pointer.
                    314:  * Will sync with environ as needed.
1.18      millert   315:  */
1.19      millert   316: #ifdef UNSETENV_VOID
1.18      millert   317: void
1.19      millert   318: #else
                    319: int
                    320: #endif
                    321: unsetenv(var)
1.18      millert   322:     const char *var;
                    323: {
1.19      millert   324:     char **ep;
                    325:     size_t len;
                    326:
                    327:     if (strchr(var, '=') != NULL) {
                    328:        errno = EINVAL;
                    329: #ifdef UNSETENV_VOID
                    330:        return;
                    331: #else
                    332:        return(-1);
                    333: #endif
                    334:     }
1.9       millert   335:
1.18      millert   336:     /* Make sure we are operating on the current environment. */
1.19      millert   337:     /* XXX - this could be optimized to include the search */
                    338:     if (env.envp != environ) {
                    339:        for (ep = environ; *ep != NULL; ep++)
                    340:            continue;
                    341:        len = ep - environ;
                    342:        if (len + 1 > env.env_size) {
                    343:            efree(env.envp);
                    344:            env.env_size = len + 1 + 128;
                    345:            env.envp = emalloc2(env.env_size, sizeof(char *));
                    346: #ifdef ENV_DEBUG
                    347:            memset(env.envp, 0, env.env_size * sizeof(char *));
                    348: #endif
                    349:        }
                    350:        memcpy(env.envp, environ, len * sizeof(char *));
                    351:        env.envp[len] = NULL;
                    352:        env.env_len = len;
                    353:        environ = env.envp;
                    354: #ifdef ENV_DEBUG
                    355:     } else {
                    356:        if (env.envp[env.env_len] != NULL)
                    357:            errorx(1, "unsetenv: corrupted envp, len mismatch");
                    358: #endif
                    359:     }
1.18      millert   360:
1.19      millert   361:     len = strlen(var);
                    362:     for (ep = env.envp; *ep; ep++) {
                    363:        if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') {
                    364:            /* Found it; shift remainder + NULL over by one and update len. */
                    365:            memmove(ep, ep + 1,
                    366:                (env.env_len - (ep - env.envp)) * sizeof(char *));
1.18      millert   367:            env.env_len--;
1.19      millert   368:            break;
1.18      millert   369:        }
                    370:     }
1.19      millert   371: #ifndef UNSETENV_VOID
                    372:     return(0);
                    373: #endif
1.1       millert   374: }
                    375:
                    376: /*
1.19      millert   377:  * Version of putenv(3) that uses our own environ pointer.
                    378:  * Will sync with environ as needed.
                    379:  */
                    380: int
                    381: #ifdef PUTENV_CONST
                    382: putenv(const char *string)
                    383: #else
                    384: putenv(string)
                    385:     char *string;
                    386: #endif
                    387: {
                    388:     if (strchr(string, '=') == NULL) {
                    389:        errno = EINVAL;
                    390:        return(-1);
                    391:     }
                    392:     /* Sync env.envp with environ as needed. */
                    393:     if (env.envp != environ) {
                    394:        char **ep;
                    395:        size_t len;
                    396:
                    397:        for (ep = environ; *ep != NULL; ep++)
                    398:            continue;
                    399:        len = ep - environ;
                    400:        if (len + 2 > env.env_size) {
                    401:            efree(env.envp);
                    402:            env.env_size = len + 2 + 128;
                    403:            env.envp = emalloc2(env.env_size, sizeof(char *));
                    404: #ifdef ENV_DEBUG
                    405:            memset(env.envp, 0, env.env_size * sizeof(char *));
                    406: #endif
                    407:        }
                    408:        memcpy(env.envp, environ, len * sizeof(char *));
                    409:        env.envp[len] = NULL;
                    410:        env.env_len = len;
                    411:        environ = env.envp;
                    412: #ifdef ENV_DEBUG
                    413:     } else {
                    414:        if (env.envp[env.env_len] != NULL)
                    415:            errorx(1, "putenv: corrupted envp, len mismatch");
                    416: #endif
                    417:     }
                    418:     sudo_putenv((char *)string, TRUE, TRUE);
                    419:     return(0);
                    420: }
                    421:
                    422: /*
                    423:  * Similar to putenv(3) but operates on sudo's private copy of the
                    424:  * environment (not environ) and it always overwrites.  The dupcheck param
                    425:  * determines whether we need to verify that the variable is not already set.
                    426:  * Will only overwrite an existing variable if overwrite is set.
1.1       millert   427:  */
                    428: static void
1.19      millert   429: sudo_putenv(str, dupcheck, overwrite)
1.1       millert   430:     char *str;
1.5       millert   431:     int dupcheck;
1.19      millert   432:     int overwrite;
1.1       millert   433: {
1.19      millert   434:     char **ep;
                    435:     size_t len;
1.1       millert   436:
1.8       millert   437:     /* Make sure there is room for the new entry plus a NULL. */
1.18      millert   438:     if (env.env_len + 2 > env.env_size) {
                    439:        env.env_size += 128;
                    440:        env.envp = erealloc3(env.envp, env.env_size, sizeof(char *));
1.19      millert   441: #ifdef ENV_DEBUG
                    442:        memset(env.envp + env.env_len, 0,
                    443:            (env.env_size - env.env_len) * sizeof(char *));
                    444: #endif
                    445:        environ = env.envp;
1.5       millert   446:     }
                    447:
1.19      millert   448: #ifdef ENV_DEBUG
                    449:     if (env.envp[env.env_len] != NULL)
                    450:        errorx(1, "sudo_putenv: corrupted envp, len mismatch");
                    451: #endif
                    452:
1.5       millert   453:     if (dupcheck) {
1.19      millert   454:            len = (strchr(str, '=') - str) + 1;
                    455:            for (ep = env.envp; *ep; ep++) {
                    456:                if (strncmp(str, *ep, len) == 0) {
                    457:                    if (overwrite)
                    458:                        *ep = str;
1.5       millert   459:                    return;
                    460:                }
                    461:            }
                    462:     } else
1.19      millert   463:        ep = env.envp + env.env_len;
1.5       millert   464:
1.18      millert   465:     env.env_len++;
1.19      millert   466:     *ep++ = str;
                    467:     *ep = NULL;
1.1       millert   468: }
                    469:
                    470: /*
1.14      millert   471:  * Check the env_delete blacklist.
                    472:  * Returns TRUE if the variable was found, else false.
                    473:  */
                    474: static int
                    475: matches_env_delete(var)
                    476:     const char *var;
                    477: {
                    478:     struct list_member *cur;
                    479:     size_t len;
                    480:     int iswild, match = FALSE;
                    481:
                    482:     /* Skip anything listed in env_delete. */
                    483:     for (cur = def_env_delete; cur; cur = cur->next) {
                    484:        len = strlen(cur->value);
                    485:        /* Deal with '*' wildcard */
                    486:        if (cur->value[len - 1] == '*') {
                    487:            len--;
                    488:            iswild = TRUE;
                    489:        } else
                    490:            iswild = FALSE;
                    491:        if (strncmp(cur->value, var, len) == 0 &&
                    492:            (iswild || var[len] == '=')) {
                    493:            match = TRUE;
                    494:            break;
                    495:        }
                    496:     }
                    497:     return(match);
                    498: }
                    499:
                    500: /*
                    501:  * Apply the env_check list.
                    502:  * Returns TRUE if the variable is allowed, FALSE if denied
                    503:  * or -1 if no match.
                    504:  */
                    505: static int
                    506: matches_env_check(var)
                    507:     const char *var;
                    508: {
                    509:     struct list_member *cur;
                    510:     size_t len;
                    511:     int iswild, keepit = -1;
                    512:
                    513:     for (cur = def_env_check; cur; cur = cur->next) {
                    514:        len = strlen(cur->value);
                    515:        /* Deal with '*' wildcard */
                    516:        if (cur->value[len - 1] == '*') {
                    517:            len--;
                    518:            iswild = TRUE;
                    519:        } else
                    520:            iswild = FALSE;
                    521:        if (strncmp(cur->value, var, len) == 0 &&
                    522:            (iswild || var[len] == '=')) {
                    523:            keepit = !strpbrk(var, "/%");
                    524:            break;
                    525:        }
                    526:     }
                    527:     return(keepit);
                    528: }
                    529:
                    530: /*
                    531:  * Check the env_keep list.
                    532:  * Returns TRUE if the variable is allowed else FALSE.
                    533:  */
                    534: static int
                    535: matches_env_keep(var)
                    536:     const char *var;
                    537: {
                    538:     struct list_member *cur;
                    539:     size_t len;
                    540:     int iswild, keepit = FALSE;
                    541:
                    542:     for (cur = def_env_keep; cur; cur = cur->next) {
                    543:        len = strlen(cur->value);
                    544:        /* Deal with '*' wildcard */
                    545:        if (cur->value[len - 1] == '*') {
                    546:            len--;
                    547:            iswild = TRUE;
                    548:        } else
                    549:            iswild = FALSE;
                    550:        if (strncmp(cur->value, var, len) == 0 &&
                    551:            (iswild || var[len] == '=')) {
                    552:            keepit = TRUE;
                    553:            break;
                    554:        }
                    555:     }
                    556:     return(keepit);
                    557: }
                    558:
                    559: /*
1.1       millert   560:  * Build a new environment and ether clear potentially dangerous
                    561:  * variables from the old one or start with a clean slate.
                    562:  * Also adds sudo-specific variables (SUDO_*).
                    563:  */
1.18      millert   564: void
                    565: rebuild_env(sudo_mode, noexec)
1.1       millert   566:     int sudo_mode;
1.9       millert   567:     int noexec;
1.1       millert   568: {
1.18      millert   569:     char **old_envp, **ep, *cp, *ps1;
                    570:     char idbuf[MAX_UID_T_LEN];
1.14      millert   571:     unsigned int didvar;
1.1       millert   572:
                    573:     /*
                    574:      * Either clean out the environment or reset to a safe default.
                    575:      */
                    576:     ps1 = NULL;
                    577:     didvar = 0;
1.18      millert   578:     env.env_len = 0;
                    579:     env.env_size = 128;
                    580:     old_envp = env.envp;
                    581:     env.envp = emalloc2(env.env_size, sizeof(char *));
1.19      millert   582: #ifdef ENV_DEBUG
                    583:     memset(env.envp, 0, env.env_size * sizeof(char *));
                    584: #endif
1.17      millert   585:     if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
1.1       millert   586:        /* Pull in vars we want to keep from the old environment. */
1.18      millert   587:        for (ep = environ; *ep; ep++) {
1.14      millert   588:            int keepit;
1.10      millert   589:
                    590:            /* Skip variables with values beginning with () (bash functions) */
                    591:            if ((cp = strchr(*ep, '=')) != NULL) {
                    592:                if (strncmp(cp, "=() ", 3) == 0)
                    593:                    continue;
                    594:            }
                    595:
1.14      millert   596:            /*
                    597:             * First check certain variables for '%' and '/' characters.
                    598:             * If no match there, check the keep list.
                    599:             * If nothing matched, we remove it from the environment.
                    600:             */
                    601:            keepit = matches_env_check(*ep);
                    602:            if (keepit == -1)
                    603:                keepit = matches_env_keep(*ep);
1.1       millert   604:
                    605:            /* For SUDO_PS1 -> PS1 conversion. */
                    606:            if (strncmp(*ep, "SUDO_PS1=", 8) == 0)
                    607:                ps1 = *ep + 5;
                    608:
                    609:            if (keepit) {
                    610:                /* Preserve variable. */
                    611:                switch (**ep) {
                    612:                    case 'H':
                    613:                        if (strncmp(*ep, "HOME=", 5) == 0)
1.9       millert   614:                            SET(didvar, DID_HOME);
1.5       millert   615:                        break;
1.14      millert   616:                    case 'L':
                    617:                        if (strncmp(*ep, "LOGNAME=", 8) == 0)
                    618:                            SET(didvar, DID_LOGNAME);
                    619:                        break;
                    620:                    case 'P':
                    621:                        if (strncmp(*ep, "PATH=", 5) == 0)
                    622:                            SET(didvar, DID_PATH);
                    623:                        break;
1.1       millert   624:                    case 'S':
                    625:                        if (strncmp(*ep, "SHELL=", 6) == 0)
1.9       millert   626:                            SET(didvar, DID_SHELL);
1.5       millert   627:                        break;
1.14      millert   628:                    case 'T':
                    629:                        if (strncmp(*ep, "TERM=", 5) == 0)
                    630:                            SET(didvar, DID_TERM);
1.5       millert   631:                        break;
1.1       millert   632:                    case 'U':
                    633:                        if (strncmp(*ep, "USER=", 5) == 0)
1.9       millert   634:                            SET(didvar, DID_USER);
1.14      millert   635:                        if (strncmp(*ep, "USERNAME=", 5) == 0)
                    636:                            SET(didvar, DID_USERNAME);
1.5       millert   637:                        break;
1.1       millert   638:                }
1.19      millert   639:                sudo_putenv(*ep, FALSE, FALSE);
1.1       millert   640:            }
                    641:        }
1.14      millert   642:        didvar |= didvar << 8;          /* convert DID_* to KEPT_* */
1.1       millert   643:
                    644:        /*
1.9       millert   645:         * Add in defaults.  In -i mode these come from the runas user,
                    646:         * otherwise they may be from the user's environment (depends
                    647:         * on sudoers options).
1.1       millert   648:         */
1.9       millert   649:        if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
1.19      millert   650:            sudo_setenv("HOME", runas_pw->pw_dir, ISSET(didvar, DID_HOME));
                    651:            sudo_setenv("SHELL", runas_pw->pw_shell, ISSET(didvar, DID_SHELL));
                    652:            sudo_setenv("LOGNAME", runas_pw->pw_name,
1.14      millert   653:                ISSET(didvar, DID_LOGNAME));
1.19      millert   654:            sudo_setenv("USER", runas_pw->pw_name, ISSET(didvar, DID_USER));
                    655:            sudo_setenv("USERNAME", runas_pw->pw_name,
1.14      millert   656:                ISSET(didvar, DID_USERNAME));
1.9       millert   657:        } else {
                    658:            if (!ISSET(didvar, DID_HOME))
1.19      millert   659:                sudo_setenv("HOME", user_dir, FALSE);
1.9       millert   660:            if (!ISSET(didvar, DID_SHELL))
1.19      millert   661:                sudo_setenv("SHELL", sudo_user.pw->pw_shell, FALSE);
1.9       millert   662:            if (!ISSET(didvar, DID_LOGNAME))
1.19      millert   663:                sudo_setenv("LOGNAME", user_name, FALSE);
1.9       millert   664:            if (!ISSET(didvar, DID_USER))
1.19      millert   665:                sudo_setenv("USER", user_name, FALSE);
1.14      millert   666:            if (!ISSET(didvar, DID_USERNAME))
1.19      millert   667:                sudo_setenv("USERNAME", user_name, FALSE);
1.9       millert   668:        }
1.1       millert   669:     } else {
                    670:        /*
1.18      millert   671:         * Copy environ entries as long as they don't match env_delete or
1.1       millert   672:         * env_check.
                    673:         */
1.18      millert   674:        for (ep = environ; *ep; ep++) {
1.14      millert   675:            int okvar;
1.10      millert   676:
                    677:            /* Skip variables with values beginning with () (bash functions) */
                    678:            if ((cp = strchr(*ep, '=')) != NULL) {
                    679:                if (strncmp(cp, "=() ", 3) == 0)
                    680:                    continue;
                    681:            }
1.1       millert   682:
1.14      millert   683:            /*
                    684:             * First check variables against the blacklist in env_delete.
                    685:             * If no match there check for '%' and '/' characters.
                    686:             */
                    687:            okvar = matches_env_delete(*ep) != TRUE;
                    688:            if (okvar)
                    689:                okvar = matches_env_check(*ep) != FALSE;
1.1       millert   690:
                    691:            if (okvar) {
                    692:                if (strncmp(*ep, "SUDO_PS1=", 9) == 0)
                    693:                    ps1 = *ep + 5;
                    694:                else if (strncmp(*ep, "PATH=", 5) == 0)
1.9       millert   695:                    SET(didvar, DID_PATH);
1.1       millert   696:                else if (strncmp(*ep, "TERM=", 5) == 0)
1.9       millert   697:                    SET(didvar, DID_TERM);
1.19      millert   698:                sudo_putenv(*ep, FALSE, FALSE);
1.1       millert   699:            }
                    700:        }
                    701:     }
1.18      millert   702:     /* Replace the PATH envariable with a secure one? */
                    703:     if (def_secure_path && !user_is_exempt()) {
1.19      millert   704:        sudo_setenv("PATH", def_secure_path, TRUE);
1.14      millert   705:        SET(didvar, DID_PATH);
                    706:     }
1.1       millert   707:
1.14      millert   708:     /* Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is true. */
1.17      millert   709:     /* XXX - not needed for MODE_LOGIN_SHELL */
1.9       millert   710:     if (def_set_logname && runas_pw->pw_name) {
1.14      millert   711:        if (!ISSET(didvar, KEPT_LOGNAME))
1.19      millert   712:            sudo_setenv("LOGNAME", runas_pw->pw_name, TRUE);
1.14      millert   713:        if (!ISSET(didvar, KEPT_USER))
1.19      millert   714:            sudo_setenv("USER", runas_pw->pw_name, TRUE);
1.14      millert   715:        if (!ISSET(didvar, KEPT_USERNAME))
1.19      millert   716:            sudo_setenv("USERNAME", runas_pw->pw_name, TRUE);
1.1       millert   717:     }
                    718:
1.9       millert   719:     /* Set $HOME for `sudo -H'.  Only valid at PERM_FULL_RUNAS. */
1.17      millert   720:     /* XXX - not needed for MODE_LOGIN_SHELL */
1.14      millert   721:     if (runas_pw->pw_dir) {
                    722:        if (ISSET(sudo_mode, MODE_RESET_HOME) ||
                    723:            (ISSET(sudo_mode, MODE_RUN) && (def_always_set_home ||
                    724:            (ISSET(sudo_mode, MODE_SHELL) && def_set_home))))
1.19      millert   725:            sudo_setenv("HOME", runas_pw->pw_dir, TRUE);
1.14      millert   726:     }
                    727:
                    728:     /* Provide default values for $TERM and $PATH if they are not set. */
                    729:     if (!ISSET(didvar, DID_TERM))
1.19      millert   730:        sudo_putenv("TERM=unknown", FALSE, FALSE);
1.14      millert   731:     if (!ISSET(didvar, DID_PATH))
1.19      millert   732:        sudo_setenv("PATH", _PATH_DEFPATH, FALSE);
1.9       millert   733:
                    734:     /*
                    735:      * Preload a noexec file?  For a list of LD_PRELOAD-alikes, see
                    736:      * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html
                    737:      * XXX - should prepend to original value, if any
                    738:      */
1.12      millert   739:     if (noexec && def_noexec_file != NULL) {
1.9       millert   740: #if defined(__darwin__) || defined(__APPLE__)
1.19      millert   741:        sudo_setenv("DYLD_INSERT_LIBRARIES", def_noexec_file, TRUE);
                    742:        sudo_setenv("DYLD_FORCE_FLAT_NAMESPACE", "", TRUE);
1.9       millert   743: #else
                    744: # if defined(__osf__) || defined(__sgi)
1.18      millert   745:        easprintf(&cp, "%s:DEFAULT", def_noexec_file);
1.19      millert   746:        sudo_setenv("_RLD_LIST", cp, TRUE);
1.18      millert   747:        efree(cp);
1.9       millert   748: # else
1.14      millert   749: #  ifdef _AIX
1.19      millert   750:        sudo_setenv("LDR_PRELOAD", def_noexec_file, TRUE);
1.14      millert   751: #  else
1.19      millert   752:        sudo_setenv("LD_PRELOAD", def_noexec_file, TRUE);
1.14      millert   753: #  endif /* _AIX */
                    754: # endif /* __osf__ || __sgi */
                    755: #endif /* __darwin__ || __APPLE__ */
1.12      millert   756:     }
1.1       millert   757:
                    758:     /* Set PS1 if SUDO_PS1 is set. */
1.18      millert   759:     if (ps1 != NULL)
1.19      millert   760:        sudo_putenv(ps1, TRUE, TRUE);
1.1       millert   761:
                    762:     /* Add the SUDO_COMMAND envariable (cmnd + args). */
1.18      millert   763:     if (user_args) {
                    764:        easprintf(&cp, "%s %s", user_cmnd, user_args);
1.19      millert   765:        sudo_setenv("SUDO_COMMAND", cp, TRUE);
1.18      millert   766:        efree(cp);
                    767:     } else
1.19      millert   768:        sudo_setenv("SUDO_COMMAND", user_cmnd, TRUE);
1.1       millert   769:
                    770:     /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */
1.19      millert   771:     sudo_setenv("SUDO_USER", user_name, TRUE);
1.18      millert   772:     snprintf(idbuf, sizeof(idbuf), "%lu", (unsigned long) user_uid);
1.19      millert   773:     sudo_setenv("SUDO_UID", idbuf, TRUE);
1.18      millert   774:     snprintf(idbuf, sizeof(idbuf), "%lu", (unsigned long) user_gid);
1.19      millert   775:     sudo_setenv("SUDO_GID", idbuf, TRUE);
1.18      millert   776:
                    777:     /* Install new environment. */
                    778:     environ = env.envp;
                    779:     efree(old_envp);
1.14      millert   780: }
                    781:
1.18      millert   782: void
                    783: insert_env_vars(env_vars)
1.14      millert   784:     struct list_member *env_vars;
                    785: {
                    786:     struct list_member *cur;
                    787:
                    788:     if (env_vars == NULL)
1.18      millert   789:        return;
1.14      millert   790:
                    791:     /* Add user-specified environment variables. */
                    792:     for (cur = env_vars; cur != NULL; cur = cur->next)
1.19      millert   793:        putenv(cur->value);
1.14      millert   794: }
                    795:
                    796: /*
                    797:  * Validate the list of environment variables passed in on the command
                    798:  * line against env_delete, env_check, and env_keep.
                    799:  * Calls log_error() if any specified variables are not allowed.
                    800:  */
                    801: void
                    802: validate_env_vars(env_vars)
                    803:     struct list_member *env_vars;
                    804: {
                    805:     struct list_member *var;
                    806:     char *eq, *bad = NULL;
                    807:     size_t len, blen = 0, bsize = 0;
                    808:     int okvar;
1.1       millert   809:
1.14      millert   810:     for (var = env_vars; var != NULL; var = var->next) {
1.18      millert   811:        if (def_secure_path && !user_is_exempt() &&
                    812:            strncmp(var->value, "PATH=", 5) == 0) {
1.14      millert   813:            okvar = FALSE;
1.18      millert   814:        } else if (def_env_reset) {
1.14      millert   815:            okvar = matches_env_check(var->value);
                    816:            if (okvar == -1)
                    817:                okvar = matches_env_keep(var->value);
                    818:        } else {
                    819:            okvar = matches_env_delete(var->value) == FALSE;
                    820:            if (okvar == FALSE)
                    821:                okvar = matches_env_check(var->value) != FALSE;
                    822:        }
                    823:        if (okvar == FALSE) {
                    824:            /* Not allowed, add to error string, allocating as needed. */
                    825:            if ((eq = strchr(var->value, '=')) != NULL)
                    826:                *eq = '\0';
                    827:            len = strlen(var->value) + 2;
                    828:            if (blen + len >= bsize) {
                    829:                do {
                    830:                    bsize += 1024;
                    831:                } while (blen + len >= bsize);
                    832:                bad = erealloc(bad, bsize);
                    833:                bad[blen] = '\0';
                    834:            }
                    835:            strlcat(bad, var->value, bsize);
                    836:            strlcat(bad, ", ", bsize);
                    837:            blen += len;
                    838:            if (eq != NULL)
                    839:                *eq = '=';
                    840:        }
                    841:     }
                    842:     if (bad != NULL) {
                    843:        bad[blen - 2] = '\0';           /* remove trailing ", " */
                    844:        log_error(NO_MAIL,
                    845:            "sorry, you are not allowed to set the following environment variables: %s", bad);
                    846:        /* NOTREACHED */
                    847:        efree(bad);
                    848:     }
1.18      millert   849: }
                    850:
                    851: /*
                    852:  * Read in /etc/environment ala AIX and Linux.
1.21    ! millert   853:  * Lines may be in either of three formats:
        !           854:  *  NAME=VALUE
        !           855:  *  NAME="VALUE"
        !           856:  *  NAME='VALUE'
        !           857:  * with an optional "export" prefix so the shell can source the file.
1.18      millert   858:  * Invalid lines, blank lines, or lines consisting solely of a comment
                    859:  * character are skipped.
                    860:  */
                    861: void
1.19      millert   862: read_env_file(path, overwrite)
1.18      millert   863:     const char *path;
1.19      millert   864:     int overwrite;
1.18      millert   865: {
                    866:     FILE *fp;
1.21    ! millert   867:     char *cp, *var, *val;
        !           868:     size_t var_len, val_len;
1.18      millert   869:
                    870:     if ((fp = fopen(path, "r")) == NULL)
                    871:        return;
                    872:
1.21    ! millert   873:     while ((var = sudo_parseln(fp)) != NULL) {
1.18      millert   874:        /* Skip blank or comment lines */
1.21    ! millert   875:        if (*var == '\0')
1.18      millert   876:            continue;
                    877:
1.21    ! millert   878:        /* Skip optional "export " */
        !           879:        if (strncmp(var, "export", 6) == 0 && isspace((unsigned char) var[6])) {
        !           880:            var += 7;
        !           881:            while (isspace((unsigned char) *var)) {
        !           882:                var++;
        !           883:            }
        !           884:        }
        !           885:
        !           886:        /* Must be of the form name=["']value['"] */
        !           887:        for (val = var; *val != '\0' && *val != '='; val++)
        !           888:            ;
        !           889:        if (var == val || *val != '=')
1.18      millert   890:            continue;
1.21    ! millert   891:        var_len = (size_t)(val - var);
        !           892:        val_len = strlen(++val);
        !           893:
        !           894:        /* Strip leading and trailing single/double quotes */
        !           895:        if ((val[0] == '\'' || val[0] == '\"') && val[0] == val[val_len - 1]) {
        !           896:            val[val_len - 1] = '\0';
        !           897:            val++;
        !           898:            val_len -= 2;
        !           899:        }
        !           900:
        !           901:        cp = emalloc(var_len + 1 + val_len + 1);
        !           902:        memcpy(cp, var, var_len + 1); /* includes '=' */
        !           903:        memcpy(cp + var_len + 1, val, val_len + 1); /* includes NUL */
1.18      millert   904:
1.21    ! millert   905:        sudo_putenv(cp, TRUE, overwrite);
1.18      millert   906:     }
                    907:     fclose(fp);
1.1       millert   908: }
                    909:
                    910: void
                    911: init_envtables()
                    912: {
                    913:     struct list_member *cur;
1.5       millert   914:     const char **p;
1.1       millert   915:
1.14      millert   916:     /* Fill in the "env_delete" list. */
1.1       millert   917:     for (p = initial_badenv_table; *p; p++) {
                    918:        cur = emalloc(sizeof(struct list_member));
                    919:        cur->value = estrdup(*p);
1.9       millert   920:        cur->next = def_env_delete;
                    921:        def_env_delete = cur;
1.1       millert   922:     }
                    923:
1.14      millert   924:     /* Fill in the "env_check" list. */
1.1       millert   925:     for (p = initial_checkenv_table; *p; p++) {
                    926:        cur = emalloc(sizeof(struct list_member));
                    927:        cur->value = estrdup(*p);
1.9       millert   928:        cur->next = def_env_check;
                    929:        def_env_check = cur;
1.14      millert   930:     }
                    931:
                    932:     /* Fill in the "env_keep" list. */
                    933:     for (p = initial_keepenv_table; *p; p++) {
                    934:        cur = emalloc(sizeof(struct list_member));
                    935:        cur->value = estrdup(*p);
                    936:        cur->next = def_env_keep;
                    937:        def_env_keep = cur;
1.1       millert   938:     }
                    939: }