1 | /*- |
2 | * Copyright (c) 1999-2010, Apple Inc. |
3 | * All rights reserved. |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
8 | * 1. Redistributions of source code must retain the above copyright |
9 | * notice, this list of conditions and the following disclaimer. |
10 | * 2. Redistributions in binary form must reproduce the above copyright |
11 | * notice, this list of conditions and the following disclaimer in the |
12 | * documentation and/or other materials provided with the distribution. |
13 | * 3. Neither the name of Apple Inc. ("Apple") nor the names of |
14 | * its contributors may be used to endorse or promote products derived |
15 | * from this software without specific prior written permission. |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND |
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
20 | * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR |
21 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
25 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
26 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
27 | * POSSIBILITY OF SUCH DAMAGE. |
28 | */ |
29 | /* |
30 | * NOTICE: This file was modified by McAfee Research in 2004 to introduce |
31 | * support for mandatory and extensible security protections. This notice |
32 | * is included in support of clause 2.2 (b) of the Apple Public License, |
33 | * Version 2.0. |
34 | */ |
35 | |
36 | #include <sys/param.h> |
37 | #include <sys/fcntl.h> |
38 | #include <sys/kernel.h> |
39 | #include <sys/lock.h> |
40 | #include <sys/namei.h> |
41 | #include <sys/proc_internal.h> |
42 | #include <sys/kauth.h> |
43 | #include <sys/queue.h> |
44 | #include <sys/systm.h> |
45 | #include <sys/time.h> |
46 | #include <sys/ucred.h> |
47 | #include <sys/uio.h> |
48 | #include <sys/unistd.h> |
49 | #include <sys/file_internal.h> |
50 | #include <sys/vnode_internal.h> |
51 | #include <sys/user.h> |
52 | #include <sys/syscall.h> |
53 | #include <sys/malloc.h> |
54 | #include <sys/un.h> |
55 | #include <sys/sysent.h> |
56 | #include <sys/sysproto.h> |
57 | #include <sys/vfs_context.h> |
58 | #include <sys/domain.h> |
59 | #include <sys/protosw.h> |
60 | #include <sys/socketvar.h> |
61 | |
62 | #include <bsm/audit.h> |
63 | #include <bsm/audit_internal.h> |
64 | #include <bsm/audit_kevents.h> |
65 | |
66 | #include <security/audit/audit.h> |
67 | #include <security/audit/audit_bsd.h> |
68 | #include <security/audit/audit_private.h> |
69 | |
70 | #include <mach/host_priv.h> |
71 | #include <mach/host_special_ports.h> |
72 | #include <mach/audit_triggers_server.h> |
73 | |
74 | #include <kern/host.h> |
75 | #include <kern/kalloc.h> |
76 | #include <kern/zalloc.h> |
77 | #include <kern/sched_prim.h> |
78 | |
79 | #if CONFIG_MACF |
80 | #include <bsm/audit_record.h> |
81 | #include <security/mac.h> |
82 | #include <security/mac_framework.h> |
83 | #include <security/mac_policy.h> |
84 | #endif |
85 | |
86 | #include <net/route.h> |
87 | |
88 | #include <netinet/in.h> |
89 | #include <netinet/in_pcb.h> |
90 | |
91 | #include <IOKit/IOBSD.h> |
92 | |
93 | #if CONFIG_AUDIT |
94 | |
95 | #define IS_NOT_VALID_PID(p) ((p) < 1 || (p) > PID_MAX) |
96 | |
97 | #ifdef AUDIT_API_WARNINGS |
98 | /* |
99 | * Macro to warn about auditinfo_addr_t/auditpinfo_addr_t changing sizes |
100 | * to encourage the userland code to be recompiled and updated. |
101 | */ |
102 | #define WARN_IF_AINFO_ADDR_CHANGED(sz1, sz2, scall, tp) do { \ |
103 | if ((size_t)(sz1) != (size_t)(sz2)) { \ |
104 | char pn[MAXCOMLEN + 1]; \ |
105 | \ |
106 | proc_selfname(pn, MAXCOMLEN + 1); \ |
107 | printf("Size of %s used by %s in %s is different from " \ |
108 | "kernel's. Please recompile %s.\n", (tp), \ |
109 | (scall), pn, pn); \ |
110 | } \ |
111 | } while (0) |
112 | |
113 | /* |
114 | * Macro to warn about using ASID's outside the range [1 to PID_MAX] to |
115 | * encourage userland code changes. |
116 | */ |
117 | #define WARN_IF_BAD_ASID(asid, scall) do { \ |
118 | if (((asid) < 1 || (asid) > PID_MAX) && \ |
119 | (asid) != AU_ASSIGN_ASID) { \ |
120 | char pn[MAXCOMLEN + 1]; \ |
121 | \ |
122 | proc_selfname(pn, MAXCOMLEN + 1); \ |
123 | printf("%s in %s is using an ASID (%u) outside the " \ |
124 | "range [1 to %d]. Please change %s to use an ASID "\ |
125 | "within this range or use AU_ASSIGN_ASID.\n", \ |
126 | (scall), pn, (uint32_t)(asid), PID_MAX, pn); \ |
127 | } \ |
128 | } while (0) |
129 | |
130 | #else /* ! AUDIT_API_WARNINGS */ |
131 | |
132 | #define WARN_IF_AINFO_ADDR_CHANGED(sz1, sz2, scall, tp) do { \ |
133 | } while (0) |
134 | |
135 | #define WARN_IF_BAD_ASID(asid, scall) do { \ |
136 | } while (0) |
137 | |
138 | #endif /* AUDIT_API_WARNINGS */ |
139 | |
140 | /* |
141 | * System call to allow a user space application to submit a BSM audit record |
142 | * to the kernel for inclusion in the audit log. This function does little |
143 | * verification on the audit record that is submitted. |
144 | * |
145 | * XXXAUDIT: Audit preselection for user records does not currently work, |
146 | * since we pre-select only based on the AUE_audit event type, not the event |
147 | * type submitted as part of the user audit data. |
148 | */ |
149 | /* ARGSUSED */ |
150 | int |
151 | audit(proc_t p, struct audit_args *uap, __unused int32_t *retval) |
152 | { |
153 | int error = 0; |
154 | void * rec = NULL; |
155 | void * full_rec = NULL; |
156 | struct kaudit_record *ar = NULL; |
157 | struct uthread *uthr = NULL; |
158 | int add_identity_token = 1; |
159 | int max_record_length = MAX_AUDIT_RECORD_SIZE; |
160 | void *udata = NULL; |
161 | u_int ulen = 0; |
162 | struct au_identity_info id_info = {0, NULL, 0, NULL, 0, NULL, 0}; |
163 | token_t *id_tok = NULL; |
164 | |
165 | error = suser(kauth_cred_get(), &p->p_acflag); |
166 | if (error) { |
167 | goto free_out; |
168 | } |
169 | |
170 | mtx_lock(&audit_mtx); |
171 | max_record_length = MIN(audit_qctrl.aq_bufsz, MAX_AUDIT_RECORD_SIZE); |
172 | mtx_unlock(&audit_mtx); |
173 | |
174 | if (IOTaskHasEntitlement(current_task(), |
175 | AU_CLASS_RESERVED_ENTITLEMENT)) { |
176 | /* Entitled tasks are trusted to add appropriate identity info */ |
177 | add_identity_token = 0; |
178 | } else { |
179 | /* |
180 | * If the caller is unentitled, an identity token will be added and |
181 | * the space must be accounted for |
182 | */ |
183 | max_record_length -= MAX_AUDIT_IDENTITY_SIZE; |
184 | } |
185 | |
186 | if ((uap->length <= 0) || (uap->length > max_record_length)) { |
187 | error = EINVAL; |
188 | goto free_out; |
189 | } |
190 | |
191 | ar = currecord(); |
192 | |
193 | /* |
194 | * If there's no current audit record (audit() itself not audited) |
195 | * commit the user audit record. |
196 | */ |
197 | if (ar == NULL) { |
198 | uthr = curthread(); |
199 | if (uthr == NULL) { |
200 | /* can this happen? */ |
201 | error = ENOTSUP; |
202 | goto free_out; |
203 | } |
204 | |
205 | /* |
206 | * This is not very efficient; we're required to allocate a |
207 | * complete kernel audit record just so the user record can |
208 | * tag along. |
209 | */ |
210 | uthr->uu_ar = audit_new(AUE_NULL, p, uthr); |
211 | if (uthr->uu_ar == NULL) { |
212 | error = ENOTSUP; |
213 | goto free_out; |
214 | } |
215 | ar = uthr->uu_ar; |
216 | } |
217 | |
218 | rec = malloc(uap->length, M_AUDITDATA, M_WAITOK); |
219 | if (!rec) { |
220 | error = ENOMEM; |
221 | goto free_out; |
222 | } |
223 | |
224 | error = copyin(uap->record, rec, uap->length); |
225 | if (error) { |
226 | goto free_out; |
227 | } |
228 | |
229 | #if CONFIG_MACF |
230 | error = mac_system_check_audit(kauth_cred_get(), rec, uap->length); |
231 | if (error) { |
232 | goto free_out; |
233 | } |
234 | #endif |
235 | |
236 | /* Verify the record. */ |
237 | if (bsm_rec_verify(rec, uap->length) == 0) { |
238 | error = EINVAL; |
239 | goto free_out; |
240 | } |
241 | |
242 | if (add_identity_token) { |
243 | struct hdr_tok_partial *hdr; |
244 | struct trl_tok_partial *trl; |
245 | int bytes_copied = 0; |
246 | |
247 | /* Create a new identity token for this buffer */ |
248 | audit_identity_info_construct(&id_info); |
249 | id_tok = au_to_identity(id_info.signer_type, id_info.signing_id, |
250 | id_info.signing_id_trunc, id_info.team_id, id_info.team_id_trunc, |
251 | id_info.cdhash, id_info.cdhash_len); |
252 | if (!id_tok) { |
253 | error = ENOMEM; |
254 | goto free_out; |
255 | } |
256 | |
257 | /* Splice the record together using a new buffer */ |
258 | full_rec = malloc(uap->length + id_tok->len, M_AUDITDATA, M_WAITOK); |
259 | if (!full_rec) { |
260 | error = ENOMEM; |
261 | goto free_out; |
262 | } |
263 | |
264 | /* Copy the original buffer up to but not including the trailer */ |
265 | memcpy(full_rec, rec, uap->length - AUDIT_TRAILER_SIZE); |
266 | bytes_copied = uap->length - AUDIT_TRAILER_SIZE; |
267 | |
268 | /* Copy the identity token */ |
269 | memcpy(full_rec + bytes_copied, id_tok->t_data, id_tok->len); |
270 | bytes_copied += id_tok->len; |
271 | |
272 | /* Copy the old trailer */ |
273 | memcpy(full_rec + bytes_copied, |
274 | rec + (uap->length - AUDIT_TRAILER_SIZE), AUDIT_TRAILER_SIZE); |
275 | bytes_copied += AUDIT_TRAILER_SIZE; |
276 | |
277 | /* Fix the record size stored in the header token */ |
278 | hdr = (struct hdr_tok_partial*)full_rec; |
279 | hdr->len = htonl(bytes_copied); |
280 | |
281 | /* Fix the record size stored in the trailer token */ |
282 | trl = (struct trl_tok_partial*) |
283 | (full_rec + bytes_copied - AUDIT_TRAILER_SIZE); |
284 | trl->len = htonl(bytes_copied); |
285 | |
286 | udata = full_rec; |
287 | ulen = bytes_copied; |
288 | } else { |
289 | udata = rec; |
290 | ulen = uap->length; |
291 | } |
292 | |
293 | /* |
294 | * Attach the user audit record to the kernel audit record. Because |
295 | * this system call is an auditable event, we will write the user |
296 | * record along with the record for this audit event. |
297 | * |
298 | * XXXAUDIT: KASSERT appropriate starting values of k_udata, k_ulen, |
299 | * k_ar_commit & AR_COMMIT_USER? |
300 | */ |
301 | ar->k_udata = udata; |
302 | ar->k_ulen = ulen; |
303 | ar->k_ar_commit |= AR_COMMIT_USER; |
304 | |
305 | /* |
306 | * Currently we assume that all preselection has been performed in |
307 | * userspace. We unconditionally set these masks so that the records |
308 | * get committed both to the trail and pipe. In the future we will |
309 | * want to setup kernel based preselection. |
310 | */ |
311 | ar->k_ar_commit |= (AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE); |
312 | |
313 | free_out: |
314 | /* |
315 | * If rec was allocated, it must be freed if an identity token was added |
316 | * (since full_rec will be used) OR there was an error (since nothing |
317 | * will be attached to the kernel structure). |
318 | */ |
319 | if (rec && (add_identity_token || error)) { |
320 | free(rec, M_AUDITDATA); |
321 | } |
322 | |
323 | /* Only free full_rec if an error occurred */ |
324 | if (full_rec && error) { |
325 | free(full_rec, M_AUDITDATA); |
326 | } |
327 | |
328 | audit_identity_info_destruct(&id_info); |
329 | if (id_tok) { |
330 | if (id_tok->t_data) { |
331 | free(id_tok->t_data, M_AUDITBSM); |
332 | } |
333 | free(id_tok, M_AUDITBSM); |
334 | } |
335 | |
336 | return (error); |
337 | } |
338 | |
339 | /* |
340 | * System call to manipulate auditing. |
341 | */ |
342 | /* ARGSUSED */ |
343 | int |
344 | auditon(proc_t p, struct auditon_args *uap, __unused int32_t *retval) |
345 | { |
346 | kauth_cred_t scred; |
347 | int error = 0; |
348 | union auditon_udata udata; |
349 | proc_t tp = PROC_NULL; |
350 | struct auditinfo_addr aia; |
351 | |
352 | AUDIT_ARG(cmd, uap->cmd); |
353 | |
354 | #if CONFIG_MACF |
355 | error = mac_system_check_auditon(kauth_cred_get(), uap->cmd); |
356 | if (error) |
357 | return (error); |
358 | #endif |
359 | |
360 | if ((uap->length <= 0) || (uap->length > |
361 | (int)sizeof(union auditon_udata))) |
362 | return (EINVAL); |
363 | |
364 | memset((void *)&udata, 0, sizeof(udata)); |
365 | |
366 | /* |
367 | * Some of the GET commands use the arguments too. |
368 | */ |
369 | switch (uap->cmd) { |
370 | case A_SETPOLICY: |
371 | case A_OLDSETPOLICY: |
372 | case A_SETKMASK: |
373 | case A_SETQCTRL: |
374 | case A_OLDSETQCTRL: |
375 | case A_SETSTAT: |
376 | case A_SETUMASK: |
377 | case A_SETSMASK: |
378 | case A_SETCOND: |
379 | case A_OLDSETCOND: |
380 | case A_SETCLASS: |
381 | case A_SETPMASK: |
382 | case A_SETFSIZE: |
383 | case A_SETKAUDIT: |
384 | case A_GETCLASS: |
385 | case A_GETPINFO: |
386 | case A_GETPINFO_ADDR: |
387 | case A_SENDTRIGGER: |
388 | case A_GETSINFO_ADDR: |
389 | case A_GETSFLAGS: |
390 | case A_SETSFLAGS: |
391 | case A_SETCTLMODE: |
392 | case A_SETEXPAFTER: |
393 | error = copyin(uap->data, (void *)&udata, uap->length); |
394 | if (error) |
395 | return (error); |
396 | AUDIT_ARG(auditon, &udata); |
397 | AUDIT_ARG(len, uap->length); |
398 | break; |
399 | } |
400 | |
401 | /* Check appropriate privilege. */ |
402 | switch (uap->cmd) { |
403 | /* |
404 | * A_GETSINFO doesn't require priviledge but only superuser |
405 | * gets to see the audit masks. |
406 | */ |
407 | case A_GETSINFO_ADDR: |
408 | if ((sizeof(udata.au_kau_info) != uap->length) || |
409 | (audit_session_lookup(udata.au_kau_info.ai_asid, |
410 | &udata.au_kau_info) != 0)) |
411 | error = EINVAL; |
412 | else if (!kauth_cred_issuser(kauth_cred_get())) { |
413 | udata.au_kau_info.ai_mask.am_success = ~0; |
414 | udata.au_kau_info.ai_mask.am_failure = ~0; |
415 | } |
416 | break; |
417 | case A_GETSFLAGS: |
418 | case A_SETSFLAGS: |
419 | /* Getting one's own audit session flags requires no |
420 | * privilege. Setting the flags is subject to access |
421 | * control implemented in audit_session_setaia(). |
422 | */ |
423 | break; |
424 | case A_SETCTLMODE: |
425 | case A_SETEXPAFTER: |
426 | if (!IOTaskHasEntitlement(current_task(), |
427 | AU_CLASS_RESERVED_ENTITLEMENT)) { |
428 | error = EPERM; |
429 | } |
430 | break; |
431 | default: |
432 | error = suser(kauth_cred_get(), &p->p_acflag); |
433 | break; |
434 | } |
435 | if (error) |
436 | return (error); |
437 | |
438 | /* |
439 | * If the audit subsytem is in external control mode, additional |
440 | * privilege checks are required for a subset of auditon commands |
441 | */ |
442 | if (audit_ctl_mode == AUDIT_CTLMODE_EXTERNAL) { |
443 | switch (uap->cmd) { |
444 | case A_SETCOND: |
445 | case A_SETFSIZE: |
446 | case A_SETPOLICY: |
447 | case A_SETQCTRL: |
448 | if (!IOTaskHasEntitlement(current_task(), |
449 | AU_CLASS_RESERVED_ENTITLEMENT)) { |
450 | error = EPERM; |
451 | } |
452 | break; |
453 | } |
454 | if (error) |
455 | return (error); |
456 | } |
457 | |
458 | /* |
459 | * XXX Need to implement these commands by accessing the global |
460 | * values associated with the commands. |
461 | */ |
462 | switch (uap->cmd) { |
463 | case A_OLDGETPOLICY: |
464 | case A_GETPOLICY: |
465 | if (sizeof(udata.au_policy64) == uap->length) { |
466 | mtx_lock(&audit_mtx); |
467 | if (!audit_fail_stop) |
468 | udata.au_policy64 |= AUDIT_CNT; |
469 | if (audit_panic_on_write_fail) |
470 | udata.au_policy64 |= AUDIT_AHLT; |
471 | if (audit_argv) |
472 | udata.au_policy64 |= AUDIT_ARGV; |
473 | if (audit_arge) |
474 | udata.au_policy64 |= AUDIT_ARGE; |
475 | mtx_unlock(&audit_mtx); |
476 | break; |
477 | } |
478 | if (sizeof(udata.au_policy) != uap->length) |
479 | return (EINVAL); |
480 | mtx_lock(&audit_mtx); |
481 | if (!audit_fail_stop) |
482 | udata.au_policy |= AUDIT_CNT; |
483 | if (audit_panic_on_write_fail) |
484 | udata.au_policy |= AUDIT_AHLT; |
485 | if (audit_argv) |
486 | udata.au_policy |= AUDIT_ARGV; |
487 | if (audit_arge) |
488 | udata.au_policy |= AUDIT_ARGE; |
489 | mtx_unlock(&audit_mtx); |
490 | break; |
491 | |
492 | case A_OLDSETPOLICY: |
493 | case A_SETPOLICY: |
494 | if (sizeof(udata.au_policy64) == uap->length) { |
495 | if (udata.au_policy64 & ~(AUDIT_CNT|AUDIT_AHLT| |
496 | AUDIT_ARGV|AUDIT_ARGE)) |
497 | return (EINVAL); |
498 | mtx_lock(&audit_mtx); |
499 | audit_fail_stop = ((udata.au_policy64 & AUDIT_CNT) == |
500 | 0); |
501 | audit_panic_on_write_fail = (udata.au_policy64 & |
502 | AUDIT_AHLT); |
503 | audit_argv = (udata.au_policy64 & AUDIT_ARGV); |
504 | audit_arge = (udata.au_policy64 & AUDIT_ARGE); |
505 | mtx_unlock(&audit_mtx); |
506 | break; |
507 | } |
508 | if ((sizeof(udata.au_policy) != uap->length) || |
509 | (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV| |
510 | AUDIT_ARGE))) |
511 | return (EINVAL); |
512 | /* |
513 | * XXX - Need to wake up waiters if the policy relaxes? |
514 | */ |
515 | mtx_lock(&audit_mtx); |
516 | audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0); |
517 | audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT); |
518 | audit_argv = (udata.au_policy & AUDIT_ARGV); |
519 | audit_arge = (udata.au_policy & AUDIT_ARGE); |
520 | mtx_unlock(&audit_mtx); |
521 | break; |
522 | |
523 | case A_GETKMASK: |
524 | if (sizeof(udata.au_mask) != uap->length) |
525 | return (EINVAL); |
526 | mtx_lock(&audit_mtx); |
527 | udata.au_mask = audit_nae_mask; |
528 | mtx_unlock(&audit_mtx); |
529 | break; |
530 | |
531 | case A_SETKMASK: |
532 | if (sizeof(udata.au_mask) != uap->length) |
533 | return (EINVAL); |
534 | mtx_lock(&audit_mtx); |
535 | audit_nae_mask = udata.au_mask; |
536 | AUDIT_CHECK_IF_KEVENTS_MASK(audit_nae_mask); |
537 | mtx_unlock(&audit_mtx); |
538 | break; |
539 | |
540 | case A_OLDGETQCTRL: |
541 | case A_GETQCTRL: |
542 | if (sizeof(udata.au_qctrl64) == uap->length) { |
543 | mtx_lock(&audit_mtx); |
544 | udata.au_qctrl64.aq64_hiwater = |
545 | (u_int64_t)audit_qctrl.aq_hiwater; |
546 | udata.au_qctrl64.aq64_lowater = |
547 | (u_int64_t)audit_qctrl.aq_lowater; |
548 | udata.au_qctrl64.aq64_bufsz = |
549 | (u_int64_t)audit_qctrl.aq_bufsz; |
550 | udata.au_qctrl64.aq64_delay = |
551 | (u_int64_t)audit_qctrl.aq_delay; |
552 | udata.au_qctrl64.aq64_minfree = |
553 | (int64_t)audit_qctrl.aq_minfree; |
554 | mtx_unlock(&audit_mtx); |
555 | break; |
556 | } |
557 | if (sizeof(udata.au_qctrl) != uap->length) |
558 | return (EINVAL); |
559 | mtx_lock(&audit_mtx); |
560 | udata.au_qctrl = audit_qctrl; |
561 | mtx_unlock(&audit_mtx); |
562 | break; |
563 | |
564 | case A_OLDSETQCTRL: |
565 | case A_SETQCTRL: |
566 | if (sizeof(udata.au_qctrl64) == uap->length) { |
567 | if ((udata.au_qctrl64.aq64_hiwater > AQ_MAXHIGH) || |
568 | (udata.au_qctrl64.aq64_lowater >= |
569 | udata.au_qctrl64.aq64_hiwater) || |
570 | (udata.au_qctrl64.aq64_bufsz > AQ_MAXBUFSZ) || |
571 | (udata.au_qctrl64.aq64_minfree < 0) || |
572 | (udata.au_qctrl64.aq64_minfree > 100)) |
573 | return (EINVAL); |
574 | mtx_lock(&audit_mtx); |
575 | audit_qctrl.aq_hiwater = |
576 | (int)udata.au_qctrl64.aq64_hiwater; |
577 | audit_qctrl.aq_lowater = |
578 | (int)udata.au_qctrl64.aq64_lowater; |
579 | audit_qctrl.aq_bufsz = |
580 | (int)udata.au_qctrl64.aq64_bufsz; |
581 | audit_qctrl.aq_minfree = |
582 | (int)udata.au_qctrl64.aq64_minfree; |
583 | audit_qctrl.aq_delay = -1; /* Not used. */ |
584 | mtx_unlock(&audit_mtx); |
585 | break; |
586 | } |
587 | if ((sizeof(udata.au_qctrl) != uap->length) || |
588 | (udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) || |
589 | (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) || |
590 | (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) || |
591 | (udata.au_qctrl.aq_minfree < 0) || |
592 | (udata.au_qctrl.aq_minfree > 100)) |
593 | return (EINVAL); |
594 | |
595 | mtx_lock(&audit_mtx); |
596 | audit_qctrl = udata.au_qctrl; |
597 | /* XXX The queue delay value isn't used with the kernel. */ |
598 | audit_qctrl.aq_delay = -1; |
599 | mtx_unlock(&audit_mtx); |
600 | break; |
601 | |
602 | case A_GETCWD: |
603 | return (ENOSYS); |
604 | |
605 | case A_GETCAR: |
606 | return (ENOSYS); |
607 | |
608 | case A_GETSTAT: |
609 | return (ENOSYS); |
610 | |
611 | case A_SETSTAT: |
612 | return (ENOSYS); |
613 | |
614 | case A_SETUMASK: |
615 | return (ENOSYS); |
616 | |
617 | case A_SETSMASK: |
618 | return (ENOSYS); |
619 | |
620 | case A_OLDGETCOND: |
621 | case A_GETCOND: |
622 | if (sizeof(udata.au_cond64) == uap->length) { |
623 | mtx_lock(&audit_mtx); |
624 | if (audit_enabled && !audit_suspended) |
625 | udata.au_cond64 = AUC_AUDITING; |
626 | else |
627 | udata.au_cond64 = AUC_NOAUDIT; |
628 | mtx_unlock(&audit_mtx); |
629 | break; |
630 | } |
631 | if (sizeof(udata.au_cond) != uap->length) |
632 | return (EINVAL); |
633 | mtx_lock(&audit_mtx); |
634 | if (audit_enabled && !audit_suspended) |
635 | udata.au_cond = AUC_AUDITING; |
636 | else |
637 | udata.au_cond = AUC_NOAUDIT; |
638 | mtx_unlock(&audit_mtx); |
639 | break; |
640 | |
641 | case A_OLDSETCOND: |
642 | case A_SETCOND: |
643 | if (sizeof(udata.au_cond64) == uap->length) { |
644 | mtx_lock(&audit_mtx); |
645 | if (udata.au_cond64 == AUC_NOAUDIT) |
646 | audit_suspended = 1; |
647 | if (udata.au_cond64 == AUC_AUDITING) |
648 | audit_suspended = 0; |
649 | if (udata.au_cond64 == AUC_DISABLED) { |
650 | audit_suspended = 1; |
651 | mtx_unlock(&audit_mtx); |
652 | audit_shutdown(); |
653 | break; |
654 | } |
655 | mtx_unlock(&audit_mtx); |
656 | break; |
657 | } |
658 | if (sizeof(udata.au_cond) != uap->length) { |
659 | return (EINVAL); |
660 | } |
661 | mtx_lock(&audit_mtx); |
662 | if (udata.au_cond == AUC_NOAUDIT) |
663 | audit_suspended = 1; |
664 | if (udata.au_cond == AUC_AUDITING) |
665 | audit_suspended = 0; |
666 | if (udata.au_cond == AUC_DISABLED) { |
667 | audit_suspended = 1; |
668 | mtx_unlock(&audit_mtx); |
669 | audit_shutdown(); |
670 | break; |
671 | } |
672 | mtx_unlock(&audit_mtx); |
673 | break; |
674 | |
675 | case A_GETCLASS: |
676 | if (sizeof(udata.au_evclass) != uap->length) |
677 | return (EINVAL); |
678 | udata.au_evclass.ec_class = au_event_class( |
679 | udata.au_evclass.ec_number); |
680 | break; |
681 | |
682 | case A_SETCLASS: |
683 | if (sizeof(udata.au_evclass) != uap->length) |
684 | return (EINVAL); |
685 | au_evclassmap_insert(udata.au_evclass.ec_number, |
686 | udata.au_evclass.ec_class); |
687 | break; |
688 | |
689 | case A_GETPINFO: |
690 | if ((sizeof(udata.au_aupinfo) != uap->length) || |
691 | IS_NOT_VALID_PID(udata.au_aupinfo.ap_pid)) |
692 | return (EINVAL); |
693 | if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL) |
694 | return (ESRCH); |
695 | |
696 | scred = kauth_cred_proc_ref(tp); |
697 | if (scred->cr_audit.as_aia_p->ai_termid.at_type == AU_IPv6) { |
698 | kauth_cred_unref(&scred); |
699 | proc_rele(tp); |
700 | return (EINVAL); |
701 | } |
702 | |
703 | udata.au_aupinfo.ap_auid = |
704 | scred->cr_audit.as_aia_p->ai_auid; |
705 | udata.au_aupinfo.ap_mask.am_success = |
706 | scred->cr_audit.as_mask.am_success; |
707 | udata.au_aupinfo.ap_mask.am_failure = |
708 | scred->cr_audit.as_mask.am_failure; |
709 | udata.au_aupinfo.ap_termid.machine = |
710 | scred->cr_audit.as_aia_p->ai_termid.at_addr[0]; |
711 | udata.au_aupinfo.ap_termid.port = |
712 | scred->cr_audit.as_aia_p->ai_termid.at_port; |
713 | udata.au_aupinfo.ap_asid = |
714 | scred->cr_audit.as_aia_p->ai_asid; |
715 | kauth_cred_unref(&scred); |
716 | proc_rele(tp); |
717 | tp = PROC_NULL; |
718 | break; |
719 | |
720 | case A_SETPMASK: |
721 | if ((sizeof(udata.au_aupinfo) != uap->length) || |
722 | IS_NOT_VALID_PID(udata.au_aupinfo.ap_pid)) |
723 | return (EINVAL); |
724 | if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL) |
725 | return (ESRCH); |
726 | scred = kauth_cred_proc_ref(tp); |
727 | bcopy(scred->cr_audit.as_aia_p, &aia, sizeof(aia)); |
728 | kauth_cred_unref(&scred); |
729 | aia.ai_mask.am_success = |
730 | udata.au_aupinfo.ap_mask.am_success; |
731 | aia.ai_mask.am_failure = |
732 | udata.au_aupinfo.ap_mask.am_failure; |
733 | AUDIT_CHECK_IF_KEVENTS_MASK(aia.ai_mask); |
734 | error = audit_session_setaia(tp, &aia); |
735 | proc_rele(tp); |
736 | tp = PROC_NULL; |
737 | if (error) |
738 | return (error); |
739 | break; |
740 | |
741 | case A_SETFSIZE: |
742 | if ((sizeof(udata.au_fstat) != uap->length) || |
743 | ((udata.au_fstat.af_filesz != 0) && |
744 | (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE))) |
745 | return (EINVAL); |
746 | mtx_lock(&audit_mtx); |
747 | audit_fstat.af_filesz = udata.au_fstat.af_filesz; |
748 | mtx_unlock(&audit_mtx); |
749 | break; |
750 | |
751 | case A_GETFSIZE: |
752 | if (sizeof(udata.au_fstat) != uap->length) |
753 | return (EINVAL); |
754 | mtx_lock(&audit_mtx); |
755 | udata.au_fstat.af_filesz = audit_fstat.af_filesz; |
756 | udata.au_fstat.af_currsz = audit_fstat.af_currsz; |
757 | mtx_unlock(&audit_mtx); |
758 | break; |
759 | |
760 | case A_GETPINFO_ADDR: |
761 | if ((sizeof(udata.au_aupinfo_addr) != uap->length) || |
762 | IS_NOT_VALID_PID(udata.au_aupinfo_addr.ap_pid)) |
763 | return (EINVAL); |
764 | if ((tp = proc_find(udata.au_aupinfo.ap_pid)) == NULL) |
765 | return (ESRCH); |
766 | WARN_IF_AINFO_ADDR_CHANGED(uap->length, |
767 | sizeof(auditpinfo_addr_t), "auditon(A_GETPINFO_ADDR,...)" , |
768 | "auditpinfo_addr_t" ); |
769 | scred = kauth_cred_proc_ref(tp); |
770 | udata.au_aupinfo_addr.ap_auid = |
771 | scred->cr_audit.as_aia_p->ai_auid; |
772 | udata.au_aupinfo_addr.ap_asid = |
773 | scred->cr_audit.as_aia_p->ai_asid; |
774 | udata.au_aupinfo_addr.ap_mask.am_success = |
775 | scred->cr_audit.as_mask.am_success; |
776 | udata.au_aupinfo_addr.ap_mask.am_failure = |
777 | scred->cr_audit.as_mask.am_failure; |
778 | bcopy(&scred->cr_audit.as_aia_p->ai_termid, |
779 | &udata.au_aupinfo_addr.ap_termid, |
780 | sizeof(au_tid_addr_t)); |
781 | udata.au_aupinfo_addr.ap_flags = |
782 | scred->cr_audit.as_aia_p->ai_flags; |
783 | kauth_cred_unref(&scred); |
784 | proc_rele(tp); |
785 | tp = PROC_NULL; |
786 | break; |
787 | |
788 | case A_GETKAUDIT: |
789 | if (sizeof(udata.au_kau_info) != uap->length) |
790 | return (EINVAL); |
791 | audit_get_kinfo(&udata.au_kau_info); |
792 | break; |
793 | |
794 | case A_SETKAUDIT: |
795 | if ((sizeof(udata.au_kau_info) != uap->length) || |
796 | (udata.au_kau_info.ai_termid.at_type != AU_IPv4 && |
797 | udata.au_kau_info.ai_termid.at_type != AU_IPv6)) |
798 | return (EINVAL); |
799 | audit_set_kinfo(&udata.au_kau_info); |
800 | break; |
801 | |
802 | case A_SENDTRIGGER: |
803 | if ((sizeof(udata.au_trigger) != uap->length) || |
804 | (udata.au_trigger < AUDIT_TRIGGER_MIN) || |
805 | (udata.au_trigger > AUDIT_TRIGGER_MAX)) |
806 | return (EINVAL); |
807 | return (audit_send_trigger(udata.au_trigger)); |
808 | |
809 | case A_GETSINFO_ADDR: |
810 | /* Handled above before switch(). */ |
811 | break; |
812 | |
813 | case A_GETSFLAGS: |
814 | if (sizeof(udata.au_flags) != uap->length) |
815 | return (EINVAL); |
816 | bcopy(&(kauth_cred_get()->cr_audit.as_aia_p->ai_flags), |
817 | &udata.au_flags, sizeof(udata.au_flags)); |
818 | break; |
819 | |
820 | case A_SETSFLAGS: |
821 | if (sizeof(udata.au_flags) != uap->length) |
822 | return (EINVAL); |
823 | bcopy(kauth_cred_get()->cr_audit.as_aia_p, &aia, sizeof(aia)); |
824 | aia.ai_flags = udata.au_flags; |
825 | error = audit_session_setaia(p, &aia); |
826 | if (error) |
827 | return (error); |
828 | break; |
829 | |
830 | case A_GETCTLMODE: |
831 | if (sizeof(udata.au_ctl_mode) != uap->length) { |
832 | return (EINVAL); |
833 | } |
834 | mtx_lock(&audit_mtx); |
835 | udata.au_ctl_mode = audit_ctl_mode; |
836 | mtx_unlock(&audit_mtx); |
837 | break; |
838 | |
839 | case A_SETCTLMODE: |
840 | if (sizeof(udata.au_ctl_mode) != uap->length) { |
841 | return (EINVAL); |
842 | } |
843 | |
844 | mtx_lock(&audit_mtx); |
845 | |
846 | if (udata.au_ctl_mode == AUDIT_CTLMODE_NORMAL) { |
847 | audit_ctl_mode = AUDIT_CTLMODE_NORMAL; |
848 | } else if (udata.au_ctl_mode == AUDIT_CTLMODE_EXTERNAL) { |
849 | audit_ctl_mode = AUDIT_CTLMODE_EXTERNAL; |
850 | } else { |
851 | mtx_unlock(&audit_mtx); |
852 | return (EINVAL); |
853 | } |
854 | |
855 | mtx_unlock(&audit_mtx); |
856 | break; |
857 | |
858 | case A_GETEXPAFTER: |
859 | if (sizeof(udata.au_expire_after) != uap->length) { |
860 | return (EINVAL); |
861 | } |
862 | mtx_lock(&audit_mtx); |
863 | udata.au_expire_after.age = audit_expire_after.age; |
864 | udata.au_expire_after.size = audit_expire_after.size; |
865 | udata.au_expire_after.op_type = audit_expire_after.op_type; |
866 | mtx_unlock(&audit_mtx); |
867 | break; |
868 | |
869 | case A_SETEXPAFTER: |
870 | if (sizeof(udata.au_expire_after) != uap->length) { |
871 | return (EINVAL); |
872 | } |
873 | mtx_lock(&audit_mtx); |
874 | audit_expire_after.age = udata.au_expire_after.age; |
875 | audit_expire_after.size = udata.au_expire_after.size; |
876 | audit_expire_after.op_type = udata.au_expire_after.op_type; |
877 | mtx_unlock(&audit_mtx); |
878 | break; |
879 | |
880 | default: |
881 | return (EINVAL); |
882 | } |
883 | |
884 | /* |
885 | * Copy data back to userspace for the GET comands. |
886 | */ |
887 | switch (uap->cmd) { |
888 | case A_GETPOLICY: |
889 | case A_OLDGETPOLICY: |
890 | case A_GETKMASK: |
891 | case A_GETQCTRL: |
892 | case A_OLDGETQCTRL: |
893 | case A_GETCWD: |
894 | case A_GETCAR: |
895 | case A_GETSTAT: |
896 | case A_GETCOND: |
897 | case A_OLDGETCOND: |
898 | case A_GETCLASS: |
899 | case A_GETPINFO: |
900 | case A_GETFSIZE: |
901 | case A_GETPINFO_ADDR: |
902 | case A_GETKAUDIT: |
903 | case A_GETSINFO_ADDR: |
904 | case A_GETSFLAGS: |
905 | case A_GETCTLMODE: |
906 | case A_GETEXPAFTER: |
907 | error = copyout((void *)&udata, uap->data, uap->length); |
908 | if (error) |
909 | return (ENOSYS); |
910 | break; |
911 | } |
912 | |
913 | return (0); |
914 | } |
915 | |
916 | /* |
917 | * System calls to manage the user audit information. |
918 | */ |
919 | /* ARGSUSED */ |
920 | int |
921 | getauid(proc_t p, struct getauid_args *uap, __unused int32_t *retval) |
922 | { |
923 | au_id_t id; |
924 | int error; |
925 | kauth_cred_t scred; |
926 | |
927 | #if CONFIG_MACF |
928 | error = mac_proc_check_getauid(p); |
929 | if (error) |
930 | return (error); |
931 | #endif |
932 | scred = kauth_cred_proc_ref(p); |
933 | id = scred->cr_audit.as_aia_p->ai_auid; |
934 | kauth_cred_unref(&scred); |
935 | |
936 | error = copyout((void *)&id, uap->auid, sizeof(id)); |
937 | if (error) |
938 | return (error); |
939 | |
940 | return (0); |
941 | } |
942 | |
943 | /* ARGSUSED */ |
944 | int |
945 | setauid(proc_t p, struct setauid_args *uap, __unused int32_t *retval) |
946 | { |
947 | int error; |
948 | au_id_t id; |
949 | kauth_cred_t scred; |
950 | struct auditinfo_addr aia; |
951 | |
952 | error = copyin(uap->auid, &id, sizeof(id)); |
953 | if (error) |
954 | return (error); |
955 | AUDIT_ARG(auid, id); |
956 | |
957 | #if CONFIG_MACF |
958 | error = mac_proc_check_setauid(p, id); |
959 | if (error) |
960 | return (error); |
961 | #endif |
962 | |
963 | scred = kauth_cred_proc_ref(p); |
964 | error = suser(scred, &p->p_acflag); |
965 | if (error) { |
966 | kauth_cred_unref(&scred); |
967 | return (error); |
968 | } |
969 | |
970 | bcopy(scred->cr_audit.as_aia_p, &aia, sizeof(aia)); |
971 | if (aia.ai_asid == AU_DEFAUDITSID) { |
972 | aia.ai_asid = AU_ASSIGN_ASID; |
973 | } |
974 | bcopy(&scred->cr_audit.as_mask, &aia.ai_mask, sizeof(au_mask_t)); |
975 | kauth_cred_unref(&scred); |
976 | aia.ai_auid = id; |
977 | error = audit_session_setaia(p, &aia); |
978 | |
979 | return (error); |
980 | } |
981 | |
982 | static int |
983 | getaudit_addr_internal(proc_t p, user_addr_t user_addr, size_t length) |
984 | { |
985 | kauth_cred_t scred; |
986 | auditinfo_addr_t aia; |
987 | |
988 | scred = kauth_cred_proc_ref(p); |
989 | bcopy(scred->cr_audit.as_aia_p, &aia, sizeof (auditinfo_addr_t)); |
990 | /* |
991 | * Only superuser gets to see the real mask. |
992 | */ |
993 | if (suser(scred, &p->p_acflag)) { |
994 | aia.ai_mask.am_success = ~0; |
995 | aia.ai_mask.am_failure = ~0; |
996 | } |
997 | kauth_cred_unref(&scred); |
998 | |
999 | return (copyout(&aia, user_addr, min(sizeof(aia), length))); |
1000 | } |
1001 | |
1002 | /* ARGSUSED */ |
1003 | int |
1004 | getaudit_addr(proc_t p, struct getaudit_addr_args *uap, |
1005 | __unused int32_t *retval) |
1006 | { |
1007 | #if CONFIG_MACF |
1008 | int error = mac_proc_check_getaudit(p); |
1009 | |
1010 | if (error) |
1011 | return (error); |
1012 | #endif /* CONFIG_MACF */ |
1013 | WARN_IF_AINFO_ADDR_CHANGED(uap->length, sizeof(auditinfo_addr_t), |
1014 | "getaudit_addr(2)" , "auditinfo_addr_t" ); |
1015 | |
1016 | return (getaudit_addr_internal(p, uap->auditinfo_addr, uap->length)); |
1017 | } |
1018 | |
1019 | /* ARGSUSED */ |
1020 | int |
1021 | setaudit_addr(proc_t p, struct setaudit_addr_args *uap, |
1022 | __unused int32_t *retval) |
1023 | { |
1024 | struct auditinfo_addr aia; |
1025 | kauth_cred_t scred; |
1026 | int error; |
1027 | |
1028 | bzero(&aia, sizeof(auditinfo_addr_t)); |
1029 | error = copyin(uap->auditinfo_addr, &aia, |
1030 | min(sizeof(aia), uap->length)); |
1031 | if (error) |
1032 | return (error); |
1033 | AUDIT_ARG(auditinfo_addr, &aia); |
1034 | if (aia.ai_termid.at_type != AU_IPv6 && |
1035 | aia.ai_termid.at_type != AU_IPv4) |
1036 | return (EINVAL); |
1037 | if (aia.ai_asid != AU_ASSIGN_ASID && |
1038 | (uint32_t)aia.ai_asid > ASSIGNED_ASID_MAX) |
1039 | return (EINVAL); |
1040 | |
1041 | #if CONFIG_MACF |
1042 | error = mac_proc_check_setaudit(p, &aia); |
1043 | if (error) |
1044 | return (error); |
1045 | #endif |
1046 | |
1047 | scred = kauth_cred_proc_ref(p); |
1048 | error = suser(scred, &p->p_acflag); |
1049 | if (error) { |
1050 | kauth_cred_unref(&scred); |
1051 | return (error); |
1052 | } |
1053 | |
1054 | WARN_IF_AINFO_ADDR_CHANGED(uap->length, sizeof(auditinfo_addr_t), |
1055 | "setaudit_addr(2)" , "auditinfo_addr_t" ); |
1056 | WARN_IF_BAD_ASID(aia.ai_asid, "setaudit_addr(2)" ); |
1057 | kauth_cred_unref(&scred); |
1058 | |
1059 | AUDIT_CHECK_IF_KEVENTS_MASK(aia.ai_mask); |
1060 | if (aia.ai_asid == AU_DEFAUDITSID) |
1061 | aia.ai_asid = AU_ASSIGN_ASID; |
1062 | |
1063 | error = audit_session_setaia(p, &aia); |
1064 | if (error) |
1065 | return (error); |
1066 | |
1067 | /* |
1068 | * If asked to assign an ASID then let the user know what the ASID is |
1069 | * by copying the auditinfo_addr struct back out. |
1070 | */ |
1071 | if (aia.ai_asid == AU_ASSIGN_ASID) |
1072 | error = getaudit_addr_internal(p, uap->auditinfo_addr, |
1073 | uap->length); |
1074 | |
1075 | return (error); |
1076 | } |
1077 | |
1078 | /* |
1079 | * Syscall to manage audit files. |
1080 | * |
1081 | */ |
1082 | /* ARGSUSED */ |
1083 | int |
1084 | auditctl(proc_t p, struct auditctl_args *uap, __unused int32_t *retval) |
1085 | { |
1086 | struct nameidata nd; |
1087 | kauth_cred_t cred; |
1088 | struct vnode *vp; |
1089 | int error = 0; |
1090 | au_ctlmode_t ctlmode; |
1091 | |
1092 | error = suser(kauth_cred_get(), &p->p_acflag); |
1093 | if (error) |
1094 | return (error); |
1095 | |
1096 | ctlmode = audit_ctl_mode; |
1097 | |
1098 | /* |
1099 | * Do not allow setting of a path when auditing is in reserved mode |
1100 | */ |
1101 | if (ctlmode == AUDIT_CTLMODE_EXTERNAL && |
1102 | !IOTaskHasEntitlement(current_task(), AU_AUDITCTL_RESERVED_ENTITLEMENT)) { |
1103 | return (EPERM); |
1104 | } |
1105 | |
1106 | vp = NULL; |
1107 | cred = NULL; |
1108 | |
1109 | /* |
1110 | * If a path is specified, open the replacement vnode, perform |
1111 | * validity checks, and grab another reference to the current |
1112 | * credential. |
1113 | * |
1114 | * XXX Changes API slightly. NULL path no longer disables audit but |
1115 | * returns EINVAL. |
1116 | */ |
1117 | if (uap->path == USER_ADDR_NULL) |
1118 | return (EINVAL); |
1119 | |
1120 | NDINIT(&nd, LOOKUP, OP_OPEN, FOLLOW | LOCKLEAF | AUDITVNPATH1, |
1121 | (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : |
1122 | UIO_USERSPACE32), uap->path, vfs_context_current()); |
1123 | error = vn_open(&nd, AUDIT_OPEN_FLAGS, 0); |
1124 | if (error) |
1125 | return (error); |
1126 | vp = nd.ni_vp; |
1127 | #if CONFIG_MACF |
1128 | /* |
1129 | * Accessibility of the vnode was determined in vn_open; the |
1130 | * mac_system_check_auditctl should only determine whether that vnode |
1131 | * is appropriate for storing audit data, or that the caller was |
1132 | * permitted to control the auditing system at all. For example, a |
1133 | * confidentiality policy may want to ensure that audit files are |
1134 | * always high sensitivity. |
1135 | */ |
1136 | error = mac_system_check_auditctl(kauth_cred_get(), vp); |
1137 | if (error) { |
1138 | vn_close(vp, AUDIT_CLOSE_FLAGS, vfs_context_current()); |
1139 | vnode_put(vp); |
1140 | return (error); |
1141 | } |
1142 | #endif |
1143 | if (vp->v_type != VREG) { |
1144 | vn_close(vp, AUDIT_CLOSE_FLAGS, vfs_context_current()); |
1145 | vnode_put(vp); |
1146 | return (EINVAL); |
1147 | } |
1148 | mtx_lock(&audit_mtx); |
1149 | /* |
1150 | * XXXAUDIT: Should audit_suspended actually be cleared by |
1151 | * audit_worker? |
1152 | */ |
1153 | audit_suspended = 0; |
1154 | mtx_unlock(&audit_mtx); |
1155 | |
1156 | /* |
1157 | * The following gets unreferenced in audit_rotate_vnode() |
1158 | * after the rotation and it is no longer needed. |
1159 | */ |
1160 | cred = kauth_cred_get_with_ref(); |
1161 | audit_rotate_vnode(cred, vp); |
1162 | vnode_put(vp); |
1163 | |
1164 | return (error); |
1165 | } |
1166 | |
1167 | #else /* !CONFIG_AUDIT */ |
1168 | |
1169 | int |
1170 | audit(proc_t p, struct audit_args *uap, int32_t *retval) |
1171 | { |
1172 | #pragma unused(p, uap, retval) |
1173 | |
1174 | return (ENOSYS); |
1175 | } |
1176 | |
1177 | int |
1178 | auditon(proc_t p, struct auditon_args *uap, int32_t *retval) |
1179 | { |
1180 | #pragma unused(p, uap, retval) |
1181 | |
1182 | return (ENOSYS); |
1183 | } |
1184 | |
1185 | int |
1186 | getauid(proc_t p, struct getauid_args *uap, int32_t *retval) |
1187 | { |
1188 | #pragma unused(p, uap, retval) |
1189 | |
1190 | return (ENOSYS); |
1191 | } |
1192 | |
1193 | int |
1194 | setauid(proc_t p, struct setauid_args *uap, int32_t *retval) |
1195 | { |
1196 | #pragma unused(p, uap, retval) |
1197 | |
1198 | return (ENOSYS); |
1199 | } |
1200 | |
1201 | int |
1202 | getaudit_addr(proc_t p, struct getaudit_addr_args *uap, int32_t *retval) |
1203 | { |
1204 | #pragma unused(p, uap, retval) |
1205 | |
1206 | return (ENOSYS); |
1207 | } |
1208 | |
1209 | int |
1210 | setaudit_addr(proc_t p, struct setaudit_addr_args *uap, int32_t *retval) |
1211 | { |
1212 | #pragma unused(p, uap, retval) |
1213 | |
1214 | return (ENOSYS); |
1215 | } |
1216 | |
1217 | int |
1218 | auditctl(proc_t p, struct auditctl_args *uap, int32_t *retval) |
1219 | { |
1220 | #pragma unused(p, uap, retval) |
1221 | |
1222 | return (ENOSYS); |
1223 | } |
1224 | |
1225 | #endif /* CONFIG_AUDIT */ |
1226 | |