Annotation of embedaddon/sudo/src/hooks.c, revision 1.1.1.3

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: 
1.1.1.2   misho      63: /* NOTE: must not anything that might call setenv() */
1.1       misho      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:
1.1.1.3 ! misho      80:                warningx_nodebug("invalid setenv hook return value: %d", rc);
1.1       misho      81:                break;
                     82:        }
                     83:     }
                     84: done:
1.1.1.2   misho      85:     return rc;
1.1       misho      86: }
                     87: 
1.1.1.2   misho      88: /* NOTE: must not anything that might call putenv() */
1.1       misho      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:
1.1.1.3 ! misho     105:                warningx_nodebug("invalid putenv hook return value: %d", rc);
1.1       misho     106:                break;
                    107:        }
                    108:     }
                    109: done:
1.1.1.2   misho     110:     return rc;
1.1       misho     111: }
                    112: 
1.1.1.2   misho     113: /* NOTE: must not anything that might call getenv() */
1.1       misho     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:
1.1.1.3 ! misho     131:                warningx_nodebug("invalid getenv hook return value: %d", rc);
1.1       misho     132:                break;
                    133:        }
                    134:     }
                    135: done:
                    136:     if (val != NULL)
                    137:        *value = val;
1.1.1.2   misho     138:     return rc;
1.1       misho     139: }
                    140: 
1.1.1.2   misho     141: /* NOTE: must not anything that might call unsetenv() */
1.1       misho     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:
1.1.1.3 ! misho     158:                warningx_nodebug("invalid unsetenv hook return value: %d", rc);
1.1       misho     159:                break;
                    160:        }
                    161:     }
                    162: done:
1.1.1.2   misho     163:     return rc;
1.1       misho     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>