2 * Copyright (c) 2009-2015 Todd C. Miller <Todd.Miller@sudo.ws>
3 * Copyright (c) 2009 Christian S.J. Peron
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 * This is an open source non-commercial project. Dear PVS-Studio, please check it.
20 * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
27 #include <sys/types.h>
29 #include <bsm/audit.h>
30 #include <bsm/libbsm.h>
31 #include <bsm/audit_uevents.h>
41 #include "bsm_audit.h"
44 * Solaris auditon() returns EINVAL if BSM audit not configured.
45 * OpenBSM returns ENOSYS for unimplemented options.
48 # define AUDIT_NOT_CONFIGURED EINVAL
50 # define AUDIT_NOT_CONFIGURED ENOSYS
54 # define BSM_AUDIT_COMPAT
57 static au_event_t sudo_audit_event = AUE_sudo;
60 audit_sudo_selected(int sorf)
62 auditinfo_addr_t ainfo_addr;
65 debug_decl(audit_sudo_selected, SUDOERS_DEBUG_AUDIT)
67 if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) < 0) {
68 #ifdef BSM_AUDIT_COMPAT
69 if (errno == ENOSYS) {
72 /* Fall back to older BSM API. */
73 if (getaudit(&ainfo) < 0) {
74 sudo_warn("getaudit");
77 mask = &ainfo.ai_mask;
79 #endif /* BSM_AUDIT_COMPAT */
81 sudo_warn("getaudit_addr");
85 mask = &ainfo_addr.ai_mask;
87 rc = au_preselect(sudo_audit_event, mask, sorf, AU_PRS_REREAD);
89 #if defined(__APPLE__) && defined(AUE_DARWIN_sudo)
91 * Mac OS X 10.10 au_preselect() only accepts AUE_DARWIN_sudo.
93 sudo_audit_event = AUE_DARWIN_sudo;
94 rc = au_preselect(sudo_audit_event, mask, sorf, AU_PRS_REREAD);
98 sudo_warn("au_preselect");
100 debug_return_int(rc);
104 * Returns 0 on success or -1 on error.
107 bsm_audit_success(char *exec_args[])
109 auditinfo_addr_t ainfo_addr;
115 debug_decl(bsm_audit_success, SUDOERS_DEBUG_AUDIT)
118 * If we are not auditing, don't cut an audit record; just return.
120 if (auditon(A_GETCOND, (caddr_t)&au_cond, sizeof(long)) < 0) {
121 if (errno == AUDIT_NOT_CONFIGURED)
123 sudo_warn(U_("Could not determine audit condition"));
124 debug_return_int(-1);
126 if (au_cond == AUC_NOAUDIT)
129 * Check to see if the preselection masks are interested in seeing
132 selected = audit_sudo_selected(AU_PRS_SUCCESS);
134 debug_return_int(!selected ? 0 : -1);
135 if (getauid(&auid) < 0) {
136 sudo_warn("getauid");
137 debug_return_int(-1);
139 if ((aufd = au_open()) == -1) {
140 sudo_warn("au_open");
141 debug_return_int(-1);
144 if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) {
145 tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(),
146 getuid(), pid, pid, &ainfo_addr.ai_termid);
147 #ifdef BSM_AUDIT_COMPAT
148 } else if (errno == ENOSYS) {
152 * NB: We should probably watch out for ERANGE here.
154 if (getaudit(&ainfo) < 0) {
155 sudo_warn("getaudit");
156 debug_return_int(-1);
158 tok = au_to_subject(auid, geteuid(), getegid(), getuid(),
159 getuid(), pid, pid, &ainfo.ai_termid);
160 #endif /* BSM_AUDIT_COMPAT */
162 sudo_warn("getaudit_addr");
163 debug_return_int(-1);
166 sudo_warn("au_to_subject");
167 debug_return_int(-1);
170 tok = au_to_exec_args(exec_args);
172 sudo_warn("au_to_exec_args");
173 debug_return_int(-1);
176 tok = au_to_return32(0, 0);
178 sudo_warn("au_to_return32");
179 debug_return_int(-1);
182 #ifdef HAVE_AU_CLOSE_SOLARIS11
183 if (au_close(aufd, 1, sudo_audit_event, 0) == -1)
185 if (au_close(aufd, 1, sudo_audit_event) == -1)
188 sudo_warn(U_("unable to commit audit record"));
189 debug_return_int(-1);
195 * Returns 0 on success or -1 on error.
198 bsm_audit_failure(char *exec_args[], char const *const fmt, va_list ap)
200 auditinfo_addr_t ainfo_addr;
207 debug_decl(bsm_audit_success, SUDOERS_DEBUG_AUDIT)
210 * If we are not auditing, don't cut an audit record; just return.
212 if (auditon(A_GETCOND, (caddr_t)&au_cond, sizeof(long)) < 0) {
213 if (errno == AUDIT_NOT_CONFIGURED)
215 sudo_warn(U_("Could not determine audit condition"));
216 debug_return_int(-1);
218 if (au_cond == AUC_NOAUDIT)
220 if (!audit_sudo_selected(AU_PRS_FAILURE))
222 if (getauid(&auid) < 0) {
223 sudo_warn("getauid");
224 debug_return_int(-1);
226 if ((aufd = au_open()) == -1) {
227 sudo_warn("au_open");
228 debug_return_int(-1);
231 if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) {
232 tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(),
233 getuid(), pid, pid, &ainfo_addr.ai_termid);
234 #ifdef BSM_AUDIT_COMPAT
235 } else if (errno == ENOSYS) {
238 if (getaudit(&ainfo) < 0) {
239 sudo_warn("getaudit");
240 debug_return_int(-1);
242 tok = au_to_subject(auid, geteuid(), getegid(), getuid(),
243 getuid(), pid, pid, &ainfo.ai_termid);
244 #endif /* BSM_AUDIT_COMPAT */
246 sudo_warn("getaudit_addr");
247 debug_return_int(-1);
250 sudo_warn("au_to_subject");
251 debug_return_int(-1);
254 tok = au_to_exec_args(exec_args);
256 sudo_warn("au_to_exec_args");
257 debug_return_int(-1);
260 (void) vsnprintf(text, sizeof(text), fmt, ap);
261 tok = au_to_text(text);
263 sudo_warn("au_to_text");
264 debug_return_int(-1);
267 tok = au_to_return32(EPERM, 1);
269 sudo_warn("au_to_return32");
270 debug_return_int(-1);
273 #ifdef HAVE_AU_CLOSE_SOLARIS11
274 if (au_close(aufd, 1, sudo_audit_event, PAD_FAILURE) == -1)
276 if (au_close(aufd, 1, sudo_audit_event) == -1)
279 sudo_warn(U_("unable to commit audit record"));
280 debug_return_int(-1);
285 #endif /* HAVE_BSM_AUDIT */