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>