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>