Treat an authentication failure as a reject, not an alert.

This matters when logging via sudo_logsrvd.
It also lets us remove a special case in vlog_warning().
This commit is contained in:
Todd C. Miller
2020-11-09 17:13:04 -07:00
parent 0dd4c5797a
commit ad40241703

View File

@@ -54,22 +54,40 @@
#include "sudoers.h"
/* Special message for log_warning() so we know to use ngettext() */
#define INCORRECT_PASSWORD_ATTEMPT ((char *)0x01)
static bool should_mail(int);
static bool warned = false;
/*
* Log a reject event to syslog, a log file, sudo_logsrvd and/or email.
*/
static bool
log_reject(const char *message, bool logit, bool mailit)
{
int evl_flags = 0;
struct eventlog evlog;
bool ret = true;
debug_decl(log_reject, SUDOERS_DEBUG_LOGGING);
if (mailit) {
SET(evl_flags, EVLOG_MAIL);
if (!logit)
SET(evl_flags, EVLOG_MAIL_ONLY);
}
sudoers_to_eventlog(&evlog);
if (!eventlog_reject(&evlog, evl_flags, message, NULL, NULL))
ret = false;
debug_return_bool(ret);
}
/*
* Log, audit and mail the denial message, optionally informing the user.
*/
bool
log_denial(int status, bool inform_user)
{
struct eventlog evlog;
const char *message;
int oldlocale;
int evl_flags = 0;
bool mailit, ret = true;
debug_decl(log_denial, SUDOERS_DEBUG_LOGGING);
@@ -91,20 +109,14 @@ log_denial(int status, bool inform_user)
/* Log and mail messages should be in the sudoers locale. */
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
if (mailit) {
SET(evl_flags, EVLOG_MAIL);
if (!def_log_denied)
SET(evl_flags, EVLOG_MAIL_ONLY);
}
sudoers_to_eventlog(&evlog);
if (!eventlog_reject(&evlog, evl_flags, message, NULL, NULL))
if (!log_reject(message, def_log_denied, mailit))
ret = false;
/* Restore locale. */
sudoers_setlocale(oldlocale, NULL);
}
/* Inform the user if they failed to authenticate (in their locale). */
/* Inform the user of the failure (in their locale). */
if (inform_user) {
sudoers_setlocale(SUDOERS_LOCALE_USER, &oldlocale);
@@ -164,90 +176,13 @@ log_failure(int status, int flags)
debug_return_bool(ret);
}
/*
* Log and audit that user was not able to authenticate themselves.
*/
bool
log_auth_failure(int status, unsigned int tries)
{
int flags = 0;
bool ret = true;
debug_decl(log_auth_failure, SUDOERS_DEBUG_LOGGING);
/* Do auditing first (audit_failure() handles the locale itself). */
audit_failure(NewArgv, "%s", N_("authentication failure"));
/*
* Do we need to send mail?
* We want to avoid sending multiple messages for the same command
* so if we are going to send an email about the denial, that takes
* precedence.
*/
if (ISSET(status, VALIDATE_SUCCESS)) {
/* Command allowed, auth failed; do we need to send mail? */
if (def_mail_badpass || def_mail_always)
SET(flags, SLOG_SEND_MAIL);
} else {
/* Command denied, auth failed; make sure we don't send mail twice. */
if (def_mail_badpass && !should_mail(status))
SET(flags, SLOG_SEND_MAIL);
/* Don't log the bad password message, we'll log a denial instead. */
SET(flags, SLOG_NO_LOG);
}
/*
* If sudoers denied the command we'll log that separately.
*/
if (ISSET(status, FLAG_BAD_PASSWORD))
ret = log_warningx(flags, INCORRECT_PASSWORD_ATTEMPT, tries);
else if (ISSET(status, FLAG_NON_INTERACTIVE))
ret = log_warningx(flags, N_("a password is required"));
debug_return_bool(ret);
}
/*
* Log and potentially mail the allowed command.
*/
bool
log_allowed(void)
{
struct eventlog evlog;
int oldlocale;
int evl_flags = 0;
bool mailit, ret = true;
debug_decl(log_allowed, SUDOERS_DEBUG_LOGGING);
/* Send mail based on status. */
mailit = should_mail(VALIDATE_SUCCESS);
if (def_log_allowed || mailit) {
/* Log and mail messages should be in the sudoers locale. */
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
sudoers_to_eventlog(&evlog);
if (mailit) {
SET(evl_flags, EVLOG_MAIL);
if (!def_log_allowed)
SET(evl_flags, EVLOG_MAIL_ONLY);
}
if (!eventlog_accept(&evlog, evl_flags, NULL, NULL))
ret = false;
sudoers_setlocale(oldlocale, NULL);
}
debug_return_bool(ret);
}
/*
* Format an authentication failure message, using either
* authfail_message from sudoers or a locale-specific message.
*/
static int
fmt_authfail_message(char **str, va_list ap)
fmt_authfail_message(char **str, unsigned int tries)
{
unsigned int tries = va_arg(ap, unsigned int);
char *src, *dst0, *dst, *dst_end;
size_t size;
int len;
@@ -296,6 +231,122 @@ done:
debug_return_int(dst - dst0);
}
/*
* Log and audit that user was not able to authenticate themselves.
*/
bool
log_auth_failure(int status, unsigned int tries)
{
char *message = NULL;
int oldlocale;
bool ret = true;
bool mailit = false;
bool logit = true;
debug_decl(log_auth_failure, SUDOERS_DEBUG_LOGGING);
/* Do auditing first (audit_failure() handles the locale itself). */
audit_failure(NewArgv, "%s", N_("authentication failure"));
/* If sudoers denied the command we'll log that separately. */
if (!ISSET(status, FLAG_BAD_PASSWORD|FLAG_NON_INTERACTIVE))
logit = false;
/*
* Do we need to send mail?
* We want to avoid sending multiple messages for the same command
* so if we are going to send an email about the denial, that takes
* precedence.
*/
if (ISSET(status, VALIDATE_SUCCESS)) {
/* Command allowed, auth failed; do we need to send mail? */
if (def_mail_badpass || def_mail_always)
mailit = true;
if (!def_log_denied)
logit = false;
} else {
/* Command denied, auth failed; make sure we don't send mail twice. */
if (def_mail_badpass && !should_mail(status))
mailit = true;
/* Don't log the bad password message, we'll log a denial instead. */
logit = false;
}
if (logit || mailit) {
/* Log and mail messages should be in the sudoers locale. */
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
if (ISSET(status, FLAG_BAD_PASSWORD)) {
if (fmt_authfail_message(&message, tries) == -1) {
sudo_warnx(U_("%s: %s"), __func__,
U_("unable to allocate memory"));
ret = false;
} else {
ret = log_reject(message, logit, mailit);
free(message);
}
} else {
ret = log_reject(_("a password is required"), logit, mailit);
}
/* Restore locale. */
sudoers_setlocale(oldlocale, NULL);
}
/* Inform the user if they failed to authenticate (in their locale). */
sudoers_setlocale(SUDOERS_LOCALE_USER, &oldlocale);
if (ISSET(status, FLAG_BAD_PASSWORD)) {
if (fmt_authfail_message(&message, tries) == -1) {
sudo_warnx(U_("%s: %s"), __func__,
U_("unable to allocate memory"));
ret = false;
} else {
sudo_warnx("%s", message);
free(message);
}
} else {
sudo_warnx("%s", _("a password is required"));
}
sudoers_setlocale(oldlocale, NULL);
debug_return_bool(ret);
}
/*
* Log and potentially mail the allowed command.
*/
bool
log_allowed(void)
{
struct eventlog evlog;
int oldlocale;
int evl_flags = 0;
bool mailit, ret = true;
debug_decl(log_allowed, SUDOERS_DEBUG_LOGGING);
/* Send mail based on status. */
mailit = should_mail(VALIDATE_SUCCESS);
if (def_log_allowed || mailit) {
/* Log and mail messages should be in the sudoers locale. */
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
sudoers_to_eventlog(&evlog);
if (mailit) {
SET(evl_flags, EVLOG_MAIL);
if (!def_log_allowed)
SET(evl_flags, EVLOG_MAIL_ONLY);
}
if (!eventlog_accept(&evlog, evl_flags, NULL, NULL))
ret = false;
sudoers_setlocale(oldlocale, NULL);
}
debug_return_bool(ret);
}
/*
* Perform logging for log_warning()/log_warningx().
*/
@@ -325,12 +376,8 @@ vlog_warning(int flags, int errnum, const char *fmt, va_list ap)
/* Log messages should be in the sudoers locale. */
sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
/* Expand printf-style format + args (with a special case). */
if (fmt == INCORRECT_PASSWORD_ATTEMPT) {
len = fmt_authfail_message(&message, ap);
} else {
len = vasprintf(&message, _(fmt), ap);
}
/* Expand printf-style format + args. */
len = vasprintf(&message, _(fmt), ap);
if (len == -1) {
sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
ret = false;
@@ -372,24 +419,13 @@ vlog_warning(int flags, int errnum, const char *fmt, va_list ap)
*/
if (!ISSET(flags, SLOG_NO_STDERR)) {
sudoers_setlocale(SUDOERS_LOCALE_USER, NULL);
if (fmt == INCORRECT_PASSWORD_ATTEMPT) {
len = fmt_authfail_message(&message, ap2);
if (len == -1) {
sudo_warnx(U_("%s: %s"), __func__,
U_("unable to allocate memory"));
ret = false;
goto done;
}
sudo_warnx_nodebug("%s", message);
free(message);
if (ISSET(flags, SLOG_USE_ERRNO)) {
errno = errnum;
sudo_vwarn_nodebug(_(fmt), ap2);
} else if (ISSET(flags, SLOG_GAI_ERRNO)) {
sudo_gai_vwarn_nodebug(errnum, _(fmt), ap2);
} else {
if (ISSET(flags, SLOG_USE_ERRNO)) {
errno = errnum;
sudo_vwarn_nodebug(_(fmt), ap2);
} else if (ISSET(flags, SLOG_GAI_ERRNO)) {
sudo_gai_vwarn_nodebug(errnum, _(fmt), ap2);
} else
sudo_vwarnx_nodebug(_(fmt), ap2);
sudo_vwarnx_nodebug(_(fmt), ap2);
}
}