Annotation of embedaddon/sudo/src/env_hooks.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:  * Copyright (c) 2010, 2012 Todd C. Miller <Todd.Miller@courtesan.com>
                      3:  *
                      4:  * Permission to use, copy, modify, and distribute this software for any
                      5:  * purpose with or without fee is hereby granted, provided that the above
                      6:  * copyright notice and this permission notice appear in all copies.
                      7:  *
                      8:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                      9:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     10:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     11:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     12:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     13:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     14:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     15:  */
                     16: 
                     17: #include <config.h>
                     18: 
                     19: #include <sys/types.h>
                     20: 
                     21: #include <stdio.h>
                     22: #ifdef STDC_HEADERS
                     23: # include <stdlib.h>
                     24: # include <stddef.h>
                     25: #else
                     26: # ifdef HAVE_STDLIB_H
                     27: #  include <stdlib.h>
                     28: # endif
                     29: #endif /* STDC_HEADERS */
                     30: #ifdef HAVE_STRING_H
                     31: # include <string.h>
                     32: #endif /* HAVE_STRING_H */
                     33: #ifdef HAVE_STRINGS_H
                     34: # include <strings.h>
                     35: #endif /* HAVE_STRINGS_H */
                     36: #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
                     37: # include <malloc.h>
                     38: #endif /* HAVE_MALLOC_H && !STDC_HEADERS */
                     39: #include <errno.h>
                     40: #ifdef HAVE_DLOPEN
                     41: # include <dlfcn.h>
                     42: #else
                     43: # include "compat/dlfcn.h"
                     44: #endif
                     45: 
                     46: #include "sudo.h"
                     47: #include "sudo_plugin.h"
                     48: 
                     49: extern char **environ;         /* global environment pointer */
                     50: static char **priv_environ;    /* private environment pointer */
                     51: 
                     52: static char *
                     53: rpl_getenv(const char *name)
                     54: {
                     55:     char **ep, *val = NULL;
                     56:     size_t namelen = 0;
                     57: 
                     58:     /* For BSD compatibility, treat '=' in name like end of string. */
                     59:     while (name[namelen] != '\0' && name[namelen] != '=')
                     60:        namelen++;
                     61:     for (ep = environ; *ep != NULL; ep++) {
                     62:        if (strncmp(*ep, name, namelen) == 0 && (*ep)[namelen] == '=') {
                     63:            val = *ep + namelen + 1;
                     64:            break;
                     65:        }
                     66:     }
                     67:     return val;
                     68: }
                     69: 
                     70: typedef char * (*sudo_fn_getenv_t)(const char *);
                     71: 
                     72: char *
1.1.1.2 ! misho      73: getenv_unhooked(const char *name)
        !            74: {
        !            75: #if defined(HAVE_DLOPEN) && defined(RTLD_NEXT)
        !            76:     sudo_fn_getenv_t fn;
        !            77: 
        !            78:     fn = (sudo_fn_getenv_t)dlsym(RTLD_NEXT, "getenv");
        !            79:     if (fn != NULL)
        !            80:        return fn(name);
        !            81: #endif /* HAVE_DLOPEN && RTLD_NEXT */
        !            82:     return rpl_getenv(name);
        !            83: }
        !            84: 
        !            85: char *
