]> granicus.if.org Git - sudo/blob - plugins/sudoers/bsm_audit.c
c0a8de4a74dc96b3a542b461522dbbdd7257afb6
[sudo] / plugins / sudoers / bsm_audit.c
1 /*
2  * Copyright (c) 2009-2015 Todd C. Miller <Todd.Miller@sudo.ws>
3  * Copyright (c) 2009 Christian S.J. Peron
4  *
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.
8  *
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.
16  */
17
18 /*
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
21  */
22
23 #include <config.h>
24
25 #ifdef HAVE_BSM_AUDIT
26
27 #include <sys/types.h>
28
29 #include <bsm/audit.h>
30 #include <bsm/libbsm.h>
31 #include <bsm/audit_uevents.h>
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <stdarg.h>
36 #include <pwd.h>
37 #include <errno.h>
38 #include <unistd.h>
39
40 #include "sudoers.h"
41 #include "bsm_audit.h"
42
43 /*
44  * Solaris auditon() returns EINVAL if BSM audit not configured.
45  * OpenBSM returns ENOSYS for unimplemented options.
46  */
47 #ifdef __sun
48 # define AUDIT_NOT_CONFIGURED   EINVAL
49 #else
50 # define AUDIT_NOT_CONFIGURED   ENOSYS
51 #endif
52
53 #ifdef __FreeBSD__
54 # define BSM_AUDIT_COMPAT
55 #endif
56
57 static au_event_t sudo_audit_event = AUE_sudo;
58
59 static int
60 audit_sudo_selected(int sorf)
61 {
62         auditinfo_addr_t ainfo_addr;
63         struct au_mask *mask;
64         int rc;
65         debug_decl(audit_sudo_selected, SUDOERS_DEBUG_AUDIT)
66
67         if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) < 0) {
68 #ifdef BSM_AUDIT_COMPAT
69                 if (errno == ENOSYS) {
70                         auditinfo_t ainfo;
71
72                         /* Fall back to older BSM API. */
73                         if (getaudit(&ainfo) < 0) {
74                                 sudo_warn("getaudit");
75                                 debug_return_int(-1);
76                         }
77                         mask = &ainfo.ai_mask;
78                 } else
79 #endif /* BSM_AUDIT_COMPAT */
80                 {
81                         sudo_warn("getaudit_addr");
82                         debug_return_int(-1);
83                 }
84         } else {
85                 mask = &ainfo_addr.ai_mask;
86         }
87         rc = au_preselect(sudo_audit_event, mask, sorf, AU_PRS_REREAD);
88         if (rc == -1) {
89 #if defined(__APPLE__) && defined(AUE_DARWIN_sudo)
90             /*
91              * Mac OS X 10.10 au_preselect() only accepts AUE_DARWIN_sudo.
92              */
93             sudo_audit_event = AUE_DARWIN_sudo;
94             rc = au_preselect(sudo_audit_event, mask, sorf, AU_PRS_REREAD);
95             if (rc == -1)
96 #endif
97
98                 sudo_warn("au_preselect");
99         }
100         debug_return_int(rc);
101 }
102
103 /*
104  * Returns 0 on success or -1 on error.
105  */
106 int
107 bsm_audit_success(char *exec_args[])
108 {
109         auditinfo_addr_t ainfo_addr;
110         token_t *tok;
111         au_id_t auid;
112         long au_cond;
113         int aufd, selected;
114         pid_t pid;
115         debug_decl(bsm_audit_success, SUDOERS_DEBUG_AUDIT)
116
117         /*
118          * If we are not auditing, don't cut an audit record; just return.
119          */
120         if (auditon(A_GETCOND, (caddr_t)&au_cond, sizeof(long)) < 0) {
121                 if (errno == AUDIT_NOT_CONFIGURED)
122                         debug_return_int(0);
123                 sudo_warn(U_("Could not determine audit condition"));
124                 debug_return_int(-1);
125         }
126         if (au_cond == AUC_NOAUDIT)
127                 debug_return_int(0);
128         /*
129          * Check to see if the preselection masks are interested in seeing
130          * this event.
131          */
132         selected = audit_sudo_selected(AU_PRS_SUCCESS);
133         if (selected != 1)
134                 debug_return_int(!selected ? 0 : -1);
135         if (getauid(&auid) < 0) {
136                 sudo_warn("getauid");
137                 debug_return_int(-1);
138         }
139         if ((aufd = au_open()) == -1) {
140                 sudo_warn("au_open");
141                 debug_return_int(-1);
142         }
143         pid = getpid();
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) {
149                 auditinfo_t ainfo;
150
151                 /*
152                  * NB: We should probably watch out for ERANGE here.
153                  */
154                 if (getaudit(&ainfo) < 0) {
155                         sudo_warn("getaudit");
156                         debug_return_int(-1);
157                 }
158                 tok = au_to_subject(auid, geteuid(), getegid(), getuid(),
159                     getuid(), pid, pid, &ainfo.ai_termid);
160 #endif /* BSM_AUDIT_COMPAT */
161         } else {
162                 sudo_warn("getaudit_addr");
163                 debug_return_int(-1);
164         }
165         if (tok == NULL) {
166                 sudo_warn("au_to_subject");
167                 debug_return_int(-1);
168         }
169         au_write(aufd, tok);
170         tok = au_to_exec_args(exec_args);
171         if (tok == NULL) {
172                 sudo_warn("au_to_exec_args");
173                 debug_return_int(-1);
174         }
175         au_write(aufd, tok);
176         tok = au_to_return32(0, 0);
177         if (tok == NULL) {
178                 sudo_warn("au_to_return32");
179                 debug_return_int(-1);
180         }
181         au_write(aufd, tok);
182 #ifdef HAVE_AU_CLOSE_SOLARIS11
183         if (au_close(aufd, 1, sudo_audit_event, 0) == -1)
184 #else
185         if (au_close(aufd, 1, sudo_audit_event) == -1)
186 #endif
187         {
188                 sudo_warn(U_("unable to commit audit record"));
189                 debug_return_int(-1);
190         }
191         debug_return_int(0);
192 }
193
194 /*
195  * Returns 0 on success or -1 on error.
196  */
197 int
198 bsm_audit_failure(char *exec_args[], char const *const fmt, va_list ap)
199 {
200         auditinfo_addr_t ainfo_addr;
201         char text[256];
202         token_t *tok;
203         long au_cond;
204         au_id_t auid;
205         pid_t pid;
206         int aufd;
207         debug_decl(bsm_audit_success, SUDOERS_DEBUG_AUDIT)
208
209         /*
210          * If we are not auditing, don't cut an audit record; just return.
211          */
212         if (auditon(A_GETCOND, (caddr_t)&au_cond, sizeof(long)) < 0) {
213                 if (errno == AUDIT_NOT_CONFIGURED)
214                         debug_return_int(0);
215                 sudo_warn(U_("Could not determine audit condition"));
216                 debug_return_int(-1);
217         }
218         if (au_cond == AUC_NOAUDIT)
219                 debug_return_int(0);
220         if (!audit_sudo_selected(AU_PRS_FAILURE))
221                 debug_return_int(0);
222         if (getauid(&auid) < 0) {
223                 sudo_warn("getauid");
224                 debug_return_int(-1);
225         }
226         if ((aufd = au_open()) == -1) {
227                 sudo_warn("au_open");
228                 debug_return_int(-1);
229         }
230         pid = getpid();
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) {
236                 auditinfo_t ainfo;
237
238                 if (getaudit(&ainfo) < 0) {
239                         sudo_warn("getaudit");
240                         debug_return_int(-1);
241                 }
242                 tok = au_to_subject(auid, geteuid(), getegid(), getuid(),
243                     getuid(), pid, pid, &ainfo.ai_termid);
244 #endif /* BSM_AUDIT_COMPAT */
245         } else {
246                 sudo_warn("getaudit_addr");
247                 debug_return_int(-1);
248         }
249         if (tok == NULL) {
250                 sudo_warn("au_to_subject");
251                 debug_return_int(-1);
252         }
253         au_write(aufd, tok);
254         tok = au_to_exec_args(exec_args);
255         if (tok == NULL) {
256                 sudo_warn("au_to_exec_args");
257                 debug_return_int(-1);
258         }
259         au_write(aufd, tok);
260         (void) vsnprintf(text, sizeof(text), fmt, ap);
261         tok = au_to_text(text);
262         if (tok == NULL) {
263                 sudo_warn("au_to_text");
264                 debug_return_int(-1);
265         }
266         au_write(aufd, tok);
267         tok = au_to_return32(EPERM, 1);
268         if (tok == NULL) {
269                 sudo_warn("au_to_return32");
270                 debug_return_int(-1);
271         }
272         au_write(aufd, tok);
273 #ifdef HAVE_AU_CLOSE_SOLARIS11
274         if (au_close(aufd, 1, sudo_audit_event, PAD_FAILURE) == -1)
275 #else
276         if (au_close(aufd, 1, sudo_audit_event) == -1)
277 #endif
278         {
279                 sudo_warn(U_("unable to commit audit record"));
280                 debug_return_int(-1);
281         }
282         debug_return_int(0);
283 }
284
285 #endif /* HAVE_BSM_AUDIT */