Annotation of embedaddon/sudo/src/hooks.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (c) 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: #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"
43:
44: /* Singly linked hook list. */
45: struct sudo_hook_list {
46: struct sudo_hook_list *next;
47: union {
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;
53: } u;
54: void *closure;
55: };
56:
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;
62:
63: int
64: process_hooks_setenv(const char *name, const char *value, int overwrite)
65: {
66: struct sudo_hook_list *hook;
67: int rc = SUDO_HOOK_RET_NEXT;
68: debug_decl(process_hooks_setenv, SUDO_DEBUG_HOOKS)
69:
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);
73: switch (rc) {
74: case SUDO_HOOK_RET_NEXT:
75: break;
76: case SUDO_HOOK_RET_ERROR:
77: case SUDO_HOOK_RET_STOP:
78: goto done;
79: default:
80: warningx("invalid setenv hook return value: %d", rc);
81: break;
82: }
83: }
84: done:
85: debug_return_int(rc);
86: }
87:
88: int
89: process_hooks_putenv(char *string)
90: {
91: struct sudo_hook_list *hook;
92: int rc = SUDO_HOOK_RET_NEXT;
93: debug_decl(process_hooks_putenv, SUDO_DEBUG_HOOKS)
94:
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);
98: switch (rc) {
99: case SUDO_HOOK_RET_NEXT:
100: break;
101: case SUDO_HOOK_RET_ERROR:
102: case SUDO_HOOK_RET_STOP:
103: goto done;
104: default:
105: warningx("invalid putenv hook return value: %d", rc);
106: break;
107: }
108: }
109: done:
110: debug_return_int(rc);
111: }
112:
113: int
114: process_hooks_getenv(const char *name, char **value)
115: {
116: struct sudo_hook_list *hook;
117: char *val = NULL;
118: int rc = SUDO_HOOK_RET_NEXT;
119: debug_decl(process_hooks_getenv, SUDO_DEBUG_HOOKS)
120:
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);
124: switch (rc) {
125: case SUDO_HOOK_RET_NEXT:
126: break;
127: case SUDO_HOOK_RET_ERROR:
128: case SUDO_HOOK_RET_STOP:
129: goto done;
130: default:
131: warningx("invalid getenv hook return value: %d", rc);
132: break;
133: }
134: }
135: done:
136: if (val != NULL)
137: *value = val;
138: debug_return_int(rc);
139: }
140:
141: int
142: process_hooks_unsetenv(const char *name)
143: {
144: struct sudo_hook_list *hook;
145: int rc = SUDO_HOOK_RET_NEXT;
146: debug_decl(process_hooks_unsetenv, SUDO_DEBUG_HOOKS)
147:
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);
151: switch (rc) {
152: case SUDO_HOOK_RET_NEXT:
153: break;
154: case SUDO_HOOK_RET_ERROR:
155: case SUDO_HOOK_RET_STOP:
156: goto done;
157: default:
158: warningx("invalid unsetenv hook return value: %d", rc);
159: break;
160: }
161: }
162: done:
163: debug_return_int(rc);
164: }
165:
166: /* Hook registration internals. */
167: static void
168: register_hook_internal(struct sudo_hook_list **head,
169: int (*hook_fn)(), void *closure)
170: {
171: struct sudo_hook_list *hook;
172: debug_decl(register_hook_internal, SUDO_DEBUG_HOOKS)
173:
174: hook = ecalloc(1, sizeof(*hook));
175: hook->u.generic_fn = hook_fn;
176: hook->closure = closure;
177: hook->next = *head;
178: *head = hook;
179:
180: debug_return;
181: }
182:
183: /* Register the specified hook. */
184: int
185: register_hook(struct sudo_hook *hook)
186: {
187: int rval = 0;
188: debug_decl(register_hook, SUDO_DEBUG_HOOKS)
189:
190: if (SUDO_HOOK_VERSION_GET_MAJOR(hook->hook_version) != SUDO_HOOK_VERSION_MAJOR) {
191: /* Major versions must match. */
192: rval = -1;
193: } else {
194: switch (hook->hook_type) {
195: case SUDO_HOOK_GETENV:
196: register_hook_internal(&sudo_hook_getenv_list, hook->hook_fn,
197: hook->closure);
198: break;
199: case SUDO_HOOK_PUTENV:
200: register_hook_internal(&sudo_hook_putenv_list, hook->hook_fn,
201: hook->closure);
202: break;
203: case SUDO_HOOK_SETENV:
204: register_hook_internal(&sudo_hook_setenv_list, hook->hook_fn,
205: hook->closure);
206: break;
207: case SUDO_HOOK_UNSETENV:
208: register_hook_internal(&sudo_hook_unsetenv_list, hook->hook_fn,
209: hook->closure);
210: break;
211: default:
212: /* XXX - use define for unknown value */
213: rval = 1;
214: break;
215: }
216: }
217:
218: debug_return_int(rval);
219: }
220:
221: /* Hook deregistration internals. */
222: static void
223: deregister_hook_internal(struct sudo_hook_list **head,
224: int (*hook_fn)(), void *closure)
225: {
226: struct sudo_hook_list *hook, *prev = NULL;
227: debug_decl(deregister_hook_internal, SUDO_DEBUG_HOOKS)
228:
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. */
232: if (prev == NULL)
233: *head = hook->next;
234: else
235: prev->next = hook->next;
236: efree(hook);
237: break;
238: }
239: }
240:
241: debug_return;
242: }
243:
244: /* Deregister the specified hook. */
245: int
246: deregister_hook(struct sudo_hook *hook)
247: {
248: int rval = 0;
249: debug_decl(deregister_hook, SUDO_DEBUG_HOOKS)
250:
251: if (SUDO_HOOK_VERSION_GET_MAJOR(hook->hook_version) != SUDO_HOOK_VERSION_MAJOR) {
252: /* Major versions must match. */
253: rval = -1;
254: } else {
255: switch (hook->hook_type) {
256: case SUDO_HOOK_GETENV:
257: deregister_hook_internal(&sudo_hook_getenv_list, hook->hook_fn,
258: hook->closure);
259: break;
260: case SUDO_HOOK_PUTENV:
261: deregister_hook_internal(&sudo_hook_putenv_list, hook->hook_fn,
262: hook->closure);
263: break;
264: case SUDO_HOOK_SETENV:
265: deregister_hook_internal(&sudo_hook_setenv_list, hook->hook_fn,
266: hook->closure);
267: break;
268: case SUDO_HOOK_UNSETENV:
269: deregister_hook_internal(&sudo_hook_unsetenv_list, hook->hook_fn,
270: hook->closure);
271: break;
272: default:
273: /* XXX - use define for unknown value */
274: rval = 1;
275: break;
276: }
277: }
278:
279: debug_return_int(rval);
280: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>