a673d281e3c1a7f0456d3635adcdd6dfe98f51aa
[debian/sudo] / bsm_audit.c
1 /*
2  * Copyright (c) 2009 Christian S.J. Peron
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <config.h>
18
19 #include <sys/types.h>
20
21 #include <bsm/audit.h>
22 #include <bsm/libbsm.h>
23 #include <bsm/audit_uevents.h>
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <pwd.h>
29 #include <errno.h>
30 #include <unistd.h>
31
32 #include "bsm_audit.h"
33
34 /*
35  * Solaris auditon() returns EINVAL if BSM audit not configured.
36  * OpenBSM returns ENOSYS for unimplemented options.
37  */
38 #ifdef __sun__
39 # define AUDIT_NOT_CONFIGURED   EINVAL
40 #else
41 # define AUDIT_NOT_CONFIGURED   ENOSYS
42 #endif
43
44 void log_error(int flags, const char *fmt, ...) __attribute__((__noreturn__));
45
46 static int
47 audit_sudo_selected(int sf)
48 {
49         auditinfo_addr_t ainfo_addr;
50         struct au_mask *mask;
51         auditinfo_t ainfo;
52         int rc, sorf;
53
54         if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) < 0) {
55                 if (errno == ENOSYS) {
56                         if (getaudit(&ainfo) < 0)
57                                 log_error(0, "getaudit: failed");
58                         mask = &ainfo.ai_mask;
59                 } else
60                         log_error(0, "getaudit: failed");
61         } else
62                 mask = &ainfo_addr.ai_mask;
63         sorf = (sf == 0) ? AU_PRS_SUCCESS : AU_PRS_FAILURE;
64         rc = au_preselect(AUE_sudo, mask, sorf, AU_PRS_REREAD);
65         return (rc);
66 }
67
68 void
69 bsm_audit_success(char **exec_args)
70 {
71         auditinfo_addr_t ainfo_addr;
72         auditinfo_t ainfo;
73         token_t *tok;
74         au_id_t auid;
75         long au_cond;
76         int aufd;
77         pid_t pid;
78
79         pid = getpid();
80         /*
81          * If we are not auditing, don't cut an audit record; just return.
82          */
83         if (auditon(A_GETCOND, (caddr_t)&au_cond, sizeof(long)) < 0) {
84                 if (errno == AUDIT_NOT_CONFIGURED)
85                         return;
86                 log_error(0, "Could not determine audit condition");
87         }
88         if (au_cond == AUC_NOAUDIT)
89                 return;
90         /*
91          * Check to see if the preselection masks are interested in seeing
92          * this event.
93          */
94         if (!audit_sudo_selected(0))
95                 return;
96         if (getauid(&auid) < 0)
97                 log_error(0, "getauid failed");
98         if ((aufd = au_open()) == -1)
99                 log_error(0, "au_open: failed");
100         if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) {
101                 tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(),
102                     getuid(), pid, pid, &ainfo_addr.ai_termid);
103         } else if (errno == ENOSYS) {
104                 /*
105                  * NB: We should probably watch out for ERANGE here.
106                  */
107                 if (getaudit(&ainfo) < 0)
108                         log_error(0, "getaudit: failed");
109                 tok = au_to_subject(auid, geteuid(), getegid(), getuid(),
110                     getuid(), pid, pid, &ainfo.ai_termid);
111         } else
112                 log_error(0, "getaudit: failed");
113         if (tok == NULL)
114                 log_error(0, "au_to_subject: failed");
115         au_write(aufd, tok);
116         tok = au_to_exec_args(exec_args);
117         if (tok == NULL)
118                 log_error(0, "au_to_exec_args: failed");
119         au_write(aufd, tok);
120         tok = au_to_return32(0, 0);
121         if (tok == NULL)
122                 log_error(0, "au_to_return32: failed");
123         au_write(aufd, tok);
124         if (au_close(aufd, 1, AUE_sudo) == -1)
125                 log_error(0, "unable to commit audit record");
126 }
127
128 void
129 bsm_audit_failure(char **exec_args, char const *const fmt, va_list ap)
130 {
131         auditinfo_addr_t ainfo_addr;
132         auditinfo_t ainfo;
133         char text[256];
134         token_t *tok;
135         long au_cond;
136         au_id_t auid;
137         pid_t pid;
138         int aufd;
139
140         pid = getpid();
141         /*
142          * If we are not auditing, don't cut an audit record; just return.
143          */
144         if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
145                 if (errno == AUDIT_NOT_CONFIGURED)
146                         return;
147                 log_error(0, "Could not determine audit condition");
148         }
149         if (au_cond == AUC_NOAUDIT)
150                 return;
151         if (!audit_sudo_selected(1))
152                 return;
153         if (getauid(&auid) < 0)
154                 log_error(0, "getauid: failed");
155         if ((aufd = au_open()) == -1)
156                 log_error(0, "au_open: failed");
157         if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) { 
158                 tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(),
159                     getuid(), pid, pid, &ainfo_addr.ai_termid);
160         } else if (errno == ENOSYS) {
161                 if (getaudit(&ainfo) < 0) 
162                         log_error(0, "getaudit: failed");
163                 tok = au_to_subject(auid, geteuid(), getegid(), getuid(),
164                     getuid(), pid, pid, &ainfo.ai_termid);
165         } else
166                 log_error(0, "getaudit: failed");
167         if (tok == NULL)
168                 log_error(0, "au_to_subject: failed");
169         au_write(aufd, tok);
170         tok = au_to_exec_args(exec_args);
171         if (tok == NULL)
172                 log_error(0, "au_to_exec_args: failed");
173         au_write(aufd, tok);
174         (void) vsnprintf(text, sizeof(text), fmt, ap);
175         tok = au_to_text(text);
176         if (tok == NULL)
177                 log_error(0, "au_to_text: failed");
178         au_write(aufd, tok);
179         tok = au_to_return32(EPERM, 1);
180         if (tok == NULL)
181                 log_error(0, "au_to_return32: failed");
182         au_write(aufd, tok);
183         if (au_close(aufd, 1, AUE_sudo) == -1)
184                 log_error(0, "unable to commit audit record");
185 }