New debug framework for sudo and plugins using /etc/sudo.conf that

also supports function call tracing.
This commit is contained in:
Todd C. Miller
2011-10-22 14:00:52 -04:00
parent 697caf8df3
commit 53e3ad11b5
10 changed files with 769 additions and 76 deletions

View File

@@ -16,6 +16,7 @@ common/fmt_string.c
common/lbuf.c
common/list.c
common/setgroups.c
common/sudo_debug.c
common/term.c
common/zero_bytes.c
compat/Makefile.in
@@ -101,6 +102,7 @@ include/gettext.h
include/lbuf.h
include/list.h
include/missing.h
include/sudo_debug.h
include/sudo_plugin.h
indent.pro
install-sh

View File

@@ -42,8 +42,8 @@ DEFS = @OSDEFS@
SHELL = @SHELL@
LTOBJS = alloc.lo atobool.lo fileops.lo fmt_string.lo \
lbuf.lo list.lo setgroups.lo term.lo zero_bytes.lo @COMMON_OBJS@
LTOBJS = alloc.lo atobool.lo fileops.lo fmt_string.lo lbuf.lo list.lo \
setgroups.lo sudo_debug.lo term.lo zero_bytes.lo @COMMON_OBJS@
all: libcommon.la
@@ -115,6 +115,10 @@ list.lo: $(srcdir)/list.c $(top_builddir)/config.h $(incdir)/missing.h \
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/list.c
setgroups.lo: $(srcdir)/setgroups.c $(top_builddir)/config.h $(incdir)/missing.h
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/setgroups.c
sudo_debug.lo: $(srcdir)/sudo_debug.c $(top_builddir)/config.h \
$(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \
$(incdir)/gettext.h $(incdir)/sudo_debug.h
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sudo_debug.c
term.lo: $(srcdir)/term.c $(top_builddir)/config.h $(incdir)/missing.h
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/term.c
zero_bytes.lo: $(srcdir)/zero_bytes.c $(top_builddir)/config.h \

381
common/sudo_debug.c Normal file
View File

@@ -0,0 +1,381 @@
/*
* Copyright (c) 2011 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <config.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#ifdef HAVE_STRING_H
# include <string.h>
#endif /* HAVE_STRING_H */
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif /* HAVE_STRINGS_H */
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include "missing.h"
#include "alloc.h"
#include "error.h"
#include "gettext.h"
#include "sudo_debug.h"
/*
* The debug priorities and subsystems are currently hard-coded.
* In the future we might consider allowing plugins to register their
* own subsystems and provide direct access to the debugging API.
*/
/* Note: this must match the order in sudo_debug.h */
const char *const sudo_debug_priorities[] = {
"crit",
"syserr",
"progerr",
"warn",
"notice",
"diag",
"info",
"trace",
"debug",
NULL
};
/* Note: this must match the order in sudo_debug.h */
const char *const sudo_debug_subsystems[] = {
"main",
"memory",
"args",
"exec",
"pty",
"utmp",
"conv",
"pcomm",
"util",
"list",
"netif",
"audit",
"edit",
"selinux",
"ldap",
"match",
"parser",
"alias",
"defaults",
"auth",
"env",
"logging",
"nss",
"rbtree",
"perms",
"plugin",
NULL
};
#define NUM_SUBSYSTEMS (sizeof(sudo_debug_subsystems) / sizeof(sudo_debug_subsystems[0]) - 1)
static int sudo_debug_settings[NUM_SUBSYSTEMS];
static int sudo_debug_fd = -1;
/*
* Parse settings string from sudo.conf and open debugfile.
* Returns 1 on success, 0 if cannot open debugfile.
* Unsupported subsystems and priorities are silently ignored.
*/
int sudo_debug_init(const char *debugfile, const char *settings)
{
char *buf, *cp, *subsys, *pri;
int i, j;
/* Init per-subsystems settings to -1 since 0 is a valid priority. */
for (i = 0; i < NUM_SUBSYSTEMS; i++)
sudo_debug_settings[i] = -1;
/* Open debug file descriptor. */
if (sudo_debug_fd != -1)
close(sudo_debug_fd);
sudo_debug_fd = open(debugfile, O_WRONLY|O_APPEND|O_CREAT, S_IRUSR|S_IWUSR);
if (sudo_debug_fd == -1)
return 0;
(void)fcntl(sudo_debug_fd, F_SETFD, FD_CLOEXEC);
/* Parse settings string. */
buf = estrdup(settings);
for ((cp = strtok(buf, ",")); cp != NULL; (cp = strtok(NULL, ","))) {
/* Should be in the form subsys@pri. */
subsys = cp;
if ((pri = strchr(cp, '@')) == NULL)
continue;
*pri++ = '\0';
/* Look up priority and subsystem, fill in sudo_debug_settings[]. */
for (i = 0; sudo_debug_priorities[i] != NULL; i++) {
if (strcasecmp(pri, sudo_debug_priorities[i]) == 0) {
for (j = 0; sudo_debug_subsystems[j] != NULL; j++) {
if (strcasecmp(subsys, "all") == 0) {
sudo_debug_settings[j] = i;
continue;
}
if (strcasecmp(subsys, sudo_debug_subsystems[j]) == 0) {
sudo_debug_settings[j] = i;
break;
}
}
break;
}
}
}
efree(buf);
return 1;
}
void
sudo_debug_enter(const char *func, const char *file, int line,
int subsys)
{
sudo_debug_printf2(subsys | SUDO_DEBUG_TRACE, "-> %s @ %s:%d", func,
file, line);
}
void sudo_debug_exit(const char *func, const char *file, int line,
int subsys)
{
sudo_debug_printf2(subsys | SUDO_DEBUG_TRACE, "<- %s @ %s:%d", func,
file, line);
}
void sudo_debug_exit_int(const char *func, const char *file, int line,
int subsys, int rval)
{
sudo_debug_printf2(subsys | SUDO_DEBUG_TRACE, "<- %s @ %s:%d := %d", func,
file, line, rval);
}
void sudo_debug_exit_long(const char *func, const char *file, int line,
int subsys, long rval)
{
sudo_debug_printf2(subsys | SUDO_DEBUG_TRACE, "<- %s @ %s:%d := %ld", func,
file, line, rval);
}
void sudo_debug_exit_size_t(const char *func, const char *file, int line,
int subsys, size_t rval)
{
/* XXX - should use %zu but snprintf.c doesn't support it */
sudo_debug_printf2(subsys | SUDO_DEBUG_TRACE, "<- %s @ %s:%d := %lu", func,
file, line, (unsigned long)rval);
}
void sudo_debug_exit_bool(const char *func, const char *file, int line,
int subsys, int rval)
{
if (rval == 0 || rval == 1) {
sudo_debug_printf2(subsys | SUDO_DEBUG_TRACE, "<- %s @ %s:%d := %s",
func, file, line, rval ? "true" : "false");
} else {
sudo_debug_printf2(subsys | SUDO_DEBUG_TRACE, "<- %s @ %s:%d := %d",
func, file, line, rval);
}
}
void sudo_debug_exit_str(const char *func, const char *file, int line,
int subsys, const char *rval)
{
sudo_debug_printf2(subsys | SUDO_DEBUG_TRACE, "<- %s @ %s:%d := %s", func,
file, line, rval ? rval : "(null)");
}
void sudo_debug_exit_str_masked(const char *func, const char *file, int line,
int subsys, const char *rval)
{
static const char stars[] = "********************************************************************************";
int len = rval ? strlen(rval) : sizeof("(null)") - 1;
sudo_debug_printf2(subsys | SUDO_DEBUG_TRACE, "<- %s @ %s:%d := %.*s", func,
file, line, len, rval ? stars : "(null)");
}
void sudo_debug_exit_ptr(const char *func, const char *file, int line,
int subsys, const void *rval)
{
sudo_debug_printf2(subsys | SUDO_DEBUG_TRACE, "<- %s @ %s:%d := %p", func,
file, line, rval);
}
void
sudo_debug_write(const char *str, int len)
{
char *timestr;
time_t now;
ssize_t n;
struct iovec iov[5];
int iovcnt = 4;
if (sudo_debug_fd == -1 || len <= 0)
return;
/* Prepend program name with trailing space. */
iov[1].iov_base = (char *)getprogname();
iov[1].iov_len = strlen(iov[1].iov_base);
iov[2].iov_base = " ";
iov[2].iov_len = 1;
/* Add string along with newline if it doesn't have one. */
iov[3].iov_base = (char *)str;
iov[3].iov_len = len;
if (str[len - 1] != '\n') {
/* force newline */
iov[4].iov_base = "\n";
iov[4].iov_len = 1;
iovcnt++;
}
/* Do timestamp last due to ctime's static buffer. */
now = time(NULL);
timestr = ctime(&now) + 4;
timestr[15] = ' '; /* replace year with a space */
timestr[16] = '\0';
iov[0].iov_base = timestr;
iov[0].iov_len = 16;
/* Write message in a single syscall */
n = writev(sudo_debug_fd, iov, iovcnt);
}
void
sudo_debug_printf2(int level, const char *fmt, ...)
{
int buflen, pri, subsys;
va_list ap;
char *buf;
if (sudo_debug_fd == -1)
return;
/* Extract pri and subsystem from level. */
pri = SUDO_DEBUG_PRI(level);
subsys = SUDO_DEBUG_SUBSYS(level);
/* Make sure we want debug info at this level. */
if (subsys >= NUM_SUBSYSTEMS || sudo_debug_settings[subsys] < pri)
return;
va_start(ap, fmt);
buflen = vasprintf(&buf, fmt, ap);
va_end(ap);
if (buflen != -1) {
sudo_debug_write(buf, buflen);
free(buf);
}
}
void
sudo_debug_execve2(int level, const char *path, char *const argv[], char *const envp[])
{
char * const *av;
char *buf, *cp;
int buflen, pri, subsys, log_envp = 0;
size_t plen;
if (sudo_debug_fd == -1)
return;
#define EXEC_PREFIX "exec "
if (sudo_debug_fd == -1)
return;
/* Extract pri and subsystem from level. */
pri = SUDO_DEBUG_PRI(level);
subsys = SUDO_DEBUG_SUBSYS(level);
/* Make sure we want debug info at this level. */
if (subsys >= NUM_SUBSYSTEMS || sudo_debug_settings[subsys] < pri)
return;
/* Log envp for debug level "debug". */
if (sudo_debug_settings[subsys] >= SUDO_DEBUG_DEBUG - 1 && envp[0] != NULL)
log_envp = 1;
/* Alloc and build up buffer. */
plen = strlen(path);
buflen = sizeof(EXEC_PREFIX) -1 + plen;
if (argv[0] != NULL) {
buflen += sizeof(" []") - 1;
for (av = argv; *av; av++)
buflen += strlen(*av) + 1;
buflen--;
}
if (log_envp) {
buflen += sizeof(" []") - 1;
for (av = envp; *av; av++)
buflen += strlen(*av) + 1;
buflen--;
}
buf = malloc(buflen + 1);
if (buf == NULL)
return;
/* Copy prefix and command. */
memcpy(buf, EXEC_PREFIX, sizeof(EXEC_PREFIX) - 1);
cp = buf + sizeof(EXEC_PREFIX) - 1;
memcpy(cp, path, plen);
cp += plen;
/* Copy argv. */
if (argv[0] != NULL) {
*cp++ = ' ';
*cp++ = '[';
for (av = argv; *av; av++) {
size_t avlen = strlen(*av);
memcpy(cp, *av, avlen);
cp += avlen;
*cp++ = ' ';
}
cp[-1] = ']';
}
if (log_envp) {
*cp++ = ' ';
*cp++ = '[';
for (av = envp; *av; av++) {
size_t avlen = strlen(*av);
memcpy(cp, *av, avlen);
cp += avlen;
*cp++ = ' ';
}
cp[-1] = ']';
}
*cp = '\0';
sudo_debug_write(buf, buflen);
free(buf);
}

197
include/sudo_debug.h Normal file
View File

@@ -0,0 +1,197 @@
/*
* Copyright (c) 2011 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _SUDO_DEBUG_H
#define _SUDO_DEBUG_H
#include <stdarg.h>
/*
* The priority and subsystem are encoded in a single 32-bit value.
* The lower 4 bits are the priority and the top 28 bits are the subsystem.
* This allows for 16 priorities and a very large number of subsystems.
*/
/*
* Sudo debug priorities, ordered least to most verbose,
* in other words, highest to lowest priority. Max pri is 15.
* Note: order must match sudo_debug_priorities[]
*/
#define SUDO_DEBUG_CRIT 1 /* critical errors */
#define SUDO_DEBUG_SYSERR 2 /* system errors */
#define SUDO_DEBUG_PROGERR 3 /* program errors */
#define SUDO_DEBUG_WARN 4 /* non-fatal warnings */
#define SUDO_DEBUG_NOTICE 5 /* non-error condition notices */
#define SUDO_DEBUG_DIAG 6 /* diagnostic messages */
#define SUDO_DEBUG_INFO 7 /* informational message */
#define SUDO_DEBUG_TRACE 8 /* log function enter/exit */
#define SUDO_DEBUG_DEBUG 9 /* very verbose debugging */
/*
* Sudo debug subsystems.
* This includes subsystems in the sudoers plugin.
* Note: order must match sudo_debug_subsystems[]
*/
#define SUDO_DEBUG_MAIN (1<<4) /* sudo main() */
#define SUDO_DEBUG_MEMORY (2<<4) /* memory subsystems */
#define SUDO_DEBUG_ARGS (3<<4) /* command line argument processing */
#define SUDO_DEBUG_EXEC (4<<4) /* command execution */
#define SUDO_DEBUG_PTY (5<<4) /* pseudo-tty */
#define SUDO_DEBUG_UTMP (6<<4) /* utmp file ops */
#define SUDO_DEBUG_CONV (7<<4) /* user conversation */
#define SUDO_DEBUG_PCOMM (8<<4) /* plugin communications */
#define SUDO_DEBUG_UTIL (9<<4) /* utility functions */
#define SUDO_DEBUG_LIST (10<<4) /* linked list functions */
#define SUDO_DEBUG_NETIF (11<<4) /* network interface functions */
#define SUDO_DEBUG_AUDIT (12<<4) /* audit */
#define SUDO_DEBUG_EDIT (13<<4) /* sudoedit */
#define SUDO_DEBUG_SELINUX (14<<4) /* selinux */
#define SUDO_DEBUG_LDAP (15<<4) /* sudoers LDAP */
#define SUDO_DEBUG_MATCH (16<<4) /* sudoers matching */
#define SUDO_DEBUG_PARSER (17<<4) /* sudoers parser */
#define SUDO_DEBUG_ALIAS (18<<4) /* sudoers alias functions */
#define SUDO_DEBUG_DEFAULTS (19<<4) /* sudoers defaults settings */
#define SUDO_DEBUG_AUTH (20<<4) /* authentication functions */
#define SUDO_DEBUG_ENV (21<<4) /* environment handling */
#define SUDO_DEBUG_LOGGING (22<<4) /* logging functions */
#define SUDO_DEBUG_NSS (23<<4) /* network service switch */
#define SUDO_DEBUG_RBTREE (24<<4) /* red-black tree functions */
#define SUDO_DEBUG_PERMS (25<<4) /* uid/gid swapping functions */
#define SUDO_DEBUG_PLUGIN (26<<4) /* main plugin functions */
#define SUDO_DEBUG_ALL 0xfff0 /* all subsystems */
/* Extract priority and convert to an index. */
#define SUDO_DEBUG_PRI(n) (((n) & 0xf) - 1)
/* Extract subsystem and convert to an index. */
#define SUDO_DEBUG_SUBSYS(n) (((n) >> 4) - 1)
/*
* Wrapper for sudo_debug_enter() that declares __func__ as needed
* and sets sudo_debug_subsys for sudo_debug_exit().
*/
#ifdef HAVE___FUNC__
# define debug_decl(funcname, subsys) \
const int sudo_debug_subsys = (subsys); \
sudo_debug_enter(__func__, __FILE__, __LINE__, sudo_debug_subsys);
#else
# define debug_decl(funcname, subsys) \
const int sudo_debug_subsys = (subsys); \
const char *__func__ = #funcname; \
sudo_debug_enter(__func__, __FILE__, __LINE__, sudo_debug_subsys);
#endif
/*
* Wrappers for sudo_debug_exit() and friends.
*/
#define debug_return \
do { \
sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys); \
return; \
} while (0)
#define debug_return_int(rval) \
do { \
int sudo_debug_rval = (rval); \
sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, \
sudo_debug_rval); \
return sudo_debug_rval; \
} while (0)
#define debug_return_size_t(rval) \
do { \
size_t sudo_debug_rval = (rval); \
sudo_debug_exit_size_t(__func__, __FILE__, __LINE__, sudo_debug_subsys,\
sudo_debug_rval); \
return sudo_debug_rval; \
} while (0)
#define debug_return_long(rval) \
do { \
long sudo_debug_rval = (rval); \
sudo_debug_exit_long(__func__, __FILE__, __LINE__, sudo_debug_subsys, \
sudo_debug_rval); \
return sudo_debug_rval; \
} while (0)
#define debug_return_bool(rval) \
do { \
int sudo_debug_rval = (rval); \
sudo_debug_exit_bool(__func__, __FILE__, __LINE__, sudo_debug_subsys, \
sudo_debug_rval); \
return sudo_debug_rval; \
} while (0)
#define debug_return_str(rval) \
do { \
const char *sudo_debug_rval = (rval); \
sudo_debug_exit_str(__func__, __FILE__, __LINE__, sudo_debug_subsys, \
sudo_debug_rval); \
return (char *)sudo_debug_rval; \
} while (0)
#define debug_return_str_masked(rval) \
do { \
const char *sudo_debug_rval = (rval); \
sudo_debug_exit_str_masked(__func__, __FILE__, __LINE__, \
sudo_debug_subsys, sudo_debug_rval); \
return (char *)sudo_debug_rval; \
} while (0)
#define debug_return_ptr(rval) \
do { \
const void *sudo_debug_rval = (rval); \
sudo_debug_exit_ptr(__func__, __FILE__, __LINE__, sudo_debug_subsys, \
sudo_debug_rval); \
return (void *)sudo_debug_rval; \
} while (0)
/*
* Variadic macros are a C99 feature but GNU cpp has supported
* a (different) version of them for a long time.
*/
#if defined(__GNUC__) && __GNUC__ == 2
# define sudo_debug_printf(pri, fmt...) \
sudo_debug_printf2((pri)|sudo_debug_subsys, (fmt))
#else
# define sudo_debug_printf(pri, ...) \
sudo_debug_printf2((pri)|sudo_debug_subsys, __VA_ARGS__)
#endif
#define sudo_debug_execve(pri, path, argv, envp) \
sudo_debug_execve2((pri)|sudo_debug_subsys, (path), (argv), (envp))
/*
* NULL-terminated string lists of priorities and subsystems.
*/
extern const char *const sudo_debug_priorities[];
extern const char *const sudo_debug_subsystems[];
void sudo_debug_enter(const char *func, const char *file, int line, int subsys);
void sudo_debug_exit(const char *func, const char *file, int line, int subsys);
void sudo_debug_exit_int(const char *func, const char *file, int line, int subsys, int rval);
void sudo_debug_exit_long(const char *func, const char *file, int line, int subsys, long rval);
void sudo_debug_exit_size_t(const char *func, const char *file, int line, int subsys, size_t rval);
void sudo_debug_exit_bool(const char *func, const char *file, int line, int subsys, int rval);
void sudo_debug_exit_str(const char *func, const char *file, int line, int subsys, const char *rval);
void sudo_debug_exit_str_masked(const char *func, const char *file, int line, int subsys, const char *rval);
void sudo_debug_exit_ptr(const char *func, const char *file, int line, int subsys, const void *rval);
int sudo_debug_init(const char *debugfile, const char *settings);
void sudo_debug_printf2(int level, const char *format, ...) __printflike(2, 3);
void sudo_debug_write(const char *str, int len);
void sudo_debug_execve2(int level, const char *path, char *const argv[], char *const envp[]);
#endif /* _SUDO_DEBUG_H */

