File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sudo / src / hooks.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 10:46:13 2013 UTC (10 years, 11 months ago) by misho
Branches: sudo, MAIN
CVS tags: v1_8_8p0, v1_8_8, v1_8_7p0, v1_8_7, HEAD
1.8.7

    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: /* NOTE: must not anything that might call setenv() */
   64: int
   65: process_hooks_setenv(const char *name, const char *value, int overwrite)
   66: {
   67:     struct sudo_hook_list *hook;
   68:     int rc = SUDO_HOOK_RET_NEXT;
   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_nodebug("invalid setenv hook return value: %d", rc);
   81: 		break;
   82: 	}
   83:     }
   84: done:
   85:     return rc;
   86: }
   87: 
   88: /* NOTE: must not anything that might call putenv() */
   89: int
   90: process_hooks_putenv(char *string)
   91: {
   92:     struct sudo_hook_list *hook;
   93:     int rc = SUDO_HOOK_RET_NEXT;
   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_nodebug("invalid putenv hook return value: %d", rc);
  106: 		break;
  107: 	}
  108:     }
  109: done:
  110:     return rc;
  111: }
  112: 
  113: /* NOTE: must not anything that might call getenv() */
  114: int
  115: process_hooks_getenv(const char *name, char **value)
  116: {
  117:     struct sudo_hook_list *hook;
  118:     char *val = NULL;
  119:     int rc = SUDO_HOOK_RET_NEXT;
  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_nodebug("invalid getenv hook return value: %d", rc);
  132: 		break;
  133: 	}
  134:     }
  135: done:
  136:     if (val != NULL)
  137: 	*value = val;
  138:     return rc;
  139: }
  140: 
  141: /* NOTE: must not anything that might call unsetenv() */
  142: int
  143: process_hooks_unsetenv(const char *name)
  144: {
  145:     struct sudo_hook_list *hook;
  146:     int rc = SUDO_HOOK_RET_NEXT;
  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_nodebug("invalid unsetenv hook return value: %d", rc);
  159: 		break;
  160: 	}
  161:     }
  162: done:
  163:     return 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>