patch from upstream to fix special case in password checking code
[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 void log_error(int flags, const char *fmt, ...) __attribute__((__noreturn__));
35
36 static int
37 audit_sudo_selected(int sf)
38 {
39         auditinfo_addr_t ainfo_addr;
40         struct au_mask *mask;
41         auditinfo_t ainfo;
42         int rc, sorf;
43
44         if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) < 0) {
45                 if (errno == ENOSYS) {
46                         if (getaudit(&ainfo) < 0)
47                                 log_error(0, "getaudit: failed");
48                         mask = &ainfo.ai_mask;
49                 } else
50                         log_error(0, "getaudit: failed");
51         } else
52                 mask = &ainfo_addr.ai_mask;
53         sorf = (sf == 0) ? AU_PRS_SUCCESS : AU_PRS_FAILURE;
54         rc = au_preselect(AUE_sudo, mask, sorf, AU_PRS_REREAD);
55         return (rc);
56 }
57
58 void
59 bsm_audit_success(char **exec_args)
60 {
61         auditinfo_addr_t ainfo_addr;
62         auditinfo_t ainfo;
63         token_t *tok;
64         au_id_t auid;
65         long au_cond;
66         int aufd;
67         pid_t pid;
68
69         pid = getpid();
70         /*
71          * If we are not auditing, don't cut an audit record; just return.
72          */
73         if (auditon(A_GETCOND, (caddr_t)&au_cond, sizeof(long)) < 0) {
74                 if (errno == ENOSYS)
75                         return;
76                 log_error(0, "Could not determine audit condition");
77         }
78         if (au_cond == AUC_NOAUDIT)
79                 return;
80         /*
81          * Check to see if the preselection masks are interested in seeing
82          * this event.
83          */
84         if (!audit_sudo_selected(0))
85                 return;
86         if (getauid(&auid) < 0)
87                 log_error(0, "getauid failed");
88         if ((aufd = au_open()) == -1)
89                 log_error(0, "au_open: failed");
90         if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) {
91                 tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(),
92                     getuid(), pid, pid, &ainfo_addr.ai_termid);
93         } else if (errno == ENOSYS) {
94                 /*
95                  * NB: We should probably watch out for ERANGE here.
96                  */
97                 if (getaudit(&ainfo) < 0)
98                         log_error(0, "getaudit: failed");
99                 tok = au_to_subject(auid, geteuid(), getegid(), getuid(),
100                     getuid(), pid, pid, &ainfo.ai_termid);
101         } else
102                 log_error(0, "getaudit: failed");
103         if (tok == NULL)
104                 log_error(0, "au_to_subject: failed");
105         au_write(aufd, tok);
106         tok = au_to_exec_args(exec_args);
107         if (tok == NULL)
108                 log_error(0, "au_to_exec_args: failed");
109         au_write(aufd, tok);
110         tok = au_to_return32(0, 0);
111         if (tok == NULL)
112                 log_error(0, "au_to_return32: failed");
113         au_write(aufd, tok);
114         if (au_close(aufd, 1, AUE_sudo) == -1)
115                 log_error(0, "unable to commit audit record");
116 }
117
118 void
119 bsm_audit_failure(char **exec_args, char const *const fmt, va_list ap)
120 {
121         auditinfo_addr_t ainfo_addr;
122         auditinfo_t ainfo;
123         char text[256];
124         token_t *tok;
125         long au_cond;
126         au_id_t auid;
127         pid_t pid;
128         int aufd;
129
130         pid = getpid();
131         /*
132          * If we are not auditing, don't cut an audit record; just return.
133          */
134         if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
135                 if (errno == ENOSYS)
136                         return;
137                 log_error(0, "Could not determine audit condition");
138         }
139         if (au_cond == AUC_NOAUDIT)
140                 return;
141         if (!audit_sudo_selected(1))
142                 return;
143         if (getauid(&auid) < 0)
144                 log_error(0, "getauid: failed");
145         if ((aufd = au_open()) == -1)
146                 log_error(0, "au_open: failed");
147         if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) { 
148                 tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(),
149                     getuid(), pid, pid, &ainfo_addr.ai_termid);
150         } else if (errno == ENOSYS) {
151                 if (getaudit(&ainfo) < 0) 
152                         log_error(0, "getaudit: failed");
153                 tok = au_to_subject(auid, geteuid(), getegid(), getuid(),
154                     getuid(), pid, pid, &ainfo.ai_termid);
155         } else
156                 log_error(0, "getaudit: failed");
157         if (tok == NULL)
158                 log_error(0, "au_to_subject: failed");
159         au_write(aufd, tok);
160         tok = au_to_exec_args(exec_args);
161         if (tok == NULL)
162                 log_error(0, "au_to_exec_args: failed");
163         au_write(aufd, tok);
164         (void) vsnprintf(text, sizeof(text), fmt, ap);
165         tok = au_to_text(text);
166         if (tok == NULL)
167                 log_error(0, "au_to_text: failed");
168         au_write(aufd, tok);
169         tok = au_to_return32(EPERM, 1);
170         if (tok == NULL)
171                 log_error(0, "au_to_return32: failed");
172         au_write(aufd, tok);
173         if (au_close(aufd, 1, AUE_sudo) == -1)
174                 log_error(0, "unable to commit audit record");
175 }