View File

@@ -40,6 +40,7 @@ struct sudo_conv_message {
#define SUDO_CONV_ERROR_MSG 0x0003 /* error message */
#define SUDO_CONV_INFO_MSG 0x0004 /* informational message */
#define SUDO_CONV_PROMPT_MASK 0x0005 /* mask user input */
#define SUDO_CONV_DEBUG_MSG 0x0006 /* debugging message */
#define SUDO_CONV_PROMPT_ECHO_OK 0x1000 /* flag: allow echo if no tty */
int msg_type;
int timeout;

View File

@@ -47,6 +47,7 @@
#include "sudo.h"
#include "sudo_plugin.h"
#include "sudo_debug.h"
extern int tgetpass_flags; /* XXX */
@@ -91,6 +92,10 @@ sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[],
if (msg->msg)
(void) fputs(msg->msg, stderr);
break;
case SUDO_CONV_DEBUG_MSG:
if (msg->msg)
sudo_debug_write(msg->msg, strlen(msg->msg));
break;
default:
goto err;
}

View File

@@ -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) {

View File

@@ -53,6 +53,10 @@
extern char *optarg;
extern int optind;
/* XXX */
extern const char *debug_file;
extern const char *debug_flags;
int tgetpass_flags;
/*
@@ -72,43 +76,47 @@ static struct sudo_settings {
{ "bsdauth_type" },
#define ARG_LOGIN_CLASS 1
{ "login_class" },
#define ARG_DEBUG_LEVEL 2
#define ARG_DEBUG_FILE 2
{ "debug_file" },
#define ARG_DEBUG_FLAGS 3
{ "debug_flags" },
#define ARG_DEBUG_LEVEL 4
{ "debug_level" },
#define ARG_PRESERVE_ENVIRONMENT 3
#define ARG_PRESERVE_ENVIRONMENT 5
{ "preserve_environment" },
#define ARG_RUNAS_GROUP 4
#define ARG_RUNAS_GROUP 6
{ "runas_group" },
#define ARG_SET_HOME 5
#define ARG_SET_HOME 7
{ "set_home" },
#define ARG_USER_SHELL 6
#define ARG_USER_SHELL 8
{ "run_shell" },
#define ARG_LOGIN_SHELL 7
#define ARG_LOGIN_SHELL 9
{ "login_shell" },
#define ARG_IGNORE_TICKET 8
#define ARG_IGNORE_TICKET 10
{ "ignore_ticket" },
#define ARG_PROMPT 9
#define ARG_PROMPT 11
{ "prompt" },
#define ARG_SELINUX_ROLE 10
#define ARG_SELINUX_ROLE 12
{ "selinux_role" },
#define ARG_SELINUX_TYPE 11
#define ARG_SELINUX_TYPE 13
{ "selinux_type" },
#define ARG_RUNAS_USER 12
#define ARG_RUNAS_USER 14
{ "runas_user" },
#define ARG_PROGNAME 13
#define ARG_PROGNAME 15
{ "progname" },
#define ARG_IMPLIED_SHELL 14
#define ARG_IMPLIED_SHELL 16
{ "implied_shell" },
#define ARG_PRESERVE_GROUPS 15
#define ARG_PRESERVE_GROUPS 17
{ "preserve_groups" },
#define ARG_NONINTERACTIVE 16
#define ARG_NONINTERACTIVE 18
{ "noninteractive" },
#define ARG_SUDOEDIT 17
#define ARG_SUDOEDIT 19
{ "sudoedit" },
#define ARG_CLOSEFROM 18
#define ARG_CLOSEFROM 20
{ "closefrom" },
#define ARG_NET_ADDRS 19
#define ARG_NET_ADDRS 21
{ "network_addrs" },
#define NUM_SETTINGS 20
#define NUM_SETTINGS 22
{ NULL }
};
@@ -144,6 +152,12 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp,
if (get_net_ifs(&cp) > 0)
sudo_settings[ARG_NET_ADDRS].value = cp;
/* Set debug file and flags from sudo.conf. */
if (debug_file != NULL)
sudo_settings[ARG_DEBUG_FILE].value = debug_file;
if (debug_flags != NULL)
sudo_settings[ARG_DEBUG_FLAGS].value = debug_flags;
/* Returns true if the last option string was "--" */
#define got_end_of_args (optind > 1 && argv[optind - 1][0] == '-' && \
argv[optind - 1][1] == '-' && argv[optind - 1][2] == '\0')

