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

1.1       millert     1: /*
                      2:  * Copyright (c) 2000, 2001 Todd C. Miller <Todd.Miller@courtesan.com>
                      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.3     ! millert    65: static const char rcsid[] = "$Sudo: env.c,v 1.15 2002/01/15 23:43:58 millert Exp $";
1.1       millert    66: #endif /* lint */
                     67:
                     68: /*
                     69:  * Flags used in env_reset()
                     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 **));
                     89: static void insert_env         __P((char **, char *));
                     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:  */
                     96: char *initial_badenv_table[] = {
                     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 */
                    111: #ifdef HAVE_KERB4
                    112:     "KRB_CONF*",
                    113:     "KRBCONFDIR"
                    114:     "KRBTKFILE",
                    115: #endif /* HAVE_KERB4 */
                    116: #ifdef HAVE_KERB5
                    117:     "KRB5_CONFIG*",
                    118: #endif /* HAVE_KERB5 */
                    119: #ifdef HAVE_SECURID
                    120:     "VAR_ACE",
                    121:     "USR_ACE",
                    122:     "DLC_ACE",
                    123: #endif /* HAVE_SECURID */
                    124:     "TERMINFO",
                    125:     "TERMINFO_DIRS",
                    126:     "TERMPATH",
                    127:     "TERMCAP",                 /* XXX - only if it starts with '/' */
                    128:     "ENV",
                    129:     "BASH_ENV",
                    130:     NULL
                    131: };
                    132:
                    133: /*
                    134:  * Default table of variables to check for '%' and '/' characters.
                    135:  */
                    136: char *initial_checkenv_table[] = {
                    137:     "LC_*",
                    138:     "LANG",
                    139:     "LANGUAGE",
                    140:     NULL
                    141: };
                    142:
                    143: /*
                    144:  * Zero out environment and replace with a minimal set of
                    145:  * USER, LOGNAME, HOME, TZ, PATH (XXX - should just set path to default)
                    146:  * May set user_path, user_shell, and/or user_prompt as side effects.
                    147:  */
                    148: char **
                    149: zero_env(envp)
                    150:     char **envp;
                    151: {
                    152:     char **ep, **nep;
                    153:     static char *newenv[7];
                    154:
                    155:     for (ep = envp; *ep; ep++) {
                    156:        switch (**ep) {
                    157:            case 'H':
                    158:                if (strncmp("HOME=", *ep, 5) == 0)
                    159:                    break;
1.2       millert   160:                continue;
1.1       millert   161:            case 'L':
                    162:                if (strncmp("LOGNAME=", *ep, 8) == 0)
                    163:                    break;
1.2       millert   164:                continue;
1.1       millert   165:            case 'P':
                    166:                if (strncmp("PATH=", *ep, 5) == 0) {
                    167:                    user_path = *ep + 5;
                    168:                    /* XXX - set to sane default instead of user's? */
                    169:                    break;
                    170:                }
1.2       millert   171:                continue;
1.1       millert   172:            case 'S':
1.2       millert   173:                if (strncmp("SHELL=", *ep, 6) == 0)
1.1       millert   174:                    user_shell = *ep + 6;
1.2       millert   175:                else if (!user_prompt && !strncmp("SUDO_PROMPT=", *ep, 12))
1.1       millert   176:                    user_prompt = *ep + 12;
1.2       millert   177:                continue;
1.1       millert   178:            case 'T':
                    179:                if (strncmp("TZ=", *ep, 3) == 0)
                    180:                    break;
1.2       millert   181:                continue;
1.1       millert   182:            case 'U':
                    183:                if (strncmp("USER=", *ep, 5) == 0)
                    184:                    break;
1.2       millert   185:                continue;
1.1       millert   186:            default:
                    187:                continue;
                    188:        }
                    189:
                    190:        /* Deal with multiply defined variables (take first instance) */
                    191:        for (nep = newenv; *nep; nep++) {
                    192:            if (**nep == **ep)
                    193:                break;
                    194:        }
                    195:        if (*nep == NULL)
                    196:            *nep++ = *ep;
                    197:     }
                    198:     return(&newenv[0]);
                    199: }
                    200:
                    201: /*
                    202:  * Given a variable and value, allocate and format an environment string.
                    203:  */
                    204: static char *
                    205: format_env(var, val)
                    206:     char *var;
                    207:     char *val;
                    208: {
                    209:     char *estring, *p;
                    210:     size_t varlen, vallen;
                    211:
                    212:     varlen = strlen(var);
                    213:     vallen = strlen(val);
                    214:     p = estring = (char *) emalloc(varlen + vallen + 2);
                    215:     strcpy(p, var);
                    216:     p += varlen;
                    217:     *p++ = '=';
                    218:     strcpy(p, val);
                    219:
                    220:     return(estring);
                    221: }
                    222:
                    223: /*
                    224:  * Insert str into envp.
                    225:  * Assumes str has an '=' in it and does not check for available space!
                    226:  */
                    227: static void
                    228: insert_env(envp, str)
                    229:     char **envp;
                    230:     char *str;
                    231: {
                    232:     char **ep;
                    233:     size_t varlen;
                    234:
                    235:     varlen = (strchr(str, '=') - str) + 1;
                    236:
                    237:     for (ep = envp; *ep; ep++) {
                    238:        if (strncmp(str, *ep, varlen) == 0) {
                    239:            *ep = str;
                    240:            break;
                    241:        }
                    242:     }
                    243:     if (*ep == NULL) {
                    244:        *ep++ = str;
                    245:        *ep = NULL;
                    246:     }
                    247: }
                    248:
                    249: /*
                    250:  * Build a new environment and ether clear potentially dangerous
                    251:  * variables from the old one or start with a clean slate.
                    252:  * Also adds sudo-specific variables (SUDO_*).
                    253:  */
                    254: char **
                    255: rebuild_env(sudo_mode, envp)
                    256:     int sudo_mode;
                    257:     char **envp;
                    258: {
                    259:     char **newenvp, **ep, **nep, *cp, *ps1;
                    260:     int okvar, iswild, didvar;
                    261:     size_t env_size, len;
                    262:     struct list_member *cur;
                    263:
                    264:     /* Count number of items in "env_keep" list (if any) */
                    265:     for (len = 0, cur = def_list(I_ENV_KEEP); cur; cur = cur->next)
                    266:        len++;
                    267:
                    268:     /*
                    269:      * Either clean out the environment or reset to a safe default.
                    270:      */
                    271:     ps1 = NULL;
                    272:     didvar = 0;
                    273:     if (def_flag(I_ENV_RESET)) {
                    274:        int keepit;
                    275:
                    276:        /* Alloc space for new environment. */
                    277:        env_size = 32 + len;
                    278:        nep = newenvp = (char **) emalloc(env_size * sizeof(char *));
                    279:
                    280:        /* Pull in vars we want to keep from the old environment. */
                    281:        for (ep = envp; *ep; ep++) {
                    282:            keepit = 0;
                    283:            for (cur = def_list(I_ENV_KEEP); cur; cur = cur->next) {
                    284:                len = strlen(cur->value);
                    285:                /* Deal with '*' wildcard */
                    286:                if (cur->value[len - 1] == '*') {
                    287:                    len--;
                    288:                    iswild = 1;
                    289:                } else
                    290:                    iswild = 0;
                    291:                if (strncmp(cur->value, *ep, len) == 0 &&
                    292:                    (iswild || (*ep)[len] == '=')) {
                    293:                    /* We always preserve TERM, no special treatment needed. */
                    294:                    if (strncmp(*ep, "TERM=", 5) != 0)
                    295:                        keepit = 1;
                    296:                    break;
                    297:                }
                    298:            }
                    299:
                    300:            /* For SUDO_PS1 -> PS1 conversion. */
                    301:            if (strncmp(*ep, "SUDO_PS1=", 8) == 0)
                    302:                ps1 = *ep + 5;
                    303:
                    304:            if (keepit) {
                    305:                /* Preserve variable. */
                    306:                switch (**ep) {
                    307:                    case 'H':
                    308:                        if (strncmp(*ep, "HOME=", 5) == 0)
                    309:                            didvar |= DID_HOME;
                    310:                            break;
                    311:                    case 'S':
                    312:                        if (strncmp(*ep, "SHELL=", 6) == 0)
                    313:                            didvar |= DID_SHELL;
                    314:                            break;
                    315:                    case 'L':
                    316:                        if (strncmp(*ep, "LOGNAME=", 8) == 0)
                    317:                            didvar |= DID_LOGNAME;
                    318:                            break;
                    319:                    case 'U':
                    320:                        if (strncmp(*ep, "USER=", 5) == 0)
                    321:                            didvar |= DID_USER;
                    322:                            break;
                    323:                }
                    324:                *nep++ = *ep;
                    325:            } else {
                    326:                /* Preserve TERM and PATH, ignore anything else. */
                    327:                if (!(didvar & DID_TERM) && !strncmp(*ep, "TERM=", 5)) {
                    328:                    *nep++ = *ep;
                    329:                    didvar |= DID_TERM;
                    330:                } else if (!(didvar & DID_PATH) && !strncmp(*ep, "PATH=", 5)) {
                    331:                    *nep++ = *ep;
                    332:                    didvar |= DID_PATH;
                    333:                }
                    334:            }
                    335:        }
                    336:
                    337:        /*
                    338:         * Add in defaults unless they were preserved from the
                    339:         * user's environment.
                    340:         */
                    341:        if (!(didvar & DID_HOME))
                    342:            *nep++ = format_env("HOME", user_dir);
                    343:        if (!(didvar & DID_SHELL))
1.3     ! millert   344:            *nep++ = format_env("SHELL", sudo_user.pw->pw_shell);
1.1       millert   345:        if (!(didvar & DID_LOGNAME))
                    346:            *nep++ = format_env("LOGNAME", user_name);
                    347:        if (!(didvar & DID_USER))
                    348:            *nep++ = format_env("USER", user_name);
                    349:     } else {
                    350:        /* Alloc space for new environment. */
                    351:        for (env_size = 16 + len, ep = envp; *ep; ep++, env_size++)
                    352:            ;
                    353:        nep = newenvp = (char **) emalloc(env_size * sizeof(char *));
                    354:
                    355:        /*
                    356:         * Copy envp entries as long as they don't match env_delete or
                    357:         * env_check.
                    358:         */
                    359:        for (ep = envp; *ep; ep++) {
                    360:            okvar = 1;
                    361:
                    362:            /* Skip anything listed in env_delete. */
                    363:            for (cur = def_list(I_ENV_DELETE); cur && okvar; cur = cur->next) {
                    364:                len = strlen(cur->value);
                    365:                /* Deal with '*' wildcard */
                    366:                if (cur->value[len - 1] == '*') {
                    367:                    len--;
                    368:                    iswild = 1;
                    369:                } else
                    370:                    iswild = 0;
                    371:                if (strncmp(cur->value, *ep, len) == 0 &&
                    372:                    (iswild || (*ep)[len] == '=')) {
                    373:                    okvar = 0;
                    374:                }
                    375:            }
                    376:
                    377:            /* Check certain variables for '%' and '/' characters. */
                    378:            for (cur = def_list(I_ENV_CHECK); cur && okvar; cur = cur->next) {
                    379:                len = strlen(cur->value);
                    380:                /* Deal with '*' wildcard */
                    381:                if (cur->value[len - 1] == '*') {
                    382:                    len--;
                    383:                    iswild = 1;
                    384:                } else
                    385:                    iswild = 0;
                    386:                if (strncmp(cur->value, *ep, len) == 0 &&
                    387:                    (iswild || (*ep)[len] == '=') &&
                    388:                    strpbrk(*ep, "/%")) {
                    389:                    okvar = 0;
                    390:                }
                    391:            }
                    392:
                    393:            if (okvar) {
                    394:                if (strncmp(*ep, "SUDO_PS1=", 9) == 0)
                    395:                    ps1 = *ep + 5;
                    396:                else if (strncmp(*ep, "PATH=", 5) == 0)
                    397:                    didvar |= DID_PATH;
                    398:                else if (strncmp(*ep, "TERM=", 5) == 0)
                    399:                    didvar |= DID_TERM;
                    400:                *nep++ = *ep;
                    401:            }
                    402:        }
                    403:     }
                    404:     /* Provide default values for $TERM and $PATH if they are not set. */
                    405:     if (!(didvar & DID_TERM))
                    406:        *nep++ = "TERM=unknown";
                    407:     if (!(didvar & DID_PATH))
                    408:        *nep++ = format_env("PATH", _PATH_DEFPATH);
                    409:     *nep = NULL;
                    410:
                    411:     /*
                    412:      * At this point we must use insert_env() to modify newenvp.
                    413:      * Access via 'nep' is not allowed (since we must check for dupes).
                    414:      */
                    415:
                    416: #ifdef SECURE_PATH
                    417:     /* Replace the PATH envariable with a secure one. */
                    418:     insert_env(newenvp, format_env("PATH", SECURE_PATH));
                    419: #endif
                    420:
                    421:     /* Set $USER and $LOGNAME to target if "set_logname" is true. */
                    422:     if (def_flag(I_SET_LOGNAME) && runas_pw->pw_name) {
                    423:        insert_env(newenvp, format_env("LOGNAME", runas_pw->pw_name));
                    424:        insert_env(newenvp, format_env("USER", runas_pw->pw_name));
                    425:     }
                    426:
                    427:     /* Set $HOME for `sudo -H'.  Only valid at PERM_RUNAS. */
                    428:     if ((sudo_mode & MODE_RESET_HOME) && runas_pw->pw_dir)
                    429:        insert_env(newenvp, format_env("HOME", runas_pw->pw_dir));
                    430:
                    431:     /* Set PS1 if SUDO_PS1 is set. */
                    432:     if (ps1)
                    433:        insert_env(newenvp, ps1);
                    434:
                    435:     /* Add the SUDO_COMMAND envariable (cmnd + args). */
                    436:     if (user_args) {
                    437:        cp = emalloc(strlen(user_cmnd) + strlen(user_args) + 15);
                    438:        sprintf(cp, "SUDO_COMMAND=%s %s", user_cmnd, user_args);
                    439:        insert_env(newenvp, cp);
                    440:     } else
                    441:        insert_env(newenvp, format_env("SUDO_COMMAND", user_cmnd));
                    442:
                    443:     /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */
                    444:     insert_env(newenvp, format_env("SUDO_USER", user_name));
                    445:     cp = emalloc(MAX_UID_T_LEN + 10);
                    446:     sprintf(cp, "SUDO_UID=%ld", (long) user_uid);
                    447:     insert_env(newenvp, cp);
                    448:     cp = emalloc(MAX_UID_T_LEN + 10);
                    449:     sprintf(cp, "SUDO_GID=%ld", (long) user_gid);
                    450:     insert_env(newenvp, cp);
                    451:
                    452:     return(newenvp);
                    453: }
                    454:
                    455: void
                    456: dump_badenv()
                    457: {
                    458:     struct list_member *cur;
                    459:
                    460:     puts("Default table of environment variables to clear");
                    461:     for (cur = def_list(I_ENV_DELETE); cur; cur = cur->next)
                    462:        printf("\t%s\n", cur->value);
                    463:
                    464:     puts("Default table of environment variables to sanity check");
                    465:     for (cur = def_list(I_ENV_CHECK); cur; cur = cur->next)
                    466:        printf("\t%s\n", cur->value);
                    467: }
                    468:
                    469: void
                    470: init_envtables()
                    471: {
                    472:     struct list_member *cur;
                    473:     char **p;
                    474:
                    475:     /* Fill in "env_delete" variable. */
                    476:     for (p = initial_badenv_table; *p; p++) {
                    477:        cur = emalloc(sizeof(struct list_member));
                    478:        cur->value = estrdup(*p);
                    479:        cur->next = def_list(I_ENV_DELETE);
                    480:        def_list(I_ENV_DELETE) = cur;
                    481:     }
                    482:
                    483:     /* Fill in "env_check" variable. */
                    484:     for (p = initial_checkenv_table; *p; p++) {
                    485:        cur = emalloc(sizeof(struct list_member));
                    486:        cur->value = estrdup(*p);
                    487:        cur->next = def_list(I_ENV_CHECK);
                    488:        def_list(I_ENV_CHECK) = cur;
                    489:     }
                    490: }