New debug framework for sudo and plugins using /etc/sudo.conf that
also supports function call tracing.
This commit is contained in:
@@ -42,11 +42,13 @@
|
||||
#else
|
||||
# include "compat/dlfcn.h"
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "sudo.h"
|
||||
#include "sudo_plugin.h"
|
||||
#include "sudo_plugin_int.h"
|
||||
#include "sudo_debug.h"
|
||||
|
||||
#ifndef RTLD_GLOBAL
|
||||
# define RTLD_GLOBAL 0
|
||||
@@ -56,19 +58,130 @@
|
||||
const char *noexec_path = _PATH_SUDO_NOEXEC;
|
||||
#endif
|
||||
|
||||
/* XXX - for parse_args() */
|
||||
const char *debug_file;
|
||||
const char *debug_flags;
|
||||
|
||||
struct sudo_conf_table {
|
||||
const char *name;
|
||||
unsigned int namelen;
|
||||
int (*setter)(const char *entry, void *data);
|
||||
};
|
||||
|
||||
struct sudo_conf_paths {
|
||||
const char *pname;
|
||||
unsigned int pnamelen;
|
||||
const char **pval;
|
||||
};
|
||||
|
||||
static int set_debug(const char *entry, void *data);
|
||||
static int set_path(const char *entry, void *data);
|
||||
static int set_plugin(const char *entry, void *data);
|
||||
|
||||
static struct plugin_info_list plugin_info_list;
|
||||
|
||||
static struct sudo_conf_table sudo_conf_table[] = {
|
||||
{ "Debug", sizeof("Debug") - 1, set_debug },
|
||||
{ "Path", sizeof("Path") - 1, set_path },
|
||||
{ "Plugin", sizeof("Plugin") - 1, set_plugin },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static struct sudo_conf_paths sudo_conf_paths[] = {
|
||||
{ "askpass", sizeof("askpass"), &askpass_path },
|
||||
#ifdef _PATH_SUDO_NOEXEC
|
||||
{ "noexec", sizeof("noexec"), &noexec_path },
|
||||
#endif
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static int
|
||||
set_debug(const char *entry, void *data)
|
||||
{
|
||||
size_t filelen;
|
||||
|
||||
/* Parse Debug line */
|
||||
debug_flags = strpbrk(entry, " \t");
|
||||
if (debug_flags == NULL)
|
||||
return FALSE;
|
||||
filelen = (size_t)(debug_flags - entry);
|
||||
while (isblank((unsigned char)*debug_flags))
|
||||
debug_flags++;
|
||||
|
||||
/* Set debug file and parse the flags. */
|
||||
debug_file = estrndup(entry, filelen);
|
||||
debug_flags = estrdup(debug_flags);
|
||||
sudo_debug_init(debug_file, debug_flags);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
set_path(const char *entry, void *data)
|
||||
{
|
||||
const char *name, *path;
|
||||
struct sudo_conf_paths *cur;
|
||||
|
||||
/* Parse Path line */
|
||||
name = entry;
|
||||
path = strpbrk(entry, " \t");
|
||||
if (path == NULL)
|
||||
return FALSE;
|
||||
while (isblank((unsigned char)*path))
|
||||
path++;
|
||||
|
||||
/* Match supported paths, ignore the rest. */
|
||||
for (cur = sudo_conf_paths; cur->pname != NULL; cur++) {
|
||||
if (strncasecmp(name, cur->pname, cur->pnamelen) == 0 &&
|
||||
isblank((unsigned char)name[cur->pnamelen])) {
|
||||
*(cur->pval) = estrdup(path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
set_plugin(const char *entry, void *data)
|
||||
{
|
||||
struct plugin_info_list *pil = data;
|
||||
struct plugin_info *info;
|
||||
const char *name, *path;
|
||||
size_t namelen;
|
||||
|
||||
/* Parse Plugin line */
|
||||
name = entry;
|
||||
path = strpbrk(entry, " \t");
|
||||
if (path == NULL)
|
||||
return FALSE;
|
||||
namelen = (size_t)(path - name);
|
||||
while (isblank((unsigned char)*path))
|
||||
path++;
|
||||
|
||||
info = emalloc(sizeof(*info));
|
||||
info->symbol_name = estrndup(name, namelen);
|
||||
info->path = estrdup(path);
|
||||
info->prev = info;
|
||||
info->next = NULL;
|
||||
tq_append(pil, info);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read in /etc/sudo.conf
|
||||
* Reads in /etc/sudo.conf
|
||||
* Returns a list of plugins.
|
||||
*/
|
||||
static struct plugin_info_list *
|
||||
sudo_read_conf(const char *conf_file)
|
||||
void
|
||||
sudo_read_conf(void)
|
||||
{
|
||||
FILE *fp;
|
||||
char *cp, *name, *path;
|
||||
struct sudo_conf_table *cur;
|
||||
struct plugin_info *info;
|
||||
static struct plugin_info_list pil; /* XXX */
|
||||
FILE *fp;
|
||||
char *cp;
|
||||
|
||||
if ((fp = fopen(conf_file, "r")) == NULL)
|
||||
if ((fp = fopen(_PATH_SUDO_CONF, "r")) == NULL)
|
||||
goto done;
|
||||
|
||||
while ((cp = sudo_parseln(fp)) != NULL) {
|
||||
@@ -76,49 +189,28 @@ sudo_read_conf(const char *conf_file)
|
||||
if (*cp == '\0')
|
||||
continue;
|
||||
|
||||
/* Look for a line starting with "Path" */
|
||||
if (strncasecmp(cp, "Path", 4) == 0) {
|
||||
/* Parse line */
|
||||
if ((name = strtok(cp + 4, " \t")) == NULL ||
|
||||
(path = strtok(NULL, " \t")) == NULL) {
|
||||
continue;
|
||||
for (cur = sudo_conf_table; cur->name != NULL; cur++) {
|
||||
if (strncasecmp(cp, cur->name, cur->namelen) == 0 &&
|
||||
isblank((unsigned char)cp[cur->namelen])) {
|
||||
cp += cur->namelen;
|
||||
while (isblank((unsigned char)*cp))
|
||||
cp++;
|
||||
if (cur->setter(cp, &plugin_info_list))
|
||||
break;
|
||||
}
|
||||
if (strcasecmp(name, "askpass") == 0)
|
||||
askpass_path = estrdup(path);
|
||||
#ifdef _PATH_SUDO_NOEXEC
|
||||
else if (strcasecmp(name, "noexec") == 0)
|
||||
noexec_path = estrdup(path);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Look for a line starting with "Plugin" */
|
||||
if (strncasecmp(cp, "Plugin", 6) == 0) {
|
||||
/* Parse line */
|
||||
if ((name = strtok(cp + 6, " \t")) == NULL ||
|
||||
(path = strtok(NULL, " \t")) == NULL) {
|
||||
continue;
|
||||
}
|
||||
info = emalloc(sizeof(*info));
|
||||
info->symbol_name = estrdup(name);
|
||||
info->path = estrdup(path);
|
||||
info->prev = info;
|
||||
info->next = NULL;
|
||||
tq_append(&pil, info);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
done:
|
||||
if (tq_empty(&pil)) {
|
||||
if (tq_empty(&plugin_info_list)) {
|
||||
/* Default policy plugin */
|
||||
info = emalloc(sizeof(*info));
|
||||
info->symbol_name = "sudoers_policy";
|
||||
info->path = SUDOERS_PLUGIN;
|
||||
info->prev = info;
|
||||
info->next = NULL;
|
||||
tq_append(&pil, info);
|
||||
tq_append(&plugin_info_list, info);
|
||||
|
||||
/* Default I/O plugin */
|
||||
info = emalloc(sizeof(*info));
|
||||
@@ -126,33 +218,27 @@ done:
|
||||
info->path = SUDOERS_PLUGIN;
|
||||
info->prev = info;
|
||||
info->next = NULL;
|
||||
tq_append(&pil, info);
|
||||
tq_append(&plugin_info_list, info);
|
||||
}
|
||||
|
||||
return &pil;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load the plugins listed in conf_file.
|
||||
* Load the plugins listed in sudo.conf.
|
||||
*/
|
||||
int
|
||||
sudo_load_plugins(const char *conf_file,
|
||||
struct plugin_container *policy_plugin,
|
||||
sudo_load_plugins(struct plugin_container *policy_plugin,
|
||||
struct plugin_container_list *io_plugins)
|
||||
{
|
||||
struct generic_plugin *plugin;
|
||||
struct plugin_container *container;
|
||||
struct plugin_info *info;
|
||||
struct plugin_info_list *plugin_list;
|
||||
struct stat sb;
|
||||
void *handle;
|
||||
char path[PATH_MAX];
|
||||
int rval = FALSE;
|
||||
|
||||
/* Parse sudo.conf */
|
||||
plugin_list = sudo_read_conf(conf_file);
|
||||
|
||||
tq_foreach_fwd(plugin_list, info) {
|
||||
/* Walk plugin list. */
|
||||
tq_foreach_fwd(&plugin_info_list, info) {
|
||||
if (info->path[0] == '/') {
|
||||
if (strlcpy(path, info->path, sizeof(path)) >= sizeof(path)) {
|
||||
warningx(_("%s: %s"), info->path, strerror(ENAMETOOLONG));
|
||||
@@ -205,7 +291,7 @@ sudo_load_plugins(const char *conf_file,
|
||||
if (plugin->type == SUDO_POLICY_PLUGIN) {
|
||||
if (policy_plugin->handle) {
|
||||
warningx(_("%s: only a single policy plugin may be loaded"),
|
||||
conf_file);
|
||||
_PATH_SUDO_CONF);
|
||||
goto done;
|
||||
}
|
||||
policy_plugin->handle = handle;
|
||||
@@ -223,7 +309,7 @@ sudo_load_plugins(const char *conf_file,
|
||||
}
|
||||
if (policy_plugin->handle == NULL) {
|
||||
warningx(_("%s: at least one policy plugin must be specified"),
|
||||
conf_file);
|
||||
_PATH_SUDO_CONF);
|
||||
goto done;
|
||||
}
|
||||
if (policy_plugin->u.policy->check_policy == NULL) {
|
||||
|
Reference in New Issue
Block a user