Annotation of embedaddon/sudo/src/env_hooks.c, revision 1.1.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>