File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / src / hooks.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 16:12:55 2014 UTC (10 years, 2 months ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_10p3_0, v1_8_10p3, HEAD
sudo v 1.8.10p3

    1: /*
    2:  * Copyright (c) 2012-2013 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: #include "queue.h"
   44: 
   45: /* Singly linked hook list. */
   46: struct sudo_hook_entry {
   47:     SLIST_ENTRY(sudo_hook_entry) entries;
   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: };
   57: SLIST_HEAD(sudo_hook_list, sudo_hook_entry);
   58: 
   59: /* Each hook type gets own hook list. */
   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);
   68: 
   69: /* NOTE: must not anything that might call setenv() */
   70: int
   71: process_hooks_setenv(const char *name, const char *value, int overwrite)
   72: {
   73:     struct sudo_hook_entry *hook;
   74:     int rc = SUDO_HOOK_RET_NEXT;
   75: 
   76:     /* First process the hooks. */
   77:     SLIST_FOREACH(hook, &sudo_hook_setenv_list, entries) {
   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:
   86: 		warningx_nodebug("invalid setenv hook return value: %d", rc);
   87: 		break;
   88: 	}
   89:     }
   90: done:
   91:     return rc;
   92: }
   93: 
   94: /* NOTE: must not anything that might call putenv() */
   95: int
   96: process_hooks_putenv(char *string)
   97: {
   98:     struct sudo_hook_entry *hook;
   99:     int rc = SUDO_HOOK_RET_NEXT;
  100: 
  101:     /* First process the hooks. */
  102:     SLIST_FOREACH(hook, &sudo_hook_putenv_list, entries) {
  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:
  111: 		warningx_nodebug("invalid putenv hook return value: %d", rc);
  112: 		break;
  113: 	}
  114:     }
  115: done:
  116:     return rc;
  117: }
  118: 
  119: /* NOTE: must not anything that might call getenv() */
  120: int
  121: process_hooks_getenv(const char *name, char **value)
  122: {
  123:     struct sudo_hook_entry *hook;
  124:     char *val = NULL;
  125:     int rc = SUDO_HOOK_RET_NEXT;
  126: 
  127:     /* First process the hooks. */
  128:     SLIST_FOREACH(hook, &sudo_hook_getenv_list, entries) {
  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:
  137: 		warningx_nodebug("invalid getenv hook return value: %d", rc);
  138: 		break;
  139: 	}
  140:     }
  141: done:
  142:     if (val != NULL)
  143: 	*value = val;
  144:     return rc;
  145: }
  146: 
  147: /* NOTE: must not anything that might call unsetenv() */
  148: int
  149: process_hooks_unsetenv(const char *name)
  150: {
  151:     struct sudo_hook_entry *hook;
  152:     int rc = SUDO_HOOK_RET_NEXT;
  153: 
  154:     /* First process the hooks. */
  155:     SLIST_FOREACH(hook, &sudo_hook_unsetenv_list, entries) {
  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:
  164: 		warningx_nodebug("invalid unsetenv hook return value: %d", rc);
  165: 		break;
  166: 	}
  167:     }
  168: done:
  169:     return rc;
  170: }
  171: 
  172: /* Hook registration internals. */
  173: static void
  174: register_hook_internal(struct sudo_hook_list *head,
  175:     int (*hook_fn)(), void *closure)
  176: {
  177:     struct sudo_hook_entry *hook;
  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;
  183:     SLIST_INSERT_HEAD(head, hook, entries);
  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
  228: deregister_hook_internal(struct sudo_hook_list *head,
  229:     int (*hook_fn)(), void *closure)
  230: {
  231:     struct sudo_hook_entry *hook, *prev = NULL;
  232:     debug_decl(deregister_hook_internal, SUDO_DEBUG_HOOKS)
  233: 
  234:     SLIST_FOREACH(hook, head, entries) {
  235: 	if (hook->u.generic_fn == hook_fn && hook->closure == closure) {
  236: 	    /* Remove from list and free. */
  237: 	    if (prev == NULL)
  238: 		SLIST_REMOVE_HEAD(head, entries);
  239: 	    else
  240: 		SLIST_REMOVE_AFTER(prev, entries);
  241: 	    efree(hook);
  242: 	    break;
  243: 	}
  244: 	prev = hook;
  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>