1.1       misho      86: getenv(const char *name)
                     87: {
                     88:     char *val = NULL;
                     89: 
                     90:     switch (process_hooks_getenv(name, &val)) {
                     91:        case SUDO_HOOK_RET_STOP:
                     92:            return val;
                     93:        case SUDO_HOOK_RET_ERROR:
                     94:            return NULL;
1.1.1.2 ! misho      95:        default:
        !            96:            return getenv_unhooked(name);
1.1       misho      97:     }
                     98: }
                     99: 
                    100: static int
                    101: rpl_putenv(PUTENV_CONST char *string)
                    102: {
                    103:     char **ep;
                    104:     size_t len;
                    105:     bool found = false;
                    106: 
                    107:     /* Look for existing entry. */
                    108:     len = (strchr(string, '=') - string) + 1;
                    109:     for (ep = environ; *ep != NULL; ep++) {
                    110:        if (strncmp(string, *ep, len) == 0) {
                    111:            *ep = (char *)string;
                    112:            found = true;
                    113:            break;
                    114:        }
                    115:     }
                    116:     /* Prune out duplicate variables. */
                    117:     if (found) {
                    118:        while (*ep != NULL) {
                    119:            if (strncmp(string, *ep, len) == 0) {
                    120:                char **cur = ep;
                    121:                while ((*cur = *(cur + 1)) != NULL)
                    122:                    cur++;
                    123:            } else {
                    124:                ep++;
                    125:            }
                    126:        }
                    127:     }
                    128: 
                    129:     /* Append at the end if not already found. */
                    130:     if (!found) {
                    131:        size_t env_len = (size_t)(ep - environ);
                    132:        char **envp = erealloc3(priv_environ, env_len + 2, sizeof(char *));
                    133:        if (environ != priv_environ)
                    134:            memcpy(envp, environ, env_len * sizeof(char *));
                    135:        envp[env_len++] = (char *)string;
                    136:        envp[env_len] = NULL;
                    137:        priv_environ = environ = envp;
                    138:     }
                    139:     return 0;
                    140: }
                    141: 
                    142: typedef int (*sudo_fn_putenv_t)(PUTENV_CONST char *);
                    143: 
1.1.1.2 ! misho     144: static int
        !           145: putenv_unhooked(PUTENV_CONST char *string)
        !           146: {
        !           147: #if defined(HAVE_DLOPEN) && defined(RTLD_NEXT)
        !           148:     sudo_fn_putenv_t fn;
        !           149: 
        !           150:     fn = (sudo_fn_putenv_t)dlsym(RTLD_NEXT, "putenv");
        !           151:     if (fn != NULL)
        !           152:        return fn(string);
        !           153: #endif /* HAVE_DLOPEN && RTLD_NEXT */
        !           154:     return rpl_putenv(string);
        !           155: }
        !           156: 
1.1       misho     157: int
                    158: putenv(PUTENV_CONST char *string)
                    159: {
                    160:     switch (process_hooks_putenv((char *)string)) {
                    161:        case SUDO_HOOK_RET_STOP:
                    162:            return 0;
                    163:        case SUDO_HOOK_RET_ERROR:
                    164:            return -1;
1.1.1.2 ! misho     165:        default:
        !           166:            return putenv_unhooked(string);
1.1       misho     167:     }
                    168: }
                    169: 
                    170: static int
                    171: rpl_setenv(const char *var, const char *val, int overwrite)
                    172: {
                    173:     char *envstr, *dst;
                    174:     const char *src;
                    175:     size_t esize;
                    176: 
                    177:     if (!var || *var == '\0') {
                    178:        errno = EINVAL;
                    179:        return -1;
                    180:     }
                    181: 
                    182:     /*
                    183:      * POSIX says a var name with '=' is an error but BSD
                    184:      * just ignores the '=' and anything after it.
                    185:      */
                    186:     for (src = var; *src != '\0' && *src != '='; src++)
                    187:        ;
                    188:     esize = (size_t)(src - var) + 2;
                    189:     if (val) {
                    190:         esize += strlen(val);  /* glibc treats a NULL val as "" */
                    191:     }
                    192: 
                    193:     /* Allocate and fill in envstr. */
                    194:     if ((envstr = malloc(esize)) == NULL)
                    195:        return -1;
                    196:     for (src = var, dst = envstr; *src != '\0' && *src != '=';)
                    197:        *dst++ = *src++;
                    198:     *dst++ = '=';
                    199:     if (val) {
                    200:        for (src = val; *src != '\0';)
                    201:            *dst++ = *src++;
                    202:     }
                    203:     *dst = '\0';
                    204: 
                    205:     if (!overwrite && getenv(var) != NULL) {
                    206:        free(envstr);
                    207:        return 0;
                    208:     }
                    209:     return rpl_putenv(envstr);
                    210: }
                    211: 
                    212: typedef int (*sudo_fn_setenv_t)(const char *, const char *, int);
                    213: 
