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>