diff options
Diffstat (limited to '')
-rw-r--r-- | plugins/sudoers/bsm_audit.c | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/plugins/sudoers/bsm_audit.c b/plugins/sudoers/bsm_audit.c new file mode 100644 index 0000000..c0a8de4 --- /dev/null +++ b/plugins/sudoers/bsm_audit.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2009-2015 Todd C. Miller <Todd.Miller@sudo.ws> + * 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. + */ + +/* + * This is an open source non-commercial project. Dear PVS-Studio, please check it. + * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + */ + +#include <config.h> + +#ifdef HAVE_BSM_AUDIT + +#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> + +#include "sudoers.h" +#include "bsm_audit.h" + +/* + * Solaris auditon() returns EINVAL if BSM audit not configured. + * OpenBSM returns ENOSYS for unimplemented options. + */ +#ifdef __sun +# define AUDIT_NOT_CONFIGURED EINVAL +#else +# define AUDIT_NOT_CONFIGURED ENOSYS +#endif + +#ifdef __FreeBSD__ +# define BSM_AUDIT_COMPAT +#endif + +static au_event_t sudo_audit_event = AUE_sudo; + +static int +audit_sudo_selected(int sorf) +{ + auditinfo_addr_t ainfo_addr; + struct au_mask *mask; + int rc; + debug_decl(audit_sudo_selected, SUDOERS_DEBUG_AUDIT) + + if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) < 0) { +#ifdef BSM_AUDIT_COMPAT + if (errno == ENOSYS) { + auditinfo_t ainfo; + + /* Fall back to older BSM API. */ + if (getaudit(&ainfo) < 0) { + sudo_warn("getaudit"); + debug_return_int(-1); + } + mask = &ainfo.ai_mask; + } else +#endif /* BSM_AUDIT_COMPAT */ + { + sudo_warn("getaudit_addr"); + debug_return_int(-1); + } + } else { + mask = &ainfo_addr.ai_mask; + } + rc = au_preselect(sudo_audit_event, mask, sorf, AU_PRS_REREAD); + if (rc == -1) { +#if defined(__APPLE__) && defined(AUE_DARWIN_sudo) + /* + * Mac OS X 10.10 au_preselect() only accepts AUE_DARWIN_sudo. + */ + sudo_audit_event = AUE_DARWIN_sudo; + rc = au_preselect(sudo_audit_event, mask, sorf, AU_PRS_REREAD); + if (rc == -1) +#endif + + sudo_warn("au_preselect"); + } + debug_return_int(rc); +} + +/* + * Returns 0 on success or -1 on error. + */ +int +bsm_audit_success(char *exec_args[]) +{ + auditinfo_addr_t ainfo_addr; + token_t *tok; + au_id_t auid; + long au_cond; + int aufd, selected; + pid_t pid; + debug_decl(bsm_audit_success, SUDOERS_DEBUG_AUDIT) + + /* + * 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 == AUDIT_NOT_CONFIGURED) + debug_return_int(0); + sudo_warn(U_("Could not determine audit condition")); + debug_return_int(-1); + } + if (au_cond == AUC_NOAUDIT) + debug_return_int(0); + /* + * Check to see if the preselection masks are interested in seeing + * this event. + */ + selected = audit_sudo_selected(AU_PRS_SUCCESS); + if (selected != 1) + debug_return_int(!selected ? 0 : -1); + if (getauid(&auid) < 0) { + sudo_warn("getauid"); + debug_return_int(-1); + } + if ((aufd = au_open()) == -1) { + sudo_warn("au_open"); + debug_return_int(-1); + } + pid = getpid(); + 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); +#ifdef BSM_AUDIT_COMPAT + } else if (errno == ENOSYS) { + auditinfo_t ainfo; + + /* + * NB: We should probably watch out for ERANGE here. + */ + if (getaudit(&ainfo) < 0) { + sudo_warn("getaudit"); + debug_return_int(-1); + } + tok = au_to_subject(auid, geteuid(), getegid(), getuid(), + getuid(), pid, pid, &ainfo.ai_termid); +#endif /* BSM_AUDIT_COMPAT */ + } else { + sudo_warn("getaudit_addr"); + debug_return_int(-1); + } + if (tok == NULL) { + sudo_warn("au_to_subject"); + debug_return_int(-1); + } + au_write(aufd, tok); + tok = au_to_exec_args(exec_args); + if (tok == NULL) { + sudo_warn("au_to_exec_args"); + debug_return_int(-1); + } + au_write(aufd, tok); + tok = au_to_return32(0, 0); + if (tok == NULL) { + sudo_warn("au_to_return32"); + debug_return_int(-1); + } + au_write(aufd, tok); +#ifdef HAVE_AU_CLOSE_SOLARIS11 + if (au_close(aufd, 1, sudo_audit_event, 0) == -1) +#else + if (au_close(aufd, 1, sudo_audit_event) == -1) +#endif + { + sudo_warn(U_("unable to commit audit record")); + debug_return_int(-1); + } + debug_return_int(0); +} + +/* + * Returns 0 on success or -1 on error. + */ +int +bsm_audit_failure(char *exec_args[], char const *const fmt, va_list ap) +{ + auditinfo_addr_t ainfo_addr; + char text[256]; + token_t *tok; + long au_cond; + au_id_t auid; + pid_t pid; + int aufd; + debug_decl(bsm_audit_success, SUDOERS_DEBUG_AUDIT) + + /* + * 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 == AUDIT_NOT_CONFIGURED) + debug_return_int(0); + sudo_warn(U_("Could not determine audit condition")); + debug_return_int(-1); + } + if (au_cond == AUC_NOAUDIT) + debug_return_int(0); + if (!audit_sudo_selected(AU_PRS_FAILURE)) + debug_return_int(0); + if (getauid(&auid) < 0) { + sudo_warn("getauid"); + debug_return_int(-1); + } + if ((aufd = au_open()) == -1) { + sudo_warn("au_open"); + debug_return_int(-1); + } + pid = getpid(); + 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); +#ifdef BSM_AUDIT_COMPAT + } else if (errno == ENOSYS) { + auditinfo_t ainfo; + + if (getaudit(&ainfo) < 0) { + sudo_warn("getaudit"); + debug_return_int(-1); + } + tok = au_to_subject(auid, geteuid(), getegid(), getuid(), + getuid(), pid, pid, &ainfo.ai_termid); +#endif /* BSM_AUDIT_COMPAT */ + } else { + sudo_warn("getaudit_addr"); + debug_return_int(-1); + } + if (tok == NULL) { + sudo_warn("au_to_subject"); + debug_return_int(-1); + } + au_write(aufd, tok); + tok = au_to_exec_args(exec_args); + if (tok == NULL) { + sudo_warn("au_to_exec_args"); + debug_return_int(-1); + } + au_write(aufd, tok); + (void) vsnprintf(text, sizeof(text), fmt, ap); + tok = au_to_text(text); + if (tok == NULL) { + sudo_warn("au_to_text"); + debug_return_int(-1); + } + au_write(aufd, tok); + tok = au_to_return32(EPERM, 1); + if (tok == NULL) { + sudo_warn("au_to_return32"); + debug_return_int(-1); + } + au_write(aufd, tok); +#ifdef HAVE_AU_CLOSE_SOLARIS11 + if (au_close(aufd, 1, sudo_audit_event, PAD_FAILURE) == -1) +#else + if (au_close(aufd, 1, sudo_audit_event) == -1) +#endif + { + sudo_warn(U_("unable to commit audit record")); + debug_return_int(-1); + } + debug_return_int(0); +} + +#endif /* HAVE_BSM_AUDIT */ |