2 * Copyright (c) 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>
28 #endif /* STDC_HEADERS */
31 #endif /* HAVE_STRING_H */
34 #endif /* HAVE_STRINGS_H */
37 #endif /* HAVE_UNISTD_H */
40 #include "sudo_plugin.h"
41 #include "sudo_plugin_int.h"
42 #include "sudo_debug.h"
44 /* Singly linked hook list. */
45 struct sudo_hook_list {
46 struct sudo_hook_list *next;
48 sudo_hook_fn_t generic_fn;
49 sudo_hook_fn_setenv_t setenv_fn;
50 sudo_hook_fn_unsetenv_t unsetenv_fn;
51 sudo_hook_fn_getenv_t getenv_fn;
52 sudo_hook_fn_putenv_t putenv_fn;
57 /* Each hook type gets own hook list. */
58 static struct sudo_hook_list *sudo_hook_setenv_list;
59 static struct sudo_hook_list *sudo_hook_unsetenv_list;
60 static struct sudo_hook_list *sudo_hook_getenv_list;
61 static struct sudo_hook_list *sudo_hook_putenv_list;
64 process_hooks_setenv(const char *name, const char *value, int overwrite)
66 struct sudo_hook_list *hook;
67 int rc = SUDO_HOOK_RET_NEXT;
68 debug_decl(process_hooks_setenv, SUDO_DEBUG_HOOKS)
70 /* First process the hooks. */
71 for (hook = sudo_hook_setenv_list; hook != NULL; hook = hook->next) {
72 rc = hook->u.setenv_fn(name, value, overwrite, hook->closure);
74 case SUDO_HOOK_RET_NEXT:
76 case SUDO_HOOK_RET_ERROR:
77 case SUDO_HOOK_RET_STOP:
80 warningx("invalid setenv hook return value: %d", rc);
89 process_hooks_putenv(char *string)
91 struct sudo_hook_list *hook;
92 int rc = SUDO_HOOK_RET_NEXT;
93 debug_decl(process_hooks_putenv, SUDO_DEBUG_HOOKS)
95 /* First process the hooks. */
96 for (hook = sudo_hook_putenv_list; hook != NULL; hook = hook->next) {
97 rc = hook->u.putenv_fn(string, hook->closure);
99 case SUDO_HOOK_RET_NEXT:
101 case SUDO_HOOK_RET_ERROR:
102 case SUDO_HOOK_RET_STOP:
105 warningx("invalid putenv hook return value: %d", rc);
110 debug_return_int(rc);
114 process_hooks_getenv(const char *name, char **value)
116 struct sudo_hook_list *hook;
118 int rc = SUDO_HOOK_RET_NEXT;
119 debug_decl(process_hooks_getenv, SUDO_DEBUG_HOOKS)
121 /* First process the hooks. */
122 for (hook = sudo_hook_getenv_list; hook != NULL; hook = hook->next) {
123 rc = hook->u.getenv_fn(name, &val, hook->closure);
125 case SUDO_HOOK_RET_NEXT:
127 case SUDO_HOOK_RET_ERROR:
128 case SUDO_HOOK_RET_STOP:
131 warningx("invalid getenv hook return value: %d", rc);
138 debug_return_int(rc);
142 process_hooks_unsetenv(const char *name)
144 struct sudo_hook_list *hook;
145 int rc = SUDO_HOOK_RET_NEXT;
146 debug_decl(process_hooks_unsetenv, SUDO_DEBUG_HOOKS)
148 /* First process the hooks. */
149 for (hook = sudo_hook_unsetenv_list; hook != NULL; hook = hook->next) {
150 rc = hook->u.unsetenv_fn(name, hook->closure);
152 case SUDO_HOOK_RET_NEXT:
154 case SUDO_HOOK_RET_ERROR:
155 case SUDO_HOOK_RET_STOP:
158 warningx("invalid unsetenv hook return value: %d", rc);
163 debug_return_int(rc);
166 /* Hook registration internals. */
168 register_hook_internal(struct sudo_hook_list **head,
169 int (*hook_fn)(), void *closure)
171 struct sudo_hook_list *hook;
172 debug_decl(register_hook_internal, SUDO_DEBUG_HOOKS)
174 hook = ecalloc(1, sizeof(*hook));
175 hook->u.generic_fn = hook_fn;
176 hook->closure = closure;
183 /* Register the specified hook. */
185 register_hook(struct sudo_hook *hook)
188 debug_decl(register_hook, SUDO_DEBUG_HOOKS)
190 if (SUDO_HOOK_VERSION_GET_MAJOR(hook->hook_version) != SUDO_HOOK_VERSION_MAJOR) {
191 /* Major versions must match. */
194 switch (hook->hook_type) {
195 case SUDO_HOOK_GETENV:
196 register_hook_internal(&sudo_hook_getenv_list, hook->hook_fn,
199 case SUDO_HOOK_PUTENV:
200 register_hook_internal(&sudo_hook_putenv_list, hook->hook_fn,
203 case SUDO_HOOK_SETENV:
204 register_hook_internal(&sudo_hook_setenv_list, hook->hook_fn,
207 case SUDO_HOOK_UNSETENV:
208 register_hook_internal(&sudo_hook_unsetenv_list, hook->hook_fn,
212 /* XXX - use define for unknown value */
218 debug_return_int(rval);
221 /* Hook deregistration internals. */
223 deregister_hook_internal(struct sudo_hook_list **head,
224 int (*hook_fn)(), void *closure)
226 struct sudo_hook_list *hook, *prev = NULL;
227 debug_decl(deregister_hook_internal, SUDO_DEBUG_HOOKS)
229 for (hook = *head, prev = NULL; hook != NULL; prev = hook, hook = hook->next) {
230 if (hook->u.generic_fn == hook_fn && hook->closure == closure) {
231 /* Remove from list and free. */
235 prev->next = hook->next;
244 /* Deregister the specified hook. */
246 deregister_hook(struct sudo_hook *hook)
249 debug_decl(deregister_hook, SUDO_DEBUG_HOOKS)
251 if (SUDO_HOOK_VERSION_GET_MAJOR(hook->hook_version) != SUDO_HOOK_VERSION_MAJOR) {
252 /* Major versions must match. */
255 switch (hook->hook_type) {
256 case SUDO_HOOK_GETENV:
257 deregister_hook_internal(&sudo_hook_getenv_list, hook->hook_fn,
260 case SUDO_HOOK_PUTENV:
261 deregister_hook_internal(&sudo_hook_putenv_list, hook->hook_fn,
264 case SUDO_HOOK_SETENV:
265 deregister_hook_internal(&sudo_hook_setenv_list, hook->hook_fn,
268 case SUDO_HOOK_UNSETENV:
269 deregister_hook_internal(&sudo_hook_unsetenv_list, hook->hook_fn,
273 /* XXX - use define for unknown value */
279 debug_return_int(rval);