2 * Copyright (c) 2010, 2012 Todd C. Miller <Todd.Miller@courtesan.com>
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.
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.
19 #include <sys/types.h>
29 #endif /* STDC_HEADERS */
32 #endif /* HAVE_STRING_H */
35 #endif /* HAVE_STRINGS_H */
36 #if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
38 #endif /* HAVE_MALLOC_H && !STDC_HEADERS */
43 # include "compat/dlfcn.h"
47 #include "sudo_plugin.h"
49 extern char **environ; /* global environment pointer */
50 static char **priv_environ; /* private environment pointer */
53 rpl_getenv(const char *name)
55 char **ep, *val = NULL;
58 /* For BSD compatibility, treat '=' in name like end of string. */
59 while (name[namelen] != '\0' && name[namelen] != '=')
61 for (ep = environ; *ep != NULL; ep++) {
62 if (strncmp(*ep, name, namelen) == 0 && (*ep)[namelen] == '=') {
63 val = *ep + namelen + 1;
70 typedef char * (*sudo_fn_getenv_t)(const char *);
73 getenv(const char *name)
77 switch (process_hooks_getenv(name, &val)) {
78 case SUDO_HOOK_RET_STOP:
80 case SUDO_HOOK_RET_ERROR:
83 #if defined(HAVE_DLOPEN) && defined(RTLD_NEXT)
86 fn = (sudo_fn_getenv_t)dlsym(RTLD_NEXT, "getenv");
89 #endif /* HAVE_DLOPEN && RTLD_NEXT */
90 return rpl_getenv(name);
96 rpl_putenv(PUTENV_CONST char *string)
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;
111 /* Prune out duplicate variables. */
113 while (*ep != NULL) {
114 if (strncmp(string, *ep, len) == 0) {
116 while ((*cur = *(cur + 1)) != NULL)
124 /* Append at the end if not already 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;
137 typedef int (*sudo_fn_putenv_t)(PUTENV_CONST char *);
140 putenv(PUTENV_CONST char *string)
142 switch (process_hooks_putenv((char *)string)) {
143 case SUDO_HOOK_RET_STOP:
145 case SUDO_HOOK_RET_ERROR:
148 #if defined(HAVE_DLOPEN) && defined(RTLD_NEXT)
151 fn = (sudo_fn_putenv_t)dlsym(RTLD_NEXT, "putenv");
154 #endif /* HAVE_DLOPEN && RTLD_NEXT */
155 return rpl_putenv(string);
161 rpl_setenv(const char *var, const char *val, int overwrite)
167 if (!var || *var == '\0') {
173 * POSIX says a var name with '=' is an error but BSD
174 * just ignores the '=' and anything after it.
176 for (src = var; *src != '\0' && *src != '='; src++)
178 esize = (size_t)(src - var) + 2;
180 esize += strlen(val); /* glibc treats a NULL val as "" */
183 /* Allocate and fill in envstr. */
184 if ((envstr = malloc(esize)) == NULL)
186 for (src = var, dst = envstr; *src != '\0' && *src != '=';)
190 for (src = val; *src != '\0';)
195 if (!overwrite && getenv(var) != NULL) {
199 return rpl_putenv(envstr);
202 typedef int (*sudo_fn_setenv_t)(const char *, const char *, int);
205 setenv(const char *var, const char *val, int overwrite)
207 switch (process_hooks_setenv(var, val, overwrite)) {
208 case SUDO_HOOK_RET_STOP:
210 case SUDO_HOOK_RET_ERROR:
213 #if defined(HAVE_SETENV) && defined(HAVE_DLOPEN) && defined(RTLD_NEXT)
216 fn = (sudo_fn_setenv_t)dlsym(RTLD_NEXT, "setenv");
218 return fn(var, val, overwrite);
219 #endif /* HAVE_SETENV && HAVE_DLOPEN && RTLD_NEXT */
220 return rpl_setenv(var, val, overwrite);
230 rpl_unsetenv(const char *var)
235 if (var == NULL || *var == '\0' || strchr(var, '=') != NULL) {
245 while (*ep != NULL) {
246 if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') {
247 /* Found it; shift remainder + NULL over by one. */
249 while ((*cur = *(cur + 1)) != NULL)
251 /* Keep going, could be multiple instances of the var. */
256 #ifndef UNSETENV_VOID
262 typedef void (*sudo_fn_unsetenv_t)(const char *);
264 typedef int (*sudo_fn_unsetenv_t)(const char *);
269 unsetenv(const char *var)
271 switch (process_hooks_unsetenv(var)) {
272 case SUDO_HOOK_RET_STOP:
274 case SUDO_HOOK_RET_ERROR:
277 #if defined(HAVE_UNSETENV) && defined(HAVE_DLOPEN) && defined(RTLD_NEXT)
278 sudo_fn_unsetenv_t fn;
280 fn = (sudo_fn_unsetenv_t)dlsym(RTLD_NEXT, "unsetenv");
284 #endif /* HAVE_UNSETENV && HAVE_DLOPEN && RTLD_NEXT */
291 unsetenv(const char *var)
293 switch (process_hooks_unsetenv(var)) {
294 case SUDO_HOOK_RET_STOP:
296 case SUDO_HOOK_RET_ERROR:
299 #if defined(HAVE_UNSETENV) && defined(HAVE_DLOPEN) && defined(RTLD_NEXT)
300 sudo_fn_unsetenv_t fn;
302 fn = (sudo_fn_unsetenv_t)dlsym(RTLD_NEXT, "unsetenv");
305 #endif /* HAVE_UNSETENV && HAVE_DLOPEN && RTLD_NEXT */
306 return rpl_unsetenv(var);
310 #endif /* UNSETENV_VOID */