Merge commit 'upstream/1.7.6p1'
[debian/sudo] / bsm_audit.c
1 /*
2  * Copyright (c) 2009-2010 Todd C. Miller <Todd.Miller@courtesan.com>
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 #include <config.h>
19
20 #include <sys/types.h>
21
22 #include <bsm/audit.h>
23 #include <bsm/libbsm.h>
24 #include <bsm/audit_uevents.h>
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #include <pwd.h>
30 #include <errno.h>
31 #include <unistd.h>
32
33 #include "bsm_audit.h"
34
35 /*
36  * Solaris auditon() returns EINVAL if BSM audit not configured.
37  * OpenBSM returns ENOSYS for unimplemented options.
38  */
39 #ifdef __sun
40 # define AUDIT_NOT_CONFIGURED   EINVAL
41 #else
42 # define AUDIT_NOT_CONFIGURED   ENOSYS
43 #endif
44
45 void log_error(int flags, const char *fmt, ...) __attribute__((__noreturn__));
46
47 static int
48 audit_sudo_selected(int sf)
49 {
50         auditinfo_addr_t ainfo_addr;
51         struct au_mask *mask;
52         auditinfo_t ainfo;
53         int rc, sorf;
54
55         if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) < 0) {
56                 if (errno == ENOSYS) {
57                         if (getaudit(&ainfo) < 0)
58                                 log_error(0, "getaudit: failed");
59                         mask = &ainfo.ai_mask;
60                 } else
61                         log_error(0, "getaudit: failed");
62         } else
63                 mask = &ainfo_addr.ai_mask;
64         sorf = (sf == 0) ? AU_PRS_SUCCESS : AU_PRS_FAILURE;
65         rc = au_preselect(AUE_sudo, mask, sorf, AU_PRS_REREAD);
66         return rc;
67 }
68
69 void
70 bsm_audit_success(char **exec_args)
71 {
72         auditinfo_addr_t ainfo_addr;
73         auditinfo_t ainfo;
74         token_t *tok;
75         au_id_t auid;
76         long au_cond;
77         int aufd;
78         pid_t pid;
79
80         pid = getpid();
81         /*
82          * If we are not auditing, don't cut an audit record; just return.
83          */
84         if (auditon(A_GETCOND, (caddr_t)&au_cond, sizeof(long)) < 0) {
85                 if (errno == AUDIT_NOT_CONFIGURED)
86                         return;
87                 log_error(0, "Could not determine audit condition");
88         }
89         if (au_cond == AUC_NOAUDIT)
90                 return;
91         /*
92          * Check to see if the preselection masks are interested in seeing
93          * this event.
94          */
95         if (!audit_sudo_selected(0))
96                 return;
97         if (getauid(&auid) < 0)
98                 log_error(0, "getauid failed");
99         if ((aufd = au_open()) == -1)
100                 log_error(0, "au_open: failed");
101         if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) {
102                 tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(),
103                     getuid(), pid, pid, &ainfo_addr.ai_termid);
104         } else if (errno == ENOSYS) {
105                 /*
106                  * NB: We should probably watch out for ERANGE here.
107                  */
108                 if (getaudit(&ainfo) < 0)
109                         log_error(0, "getaudit: failed");
110                 tok = au_to_subject(auid, geteuid(), getegid(), getuid(),
111                     getuid(), pid, pid, &ainfo.ai_termid);
112         } else
113                 log_error(0, "getaudit: failed");
114         if (tok == NULL)
115                 log_error(0, "au_to_subject: failed");
116         au_write(aufd, tok);
117         tok = au_to_exec_args(exec_args);
118         if (tok == NULL)
119                 log_error(0, "au_to_exec_args: failed");
120         au_write(aufd, tok);
121         tok = au_to_return32(0, 0);
122         if (tok == NULL)
123                 log_error(0, "au_to_return32: failed");
124         au_write(aufd, tok);
125         if (au_close(aufd, 1, AUE_sudo) == -1)
126                 log_error(0, "unable to commit audit record");
127 }
128
129 void
130 bsm_audit_failure(char **exec_args, char const *const fmt, va_list ap)
131 {
132         auditinfo_addr_t ainfo_addr;
133         auditinfo_t ainfo;
134         char text[256];
135         token_t *tok;
136         long au_cond;
137         au_id_t auid;
138         pid_t pid;
139         int aufd;
140
141         pid = getpid();
142         /*
143          * If we are not auditing, don't cut an audit record; just return.
144          */
145         if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
146                 if (errno == AUDIT_NOT_CONFIGURED)
147                         return;
148                 log_error(0, "Could not determine audit condition");
149         }
150         if (au_cond == AUC_NOAUDIT)
151                 return;
152         if (!audit_sudo_selected(1))
153                 return;
154         if (getauid(&auid) < 0)
155                 log_error(0, "getauid: failed");
156         if ((aufd = au_open()) == -1)
157                 log_error(0, "au_open: failed");
158         if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) { 
159                 tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(),
160                     getuid(), pid, pid, &ainfo_addr.ai_termid);
161         } else if (errno == ENOSYS) {
162                 if (getaudit(&ainfo) < 0) 
163                         log_error(0, "getaudit: failed");
164                 tok = au_to_subject(auid, geteuid(), getegid(), getuid(),
165                     getuid(), pid, pid, &ainfo.ai_termid);
166         } else
167                 log_error(0, "getaudit: failed");
168         if (tok == NULL)
169                 log_error(0, "au_to_subject: failed");
170         au_write(aufd, tok);
171         tok = au_to_exec_args(exec_args);
172         if (tok == NULL)
173                 log_error(0, "au_to_exec_args: failed");
174         au_write(aufd, tok);
175         (void) vsnprintf(text, sizeof(text), fmt, ap);
176         tok = au_to_text(text);
177         if (tok == NULL)
178                 log_error(0, "au_to_text: failed");
179         au_write(aufd, tok);
180         tok = au_to_return32(EPERM, 1);
181         if (tok == NULL)
182                 log_error(0, "au_to_return32: failed");
183         au_write(aufd, tok);
184         if (au_close(aufd, 1, AUE_sudo) == -1)
185                 log_error(0, "unable to commit audit record");
186 }