File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / src / env_hooks.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 10:46:13 2013 UTC (10 years, 11 months ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_8p0, v1_8_8, v1_8_7p0, v1_8_7, HEAD
1.8.7

    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_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 *
   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;
   95: 	default:
   96: 	    return getenv_unhooked(name);
   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: 
  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: 
  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;
  165: 	default:
  166: 	    return putenv_unhooked(string);
  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: 
  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: 
  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;
  235: 	default:
  236: 	    return setenv_unhooked(var, val, overwrite);
  237:     }
  238: }
  239: 
  240: static int
  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: 
  272: static int
  273: unsetenv_unhooked(const char *var)
  274: {
  275:     int rval = 0;
  276: #if defined(HAVE_UNSETENV) && defined(HAVE_DLOPEN) && defined(RTLD_NEXT)
  277:     sudo_fn_unsetenv_t fn;
  278: 
  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
  287: #endif /* HAVE_UNSETENV && HAVE_DLOPEN && RTLD_NEXT */
  288:     {
  289: 	rval = rpl_unsetenv(var);
  290:     }
  291:     return rval;
  292: }
  293: 
  294: #ifdef UNSETENV_VOID
  295: void
  296: #else
  297: int
  298: #endif
  299: unsetenv(const char *var)
  300: {
  301:     int rval;
  302: 
  303:     switch (process_hooks_unsetenv(var)) {
  304: 	case SUDO_HOOK_RET_STOP:
  305: 	    rval = 0;
  306: 	    break;
  307: 	case SUDO_HOOK_RET_ERROR:
  308: 	    rval = -1;
  309: 	    break;
  310: 	default:
  311: 	    rval = unsetenv_unhooked(var);
  312: 	    break;
  313:     }
  314: #ifndef UNSETENV_VOID
  315:     return rval;
  316: #endif
  317: }

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