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

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