View File

@@ -200,6 +200,9 @@ main(int argc, char *argv[], char *envp[])
memset(&user_details, 0, sizeof(user_details));
user_info = get_user_info(&user_details);
/* Read sudo.conf. */
sudo_read_conf();
/* Parse command line arguments. */
sudo_mode = parse_args(argc, argv, &nargc, &nargv, &settings, &env_add);
sudo_debug(9, "sudo_mode %d", sudo_mode);
@@ -211,8 +214,8 @@ main(int argc, char *argv[], char *envp[])
(void) printf(_("Configure options: %s\n"), CONFIGURE_ARGS);
}
/* Read sudo.conf and load plugins. */
if (!sudo_load_plugins(_PATH_SUDO_CONF, &policy_plugin, &io_plugins))
/* Load plugins. */
if (!sudo_load_plugins(&policy_plugin, &io_plugins))
errorx(1, _("fatal error, unable to load plugins"));
/* Open policy plugin. */

View File

@@ -78,8 +78,8 @@ int sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[],
struct sudo_conv_reply replies[]);
int _sudo_printf(int msg_type, const char *fmt, ...);
int sudo_load_plugins(const char *conf_file,
struct plugin_container *policy_plugin,
void sudo_read_conf(void);
int sudo_load_plugins(struct plugin_container *policy_plugin,
struct plugin_container_list *io_plugins);
#endif /* _SUDO_PLUGIN_INT_H */