Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/plugins/sudoers/bsm_audit.c
1532 views
1
/*
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 2009-2015 Todd C. Miller <[email protected]>
5
* Copyright (c) 2009 Christian S.J. Peron
6
*
7
* Permission to use, copy, modify, and distribute this software for any
8
* purpose with or without fee is hereby granted, provided that the above
9
* copyright notice and this permission notice appear in all copies.
10
*
11
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
*/
19
20
#include <config.h>
21
22
#ifdef HAVE_BSM_AUDIT
23
24
#include <sys/types.h> /* for pid_t */
25
26
#include <bsm/audit.h>
27
#include <bsm/libbsm.h>
28
#include <bsm/audit_uevents.h>
29
30
#include <stdio.h>
31
#include <stdarg.h>
32
#include <errno.h>
33
#include <unistd.h>
34
35
#include <sudoers.h>
36
#include <bsm_audit.h>
37
38
/*
39
* Solaris auditon() returns EINVAL if BSM audit not configured.
40
* OpenBSM returns ENOSYS for unimplemented options.
41
*/
42
#ifdef __sun
43
# define AUDIT_NOT_CONFIGURED EINVAL
44
#else
45
# define AUDIT_NOT_CONFIGURED ENOSYS
46
#endif
47
48
#ifdef __FreeBSD__
49
# define BSM_AUDIT_COMPAT
50
#endif
51
52
static au_event_t sudo_audit_event = AUE_sudo;
53
54
static int
55
audit_sudo_selected(int sorf)
56
{
57
auditinfo_addr_t ainfo_addr;
58
struct au_mask *mask;
59
int rc;
60
debug_decl(audit_sudo_selected, SUDOERS_DEBUG_AUDIT);
61
62
if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) < 0) {
63
#ifdef BSM_AUDIT_COMPAT
64
if (errno == ENOSYS) {
65
auditinfo_t ainfo;
66
67
/* Fall back to older BSM API. */
68
if (getaudit(&ainfo) < 0) {
69
sudo_warn("getaudit");
70
debug_return_int(-1);
71
}
72
mask = &ainfo.ai_mask;
73
} else
74
#endif /* BSM_AUDIT_COMPAT */
75
{
76
sudo_warn("getaudit_addr");
77
debug_return_int(-1);
78
}
79
} else {
80
mask = &ainfo_addr.ai_mask;
81
}
82
rc = au_preselect(sudo_audit_event, mask, sorf, AU_PRS_REREAD);
83
if (rc == -1) {
84
#if defined(__APPLE__) && defined(AUE_DARWIN_sudo)
85
/*
86
* Mac OS X 10.10 au_preselect() only accepts AUE_DARWIN_sudo.
87
*/
88
sudo_audit_event = AUE_DARWIN_sudo;
89
rc = au_preselect(sudo_audit_event, mask, sorf, AU_PRS_REREAD);
90
if (rc == -1)
91
#endif
92
93
sudo_warn("au_preselect");
94
}
95
debug_return_int(rc);
96
}
97
98
/*
99
* Returns 0 on success or -1 on error.
100
*/
101
int
102
bsm_audit_success(const struct sudoers_context *ctx, char *const exec_args[])
103
{
104
auditinfo_addr_t ainfo_addr;
105
token_t *tok;
106
au_id_t auid;
107
long au_cond;
108
int aufd, selected;
109
debug_decl(bsm_audit_success, SUDOERS_DEBUG_AUDIT);
110
111
/*
112
* If we are not auditing, don't cut an audit record; just return.
113
*/
114
if (auditon(A_GETCOND, (caddr_t)&au_cond, sizeof(long)) < 0) {
115
if (errno == AUDIT_NOT_CONFIGURED)
116
debug_return_int(0);
117
sudo_warn("%s", U_("Could not determine audit condition"));
118
debug_return_int(-1);
119
}
120
if (au_cond == AUC_NOAUDIT)
121
debug_return_int(0);
122
/*
123
* Check to see if the preselection masks are interested in seeing
124
* this event.
125
*/
126
selected = audit_sudo_selected(AU_PRS_SUCCESS);
127
if (selected != 1)
128
debug_return_int(!selected ? 0 : -1);
129
if (getauid(&auid) < 0) {
130
sudo_warn("getauid");
131
debug_return_int(-1);
132
}
133
if ((aufd = au_open()) == -1) {
134
sudo_warn("au_open");
135
debug_return_int(-1);
136
}
137
if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) {
138
tok = au_to_subject_ex(auid, ctx->user.euid, ctx->user.egid,
139
ctx->user.uid, ctx->user.gid, ctx->user.pid, ctx->user.pid,
140
&ainfo_addr.ai_termid);
141
#ifdef BSM_AUDIT_COMPAT
142
} else if (errno == ENOSYS) {
143
auditinfo_t ainfo;
144
145
/*
146
* NB: We should probably watch out for ERANGE here.
147
*/
148
if (getaudit(&ainfo) < 0) {
149
sudo_warn("getaudit");
150
debug_return_int(-1);
151
}
152
tok = au_to_subject(auid, ctx->user.euid, ctx->user.egid,
153
ctx->user.uid, ctx->user.gid, ctx->user.pid, ctx->user.pid,
154
&ainfo.ai_termid);
155
#endif /* BSM_AUDIT_COMPAT */
156
} else {
157
sudo_warn("getaudit_addr");
158
debug_return_int(-1);
159
}
160
if (tok == NULL) {
161
sudo_warn("au_to_subject");
162
debug_return_int(-1);
163
}
164
au_write(aufd, tok);
165
tok = au_to_exec_args((char **)exec_args);
166
if (tok == NULL) {
167
sudo_warn("au_to_exec_args");
168
debug_return_int(-1);
169
}
170
au_write(aufd, tok);
171
tok = au_to_return32(0, 0);
172
if (tok == NULL) {
173
sudo_warn("au_to_return32");
174
debug_return_int(-1);
175
}
176
au_write(aufd, tok);
177
#ifdef HAVE_AU_CLOSE_SOLARIS11
178
if (au_close(aufd, 1, sudo_audit_event, 0) == -1)
179
#else
180
if (au_close(aufd, 1, sudo_audit_event) == -1)
181
#endif
182
{
183
sudo_warn("%s", U_("unable to commit audit record"));
184
debug_return_int(-1);
185
}
186
debug_return_int(0);
187
}
188
189
/*
190
* Returns 0 on success or -1 on error.
191
*/
192
int
193
bsm_audit_failure(const struct sudoers_context *ctx, char *const exec_args[],
194
const char *errmsg)
195
{
196
auditinfo_addr_t ainfo_addr;
197
token_t *tok;
198
long au_cond;
199
au_id_t auid;
200
int aufd;
201
debug_decl(bsm_audit_failure, SUDOERS_DEBUG_AUDIT);
202
203
/*
204
* If we are not auditing, don't cut an audit record; just return.
205
*/
206
if (auditon(A_GETCOND, (caddr_t)&au_cond, sizeof(long)) < 0) {
207
if (errno == AUDIT_NOT_CONFIGURED)
208
debug_return_int(0);
209
sudo_warn("%s", U_("Could not determine audit condition"));
210
debug_return_int(-1);
211
}
212
if (au_cond == AUC_NOAUDIT)
213
debug_return_int(0);
214
if (!audit_sudo_selected(AU_PRS_FAILURE))
215
debug_return_int(0);
216
if (getauid(&auid) < 0) {
217
sudo_warn("getauid");
218
debug_return_int(-1);
219
}
220
if ((aufd = au_open()) == -1) {
221
sudo_warn("au_open");
222
debug_return_int(-1);
223
}
224
if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) {
225
tok = au_to_subject_ex(auid, ctx->user.euid, ctx->user.egid,
226
ctx->user.uid, ctx->user.gid, ctx->user.pid, ctx->user.pid,
227
&ainfo_addr.ai_termid);
228
#ifdef BSM_AUDIT_COMPAT
229
} else if (errno == ENOSYS) {
230
auditinfo_t ainfo;
231
232
if (getaudit(&ainfo) < 0) {
233
sudo_warn("getaudit");
234
debug_return_int(-1);
235
}
236
tok = au_to_subject(auid, ctx->user.euid, ctx->user.egid,
237
ctx->user.uid, ctx->user.gid, ctx->user.pid, ctx->user.pid,
238
&ainfo.ai_termid);
239
#endif /* BSM_AUDIT_COMPAT */
240
} else {
241
sudo_warn("getaudit_addr");
242
debug_return_int(-1);
243
}
244
if (tok == NULL) {
245
sudo_warn("au_to_subject");
246
debug_return_int(-1);
247
}
248
au_write(aufd, tok);
249
tok = au_to_exec_args((char **)exec_args);
250
if (tok == NULL) {
251
sudo_warn("au_to_exec_args");
252
debug_return_int(-1);
253
}
254
au_write(aufd, tok);
255
tok = au_to_text((char *)errmsg);
256
if (tok == NULL) {
257
sudo_warn("au_to_text");
258
debug_return_int(-1);
259
}
260
au_write(aufd, tok);
261
tok = au_to_return32(EPERM, 1);
262
if (tok == NULL) {
263
sudo_warn("au_to_return32");
264
debug_return_int(-1);
265
}
266
au_write(aufd, tok);
267
#ifdef HAVE_AU_CLOSE_SOLARIS11
268
if (au_close(aufd, 1, sudo_audit_event, PAD_FAILURE) == -1)
269
#else
270
if (au_close(aufd, 1, sudo_audit_event) == -1)
271
#endif
272
{
273
sudo_warn("%s", U_("unable to commit audit record"));
274
debug_return_int(-1);
275
}
276
debug_return_int(0);
277
}
278
279
#endif /* HAVE_BSM_AUDIT */
280
281