Annotation of embedaddon/sudo/src/hooks.c, revision 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>