Annotation of embedaddon/sudo/src/hooks.c, revision 1.1.1.4
1.1 misho 1: /*
1.1.1.4 ! misho 2: * Copyright (c) 2012-2013 Todd C. Miller <Todd.Miller@courtesan.com>
1.1 misho 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: #include <stdio.h>
21: #ifdef STDC_HEADERS
22: # include <stdlib.h>
23: # include <stddef.h>
24: #else
25: # ifdef HAVE_STDLIB_H
26: # include <stdlib.h>
27: # endif
28: #endif /* STDC_HEADERS */
29: #ifdef HAVE_STRING_H
30: # include <string.h>
31: #endif /* HAVE_STRING_H */
32: #ifdef HAVE_STRINGS_H
33: # include <strings.h>
34: #endif /* HAVE_STRINGS_H */
35: #ifdef HAVE_UNISTD_H
36: # include <unistd.h>
37: #endif /* HAVE_UNISTD_H */
38:
39: #include "sudo.h"
40: #include "sudo_plugin.h"
41: #include "sudo_plugin_int.h"
42: #include "sudo_debug.h"
1.1.1.4 ! misho 43: #include "queue.h"
1.1 misho 44:
45: /* Singly linked hook list. */
1.1.1.4 ! misho 46: struct sudo_hook_entry {
! 47: SLIST_ENTRY(sudo_hook_entry) entries;
1.1 misho 48: union {
49: sudo_hook_fn_t generic_fn;
50: sudo_hook_fn_setenv_t setenv_fn;
51: sudo_hook_fn_unsetenv_t unsetenv_fn;
52: sudo_hook_fn_getenv_t getenv_fn;
53: sudo_hook_fn_putenv_t putenv_fn;
54: } u;
55: void *closure;
56: };
1.1.1.4 ! misho 57: SLIST_HEAD(sudo_hook_list, sudo_hook_entry);
1.1 misho 58:
59: /* Each hook type gets own hook list. */
1.1.1.4 ! misho 60: static struct sudo_hook_list sudo_hook_setenv_list =
! 61: SLIST_HEAD_INITIALIZER(sudo_hook_setenv_list);
! 62: static struct sudo_hook_list sudo_hook_unsetenv_list =
! 63: SLIST_HEAD_INITIALIZER(sudo_hook_unsetenv_list);
! 64: static struct sudo_hook_list sudo_hook_getenv_list =
! 65: SLIST_HEAD_INITIALIZER(sudo_hook_getenv_list);
! 66: static struct sudo_hook_list sudo_hook_putenv_list =
! 67: SLIST_HEAD_INITIALIZER(sudo_hook_putenv_list);
1.1 misho 68:
1.1.1.2 misho 69: /* NOTE: must not anything that might call setenv() */
1.1 misho 70: int
71: process_hooks_setenv(const char *name, const char *value, int overwrite)
72: {
1.1.1.4 ! misho 73: struct sudo_hook_entry *hook;
1.1 misho 74: int rc = SUDO_HOOK_RET_NEXT;
75:
76: /* First process the hooks. */
1.1.1.4 ! misho 77: SLIST_FOREACH(hook, &sudo_hook_setenv_list, entries) {
1.1 misho 78: rc = hook->u.setenv_fn(name, value, overwrite, hook->closure);
79: switch (rc) {
80: case SUDO_HOOK_RET_NEXT:
81: break;
82: case SUDO_HOOK_RET_ERROR:
83: case SUDO_HOOK_RET_STOP:
84: goto done;
85: default:
1.1.1.3 misho 86: warningx_nodebug("invalid setenv hook return value: %d", rc);
1.1 misho 87: break;
88: }
89: }
90: done:
1.1.1.2 misho 91: return rc;
1.1 misho 92: }
93:
1.1.1.2 misho 94: /* NOTE: must not anything that might call putenv() */
1.1 misho 95: int
96: process_hooks_putenv(char *string)
97: {
1.1.1.4 ! misho 98: struct sudo_hook_entry *hook;
1.1 misho 99: int rc = SUDO_HOOK_RET_NEXT;
100:
101: /* First process the hooks. */
1.1.1.4 ! misho 102: SLIST_FOREACH(hook, &sudo_hook_putenv_list, entries) {
1.1 misho 103: rc = hook->u.putenv_fn(string, hook->closure);
104: switch (rc) {
105: case SUDO_HOOK_RET_NEXT:
106: break;
107: case SUDO_HOOK_RET_ERROR:
108: case SUDO_HOOK_RET_STOP:
109: goto done;
110: default:
1.1.1.3 misho 111: warningx_nodebug("invalid putenv hook return value: %d", rc);
1.1 misho 112: break;
113: }
114: }
115: done:
1.1.1.2 misho 116: return rc;
1.1 misho 117: }
118:
1.1.1.2 misho 119: /* NOTE: must not anything that might call getenv() */
1.1 misho 120: int
121: process_hooks_getenv(const char *name, char **value)
122: {
1.1.1.4 ! misho 123: struct sudo_hook_entry *hook;
1.1 misho 124: char *val = NULL;
125: int rc = SUDO_HOOK_RET_NEXT;
126:
127: /* First process the hooks. */
1.1.1.4 ! misho 128: SLIST_FOREACH(hook, &sudo_hook_getenv_list, entries) {
1.1 misho 129: rc = hook->u.getenv_fn(name, &val, hook->closure);
130: switch (rc) {
131: case SUDO_HOOK_RET_NEXT:
132: break;
133: case SUDO_HOOK_RET_ERROR:
134: case SUDO_HOOK_RET_STOP:
135: goto done;
136: default:
1.1.1.3 misho 137: warningx_nodebug("invalid getenv hook return value: %d", rc);
1.1 misho 138: break;
139: }
140: }
141: done:
142: if (val != NULL)
143: *value = val;
1.1.1.2 misho 144: return rc;
1.1 misho 145: }
146:
1.1.1.2 misho 147: /* NOTE: must not anything that might call unsetenv() */
1.1 misho 148: int
149: process_hooks_unsetenv(const char *name)
150: {
1.1.1.4 ! misho 151: struct sudo_hook_entry *hook;
1.1 misho 152: int rc = SUDO_HOOK_RET_NEXT;
153:
154: /* First process the hooks. */
1.1.1.4 ! misho 155: SLIST_FOREACH(hook, &sudo_hook_unsetenv_list, entries) {
1.1 misho 156: rc = hook->u.unsetenv_fn(name, hook->closure);
157: switch (rc) {
158: case SUDO_HOOK_RET_NEXT:
159: break;
160: case SUDO_HOOK_RET_ERROR:
161: case SUDO_HOOK_RET_STOP:
162: goto done;
163: default:
1.1.1.3 misho 164: warningx_nodebug("invalid unsetenv hook return value: %d", rc);
1.1 misho 165: break;
166: }
167: }
168: done:
1.1.1.2 misho 169: return rc;
1.1 misho 170: }
171:
172: /* Hook registration internals. */
173: static void
1.1.1.4 ! misho 174: register_hook_internal(struct sudo_hook_list *head,
1.1 misho 175: int (*hook_fn)(), void *closure)
176: {
1.1.1.4 ! misho 177: struct sudo_hook_entry *hook;
1.1 misho 178: debug_decl(register_hook_internal, SUDO_DEBUG_HOOKS)
179:
180: hook = ecalloc(1, sizeof(*hook));
181: hook->u.generic_fn = hook_fn;
182: hook->closure = closure;
1.1.1.4 ! misho 183: SLIST_INSERT_HEAD(head, hook, entries);
1.1 misho 184:
185: debug_return;
186: }
187:
188: /* Register the specified hook. */
189: int
190: register_hook(struct sudo_hook *hook)
191: {
192: int rval = 0;
193: debug_decl(register_hook, SUDO_DEBUG_HOOKS)
194:
195: if (SUDO_HOOK_VERSION_GET_MAJOR(hook->hook_version) != SUDO_HOOK_VERSION_MAJOR) {
196: /* Major versions must match. */
197: rval = -1;
198: } else {
199: switch (hook->hook_type) {
200: case SUDO_HOOK_GETENV:
201: register_hook_internal(&sudo_hook_getenv_list, hook->hook_fn,
202: hook->closure);
203: break;
204: case SUDO_HOOK_PUTENV:
205: register_hook_internal(&sudo_hook_putenv_list, hook->hook_fn,
206: hook->closure);
207: break;
208: case SUDO_HOOK_SETENV:
209: register_hook_internal(&sudo_hook_setenv_list, hook->hook_fn,
210: hook->closure);
211: break;
212: case SUDO_HOOK_UNSETENV:
213: register_hook_internal(&sudo_hook_unsetenv_list, hook->hook_fn,
214: hook->closure);
215: break;
216: default:
217: /* XXX - use define for unknown value */
218: rval = 1;
219: break;
220: }
221: }
222:
223: debug_return_int(rval);
224: }
225:
226: /* Hook deregistration internals. */
227: static void
1.1.1.4 ! misho 228: deregister_hook_internal(struct sudo_hook_list *head,
1.1 misho 229: int (*hook_fn)(), void *closure)
230: {
1.1.1.4 ! misho 231: struct sudo_hook_entry *hook, *prev = NULL;
1.1 misho 232: debug_decl(deregister_hook_internal, SUDO_DEBUG_HOOKS)
233:
1.1.1.4 ! misho 234: SLIST_FOREACH(hook, head, entries) {
1.1 misho 235: if (hook->u.generic_fn == hook_fn && hook->closure == closure) {
236: /* Remove from list and free. */
237: if (prev == NULL)
1.1.1.4 ! misho 238: SLIST_REMOVE_HEAD(head, entries);
1.1 misho 239: else
1.1.1.4 ! misho 240: SLIST_REMOVE_AFTER(prev, entries);
1.1 misho 241: efree(hook);
242: break;
243: }
1.1.1.4 ! misho 244: prev = hook;
1.1 misho 245: }
246:
247: debug_return;
248: }
249:
250: /* Deregister the specified hook. */
251: int
252: deregister_hook(struct sudo_hook *hook)
253: {
254: int rval = 0;
255: debug_decl(deregister_hook, SUDO_DEBUG_HOOKS)
256:
257: if (SUDO_HOOK_VERSION_GET_MAJOR(hook->hook_version) != SUDO_HOOK_VERSION_MAJOR) {
258: /* Major versions must match. */
259: rval = -1;
260: } else {
261: switch (hook->hook_type) {
262: case SUDO_HOOK_GETENV:
263: deregister_hook_internal(&sudo_hook_getenv_list, hook->hook_fn,
264: hook->closure);
265: break;
266: case SUDO_HOOK_PUTENV:
267: deregister_hook_internal(&sudo_hook_putenv_list, hook->hook_fn,
268: hook->closure);
269: break;
270: case SUDO_HOOK_SETENV:
271: deregister_hook_internal(&sudo_hook_setenv_list, hook->hook_fn,
272: hook->closure);
273: break;
274: case SUDO_HOOK_UNSETENV:
275: deregister_hook_internal(&sudo_hook_unsetenv_list, hook->hook_fn,
276: hook->closure);
277: break;
278: default:
279: /* XXX - use define for unknown value */
280: rval = 1;
281: break;
282: }
283: }
284:
285: debug_return_int(rval);
286: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>