New debug framework for sudo and plugins using /etc/sudo.conf that
also supports function call tracing.
This commit is contained in:
2
MANIFEST
2
MANIFEST
@@ -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
|
||||
|
@@ -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
381
common/sudo_debug.c
Normal 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
197
include/sudo_debug.h
Normal 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 */
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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) {
|
||||
|
@@ -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')
|
||||
|
@@ -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. */
|
||||
|
@@ -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 */
|
||||
|
Reference in New Issue
Block a user