PROGS = @PROGS@
-SRCS = aix.c alias.c alloc.c check.c closefrom.c def_data.c defaults.c env.c \
- error.c fileops.c find_path.c fnmatch.c getcwd.c getprogname.c \
- getspwuid.c gettime.c glob.c goodpath.c gram.c gram.y interfaces.c \
- isblank.c lbuf.c ldap.c list.c logging.c match.c mkstemp.c memrchr.c \
- parse.c pwutil.c set_perms.c sigaction.c snprintf.c strcasecmp.c \
- strerror.c strlcat.c strlcpy.c sudo.c sudo_noexec.c sudo_edit.c \
- sudo_nss.c term.c testsudoers.c tgetpass.c toke.c toke.l tsgetgrpw.c \
- utimes.c visudo.c zero_bytes.c redblack.c selinux.c sesh.c $(AUTH_SRCS)
+SRCS = aix.c alias.c alloc.c bsm_audit.c check.c closefrom.c def_data.c \
+ defaults.c env.c error.c fileops.c find_path.c fnmatch.c getcwd.c \
+ getprogname.c getspwuid.c gettime.c glob.c goodpath.c gram.c gram.y \
+ interfaces.c isblank.c lbuf.c ldap.c list.c logging.c match.c mkstemp.c \
+ memrchr.c parse.c pwutil.c set_perms.c sigaction.c snprintf.c \
+ strcasecmp.c strerror.c strlcat.c strlcpy.c sudo.c sudo_noexec.c \
+ sudo_edit.c sudo_nss.c term.c testsudoers.c tgetpass.c toke.c toke.l \
+ tsgetgrpw.c utimes.c visudo.c zero_bytes.c redblack.c selinux.c sesh.c \
+ $(AUTH_SRCS)
AUTH_SRCS = auth/afs.c auth/aix_auth.c auth/bsdauth.c auth/dce.c auth/fwtk.c \
auth/kerb4.c auth/kerb5.c auth/pam.c auth/passwd.c auth/rfc1938.c \
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/alias.c
alloc.o: $(srcdir)/alloc.c $(SUDODEP)
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/alloc.c
+bsm_audit.o: $(srcdir)/bsm_audit.c $(SUDODEP) bsm_audit.h
+ $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/bsm_audit.c
check.o: $(srcdir)/check.c $(SUDODEP)
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/check.c
closefrom.o: $(srcdir)/closefrom.c config.h
char *p;
sudo_auth *auth;
sigaction_t sa, osa;
+#ifdef HAVE_BSM_AUDIT
+ extern char **NewArgv;
+#endif
/* Enable suspend during password entry. */
sigemptyset(&sa.sa_mask);
(void) sigaction(SIGTSTP, &sa, &osa);
/* Make sure we have at least one auth method. */
- if (auth_switch[0].name == NULL)
+ if (auth_switch[0].name == NULL) {
+#ifdef HAVE_BSM_AUDIT
+ audit_failure(NewArgv, "no authentication methods");
+#endif
log_error(0, "%s %s %s",
"There are no authentication methods compiled into sudo!",
"If you want to turn off authentication, use the",
"--disable-authentication configure option.");
+ }
/* Set FLAG_ONEANDONLY if there is only one auth method. */
if (auth_switch[1].name == NULL)
status = (auth->init)(pw, &prompt, auth);
if (status == AUTH_FAILURE)
CLR(auth->flags, FLAG_CONFIGURED);
- else if (status == AUTH_FATAL) /* XXX log */
+ else if (status == AUTH_FATAL) { /* XXX log */
+#ifdef HAVE_BSM_AUDIT
+ audit_failure(NewArgv, "authentication failure");
+#endif
exit(1); /* assume error msg already printed */
+ }
if (NEEDS_USER(auth))
set_perms(PERM_ROOT);
status = (auth->setup)(pw, &prompt, auth);
if (status == AUTH_FAILURE)
CLR(auth->flags, FLAG_CONFIGURED);
- else if (status == AUTH_FATAL) /* XXX log */
+ else if (status == AUTH_FATAL) {/* XXX log */
+#ifdef HAVE_BSM_AUDIT
+ audit_failure(NewArgv, "authentication failure");
+#endif
exit(1); /* assume error msg already printed */
+ }
if (NEEDS_USER(auth))
set_perms(PERM_ROOT);
set_perms(PERM_USER);
status = (auth->cleanup)(pw, auth);
- if (status == AUTH_FATAL) /* XXX log */
+ if (status == AUTH_FATAL) { /* XXX log */
+#ifdef HAVE_BSM_AUDIT
+ audit_failure(NewArgv, "authentication failure");
+#endif
exit(1); /* assume error msg already printed */
+ }
if (NEEDS_USER(auth))
set_perms(PERM_ROOT);
flags = 0;
else
flags = NO_MAIL;
+#ifdef HAVE_BSM_AUDIT
+ audit_failure(NewArgv, "authentication failure");
+#endif
log_error(flags, "%d incorrect password attempt%s",
def_passwd_tries - counter,
(def_passwd_tries - counter == 1) ? "" : "s");
}
/* FALLTHROUGH */
case AUTH_FATAL:
+#ifdef HAVE_BSM_AUDIT
+ audit_failure(NewArgv, "authentication failure");
+#endif
exit(1);
}
/* NOTREACHED */
--- /dev/null
+/*
+ * Copyright (c) 2009 Christian S.J. Peron
+ *
+ * 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 <bsm/audit.h>
+#include <bsm/libbsm.h>
+#include <bsm/audit_uevents.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <pwd.h>
+#include <errno.h>
+#include <unistd.h>
+
+static int
+audit_sudo_selected(int sf)
+{
+ auditinfo_addr_t ainfo_addr;
+ struct au_mask *mask;
+ auditinfo_t ainfo;
+ int rc, sorf;
+
+ if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) < 0) {
+ if (errno == ENOSYS) {
+ if (getaudit(&ainfo) < 0)
+ log_error(0, "getaudit: failed");
+ mask = &ainfo.ai_mask;
+ } else
+ log_error(0, "getaudit: failed");
+ } else
+ mask = &ainfo_addr.ai_mask;
+ sorf = (sf == 0) ? AU_PRS_SUCCESS : AU_PRS_FAILURE;
+ rc = au_preselect(AUE_sudo, mask, sorf, AU_PRS_REREAD);
+ return (rc);
+}
+
+void
+audit_success(char **exec_args)
+{
+ auditinfo_addr_t ainfo_addr;
+ auditinfo_t ainfo;
+ token_t *tok;
+ au_id_t auid;
+ long au_cond;
+ int aufd;
+ pid_t pid;
+
+ pid = getpid();
+ /*
+ * If we are not auditing, don't cut an audit record; just return.
+ */
+ if (auditon(A_GETCOND, (caddr_t)&au_cond, sizeof(long)) < 0) {
+ if (errno == ENOSYS)
+ return;
+ log_error(0, "Could not determine audit condition");
+ }
+ if (au_cond == AUC_NOAUDIT)
+ return;
+ /*
+ * Check to see if the preselection masks are interested in seeing
+ * this event.
+ */
+ if (!audit_sudo_selected(0))
+ return;
+ if (getauid(&auid) < 0)
+ log_error(0, "getauid failed");
+ if ((aufd = au_open()) == -1)
+ log_error(0, "au_open: failed");
+ if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) {
+ tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(),
+ getuid(), pid, pid, &ainfo_addr.ai_termid);
+ } else if (errno == ENOSYS) {
+ /*
+ * NB: We should probably watch out for ERANGE here.
+ */
+ if (getaudit(&ainfo) < 0)
+ log_error(0, "getaudit: failed");
+ tok = au_to_subject(auid, geteuid(), getegid(), getuid(),
+ getuid(), pid, pid, &ainfo.ai_termid);
+ } else
+ log_error(0, "getaudit: failed");
+ if (tok == NULL)
+ log_error(0, "au_to_subject: failed");
+ au_write(aufd, tok);
+ tok = au_to_exec_args(exec_args);
+ if (tok == NULL)
+ log_error(0, "au_to_exec_args: failed");
+ au_write(aufd, tok);
+ tok = au_to_return32(0, 0);
+ if (tok == NULL)
+ log_error(0, "au_to_return32: failed");
+ au_write(aufd, tok);
+ if (au_close(aufd, 1, AUE_sudo) == -1)
+ log_error(0, "unable to commit audit record");
+}
+
+void
+audit_failure(char **exec_args, char const *const fmt, ...)
+{
+ auditinfo_addr_t ainfo_addr;
+ auditinfo_t ainfo;
+ char text[256];
+ token_t *tok;
+ long au_cond;
+ au_id_t auid;
+ va_list ap;
+ pid_t pid;
+ int aufd;
+
+ pid = getpid();
+ /*
+ * If we are not auditing, don't cut an audit record; just return.
+ */
+ if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
+ if (errno == ENOSYS)
+ return;
+ log_error(0, "Could not determine audit condition");
+ }
+ if (au_cond == AUC_NOAUDIT)
+ return;
+ if (!audit_sudo_selected(1))
+ return;
+ if (getauid(&auid) < 0)
+ log_error(0, "getauid: failed");
+ if ((aufd = au_open()) == -1)
+ log_error(0, "au_open: failed");
+ if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) {
+ tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(),
+ getuid(), pid, pid, &ainfo_addr.ai_termid);
+ } else if (errno == ENOSYS) {
+ if (getaudit(&ainfo) < 0)
+ log_error(0, "getaudit: failed");
+ tok = au_to_subject(auid, geteuid(), getegid(), getuid(),
+ getuid(), pid, pid, &ainfo.ai_termid);
+ } else
+ log_error(0, "getaudit: failed");
+ if (tok == NULL)
+ log_error(0, "au_to_subject: failed");
+ au_write(aufd, tok);
+ tok = au_to_exec_args(exec_args);
+ if (tok == NULL)
+ log_error(0, "au_to_exec_args: failed");
+ au_write(aufd, tok);
+ va_start(ap, fmt);
+ (void) vsnprintf(text, sizeof(text), fmt, ap);
+ va_end(ap);
+ tok = au_to_text(text);
+ if (tok == NULL)
+ log_error(0, "au_to_text: failed");
+ au_write(aufd, tok);
+ tok = au_to_return32(EPERM, 1);
+ if (tok == NULL)
+ log_error(0, "au_to_return32: failed");
+ au_write(aufd, tok);
+ if (au_close(aufd, 1, AUE_sudo) == -1)
+ log_error(0, "unable to commit audit record");
+}
--- /dev/null
+/*
+ * Copyright (c) 2009 Christian S.J. Peron
+ *
+ * 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_BSM_AUDIT_H
+#define _SUDO_BSM_AUDIT_H
+
+void audit_success(char **);
+void audit_failure(char **, char const *const, ...);
+
+#endif /* _SUDO_BSM_AUDIT_H */
build_alias
host_alias
target_alias
+HAVE_BSM_AUDIT
LIBTOOL
CFLAGS
PROGS
--with-CC C compiler to use
--with-rpath pass -R flag in addition to -L for lib paths
--with-blibpath=PATH pass -blibpath flag to ld for additional lib paths
+ --with-bsm-audit enable BSM audit support
--with-incpath additional places to look for include files
--with-libpath additional places to look for libraries
--with-libraries additional libraries to link with
+
timeout=5
+# Check whether --with-bsm-audit was given.
+if test "${with_bsm_audit+set}" = set; then
+ withval=$with_bsm_audit; case $with_bsm_audit in
+ yes) cat >>confdefs.h <<\_ACEOF
+#define HAVE_BSM_AUDIT 1
+_ACEOF
+
+ SUDO_LIBS="${SUDO_LIBS} -lbsm"
+ SUDO_OBJS="${SUDO_OBJS} bsm_audit.o"
+ ;;
+ no) ;;
+ *) { { echo "$as_me:$LINENO: error: \"--with-bsm-audit does not take an argument.\"" >&5
+echo "$as_me: error: \"--with-bsm-audit does not take an argument.\"" >&2;}
+ { (exit 1); exit 1; }; }
+ ;;
+esac
+fi
+
+
+
# Check whether --with-incpath was given.
if test "${with_incpath+set}" = set; then
withval=$with_incpath; case $with_incpath in
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 6212 "configure"' > conftest.$ac_ext
+ echo '#line 6235 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:8071: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:8094: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:8075: \$? = $ac_status" >&5
+ echo "$as_me:8098: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:8361: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:8384: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:8365: \$? = $ac_status" >&5
+ echo "$as_me:8388: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:8465: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:8488: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:8469: \$? = $ac_status" >&5
+ echo "$as_me:8492: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 10825 "configure"
+#line 10848 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 10925 "configure"
+#line 10948 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
build_alias!$build_alias$ac_delim
host_alias!$host_alias$ac_delim
target_alias!$target_alias$ac_delim
+HAVE_BSM_AUDIT!$HAVE_BSM_AUDIT$ac_delim
LIBTOOL!$LIBTOOL$ac_delim
CFLAGS!$CFLAGS$ac_delim
PROGS!$PROGS$ac_delim
env_editor!$env_editor$ac_delim
passwd_tries!$passwd_tries$ac_delim
tty_tickets!$tty_tickets$ac_delim
-insults!$insults$ac_delim
_ACEOF
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
ac_delim='%!_!# '
for ac_last_try in false false false false false :; do
cat >conf$$subs.sed <<_ACEOF
+insults!$insults$ac_delim
root_sudo!$root_sudo$ac_delim
path_info!$path_info$ac_delim
ldap_conf!$ldap_conf$ac_delim
LTLIBOBJS!$LTLIBOBJS$ac_delim
_ACEOF
- if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 41; then
+ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 42; then
break
elif $ac_last_try; then
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+
+
dnl
dnl Variables that get substituted in the Makefile and man pages
dnl
+AC_SUBST(HAVE_BSM_AUDIT)
AC_SUBST(LIBTOOL)
AC_SUBST(CFLAGS)
AC_SUBST(PROGS)
;;
esac])
+dnl
+dnl Handle BSM auditing support.
+dnl
+AC_ARG_WITH(bsm-audit, [ --with-bsm-audit enable BSM audit support],
+[case $with_bsm_audit in
+ yes) AC_DEFINE(HAVE_BSM_AUDIT)
+ SUDO_LIBS="${SUDO_LIBS} -lbsm"
+ SUDO_OBJS="${SUDO_OBJS} bsm_audit.o"
+ ;;
+ no) ;;
+ *) AC_MSG_ERROR(["--with-bsm-audit does not take an argument."])
+ ;;
+esac])
+
AC_ARG_WITH(incpath, [ --with-incpath additional places to look for include files],
[case $with_incpath in
yes) AC_MSG_ERROR(["must give --with-incpath an argument."])
AH_TEMPLATE(HAVE_AFS, [Define to 1 if you use AFS.])
AH_TEMPLATE(HAVE_AIXAUTH, [Define to 1 if you use AIX general authentication.])
AH_TEMPLATE(HAVE_BSD_AUTH_H, [Define to 1 if you use BSD authentication.])
+AH_TEMPLATE(HAVE_BSM_AUDIT, [Define to 1 to enable BSM auditing.])
AH_TEMPLATE(HAVE_DCE, [Define to 1 if you use OSF DCE.])
AH_TEMPLATE(HAVE_DD_FD, [Define to 1 if your `DIR' contains dd_fd.])
AH_TEMPLATE(HAVE_DIRFD, [Define to 1 if you have the `dirfd' function or macro.])
#include "interfaces.h"
#include "version.h"
+#ifdef HAVE_BSM_AUDIT
+# include "bsm_audit.h"
+#endif
+
#ifndef lint
__unused static const char rcsid[] = "$Sudo$";
#endif /* lint */
/* Bail if a tty is required and we don't have one. */
if (def_requiretty) {
- if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1)
+ if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) {
+#ifdef HAVE_BSM_AUDIT
+ audit_failure(NewArgv, "no tty");
+#endif
log_error(NO_MAIL, "sorry, you must have a tty to run sudo");
- else
+ } else
(void) close(fd);
}
if (ISSET(validated, VALIDATE_OK)) {
/* Finally tell the user if the command did not exist. */
- if (cmnd_status == NOT_FOUND_DOT)
+ if (cmnd_status == NOT_FOUND_DOT) {
+#ifdef HAVE_BSM_AUDIT
+ audit_failure(NewArgv, "command in current directory");
+#endif
errorx(1, "ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd);
- else if (cmnd_status == NOT_FOUND)
+ } else if (cmnd_status == NOT_FOUND) {
+#ifdef HAVE_BSM_AUDIT
+ audit_failure(NewArgv, "%s: command not found", user_cmnd);
+#endif
errorx(1, "%s: command not found", user_cmnd);
+ }
/* If user specified env vars make sure sudoers allows it. */
if (ISSET(sudo_mode, MODE_RUN) && !def_setenv) {
closefrom(def_closefrom + 1);
#ifndef PROFILING
- if (ISSET(sudo_mode, MODE_BACKGROUND) && fork() > 0)
+ if (ISSET(sudo_mode, MODE_BACKGROUND) && fork() > 0) {
+#ifdef HAVE_BSM_AUDIT
+ syslog(LOG_AUTH|LOG_ERR, "fork");
+ audit_success(NewArgv);
+#endif
exit(0);
- else {
+ } else {
#ifdef HAVE_SELINUX
if (is_selinux_enabled() > 0 && user_role != NULL)
selinux_exec(user_role, user_type, NewArgv,
ISSET(sudo_mode, MODE_LOGIN_SHELL));
+#endif
+#ifdef HAVE_BSM_AUDIT
+ audit_success(NewArgv);
#endif
execv(safe_cmnd, NewArgv);
}
} warning("unable to execute %s", safe_cmnd);
exit(127);
} else if (ISSET(validated, FLAG_NO_USER | FLAG_NO_HOST)) {
+#ifdef HAVE_BSM_AUDIT
+ audit_failure(NewArgv, "No user or host");
+#endif
log_denial(validated, 1);
exit(1);
} else {
/* Just tell the user they are not allowed to run foo. */
log_denial(validated, 1);
}
+#ifdef HAVE_BSM_AUDIT
+ audit_failure(NewArgv, "validation failure");
+#endif
exit(1);
}
exit(0); /* not reached */
if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL)
runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0);
} else {
- if ((runas_pw = sudo_getpwnam(user)) == NULL)
+ if ((runas_pw = sudo_getpwnam(user)) == NULL) {
+#ifdef HAVE_BSM_AUDIT
+ audit_failure(NewArgv, "unknown user: %s", user);
+#endif
log_error(NO_MAIL|MSG_ONLY, "unknown user: %s", user);
+ }
}
}