[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.5

1.1       millert     1: /*
1.5     ! millert     2:  * Copyright (c) 2000-2003 Todd C. Miller <Todd.Miller@courtesan.com>
1.1       millert     3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  *
                      9:  * 1. Redistributions of source code must retain the above copyright
                     10:  *    notice, this list of conditions and the following disclaimer.
                     11:  *
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * 3. The name of the author may not be used to endorse or promote products
                     17:  *    derived from this software without specific prior written permission.
                     18:  *
                     19:  * 4. Products derived from this software may not be called "Sudo" nor
                     20:  *    may "Sudo" appear in their names without specific prior written
                     21:  *    permission from the author.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
                     24:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
                     25:  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
                     26:  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
                     27:  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     28:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     29:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     30:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     31:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     32:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     33:  */
                     34:
                     35: #include "config.h"
                     36:
                     37: #include <sys/types.h>
                     38: #include <sys/param.h>
                     39: #include <sys/stat.h>
                     40: #include <stdio.h>
                     41: #ifdef STDC_HEADERS
                     42: # include <stdlib.h>
                     43: # include <stddef.h>
                     44: #else
                     45: # ifdef HAVE_STDLIB_H
                     46: #  include <stdlib.h>
                     47: # endif
                     48: #endif /* STDC_HEADERS */
                     49: #ifdef HAVE_STRING_H
                     50: # include <string.h>
                     51: #else
                     52: # ifdef HAVE_STRINGS_H
                     53: #  include <strings.h>
                     54: # endif
                     55: #endif /* HAVE_STRING_H */
                     56: #ifdef HAVE_UNISTD_H
                     57: # include <unistd.h>
                     58: #endif /* HAVE_UNISTD_H */
                     59: #include <pwd.h>
                     60: #include <errno.h>
                     61:
                     62: #include "sudo.h"
                     63:
                     64: #ifndef lint
1.5     ! millert    65: static const char rcsid[] = "$Sudo: env.c,v 1.25 2003/03/15 20:31:01 millert Exp $";
1.1       millert    66: #endif /* lint */
                     67:
                     68: /*
1.5     ! millert    69:  * Flags used in rebuild_env()
1.1       millert    70:  */
                     71: #undef DID_TERM
                     72: #define DID_TERM       0x01
                     73: #undef DID_PATH
                     74: #define DID_PATH       0x02
                     75: #undef DID_HOME
                     76: #define DID_HOME       0x04
                     77: #undef DID_SHELL
                     78: #define DID_SHELL      0x08
                     79: #undef DID_LOGNAME
                     80: #define DID_LOGNAME    0x10
                     81: #undef DID_USER
                     82: #define DID_USER       0x12
                     83:
                     84: /*
                     85:  * Prototypes
                     86:  */
                     87: char **rebuild_env             __P((int, char **));
                     88: char **zero_env                        __P((char **));
1.5     ! millert    89: static void insert_env         __P((char *, int));
1.1       millert    90: static char *format_env                __P((char *, char *));
                     91:
                     92: /*
                     93:  * Default table of "bad" variables to remove from the environment.
                     94:  * XXX - how to omit TERMCAP if it starts with '/'?
                     95:  */
1.5     ! millert    96: static const char *initial_badenv_table[] = {
1.1       millert    97:     "IFS",
                     98:     "LOCALDOMAIN",
                     99:     "RES_OPTIONS",
                    100:     "HOSTALIASES",
                    101:     "NLSPATH",
                    102:     "PATH_LOCALE",
                    103:     "LD_*",
                    104:     "_RLD*",
                    105: #ifdef __hpux
                    106:     "SHLIB_PATH",
                    107: #endif /* __hpux */
                    108: #ifdef _AIX
                    109:     "LIBPATH",
                    110: #endif /* _AIX */
1.5     ! millert   111: #ifdef __APPLE__
        !           112:     "DYLD_*",
        !           113: #endif
1.1       millert   114: #ifdef HAVE_KERB4
                    115:     "KRB_CONF*",
                    116:     "KRBCONFDIR"
                    117:     "KRBTKFILE",
                    118: #endif /* HAVE_KERB4 */
                    119: #ifdef HAVE_KERB5
                    120:     "KRB5_CONFIG*",
                    121: #endif /* HAVE_KERB5 */
                    122: #ifdef HAVE_SECURID
                    123:     "VAR_ACE",
                    124:     "USR_ACE",
                    125:     "DLC_ACE",
                    126: #endif /* HAVE_SECURID */
                    127:     "TERMINFO",
                    128:     "TERMINFO_DIRS",
                    129:     "TERMPATH",
                    130:     "TERMCAP",                 /* XXX - only if it starts with '/' */
                    131:     "ENV",
                    132:     "BASH_ENV",
                    133:     NULL
                    134: };
                    135:
                    136: /*
                    137:  * Default table of variables to check for '%' and '/' characters.
                    138:  */
1.5     ! millert   139: static const char *initial_checkenv_table[] = {
1.1       millert   140:     "LC_*",
                    141:     "LANG",
                    142:     "LANGUAGE",
                    143:     NULL
                    144: };
                    145:
1.5     ! millert   146: static char **new_environ;     /* Modified copy of the environment */
        !           147: static size_t env_size;                /* size of new_environ in char **'s */
        !           148: static size_t env_len;         /* number of slots used, not counting NULL */
        !           149:
1.1       millert   150: /*
                    151:  * Zero out environment and replace with a minimal set of
                    152:  * USER, LOGNAME, HOME, TZ, PATH (XXX - should just set path to default)
                    153:  * May set user_path, user_shell, and/or user_prompt as side effects.
                    154:  */
                    155: char **
                    156: zero_env(envp)
                    157:     char **envp;
                    158: {
                    159:     char **ep, **nep;
                    160:     static char *newenv[7];
                    161:
                    162:     for (ep = envp; *ep; ep++) {
                    163:        switch (**ep) {
                    164:            case 'H':
                    165:                if (strncmp("HOME=", *ep, 5) == 0)
                    166:                    break;
1.2       millert   167:                continue;
1.1       millert   168:            case 'L':
                    169:                if (strncmp("LOGNAME=", *ep, 8) == 0)
                    170:                    break;
1.2       millert   171:                continue;
1.1       millert   172:            case 'P':
                    173:                if (strncmp("PATH=", *ep, 5) == 0) {
                    174:                    user_path = *ep + 5;
                    175:                    /* XXX - set to sane default instead of user's? */
                    176:                    break;
                    177:                }
1.2       millert   178:                continue;
1.1       millert   179:            case 'S':
1.2       millert   180:                if (strncmp("SHELL=", *ep, 6) == 0)
1.1       millert   181:                    user_shell = *ep + 6;
1.2       millert   182:                else if (!user_prompt && !strncmp("SUDO_PROMPT=", *ep, 12))
1.1       millert   183:                    user_prompt = *ep + 12;
1.2       millert   184:                continue;
1.1       millert   185:            case 'T':
                    186:                if (strncmp("TZ=", *ep, 3) == 0)
                    187:                    break;
1.2       millert   188:                continue;
1.1       millert   189:            case 'U':
                    190:                if (strncmp("USER=", *ep, 5) == 0)
                    191:                    break;
1.2       millert   192:                continue;
1.1       millert   193:            default:
                    194:                continue;
                    195:        }
                    196:
                    197:        /* Deal with multiply defined variables (take first instance) */
                    198:        for (nep = newenv; *nep; nep++) {
                    199:            if (**nep == **ep)
                    200:                break;
                    201:        }
                    202:        if (*nep == NULL)
                    203:            *nep++ = *ep;
                    204:     }
                    205:     return(&newenv[0]);
                    206: }
                    207:
                    208: /*
                    209:  * Given a variable and value, allocate and format an environment string.
                    210:  */
                    211: static char *
                    212: format_env(var, val)
                    213:     char *var;
                    214:     char *val;
                    215: {
1.5     ! millert   216:     char *estring;
        !           217:     size_t esize;
1.1       millert   218:
1.5     ! millert   219:     esize = strlen(var) + 1 + strlen(val) + 1;
        !           220:     estring = (char *) emalloc(esize);
        !           221:
        !           222:     /* We pre-allocate enough space, so this should never overflow. */
        !           223:     if (strlcpy(estring, var, esize) >= esize ||
        !           224:        strlcat(estring, "=", esize) >= esize ||
        !           225:        strlcat(estring, val, esize) >= esize) {
        !           226:        (void) fprintf(stderr, "%s: internal error, format_env() overflow\n",
        !           227:            Argv[0]);
        !           228:        exit(1);
        !           229:     }
1.1       millert   230:
                    231:     return(estring);
                    232: }
                    233:
                    234: /*
1.5     ! millert   235:  * Insert str into new_environ, assumes str has an '=' in it.
        !           236:  * NOTE: no other routines may modify new_environ, env_size, or env_len.
1.1       millert   237:  */
                    238: static void
1.5     ! millert   239: insert_env(str, dupcheck)
1.1       millert   240:     char *str;
1.5     ! millert   241:     int dupcheck;
1.1       millert   242: {
1.5     ! millert   243:     char **nep;
1.1       millert   244:     size_t varlen;
                    245:
1.5     ! millert   246:     /* Make sure there is room for the new entry. */
        !           247:     if (env_len + 1 > env_size) {
        !           248:        env_size += 128;
        !           249:        new_environ = erealloc3(new_environ, env_size, sizeof(char *));
        !           250:     }
        !           251:
        !           252:     if (dupcheck) {
        !           253:            varlen = (strchr(str, '=') - str) + 1;
1.1       millert   254:
1.5     ! millert   255:            for (nep = new_environ; *nep; nep++) {
        !           256:                if (strncmp(str, *nep, varlen) == 0) {
        !           257:                    *nep = str;
        !           258:                    return;
        !           259:                }
        !           260:            }
        !           261:     } else
        !           262:        nep = &new_environ[env_len];
        !           263:
        !           264:     env_len++;
        !           265:     *nep++ = str;
        !           266:     *nep = NULL;
1.1       millert   267: }
                    268:
                    269: /*
                    270:  * Build a new environment and ether clear potentially dangerous
                    271:  * variables from the old one or start with a clean slate.
                    272:  * Also adds sudo-specific variables (SUDO_*).
                    273:  */
                    274: char **
                    275: rebuild_env(sudo_mode, envp)
                    276:     int sudo_mode;
                    277:     char **envp;
                    278: {
1.5     ! millert   279:     char **ep, *cp, *ps1;
1.1       millert   280:     int okvar, iswild, didvar;
1.5     ! millert   281:     size_t len;
1.1       millert   282:     struct list_member *cur;
                    283:
                    284:     /*
                    285:      * Either clean out the environment or reset to a safe default.
                    286:      */
                    287:     ps1 = NULL;
                    288:     didvar = 0;
                    289:     if (def_flag(I_ENV_RESET)) {
                    290:        int keepit;
                    291:
                    292:        /* Pull in vars we want to keep from the old environment. */
                    293:        for (ep = envp; *ep; ep++) {
                    294:            keepit = 0;
                    295:            for (cur = def_list(I_ENV_KEEP); cur; cur = cur->next) {
                    296:                len = strlen(cur->value);
                    297:                /* Deal with '*' wildcard */
                    298:                if (cur->value[len - 1] == '*') {
                    299:                    len--;
                    300:                    iswild = 1;
                    301:                } else
                    302:                    iswild = 0;
                    303:                if (strncmp(cur->value, *ep, len) == 0 &&
                    304:                    (iswild || (*ep)[len] == '=')) {
                    305:                    /* We always preserve TERM, no special treatment needed. */
                    306:                    if (strncmp(*ep, "TERM=", 5) != 0)
                    307:                        keepit = 1;
                    308:                    break;
                    309:                }
                    310:            }
                    311:
                    312:            /* For SUDO_PS1 -> PS1 conversion. */
                    313:            if (strncmp(*ep, "SUDO_PS1=", 8) == 0)
                    314:                ps1 = *ep + 5;
                    315:
                    316:            if (keepit) {
                    317:                /* Preserve variable. */
                    318:                switch (**ep) {
                    319:                    case 'H':
                    320:                        if (strncmp(*ep, "HOME=", 5) == 0)
                    321:                            didvar |= DID_HOME;
1.5     ! millert   322:                        break;
1.1       millert   323:                    case 'S':
                    324:                        if (strncmp(*ep, "SHELL=", 6) == 0)
                    325:                            didvar |= DID_SHELL;
1.5     ! millert   326:                        break;
1.1       millert   327:                    case 'L':
                    328:                        if (strncmp(*ep, "LOGNAME=", 8) == 0)
                    329:                            didvar |= DID_LOGNAME;
1.5     ! millert   330:                        break;
1.1       millert   331:                    case 'U':
                    332:                        if (strncmp(*ep, "USER=", 5) == 0)
                    333:                            didvar |= DID_USER;
1.5     ! millert   334:                        break;
1.1       millert   335:                }
1.5     ! millert   336:                insert_env(*ep, 0);
1.1       millert   337:            } else {
                    338:                /* Preserve TERM and PATH, ignore anything else. */
                    339:                if (!(didvar & DID_TERM) && !strncmp(*ep, "TERM=", 5)) {
1.5     ! millert   340:                    insert_env(*ep, 0);
1.1       millert   341:                    didvar |= DID_TERM;
                    342:                } else if (!(didvar & DID_PATH) && !strncmp(*ep, "PATH=", 5)) {
1.5     ! millert   343:                    insert_env(*ep, 0);
1.1       millert   344:                    didvar |= DID_PATH;
                    345:                }
                    346:            }
                    347:        }
                    348:
                    349:        /*
                    350:         * Add in defaults unless they were preserved from the
                    351:         * user's environment.
                    352:         */
                    353:        if (!(didvar & DID_HOME))
1.5     ! millert   354:            insert_env(format_env("HOME", user_dir), 0);
1.1       millert   355:        if (!(didvar & DID_SHELL))
1.5     ! millert   356:            insert_env(format_env("SHELL", sudo_user.pw->pw_shell), 0);
1.1       millert   357:        if (!(didvar & DID_LOGNAME))
1.5     ! millert   358:            insert_env(format_env("LOGNAME", user_name), 0);
1.1       millert   359:        if (!(didvar & DID_USER))
1.5     ! millert   360:            insert_env(format_env("USER", user_name), 0);
1.1       millert   361:     } else {
                    362:        /*
                    363:         * Copy envp entries as long as they don't match env_delete or
                    364:         * env_check.
                    365:         */
                    366:        for (ep = envp; *ep; ep++) {
                    367:            okvar = 1;
                    368:
                    369:            /* Skip anything listed in env_delete. */
                    370:            for (cur = def_list(I_ENV_DELETE); cur && okvar; cur = cur->next) {
                    371:                len = strlen(cur->value);
                    372:                /* Deal with '*' wildcard */
                    373:                if (cur->value[len - 1] == '*') {
                    374:                    len--;
                    375:                    iswild = 1;
                    376:                } else
                    377:                    iswild = 0;
                    378:                if (strncmp(cur->value, *ep, len) == 0 &&
                    379:                    (iswild || (*ep)[len] == '=')) {
                    380:                    okvar = 0;
                    381:                }
                    382:            }
                    383:
                    384:            /* Check certain variables for '%' and '/' characters. */
                    385:            for (cur = def_list(I_ENV_CHECK); cur && okvar; cur = cur->next) {
                    386:                len = strlen(cur->value);
                    387:                /* Deal with '*' wildcard */
                    388:                if (cur->value[len - 1] == '*') {
                    389:                    len--;
                    390:                    iswild = 1;
                    391:                } else
                    392:                    iswild = 0;
                    393:                if (strncmp(cur->value, *ep, len) == 0 &&
                    394:                    (iswild || (*ep)[len] == '=') &&
                    395:                    strpbrk(*ep, "/%")) {
                    396:                    okvar = 0;
                    397:                }
                    398:            }
                    399:
                    400:            if (okvar) {
                    401:                if (strncmp(*ep, "SUDO_PS1=", 9) == 0)
                    402:                    ps1 = *ep + 5;
                    403:                else if (strncmp(*ep, "PATH=", 5) == 0)
                    404:                    didvar |= DID_PATH;
                    405:                else if (strncmp(*ep, "TERM=", 5) == 0)
                    406:                    didvar |= DID_TERM;
1.5     ! millert   407:                insert_env(*ep, 0);
1.1       millert   408:            }
                    409:        }
                    410:     }
                    411:     /* Provide default values for $TERM and $PATH if they are not set. */
                    412:     if (!(didvar & DID_TERM))
1.5     ! millert   413:        insert_env("TERM=unknown", 0);
1.1       millert   414:     if (!(didvar & DID_PATH))
1.5     ! millert   415:        insert_env(format_env("PATH", _PATH_DEFPATH), 0);
1.1       millert   416:
                    417: #ifdef SECURE_PATH
                    418:     /* Replace the PATH envariable with a secure one. */
1.5     ! millert   419:     insert_env(format_env("PATH", SECURE_PATH), 1);
1.1       millert   420: #endif
                    421:
                    422:     /* Set $USER and $LOGNAME to target if "set_logname" is true. */
                    423:     if (def_flag(I_SET_LOGNAME) && runas_pw->pw_name) {
1.5     ! millert   424:        insert_env(format_env("LOGNAME", runas_pw->pw_name), 1);
        !           425:        insert_env(format_env("USER", runas_pw->pw_name), 1);
1.1       millert   426:     }
                    427:
                    428:     /* Set $HOME for `sudo -H'.  Only valid at PERM_RUNAS. */
                    429:     if ((sudo_mode & MODE_RESET_HOME) && runas_pw->pw_dir)
1.5     ! millert   430:        insert_env(format_env("HOME", runas_pw->pw_dir), 1);
1.1       millert   431:
                    432:     /* Set PS1 if SUDO_PS1 is set. */
                    433:     if (ps1)
1.5     ! millert   434:        insert_env(ps1, 1);
1.1       millert   435:
                    436:     /* Add the SUDO_COMMAND envariable (cmnd + args). */
                    437:     if (user_args) {
1.4       millert   438:        easprintf(&cp, "SUDO_COMMAND=%s %s", user_cmnd, user_args);
1.5     ! millert   439:        insert_env(cp, 1);
1.1       millert   440:     } else
1.5     ! millert   441:        insert_env(format_env("SUDO_COMMAND", user_cmnd), 1);
1.1       millert   442:
                    443:     /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */
1.5     ! millert   444:     insert_env(format_env("SUDO_USER", user_name), 1);
        !           445:     easprintf(&cp, "SUDO_UID=%lu", (unsigned long) user_uid);
        !           446:     insert_env(cp, 1);
        !           447:     easprintf(&cp, "SUDO_GID=%lu", (unsigned long) user_gid);
        !           448:     insert_env(cp, 1);
1.1       millert   449:
1.5     ! millert   450:     return(new_environ);
1.1       millert   451: }
                    452:
                    453: void
                    454: init_envtables()
                    455: {
                    456:     struct list_member *cur;
1.5     ! millert   457:     const char **p;
1.1       millert   458:
                    459:     /* Fill in "env_delete" variable. */
                    460:     for (p = initial_badenv_table; *p; p++) {
                    461:        cur = emalloc(sizeof(struct list_member));
                    462:        cur->value = estrdup(*p);
                    463:        cur->next = def_list(I_ENV_DELETE);
                    464:        def_list(I_ENV_DELETE) = cur;
                    465:     }
                    466:
                    467:     /* Fill in "env_check" variable. */
                    468:     for (p = initial_checkenv_table; *p; p++) {
                    469:        cur = emalloc(sizeof(struct list_member));
                    470:        cur->value = estrdup(*p);
                    471:        cur->next = def_list(I_ENV_CHECK);
                    472:        def_list(I_ENV_CHECK) = cur;
                    473:     }
                    474: }