1.1.1.2 ! misho     214: static int
        !           215: setenv_unhooked(const char *var, const char *val, int overwrite)
        !           216: {
        !           217: #if defined(HAVE_SETENV) && defined(HAVE_DLOPEN) && defined(RTLD_NEXT)
        !           218:     sudo_fn_setenv_t fn;
        !           219: 
        !           220:     fn = (sudo_fn_setenv_t)dlsym(RTLD_NEXT, "setenv");
        !           221:     if (fn != NULL)
        !           222:        return fn(var, val, overwrite);
        !           223: #endif /* HAVE_SETENV && HAVE_DLOPEN && RTLD_NEXT */
        !           224:     return rpl_setenv(var, val, overwrite);
        !           225: }
        !           226: 
1.1       misho     227: int
                    228: setenv(const char *var, const char *val, int overwrite)
                    229: {
                    230:     switch (process_hooks_setenv(var, val, overwrite)) {
                    231:        case SUDO_HOOK_RET_STOP:
                    232:            return 0;
                    233:        case SUDO_HOOK_RET_ERROR:
                    234:            return -1;
1.1.1.2 ! misho     235:        default:
        !           236:            return setenv_unhooked(var, val, overwrite);
1.1       misho     237:     }
                    238: }
                    239: 
1.1.1.2 ! misho     240: static int
1.1       misho     241: rpl_unsetenv(const char *var)
                    242: {
                    243:     char **ep = environ;
                    244:     size_t len;
                    245: 
                    246:     if (var == NULL || *var == '\0' || strchr(var, '=') != NULL) {
                    247:        errno = EINVAL;
                    248:        return -1;
                    249:     }
                    250: 
                    251:     len = strlen(var);
                    252:     while (*ep != NULL) {
                    253:        if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') {
                    254:            /* Found it; shift remainder + NULL over by one. */
                    255:            char **cur = ep;
                    256:            while ((*cur = *(cur + 1)) != NULL)
                    257:                cur++;
                    258:            /* Keep going, could be multiple instances of the var. */
                    259:        } else {
                    260:            ep++;
                    261:        }
                    262:     }
                    263:     return 0;
                    264: }
                    265: 
                    266: #ifdef UNSETENV_VOID
                    267: typedef void (*sudo_fn_unsetenv_t)(const char *);
                    268: #else
                    269: typedef int (*sudo_fn_unsetenv_t)(const char *);
                    270: #endif
                    271: 
1.1.1.2 ! misho     272: static int
        !           273: unsetenv_unhooked(const char *var)
1.1       misho     274: {
1.1.1.2 ! misho     275:     int rval = 0;
1.1       misho     276: #if defined(HAVE_UNSETENV) && defined(HAVE_DLOPEN) && defined(RTLD_NEXT)
1.1.1.2 ! misho     277:     sudo_fn_unsetenv_t fn;
1.1       misho     278: 
1.1.1.2 ! misho     279:     fn = (sudo_fn_unsetenv_t)dlsym(RTLD_NEXT, "unsetenv");
        !           280:     if (fn != NULL) {
        !           281: # ifdef UNSETENV_VOID
        !           282:        fn(var);
        !           283: # else
        !           284:        rval = fn(var);
        !           285: # endif
        !           286:     } else
1.1       misho     287: #endif /* HAVE_UNSETENV && HAVE_DLOPEN && RTLD_NEXT */
1.1.1.2 ! misho     288:     {
        !           289:        rval = rpl_unsetenv(var);
1.1       misho     290:     }
1.1.1.2 ! misho     291:     return rval;
1.1       misho     292: }
1.1.1.2 ! misho     293: 
        !           294: #ifdef UNSETENV_VOID
        !           295: void
1.1       misho     296: #else
                    297: int
1.1.1.2 ! misho     298: #endif
1.1       misho     299: unsetenv(const char *var)
                    300: {
1.1.1.2 ! misho     301:     int rval;
        !           302: 
1.1       misho     303:     switch (process_hooks_unsetenv(var)) {
                    304:        case SUDO_HOOK_RET_STOP:
1.1.1.2 ! misho     305:            rval = 0;
        !           306:            break;
1.1       misho     307:        case SUDO_HOOK_RET_ERROR:
1.1.1.2 ! misho     308:            rval = -1;
        !           309:            break;
        !           310:        default:
        !           311:            rval = unsetenv_unhooked(var);
        !           312:            break;
1.1       misho     313:     }
1.1.1.2 ! misho     314: #ifndef UNSETENV_VOID
        !           315:     return rval;
        !           316: #endif
1.1       misho     317: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>