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

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