|
version 1.1.1.3, 2013/07/22 10:46:13
|
version 1.1.1.4, 2014/06/15 16:12:55
|
|
Line 1
|
Line 1
|
| /* |
/* |
| * Copyright (c) 2012 Todd C. Miller <Todd.Miller@courtesan.com> | * Copyright (c) 2012-2013 Todd C. Miller <Todd.Miller@courtesan.com> |
| * |
* |
| * Permission to use, copy, modify, and distribute this software for any |
* Permission to use, copy, modify, and distribute this software for any |
| * purpose with or without fee is hereby granted, provided that the above |
* purpose with or without fee is hereby granted, provided that the above |
|
Line 40
|
Line 40
|
| #include "sudo_plugin.h" |
#include "sudo_plugin.h" |
| #include "sudo_plugin_int.h" |
#include "sudo_plugin_int.h" |
| #include "sudo_debug.h" |
#include "sudo_debug.h" |
| |
#include "queue.h" |
| |
|
| /* Singly linked hook list. */ |
/* Singly linked hook list. */ |
| struct sudo_hook_list { | struct sudo_hook_entry { |
| struct sudo_hook_list *next; | SLIST_ENTRY(sudo_hook_entry) entries; |
| union { |
union { |
| sudo_hook_fn_t generic_fn; |
sudo_hook_fn_t generic_fn; |
| sudo_hook_fn_setenv_t setenv_fn; |
sudo_hook_fn_setenv_t setenv_fn; |
|
Line 53 struct sudo_hook_list {
|
Line 54 struct sudo_hook_list {
|
| } u; |
} u; |
| void *closure; |
void *closure; |
| }; |
}; |
| |
SLIST_HEAD(sudo_hook_list, sudo_hook_entry); |
| |
|
| /* Each hook type gets own hook list. */ |
/* Each hook type gets own hook list. */ |
| static struct sudo_hook_list *sudo_hook_setenv_list; | static struct sudo_hook_list sudo_hook_setenv_list = |
| static struct sudo_hook_list *sudo_hook_unsetenv_list; | SLIST_HEAD_INITIALIZER(sudo_hook_setenv_list); |
| static struct sudo_hook_list *sudo_hook_getenv_list; | static struct sudo_hook_list sudo_hook_unsetenv_list = |
| static struct sudo_hook_list *sudo_hook_putenv_list; | SLIST_HEAD_INITIALIZER(sudo_hook_unsetenv_list); |
| | static struct sudo_hook_list sudo_hook_getenv_list = |
| | SLIST_HEAD_INITIALIZER(sudo_hook_getenv_list); |
| | static struct sudo_hook_list sudo_hook_putenv_list = |
| | SLIST_HEAD_INITIALIZER(sudo_hook_putenv_list); |
| |
|
| /* NOTE: must not anything that might call setenv() */ |
/* NOTE: must not anything that might call setenv() */ |
| int |
int |
| process_hooks_setenv(const char *name, const char *value, int overwrite) |
process_hooks_setenv(const char *name, const char *value, int overwrite) |
| { |
{ |
| struct sudo_hook_list *hook; | struct sudo_hook_entry *hook; |
| int rc = SUDO_HOOK_RET_NEXT; |
int rc = SUDO_HOOK_RET_NEXT; |
| |
|
| /* First process the hooks. */ |
/* First process the hooks. */ |
| for (hook = sudo_hook_setenv_list; hook != NULL; hook = hook->next) { | SLIST_FOREACH(hook, &sudo_hook_setenv_list, entries) { |
| rc = hook->u.setenv_fn(name, value, overwrite, hook->closure); |
rc = hook->u.setenv_fn(name, value, overwrite, hook->closure); |
| switch (rc) { |
switch (rc) { |
| case SUDO_HOOK_RET_NEXT: |
case SUDO_HOOK_RET_NEXT: |
|
Line 89 done:
|
Line 95 done:
|
| int |
int |
| process_hooks_putenv(char *string) |
process_hooks_putenv(char *string) |
| { |
{ |
| struct sudo_hook_list *hook; | struct sudo_hook_entry *hook; |
| int rc = SUDO_HOOK_RET_NEXT; |
int rc = SUDO_HOOK_RET_NEXT; |
| |
|
| /* First process the hooks. */ |
/* First process the hooks. */ |
| for (hook = sudo_hook_putenv_list; hook != NULL; hook = hook->next) { | SLIST_FOREACH(hook, &sudo_hook_putenv_list, entries) { |
| rc = hook->u.putenv_fn(string, hook->closure); |
rc = hook->u.putenv_fn(string, hook->closure); |
| switch (rc) { |
switch (rc) { |
| case SUDO_HOOK_RET_NEXT: |
case SUDO_HOOK_RET_NEXT: |
|
Line 114 done:
|
Line 120 done:
|
| int |
int |
| process_hooks_getenv(const char *name, char **value) |
process_hooks_getenv(const char *name, char **value) |
| { |
{ |
| struct sudo_hook_list *hook; | struct sudo_hook_entry *hook; |
| char *val = NULL; |
char *val = NULL; |
| int rc = SUDO_HOOK_RET_NEXT; |
int rc = SUDO_HOOK_RET_NEXT; |
| |
|
| /* First process the hooks. */ |
/* First process the hooks. */ |
| for (hook = sudo_hook_getenv_list; hook != NULL; hook = hook->next) { | SLIST_FOREACH(hook, &sudo_hook_getenv_list, entries) { |
| rc = hook->u.getenv_fn(name, &val, hook->closure); |
rc = hook->u.getenv_fn(name, &val, hook->closure); |
| switch (rc) { |
switch (rc) { |
| case SUDO_HOOK_RET_NEXT: |
case SUDO_HOOK_RET_NEXT: |
|
Line 142 done:
|
Line 148 done:
|
| int |
int |
| process_hooks_unsetenv(const char *name) |
process_hooks_unsetenv(const char *name) |
| { |
{ |
| struct sudo_hook_list *hook; | struct sudo_hook_entry *hook; |
| int rc = SUDO_HOOK_RET_NEXT; |
int rc = SUDO_HOOK_RET_NEXT; |
| |
|
| /* First process the hooks. */ |
/* First process the hooks. */ |
| for (hook = sudo_hook_unsetenv_list; hook != NULL; hook = hook->next) { | SLIST_FOREACH(hook, &sudo_hook_unsetenv_list, entries) { |
| rc = hook->u.unsetenv_fn(name, hook->closure); |
rc = hook->u.unsetenv_fn(name, hook->closure); |
| switch (rc) { |
switch (rc) { |
| case SUDO_HOOK_RET_NEXT: |
case SUDO_HOOK_RET_NEXT: |
|
Line 165 done:
|
Line 171 done:
|
| |
|
| /* Hook registration internals. */ |
/* Hook registration internals. */ |
| static void |
static void |
| register_hook_internal(struct sudo_hook_list **head, | register_hook_internal(struct sudo_hook_list *head, |
| int (*hook_fn)(), void *closure) |
int (*hook_fn)(), void *closure) |
| { |
{ |
| struct sudo_hook_list *hook; | struct sudo_hook_entry *hook; |
| debug_decl(register_hook_internal, SUDO_DEBUG_HOOKS) |
debug_decl(register_hook_internal, SUDO_DEBUG_HOOKS) |
| |
|
| hook = ecalloc(1, sizeof(*hook)); |
hook = ecalloc(1, sizeof(*hook)); |
| hook->u.generic_fn = hook_fn; |
hook->u.generic_fn = hook_fn; |
| hook->closure = closure; |
hook->closure = closure; |
| hook->next = *head; | SLIST_INSERT_HEAD(head, hook, entries); |
| *head = hook; | |
| |
|
| debug_return; |
debug_return; |
| } |
} |
|
Line 220 register_hook(struct sudo_hook *hook)
|
Line 225 register_hook(struct sudo_hook *hook)
|
| |
|
| /* Hook deregistration internals. */ |
/* Hook deregistration internals. */ |
| static void |
static void |
| deregister_hook_internal(struct sudo_hook_list **head, | deregister_hook_internal(struct sudo_hook_list *head, |
| int (*hook_fn)(), void *closure) |
int (*hook_fn)(), void *closure) |
| { |
{ |
| struct sudo_hook_list *hook, *prev = NULL; | struct sudo_hook_entry *hook, *prev = NULL; |
| debug_decl(deregister_hook_internal, SUDO_DEBUG_HOOKS) |
debug_decl(deregister_hook_internal, SUDO_DEBUG_HOOKS) |
| |
|
| for (hook = *head, prev = NULL; hook != NULL; prev = hook, hook = hook->next) { | SLIST_FOREACH(hook, head, entries) { |
| if (hook->u.generic_fn == hook_fn && hook->closure == closure) { |
if (hook->u.generic_fn == hook_fn && hook->closure == closure) { |
| /* Remove from list and free. */ |
/* Remove from list and free. */ |
| if (prev == NULL) |
if (prev == NULL) |
| *head = hook->next; | SLIST_REMOVE_HEAD(head, entries); |
| else |
else |
| prev->next = hook->next; | SLIST_REMOVE_AFTER(prev, entries); |
| efree(hook); |
efree(hook); |
| break; |
break; |
| } |
} |
| |
prev = hook; |
| } |
} |
| |
|
| debug_return; |
debug_return; |