Add support for deregistering hooks. If an I/O log plugin fails
to initialize, deregister its hooks (if any).
This commit is contained in:
214
src/hooks.c
214
src/hooks.c
@@ -41,42 +41,35 @@
|
|||||||
#include "sudo_plugin_int.h"
|
#include "sudo_plugin_int.h"
|
||||||
#include "sudo_debug.h"
|
#include "sudo_debug.h"
|
||||||
|
|
||||||
/* XXX - autogen from config file? */
|
/* Singly linked hook list. */
|
||||||
/* XXX - implement deregister_hook */
|
struct sudo_hook_list {
|
||||||
|
struct sudo_hook_list *next;
|
||||||
/* HOOK: setenv */
|
union {
|
||||||
|
sudo_hook_fn_t generic_fn;
|
||||||
static struct sudo_hook_setenv {
|
sudo_hook_fn_setenv_t setenv_fn;
|
||||||
struct sudo_hook_setenv *next;
|
sudo_hook_fn_unsetenv_t unsetenv_fn;
|
||||||
sudo_hook_fn_setenv_t hook_fn;
|
sudo_hook_fn_getenv_t getenv_fn;
|
||||||
|
sudo_hook_fn_putenv_t putenv_fn;
|
||||||
|
} u;
|
||||||
void *closure;
|
void *closure;
|
||||||
} *sudo_hook_setenv_list;
|
};
|
||||||
|
|
||||||
static void
|
/* Each hook type gets own hook list. */
|
||||||
register_hook_setenv(int (*hook_fn)(), void *closure)
|
static struct sudo_hook_list *sudo_hook_setenv_list;
|
||||||
{
|
static struct sudo_hook_list *sudo_hook_unsetenv_list;
|
||||||
struct sudo_hook_setenv *hook;
|
static struct sudo_hook_list *sudo_hook_getenv_list;
|
||||||
debug_decl(add_hook_setenv, SUDO_DEBUG_HOOKS)
|
static struct sudo_hook_list *sudo_hook_putenv_list;
|
||||||
|
|
||||||
hook = emalloc(sizeof(*hook));
|
|
||||||
hook->hook_fn = (sudo_hook_fn_setenv_t)hook_fn;
|
|
||||||
hook->closure = closure;
|
|
||||||
hook->next = sudo_hook_setenv_list;
|
|
||||||
sudo_hook_setenv_list = hook;
|
|
||||||
|
|
||||||
debug_return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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_setenv *hook;
|
struct sudo_hook_list *hook;
|
||||||
int rc = SUDO_HOOK_RET_NEXT;
|
int rc = SUDO_HOOK_RET_NEXT;
|
||||||
debug_decl(process_hooks_setenv, SUDO_DEBUG_HOOKS)
|
debug_decl(process_hooks_setenv, SUDO_DEBUG_HOOKS)
|
||||||
|
|
||||||
/* First process the hooks. */
|
/* First process the hooks. */
|
||||||
for (hook = sudo_hook_setenv_list; hook != NULL; hook = hook->next) {
|
for (hook = sudo_hook_setenv_list; hook != NULL; hook = hook->next) {
|
||||||
rc = hook->hook_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:
|
||||||
break;
|
break;
|
||||||
@@ -92,39 +85,16 @@ done:
|
|||||||
debug_return_int(rc);
|
debug_return_int(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* HOOK: putenv */
|
|
||||||
|
|
||||||
static struct sudo_hook_putenv {
|
|
||||||
struct sudo_hook_putenv *next;
|
|
||||||
sudo_hook_fn_putenv_t hook_fn;
|
|
||||||
void *closure;
|
|
||||||
} *sudo_hook_putenv_list;
|
|
||||||
|
|
||||||
static void
|
|
||||||
register_hook_putenv(int (*hook_fn)(), void *closure)
|
|
||||||
{
|
|
||||||
struct sudo_hook_putenv *hook;
|
|
||||||
debug_decl(add_hook_putenv, SUDO_DEBUG_HOOKS)
|
|
||||||
|
|
||||||
hook = emalloc(sizeof(*hook));
|
|
||||||
hook->hook_fn = (sudo_hook_fn_putenv_t)hook_fn;
|
|
||||||
hook->closure = closure;
|
|
||||||
hook->next = sudo_hook_putenv_list;
|
|
||||||
sudo_hook_putenv_list = hook;
|
|
||||||
|
|
||||||
debug_return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
process_hooks_putenv(char *string)
|
process_hooks_putenv(char *string)
|
||||||
{
|
{
|
||||||
struct sudo_hook_putenv *hook;
|
struct sudo_hook_list *hook;
|
||||||
int rc = SUDO_HOOK_RET_NEXT;
|
int rc = SUDO_HOOK_RET_NEXT;
|
||||||
debug_decl(process_hooks_putenv, SUDO_DEBUG_HOOKS)
|
debug_decl(process_hooks_putenv, SUDO_DEBUG_HOOKS)
|
||||||
|
|
||||||
/* First process the hooks. */
|
/* First process the hooks. */
|
||||||
for (hook = sudo_hook_putenv_list; hook != NULL; hook = hook->next) {
|
for (hook = sudo_hook_putenv_list; hook != NULL; hook = hook->next) {
|
||||||
rc = hook->hook_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:
|
||||||
break;
|
break;
|
||||||
@@ -140,40 +110,17 @@ done:
|
|||||||
debug_return_int(rc);
|
debug_return_int(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* HOOK: getenv */
|
|
||||||
|
|
||||||
static struct sudo_hook_getenv {
|
|
||||||
struct sudo_hook_getenv *next;
|
|
||||||
sudo_hook_fn_getenv_t hook_fn;
|
|
||||||
void *closure;
|
|
||||||
} *sudo_hook_getenv_list;
|
|
||||||
|
|
||||||
static void
|
|
||||||
register_hook_getenv(int (*hook_fn)(), void *closure)
|
|
||||||
{
|
|
||||||
struct sudo_hook_getenv *hook;
|
|
||||||
debug_decl(add_hook_putenv, SUDO_DEBUG_HOOKS)
|
|
||||||
|
|
||||||
hook = emalloc(sizeof(*hook));
|
|
||||||
hook->hook_fn = (sudo_hook_fn_getenv_t)hook_fn;
|
|
||||||
hook->closure = closure;
|
|
||||||
hook->next = sudo_hook_getenv_list;
|
|
||||||
sudo_hook_getenv_list = hook;
|
|
||||||
|
|
||||||
debug_return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
process_hooks_getenv(const char *name, char **value)
|
process_hooks_getenv(const char *name, char **value)
|
||||||
{
|
{
|
||||||
struct sudo_hook_getenv *hook;
|
struct sudo_hook_list *hook;
|
||||||
char *val = NULL;
|
char *val = NULL;
|
||||||
int rc = SUDO_HOOK_RET_NEXT;
|
int rc = SUDO_HOOK_RET_NEXT;
|
||||||
debug_decl(process_hooks_getenv, SUDO_DEBUG_HOOKS)
|
debug_decl(process_hooks_getenv, SUDO_DEBUG_HOOKS)
|
||||||
|
|
||||||
/* First process the hooks. */
|
/* First process the hooks. */
|
||||||
for (hook = sudo_hook_getenv_list; hook != NULL; hook = hook->next) {
|
for (hook = sudo_hook_getenv_list; hook != NULL; hook = hook->next) {
|
||||||
rc = hook->hook_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:
|
||||||
break;
|
break;
|
||||||
@@ -191,39 +138,16 @@ done:
|
|||||||
debug_return_int(rc);
|
debug_return_int(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* HOOK: unsetenv */
|
|
||||||
|
|
||||||
static struct sudo_hook_unsetenv {
|
|
||||||
struct sudo_hook_unsetenv *next;
|
|
||||||
sudo_hook_fn_unsetenv_t hook_fn;
|
|
||||||
void *closure;
|
|
||||||
} *sudo_hook_unsetenv_list;
|
|
||||||
|
|
||||||
static void
|
|
||||||
register_hook_unsetenv(int (*hook_fn)(), void *closure)
|
|
||||||
{
|
|
||||||
struct sudo_hook_unsetenv *hook;
|
|
||||||
debug_decl(add_hook_unsetenv, SUDO_DEBUG_HOOKS)
|
|
||||||
|
|
||||||
hook = emalloc(sizeof(*hook));
|
|
||||||
hook->hook_fn = (sudo_hook_fn_unsetenv_t)hook_fn;
|
|
||||||
hook->closure = closure;
|
|
||||||
hook->next = sudo_hook_unsetenv_list;
|
|
||||||
sudo_hook_unsetenv_list = hook;
|
|
||||||
|
|
||||||
debug_return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
process_hooks_unsetenv(const char *name)
|
process_hooks_unsetenv(const char *name)
|
||||||
{
|
{
|
||||||
struct sudo_hook_unsetenv *hook;
|
struct sudo_hook_list *hook;
|
||||||
int rc = SUDO_HOOK_RET_NEXT;
|
int rc = SUDO_HOOK_RET_NEXT;
|
||||||
debug_decl(process_hooks_unsetenv, SUDO_DEBUG_HOOKS)
|
debug_decl(process_hooks_unsetenv, SUDO_DEBUG_HOOKS)
|
||||||
|
|
||||||
/* First process the hooks. */
|
/* First process the hooks. */
|
||||||
for (hook = sudo_hook_unsetenv_list; hook != NULL; hook = hook->next) {
|
for (hook = sudo_hook_unsetenv_list; hook != NULL; hook = hook->next) {
|
||||||
rc = hook->hook_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:
|
||||||
break;
|
break;
|
||||||
@@ -239,6 +163,23 @@ done:
|
|||||||
debug_return_int(rc);
|
debug_return_int(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hook registration internals. */
|
||||||
|
static void
|
||||||
|
register_hook_internal(struct sudo_hook_list **head,
|
||||||
|
int (*hook_fn)(), void *closure)
|
||||||
|
{
|
||||||
|
struct sudo_hook_list *hook;
|
||||||
|
debug_decl(register_hook_internal, SUDO_DEBUG_HOOKS)
|
||||||
|
|
||||||
|
hook = emalloc(sizeof(*hook));
|
||||||
|
hook->u.generic_fn = hook_fn;
|
||||||
|
hook->closure = closure;
|
||||||
|
hook->next = *head;
|
||||||
|
*head = hook;
|
||||||
|
|
||||||
|
debug_return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Register the specified hook. */
|
/* Register the specified hook. */
|
||||||
int
|
int
|
||||||
register_hook(struct sudo_hook *hook)
|
register_hook(struct sudo_hook *hook)
|
||||||
@@ -252,16 +193,81 @@ register_hook(struct sudo_hook *hook)
|
|||||||
} else {
|
} else {
|
||||||
switch (hook->hook_type) {
|
switch (hook->hook_type) {
|
||||||
case SUDO_HOOK_GETENV:
|
case SUDO_HOOK_GETENV:
|
||||||
register_hook_getenv(hook->hook_fn, hook->closure);
|
register_hook_internal(&sudo_hook_getenv_list, hook->hook_fn,
|
||||||
|
hook->closure);
|
||||||
break;
|
break;
|
||||||
case SUDO_HOOK_PUTENV:
|
case SUDO_HOOK_PUTENV:
|
||||||
register_hook_putenv(hook->hook_fn, hook->closure);
|
register_hook_internal(&sudo_hook_putenv_list, hook->hook_fn,
|
||||||
|
hook->closure);
|
||||||
break;
|
break;
|
||||||
case SUDO_HOOK_SETENV:
|
case SUDO_HOOK_SETENV:
|
||||||
register_hook_setenv(hook->hook_fn, hook->closure);
|
register_hook_internal(&sudo_hook_setenv_list, hook->hook_fn,
|
||||||
|
hook->closure);
|
||||||
break;
|
break;
|
||||||
case SUDO_HOOK_UNSETENV:
|
case SUDO_HOOK_UNSETENV:
|
||||||
register_hook_unsetenv(hook->hook_fn, hook->closure);
|
register_hook_internal(&sudo_hook_unsetenv_list, hook->hook_fn,
|
||||||
|
hook->closure);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* XXX - use define for unknown value */
|
||||||
|
rval = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_return_int(rval);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hook deregistration internals. */
|
||||||
|
static void
|
||||||
|
deregister_hook_internal(struct sudo_hook_list **head,
|
||||||
|
int (*hook_fn)(), void *closure)
|
||||||
|
{
|
||||||
|
struct sudo_hook_list *hook, *prev = NULL;
|
||||||
|
debug_decl(deregister_hook_internal, SUDO_DEBUG_HOOKS)
|
||||||
|
|
||||||
|
for (hook = *head, prev = NULL; hook != NULL; prev = hook, hook = hook->next) {
|
||||||
|
if (hook->u.generic_fn == hook_fn && hook->closure == closure) {
|
||||||
|
/* Remove from list and free. */
|
||||||
|
if (prev == NULL)
|
||||||
|
*head = hook->next;
|
||||||
|
else
|
||||||
|
prev->next = hook->next;
|
||||||
|
efree(hook);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deregister the specified hook. */
|
||||||
|
int
|
||||||
|
deregister_hook(struct sudo_hook *hook)
|
||||||
|
{
|
||||||
|
int rval = 0;
|
||||||
|
debug_decl(deregister_hook, SUDO_DEBUG_HOOKS)
|
||||||
|
|
||||||
|
if (SUDO_HOOK_VERSION_GET_MAJOR(hook->hook_version) != SUDO_HOOK_VERSION_MAJOR) {
|
||||||
|
/* Major versions must match. */
|
||||||
|
rval = -1;
|
||||||
|
} else {
|
||||||
|
switch (hook->hook_type) {
|
||||||
|
case SUDO_HOOK_GETENV:
|
||||||
|
deregister_hook_internal(&sudo_hook_getenv_list, hook->hook_fn,
|
||||||
|
hook->closure);
|
||||||
|
break;
|
||||||
|
case SUDO_HOOK_PUTENV:
|
||||||
|
deregister_hook_internal(&sudo_hook_putenv_list, hook->hook_fn,
|
||||||
|
hook->closure);
|
||||||
|
break;
|
||||||
|
case SUDO_HOOK_SETENV:
|
||||||
|
deregister_hook_internal(&sudo_hook_setenv_list, hook->hook_fn,
|
||||||
|
hook->closure);
|
||||||
|
break;
|
||||||
|
case SUDO_HOOK_UNSETENV:
|
||||||
|
deregister_hook_internal(&sudo_hook_unsetenv_list, hook->hook_fn,
|
||||||
|
hook->closure);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* XXX - use define for unknown value */
|
/* XXX - use define for unknown value */
|
||||||
|
27
src/sudo.c
27
src/sudo.c
@@ -139,6 +139,7 @@ static int iolog_open(struct plugin_container *plugin, char * const settings[],
|
|||||||
static void iolog_close(struct plugin_container *plugin, int exit_status,
|
static void iolog_close(struct plugin_container *plugin, int exit_status,
|
||||||
int error);
|
int error);
|
||||||
static int iolog_show_version(struct plugin_container *plugin, int verbose);
|
static int iolog_show_version(struct plugin_container *plugin, int verbose);
|
||||||
|
static void iolog_unlink(struct plugin_container *plugin);
|
||||||
|
|
||||||
#ifdef RLIMIT_CORE
|
#ifdef RLIMIT_CORE
|
||||||
static struct rlimit corelimit;
|
static struct rlimit corelimit;
|
||||||
@@ -275,8 +276,8 @@ main(int argc, char *argv[], char *envp[])
|
|||||||
case 1:
|
case 1:
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
/* I/O plugin asked to be disabled, remove from list. */
|
/* I/O plugin asked to be disabled, remove and free. */
|
||||||
tq_remove(&io_plugins, plugin);
|
iolog_unlink(plugin);
|
||||||
break;
|
break;
|
||||||
case -2:
|
case -2:
|
||||||
usage(1);
|
usage(1);
|
||||||
@@ -1197,3 +1198,25 @@ iolog_show_version(struct plugin_container *plugin, int verbose)
|
|||||||
debug_decl(iolog_show_version, SUDO_DEBUG_PCOMM)
|
debug_decl(iolog_show_version, SUDO_DEBUG_PCOMM)
|
||||||
debug_return_bool(plugin->u.io->show_version(verbose));
|
debug_return_bool(plugin->u.io->show_version(verbose));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove the specified I/O logging plugin from the io_plugins list.
|
||||||
|
* Deregisters any hooks before unlinking, then frees the container.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
iolog_unlink(struct plugin_container *plugin)
|
||||||
|
{
|
||||||
|
debug_decl(iolog_unlink, SUDO_DEBUG_PCOMM)
|
||||||
|
|
||||||
|
/* Deregister hooks, if any. */
|
||||||
|
if (plugin->u.io->version >= SUDO_API_MKVERSION(1, 2)) {
|
||||||
|
if (plugin->u.io->deregister_hooks != NULL)
|
||||||
|
plugin->u.io->deregister_hooks(SUDO_HOOK_VERSION,
|
||||||
|
deregister_hook);
|
||||||
|
}
|
||||||
|
/* Remove from io_plugins list and free. */
|
||||||
|
tq_remove(&io_plugins, plugin);
|
||||||
|
efree(plugin);
|
||||||
|
|
||||||
|
debug_return;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user