Add basic support for reject and error audit events to sudoers.

This is only used when logging events from plugins other than sudoers,
such as an approval plugin.  With this change, if an approval
plugin rejects the command the denial will be logged in the
sudoers log file using the message from the approval plugin.
This commit is contained in:
Todd C. Miller
2020-06-04 14:41:35 -06:00
parent 15d93a1ca7
commit f047377a07
3 changed files with 159 additions and 65 deletions

View File

@@ -66,44 +66,59 @@ audit_success(char *const argv[])
debug_return_int(rc); debug_return_int(rc);
} }
static int
audit_failure_int(char *const argv[], const char *message)
{
int ret = 0;
debug_decl(audit_failure_int, SUDOERS_DEBUG_AUDIT);
#if defined(HAVE_BSM_AUDIT) || defined(HAVE_LINUX_AUDIT)
if (def_log_denied && argv != NULL) {
#ifdef HAVE_BSM_AUDIT
if (bsm_audit_failure(argv, message) == -1)
ret = -1;
#endif
#ifdef HAVE_LINUX_AUDIT
if (linux_audit_command(argv, 0) == -1)
ret = -1;
#endif
#ifdef HAVE_SOLARIS_AUDIT
if (solaris_audit_failure(argv, message) == -1)
ret = -1;
#endif
}
#endif /* HAVE_BSM_AUDIT || HAVE_LINUX_AUDIT */
debug_return_int(ret);
}
int int
audit_failure(char *const argv[], char const *const fmt, ...) audit_failure(char *const argv[], char const *const fmt, ...)
{ {
int oldlocale, rc = 0; int oldlocale, ret;
char *message;
va_list ap; va_list ap;
debug_decl(audit_failure, SUDOERS_DEBUG_AUDIT); debug_decl(audit_failure, SUDOERS_DEBUG_AUDIT);
/* Audit messages should be in the sudoers locale. */ /* Audit messages should be in the sudoers locale. */
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
/* Set audit_msg for audit plugin. */
free(audit_msg);
audit_msg = NULL;
va_start(ap, fmt); va_start(ap, fmt);
if (vasprintf(&audit_msg, _(fmt), ap) == -1) if ((ret = vasprintf(&message, _(fmt), ap)) == -1)
rc = -1; sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
va_end(ap); va_end(ap);
#if defined(HAVE_BSM_AUDIT) || defined(HAVE_LINUX_AUDIT) if (ret != -1) {
if (def_log_denied && argv != NULL) { /* Set audit_msg for audit plugins. */
#ifdef HAVE_BSM_AUDIT free(audit_msg);
if (bsm_audit_failure(argv, audit_msg) == -1) audit_msg = message;
rc = -1;
#endif ret = audit_failure_int(argv, audit_msg);
#ifdef HAVE_LINUX_AUDIT
if (linux_audit_command(argv, 0) == -1)
rc = -1;
#endif
#ifdef HAVE_SOLARIS_AUDIT
if (solaris_audit_failure(argv, audit_msg) == -1)
rc = -1;
#endif
} }
#endif /* HAVE_BSM_AUDIT || HAVE_LINUX_AUDIT */
sudoers_setlocale(oldlocale, NULL); sudoers_setlocale(oldlocale, NULL);
debug_return_int(rc); debug_return_int(ret);
} }
static int static int
@@ -154,21 +169,97 @@ sudoers_audit_accept(const char *plugin_name, unsigned int plugin_type,
char * const command_info[], char * const run_argv[], char * const command_info[], char * const run_argv[],
char * const run_envp[], const char **errstr) char * const run_envp[], const char **errstr)
{ {
int ret = true;
debug_decl(sudoers_audit_accept, SUDOERS_DEBUG_PLUGIN); debug_decl(sudoers_audit_accept, SUDOERS_DEBUG_PLUGIN);
/* Only log the accept event from the sudo front-end */ /* Only log the accept event from the sudo front-end */
if (plugin_type != SUDO_FRONT_END) if (plugin_type != SUDO_FRONT_END)
debug_return_bool(true); debug_return_int(true);
if (!def_log_allowed) if (def_log_allowed) {
debug_return_bool(true); if (audit_success(run_argv) != 0 && !def_ignore_audit_errors)
ret = false;
if (audit_success(run_argv) != 0 && !def_ignore_audit_errors) if (!log_allowed(VALIDATE_SUCCESS) && !def_ignore_logfile_errors)
debug_return_bool(false); ret = false;
}
if (!log_allowed(VALIDATE_SUCCESS) && !def_ignore_logfile_errors) debug_return_int(ret);
debug_return_bool(false); }
debug_return_bool(true);
static int
sudoers_audit_reject(const char *plugin_name, unsigned int plugin_type,
const char *message, char * const command_info[], const char **errstr)
{
int ret = true;
char *logline;
debug_decl(sudoers_audit_reject, SUDOERS_DEBUG_PLUGIN);
/* Skip reject events that sudoers generated itself. */
if (strncmp(plugin_name, "sudoers_", 8) == 0)
debug_return_int(true);
if (!def_log_denied)
debug_return_int(true);
if (audit_failure_int(NewArgv, message) != 0) {
if (!def_ignore_audit_errors)
ret = false;
}
logline = new_logline(message, NULL);
if (logline == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
ret = false;
goto done;
}
if (def_syslog) {
if (!do_syslog(def_syslog_badpri, logline)) {
if (!def_ignore_logfile_errors)
ret = false;
}
}
if (def_logfile) {
if (!do_logfile(logline)) {
if (!def_ignore_logfile_errors)
ret = false;
}
}
free(logline);
done:
debug_return_int(ret);
}
static int
sudoers_audit_error(const char *plugin_name, unsigned int plugin_type,
const char *message, char * const command_info[], const char **errstr)
{
int ret = true;
debug_decl(sudoers_audit_error, SUDOERS_DEBUG_PLUGIN);
/* Skip error events that sudoers generated itself. */
if (strncmp(plugin_name, "sudoers_", 8) == 0)
debug_return_int(true);
if (audit_failure_int(NewArgv, message) != 0) {
if (!def_ignore_audit_errors)
ret = false;
}
if (def_syslog) {
if (!do_syslog(def_syslog_badpri, message)) {
if (!def_ignore_logfile_errors)
ret = false;
}
}
if (def_logfile) {
if (!do_logfile(message)) {
if (!def_ignore_logfile_errors)
ret = false;
}
}
debug_return_int(ret);
} }
static int static int
@@ -188,8 +279,8 @@ __dso_public struct audit_plugin sudoers_audit = {
sudoers_audit_open, sudoers_audit_open,
NULL, /* audit_close */ NULL, /* audit_close */
sudoers_audit_accept, sudoers_audit_accept,
NULL, /* audit_reject */ sudoers_audit_reject,
NULL, /* audit_error */ sudoers_audit_error,
sudoers_audit_version, sudoers_audit_version,
NULL, /* register_hooks */ NULL, /* register_hooks */
NULL /* deregister_hooks */ NULL /* deregister_hooks */

View File

@@ -58,12 +58,9 @@
/* Special message for log_warning() so we know to use ngettext() */ /* Special message for log_warning() so we know to use ngettext() */
#define INCORRECT_PASSWORD_ATTEMPT ((char *)0x01) #define INCORRECT_PASSWORD_ATTEMPT ((char *)0x01)
static void do_syslog(int, char *);
static bool do_logfile(const char *);
static bool send_mail(const char *fmt, ...); static bool send_mail(const char *fmt, ...);
static bool should_mail(int); static bool should_mail(int);
static void mysyslog(int, const char *, ...); static void mysyslog(int, const char *, ...);
static char *new_logline(const char *, const char *);
/* /*
* We do an openlog(3)/closelog(3) for each message because some * We do an openlog(3)/closelog(3) for each message because some
@@ -89,18 +86,23 @@ mysyslog(int pri, const char *fmt, ...)
* Log a message to syslog, pre-pending the username and splitting the * Log a message to syslog, pre-pending the username and splitting the
* message into parts if it is longer than syslog_maxlen. * message into parts if it is longer than syslog_maxlen.
*/ */
static void bool
do_syslog(int pri, char *msg) do_syslog(int pri, const char *msg)
{ {
size_t len, maxlen; size_t maxlen;
char *p, *tmp, save; char *copy, *cp, *ep;
const char *fmt; const char *fmt;
int oldlocale; int oldlocale;
debug_decl(do_syslog, SUDOERS_DEBUG_LOGGING); debug_decl(do_syslog, SUDOERS_DEBUG_LOGGING);
/* A priority of -1 corresponds to "none". */ /* A priority of -1 corresponds to "none". */
if (pri == -1) if (pri == -1)
debug_return; debug_return_bool(true);
if ((copy = strdup(msg)) == NULL) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
debug_return_bool(false);
}
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
@@ -109,42 +111,40 @@ do_syslog(int pri, char *msg)
*/ */
fmt = _("%8s : %s"); fmt = _("%8s : %s");
maxlen = def_syslog_maxlen - (strlen(fmt) - 5 + strlen(user_name)); maxlen = def_syslog_maxlen - (strlen(fmt) - 5 + strlen(user_name));
for (p = msg; *p != '\0'; ) { for (cp = copy; *cp != '\0'; ) {
len = strlen(p); size_t len = strlen(cp);
if (len > maxlen) { if (len > maxlen) {
/* /*
* Break up the line into what will fit on one syslog(3) line * Break up the line into what will fit on one syslog(3) line
* Try to avoid breaking words into several lines if possible. * Try to avoid breaking words into several lines if possible.
*/ */
tmp = memrchr(p, ' ', maxlen); ep = memrchr(cp, ' ', maxlen);
if (tmp == NULL) if (ep != NULL)
tmp = p + maxlen; *ep++ = '\0';
else
ep = cp + maxlen;
/* NULL terminate line, but save the char to restore later */ mysyslog(pri, fmt, user_name, cp);
save = *tmp;
*tmp = '\0';
mysyslog(pri, fmt, user_name, p); /* Advance cp and eliminate leading whitespace */
for (cp = ep; *cp == ' '; cp++)
*tmp = save; /* restore saved character */
/* Advance p and eliminate leading whitespace */
for (p = tmp; *p == ' '; p++)
continue; continue;
} else { } else {
mysyslog(pri, fmt, user_name, p); mysyslog(pri, fmt, user_name, cp);
p += len; cp += len;
} }
fmt = _("%8s : (command continued) %s"); fmt = _("%8s : (command continued) %s");
maxlen = def_syslog_maxlen - (strlen(fmt) - 5 + strlen(user_name)); maxlen = def_syslog_maxlen - (strlen(fmt) - 5 + strlen(user_name));
} }
free(copy);
sudoers_setlocale(oldlocale, NULL); sudoers_setlocale(oldlocale, NULL);
debug_return; debug_return_bool(true);
} }
static bool bool
do_logfile(const char *msg) do_logfile(const char *msg)
{ {
static bool warned = false; static bool warned = false;
@@ -263,8 +263,8 @@ log_denial(int status, bool inform_user)
/* Log via syslog and/or a file. */ /* Log via syslog and/or a file. */
if (def_log_denied) { if (def_log_denied) {
if (def_syslog) if (def_syslog && !do_syslog(def_syslog_badpri, logline))
do_syslog(def_syslog_badpri, logline); ret = false;
if (def_logfile && !do_logfile(logline)) if (def_logfile && !do_logfile(logline))
ret = false; ret = false;
} }
@@ -414,8 +414,8 @@ log_allowed(int status)
* Log via syslog and/or a file. * Log via syslog and/or a file.
*/ */
if (def_log_allowed) { if (def_log_allowed) {
if (def_syslog) if (def_syslog && !do_syslog(def_syslog_goodpri, logline))
do_syslog(def_syslog_goodpri, logline); ret = false;
if (def_logfile && !do_logfile(logline)) if (def_logfile && !do_logfile(logline))
ret = false; ret = false;
} }
@@ -561,8 +561,8 @@ vlog_warning(int flags, int errnum, const char *fmt, va_list ap)
* Log to syslog and/or a file. * Log to syslog and/or a file.
*/ */
if (!ISSET(flags, SLOG_NO_LOG)) { if (!ISSET(flags, SLOG_NO_LOG)) {
if (def_syslog) if (def_syslog && !do_syslog(def_syslog_badpri, logline))
do_syslog(def_syslog_badpri, logline); ret = false;
if (def_logfile && !do_logfile(logline)) if (def_logfile && !do_logfile(logline))
ret = false; ret = false;
} }
@@ -942,7 +942,7 @@ should_mail(int status)
/* /*
* Allocate and fill in a new logline. * Allocate and fill in a new logline.
*/ */
static char * char *
new_logline(const char *message, const char *errstr) new_logline(const char *message, const char *errstr)
{ {
char *line = NULL, *evstr = NULL; char *line = NULL, *evstr = NULL;

View File

@@ -67,6 +67,9 @@ extern char *audit_msg;
union sudo_defs_val; union sudo_defs_val;
bool do_logfile(const char *msg);
bool do_syslog(int pri, const char *msg);
char *new_logline(const char *, const char *);
bool sudoers_warn_setlocale(bool restore, int *cookie); bool sudoers_warn_setlocale(bool restore, int *cookie);
bool sudoers_setlocale(int newlocale, int *prevlocale); bool sudoers_setlocale(int newlocale, int *prevlocale);
int sudoers_getlocale(void); int sudoers_getlocale(void);