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

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 *
        !            73: getenv(const char *name)
        !            74: {
        !            75:     char *val = NULL;
        !            76: 
        !            77:     switch (process_hooks_getenv(name, &val)) {
        !            78:        case SUDO_HOOK_RET_STOP:
        !            79:            return val;
        !            80:        case SUDO_HOOK_RET_ERROR:
        !            81:            return NULL;
        !            82:        default: {
        !            83: #if defined(HAVE_DLOPEN) && defined(RTLD_NEXT)
        !            84:            sudo_fn_getenv_t fn;
        !            85: 
        !            86:            fn = (sudo_fn_getenv_t)dlsym(RTLD_NEXT, "getenv");
        !            87:            if (fn != NULL)
        !            88:                return fn(name);
        !            89: #endif /* HAVE_DLOPEN && RTLD_NEXT */
        !            90:            return rpl_getenv(name);
        !            91:        }
        !            92:     }
        !            93: }
        !            94: 
        !            95: static int
        !            96: rpl_putenv(PUTENV_CONST char *string)
        !            97: {
        !            98:     char **ep;
        !            99:     size_t len;
        !           100:     bool found = false;
        !           101: 
        !           102:     /* Look for existing entry. */
        !           103:     len = (strchr(string, '=') - string) + 1;
        !           104:     for (ep = environ; *ep != NULL; ep++) {
        !           105:        if (strncmp(string, *ep, len) == 0) {
        !           106:            *ep = (char *)string;
        !           107:            found = true;
        !           108:            break;
        !           109:        }
        !           110:     }
        !           111:     /* Prune out duplicate variables. */
        !           112:     if (found) {
        !           113:        while (*ep != NULL) {
        !           114:            if (strncmp(string, *ep, len) == 0) {
        !           115:                char **cur = ep;
        !           116:                while ((*cur = *(cur + 1)) != NULL)
        !           117:                    cur++;
        !           118:            } else {
        !           119:                ep++;
        !           120:            }
        !           121:        }
        !           122:     }
        !           123: 
        !           124:     /* Append at the end if not already found. */
        !           125:     if (!found) {
        !           126:        size_t env_len = (size_t)(ep - environ);
        !           127:        char **envp = erealloc3(priv_environ, env_len + 2, sizeof(char *));
        !           128:        if (environ != priv_environ)
        !           129:            memcpy(envp, environ, env_len * sizeof(char *));
        !           130:        envp[env_len++] = (char *)string;
        !           131:        envp[env_len] = NULL;
        !           132:        priv_environ = environ = envp;
        !           133:     }
        !           134:     return 0;
        !           135: }
        !           136: 
        !           137: typedef int (*sudo_fn_putenv_t)(PUTENV_CONST char *);
        !           138: 
        !           139: int
        !           140: putenv(PUTENV_CONST char *string)
        !           141: {
        !           142:     switch (process_hooks_putenv((char *)string)) {
        !           143:        case SUDO_HOOK_RET_STOP:
        !           144:            return 0;
        !           145:        case SUDO_HOOK_RET_ERROR:
        !           146:            return -1;
        !           147:        default: {
        !           148: #if defined(HAVE_DLOPEN) && defined(RTLD_NEXT)
        !           149:            sudo_fn_putenv_t fn;
        !           150: 
        !           151:            fn = (sudo_fn_putenv_t)dlsym(RTLD_NEXT, "putenv");
        !           152:            if (fn != NULL)
        !           153:                return fn(string);
        !           154: #endif /* HAVE_DLOPEN && RTLD_NEXT */
        !           155:            return rpl_putenv(string);
        !           156:        }
        !           157:     }
        !           158: }
        !           159: 
        !           160: static int
        !           161: rpl_setenv(const char *var, const char *val, int overwrite)
        !           162: {
        !           163:     char *envstr, *dst;
        !           164:     const char *src;
        !           165:     size_t esize;
        !           166: 
        !           167:     if (!var || *var == '\0') {
        !           168:        errno = EINVAL;
        !           169:        return -1;
        !           170:     }
        !           171: 
        !           172:     /*
        !           173:      * POSIX says a var name with '=' is an error but BSD
        !           174:      * just ignores the '=' and anything after it.
        !           175:      */
        !           176:     for (src = var; *src != '\0' && *src != '='; src++)
        !           177:        ;
        !           178:     esize = (size_t)(src - var) + 2;
        !           179:     if (val) {
        !           180:         esize += strlen(val);  /* glibc treats a NULL val as "" */
        !           181:     }
        !           182: 
        !           183:     /* Allocate and fill in envstr. */
        !           184:     if ((envstr = malloc(esize)) == NULL)
        !           185:        return -1;
        !           186:     for (src = var, dst = envstr; *src != '\0' && *src != '=';)
        !           187:        *dst++ = *src++;
        !           188:     *dst++ = '=';
        !           189:     if (val) {
        !           190:        for (src = val; *src != '\0';)
        !           191:            *dst++ = *src++;
        !           192:     }
        !           193:     *dst = '\0';
        !           194: 
        !           195:     if (!overwrite && getenv(var) != NULL) {
        !           196:        free(envstr);
        !           197:        return 0;
        !           198:     }
        !           199:     return rpl_putenv(envstr);
        !           200: }
        !           201: 
        !           202: typedef int (*sudo_fn_setenv_t)(const char *, const char *, int);
        !           203: 
        !           204: int
        !           205: setenv(const char *var, const char *val, int overwrite)
        !           206: {
        !           207:     switch (process_hooks_setenv(var, val, overwrite)) {
        !           208:        case SUDO_HOOK_RET_STOP:
        !           209:            return 0;
        !           210:        case SUDO_HOOK_RET_ERROR:
        !           211:            return -1;
        !           212:        default: {
        !           213: #if defined(HAVE_SETENV) && defined(HAVE_DLOPEN) && defined(RTLD_NEXT)
        !           214:            sudo_fn_setenv_t fn;
        !           215: 
        !           216:            fn = (sudo_fn_setenv_t)dlsym(RTLD_NEXT, "setenv");
        !           217:            if (fn != NULL)
        !           218:                return fn(var, val, overwrite);
        !           219: #endif /* HAVE_SETENV && HAVE_DLOPEN && RTLD_NEXT */
        !           220:            return rpl_setenv(var, val, overwrite);
        !           221:        }
        !           222:     }
        !           223: }
        !           224: 
        !           225: #ifdef UNSETENV_VOID
        !           226: static void
        !           227: #else
        !           228: int
        !           229: #endif
        !           230: rpl_unsetenv(const char *var)
        !           231: {
        !           232:     char **ep = environ;
        !           233:     size_t len;
        !           234: 
        !           235:     if (var == NULL || *var == '\0' || strchr(var, '=') != NULL) {
        !           236:        errno = EINVAL;
        !           237: #ifdef UNSETENV_VOID
        !           238:        return;
        !           239: #else
        !           240:        return -1;
        !           241: #endif
        !           242:     }
        !           243: 
        !           244:     len = strlen(var);
        !           245:     while (*ep != NULL) {
        !           246:        if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') {
        !           247:            /* Found it; shift remainder + NULL over by one. */
        !           248:            char **cur = ep;
        !           249:            while ((*cur = *(cur + 1)) != NULL)
        !           250:                cur++;
        !           251:            /* Keep going, could be multiple instances of the var. */
        !           252:        } else {
        !           253:            ep++;
        !           254:        }
        !           255:     }
        !           256: #ifndef UNSETENV_VOID
        !           257:     return 0;
        !           258: #endif
        !           259: }
        !           260: 
        !           261: #ifdef UNSETENV_VOID
        !           262: typedef void (*sudo_fn_unsetenv_t)(const char *);
        !           263: #else
        !           264: typedef int (*sudo_fn_unsetenv_t)(const char *);
        !           265: #endif
        !           266: 
        !           267: #ifdef UNSETENV_VOID
        !           268: void
        !           269: unsetenv(const char *var)
        !           270: {
        !           271:     switch (process_hooks_unsetenv(var)) {
        !           272:        case SUDO_HOOK_RET_STOP:
        !           273:            return 0;
        !           274:        case SUDO_HOOK_RET_ERROR:
        !           275:            return -1;
        !           276:        default: {
        !           277: #if defined(HAVE_UNSETENV) && defined(HAVE_DLOPEN) && defined(RTLD_NEXT)
        !           278:            sudo_fn_unsetenv_t fn;
        !           279: 
        !           280:            fn = (sudo_fn_unsetenv_t)dlsym(RTLD_NEXT, "unsetenv");
        !           281:            if (fn != NULL)
        !           282:                fn(var);
        !           283:            else
        !           284: #endif /* HAVE_UNSETENV && HAVE_DLOPEN && RTLD_NEXT */
        !           285:                rpl_unsetenv(var);
        !           286:        }
        !           287:     }
        !           288: }
        !           289: #else
        !           290: int
        !           291: unsetenv(const char *var)
        !           292: {
        !           293:     switch (process_hooks_unsetenv(var)) {
        !           294:        case SUDO_HOOK_RET_STOP:
        !           295:            return 0;
        !           296:        case SUDO_HOOK_RET_ERROR:
        !           297:            return -1;
        !           298:        default: {
        !           299: #if defined(HAVE_UNSETENV) && defined(HAVE_DLOPEN) && defined(RTLD_NEXT)
        !           300:            sudo_fn_unsetenv_t fn;
        !           301: 
        !           302:            fn = (sudo_fn_unsetenv_t)dlsym(RTLD_NEXT, "unsetenv");
        !           303:            if (fn != NULL)
        !           304:                return fn(var);
        !           305: #endif /* HAVE_UNSETENV && HAVE_DLOPEN && RTLD_NEXT */
        !           306:            return rpl_unsetenv(var);
        !           307:        }
        !           308:     }
        !           309: }
        !           310: #endif /* UNSETENV_VOID */

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