xref: /freebsd/sys/security/audit/audit_syscalls.c (revision 24e4dcf4ba5e9dedcf89efd358ea3e1fe5867020)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1999-2009 Apple Inc.
5  * Copyright (c) 2016, 2018 Robert N. M. Watson
6  * All rights reserved.
7  *
8  * Portions of this software were developed by BAE Systems, the University of
9  * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL
10  * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent
11  * Computing (TC) research program.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1.  Redistributions of source code must retain the above copyright
17  *     notice, this list of conditions and the following disclaimer.
18  * 2.  Redistributions in binary form must reproduce the above copyright
19  *     notice, this list of conditions and the following disclaimer in the
20  *     documentation and/or other materials provided with the distribution.
21  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
22  *     its contributors may be used to endorse or promote products derived
23  *     from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
29  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
34  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 #include <sys/param.h>
39 #include <sys/mount.h>
40 #include <sys/namei.h>
41 #include <sys/priv.h>
42 #include <sys/proc.h>
43 #include <sys/sysproto.h>
44 #include <sys/systm.h>
45 #include <sys/vnode.h>
46 #include <sys/jail.h>
47 
48 #include <bsm/audit.h>
49 #include <bsm/audit_kevents.h>
50 
51 #include <security/audit/audit.h>
52 #include <security/audit/audit_private.h>
53 #include <security/mac/mac_framework.h>
54 
55 #ifdef AUDIT
56 
57 static int
58 audit_priv_check_cred(struct ucred *cred, int priv)
59 {
60 	int error;
61 
62 	error = priv_check_cred(cred, priv);
63 	if (error == EPERM && jailed(cred)) {
64 		/*
65 		 * The audit system calls historically returned ENOSYS when
66 		 * invoked from within a jail, and some userspace applications
67 		 * handle that case specially.  Thus, convert the error here.
68 		 */
69 		error = ENOSYS;
70 	}
71 	return (error);
72 }
73 
74 static int
75 audit_priv_check(struct thread *td, int priv)
76 {
77 	return (audit_priv_check_cred(td->td_ucred, priv));
78 }
79 
80 /*
81  * System call to allow a user space application to submit a BSM audit record
82  * to the kernel for inclusion in the audit log.  This function does little
83  * verification on the audit record that is submitted.
84  *
85  * XXXAUDIT: Audit preselection for user records does not currently work,
86  * since we pre-select only based on the AUE_audit event type, not the event
87  * type submitted as part of the user audit data.
88  */
89 /* ARGSUSED */
90 int
91 sys_audit(struct thread *td, struct audit_args *uap)
92 {
93 	int error;
94 	void * rec;
95 	struct kaudit_record *ar;
96 
97 	if (jailed(td->td_ucred))
98 		return (ENOSYS);
99 	error = priv_check(td, PRIV_AUDIT_SUBMIT);
100 	if (error)
101 		return (error);
102 
103 	if ((uap->length <= 0) || (uap->length > audit_qctrl.aq_bufsz))
104 		return (EINVAL);
105 
106 	ar = currecord();
107 
108 	/*
109 	 * If there's no current audit record (audit() itself not audited)
110 	 * commit the user audit record.
111 	 */
112 	if (ar == NULL) {
113 		/*
114 		 * This is not very efficient; we're required to allocate a
115 		 * complete kernel audit record just so the user record can
116 		 * tag along.
117 		 *
118 		 * XXXAUDIT: Maybe AUE_AUDIT in the system call context and
119 		 * special pre-select handling?
120 		 */
121 		td->td_ar = audit_new(AUE_NULL, td);
122 		if (td->td_ar == NULL)
123 			return (ENOTSUP);
124 		td->td_pflags |= TDP_AUDITREC;
125 		ar = td->td_ar;
126 	}
127 
128 	if (uap->length > MAX_AUDIT_RECORD_SIZE)
129 		return (EINVAL);
130 
131 	rec = malloc(uap->length, M_AUDITDATA, M_WAITOK);
132 
133 	error = copyin(uap->record, rec, uap->length);
134 	if (error)
135 		goto free_out;
136 
137 	/* Verify the record. */
138 	if (bsm_rec_verify(rec) == 0) {
139 		error = EINVAL;
140 		goto free_out;
141 	}
142 
143 #ifdef MAC
144 	error = mac_system_check_audit(td->td_ucred, rec, uap->length);
145 	if (error)
146 		goto free_out;
147 #endif
148 
149 	/*
150 	 * Attach the user audit record to the kernel audit record.  Because
151 	 * this system call is an auditable event, we will write the user
152 	 * record along with the record for this audit event.
153 	 *
154 	 * XXXAUDIT: KASSERT appropriate starting values of k_udata, k_ulen,
155 	 * k_ar_commit & AR_COMMIT_USER?
156 	 */
157 	ar->k_udata = rec;
158 	ar->k_ulen  = uap->length;
159 	ar->k_ar_commit |= AR_COMMIT_USER;
160 
161 	/*
162 	 * Currently we assume that all preselection has been performed in
163 	 * userspace.  We unconditionally set these masks so that the records
164 	 * get committed both to the trail and pipe.  In the future we will
165 	 * want to setup kernel based preselection.
166 	 */
167 	ar->k_ar_commit |= (AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE);
168 	return (0);
169 
170 free_out:
171 	/*
172 	 * audit_syscall_exit() will free the audit record on the thread even
173 	 * if we allocated it above.
174 	 */
175 	free(rec, M_AUDITDATA);
176 	return (error);
177 }
178 
179 /*
180  *  System call to manipulate auditing.
181  */
182 /* ARGSUSED */
183 int
184 sys_auditon(struct thread *td, struct auditon_args *uap)
185 {
186 	struct ucred *cred, *newcred, *oldcred;
187 	int error;
188 	union auditon_udata udata;
189 	struct proc *tp;
190 
191 	if (jailed(td->td_ucred))
192 		return (ENOSYS);
193 	AUDIT_ARG_CMD(uap->cmd);
194 
195 #ifdef MAC
196 	error = mac_system_check_auditon(td->td_ucred, uap->cmd);
197 	if (error)
198 		return (error);
199 #endif
200 
201 	error = priv_check(td, PRIV_AUDIT_CONTROL);
202 	if (error)
203 		return (error);
204 
205 	if ((uap->length <= 0) || (uap->length > sizeof(union auditon_udata)))
206 		return (EINVAL);
207 
208 	memset((void *)&udata, 0, sizeof(udata));
209 
210 	/*
211 	 * Some of the GET commands use the arguments too.
212 	 */
213 	switch (uap->cmd) {
214 	case A_SETPOLICY:
215 	case A_OLDSETPOLICY:
216 	case A_SETKMASK:
217 	case A_SETQCTRL:
218 	case A_OLDSETQCTRL:
219 	case A_SETSTAT:
220 	case A_SETUMASK:
221 	case A_SETSMASK:
222 	case A_SETCOND:
223 	case A_OLDSETCOND:
224 	case A_SETCLASS:
225 	case A_SETEVENT:
226 	case A_SETPMASK:
227 	case A_SETFSIZE:
228 	case A_SETKAUDIT:
229 	case A_GETCLASS:
230 	case A_GETEVENT:
231 	case A_GETPINFO:
232 	case A_GETPINFO_ADDR:
233 	case A_SENDTRIGGER:
234 		error = copyin(uap->data, (void *)&udata, uap->length);
235 		if (error)
236 			return (error);
237 		AUDIT_ARG_AUDITON(&udata);
238 		break;
239 	}
240 
241 	/*
242 	 * XXXAUDIT: Locking?
243 	 */
244 	switch (uap->cmd) {
245 	case A_OLDGETPOLICY:
246 	case A_GETPOLICY:
247 		if (uap->length == sizeof(udata.au_policy64)) {
248 			if (!audit_fail_stop)
249 				udata.au_policy64 |= AUDIT_CNT;
250 			if (audit_panic_on_write_fail)
251 				udata.au_policy64 |= AUDIT_AHLT;
252 			if (audit_argv)
253 				udata.au_policy64 |= AUDIT_ARGV;
254 			if (audit_arge)
255 				udata.au_policy64 |= AUDIT_ARGE;
256 			break;
257 		}
258 		if (uap->length != sizeof(udata.au_policy))
259 			return (EINVAL);
260 		if (!audit_fail_stop)
261 			udata.au_policy |= AUDIT_CNT;
262 		if (audit_panic_on_write_fail)
263 			udata.au_policy |= AUDIT_AHLT;
264 		if (audit_argv)
265 			udata.au_policy |= AUDIT_ARGV;
266 		if (audit_arge)
267 			udata.au_policy |= AUDIT_ARGE;
268 		break;
269 
270 	case A_OLDSETPOLICY:
271 	case A_SETPOLICY:
272 		if (uap->length == sizeof(udata.au_policy64)) {
273 			if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|
274 			    AUDIT_ARGV|AUDIT_ARGE))
275 				return (EINVAL);
276 			audit_fail_stop = ((udata.au_policy64 & AUDIT_CNT) ==
277 			    0);
278 			audit_panic_on_write_fail = (udata.au_policy64 &
279 			    AUDIT_AHLT);
280 			audit_argv = (udata.au_policy64 & AUDIT_ARGV);
281 			audit_arge = (udata.au_policy64 & AUDIT_ARGE);
282 			break;
283 		}
284 		if (uap->length != sizeof(udata.au_policy))
285 			return (EINVAL);
286 		if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV|
287 		    AUDIT_ARGE))
288 			return (EINVAL);
289 		/*
290 		 * XXX - Need to wake up waiters if the policy relaxes?
291 		 */
292 		audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0);
293 		audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT);
294 		audit_argv = (udata.au_policy & AUDIT_ARGV);
295 		audit_arge = (udata.au_policy & AUDIT_ARGE);
296 		break;
297 
298 	case A_GETKMASK:
299 		if (uap->length != sizeof(udata.au_mask))
300 			return (EINVAL);
301 		udata.au_mask = audit_nae_mask;
302 		break;
303 
304 	case A_SETKMASK:
305 		if (uap->length != sizeof(udata.au_mask))
306 			return (EINVAL);
307 		audit_nae_mask = udata.au_mask;
308 		break;
309 
310 	case A_OLDGETQCTRL:
311 	case A_GETQCTRL:
312 		if (uap->length == sizeof(udata.au_qctrl64)) {
313 			udata.au_qctrl64.aq64_hiwater =
314 			    (u_int64_t)audit_qctrl.aq_hiwater;
315 			udata.au_qctrl64.aq64_lowater =
316 			    (u_int64_t)audit_qctrl.aq_lowater;
317 			udata.au_qctrl64.aq64_bufsz =
318 			    (u_int64_t)audit_qctrl.aq_bufsz;
319 			udata.au_qctrl64.aq64_minfree =
320 			    (u_int64_t)audit_qctrl.aq_minfree;
321 			break;
322 		}
323 		if (uap->length != sizeof(udata.au_qctrl))
324 			return (EINVAL);
325 		udata.au_qctrl = audit_qctrl;
326 		break;
327 
328 	case A_OLDSETQCTRL:
329 	case A_SETQCTRL:
330 		if (uap->length == sizeof(udata.au_qctrl64)) {
331 			/* NB: aq64_minfree is unsigned unlike aq_minfree. */
332 			if ((udata.au_qctrl64.aq64_hiwater > AQ_MAXHIGH) ||
333 			    (udata.au_qctrl64.aq64_lowater >=
334 			    udata.au_qctrl.aq_hiwater) ||
335 			    (udata.au_qctrl64.aq64_bufsz > AQ_MAXBUFSZ) ||
336 			    (udata.au_qctrl64.aq64_minfree > 100))
337 				return (EINVAL);
338 			audit_qctrl.aq_hiwater =
339 			    (int)udata.au_qctrl64.aq64_hiwater;
340 			audit_qctrl.aq_lowater =
341 			    (int)udata.au_qctrl64.aq64_lowater;
342 			audit_qctrl.aq_bufsz =
343 			    (int)udata.au_qctrl64.aq64_bufsz;
344 			audit_qctrl.aq_minfree =
345 			    (int)udata.au_qctrl64.aq64_minfree;
346 			audit_qctrl.aq_delay = -1;	/* Not used. */
347 			break;
348 		}
349 		if (uap->length != sizeof(udata.au_qctrl))
350 			return (EINVAL);
351 		if ((udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) ||
352 		    (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) ||
353 		    (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) ||
354 		    (udata.au_qctrl.aq_minfree < 0) ||
355 		    (udata.au_qctrl.aq_minfree > 100))
356 			return (EINVAL);
357 
358 		audit_qctrl = udata.au_qctrl;
359 		/* XXX The queue delay value isn't used with the kernel. */
360 		audit_qctrl.aq_delay = -1;
361 		break;
362 
363 	case A_GETCWD:
364 		return (ENOSYS);
365 		break;
366 
367 	case A_GETCAR:
368 		return (ENOSYS);
369 		break;
370 
371 	case A_GETSTAT:
372 		return (ENOSYS);
373 		break;
374 
375 	case A_SETSTAT:
376 		return (ENOSYS);
377 		break;
378 
379 	case A_SETUMASK:
380 		return (ENOSYS);
381 		break;
382 
383 	case A_SETSMASK:
384 		return (ENOSYS);
385 		break;
386 
387 	case A_OLDGETCOND:
388 	case A_GETCOND:
389 		if (uap->length == sizeof(udata.au_cond64)) {
390 			if (audit_trail_enabled && !audit_trail_suspended)
391 				udata.au_cond64 = AUC_AUDITING;
392 			else
393 				udata.au_cond64 = AUC_NOAUDIT;
394 			break;
395 		}
396 		if (uap->length != sizeof(udata.au_cond))
397 			return (EINVAL);
398 		if (audit_trail_enabled && !audit_trail_suspended)
399 			udata.au_cond = AUC_AUDITING;
400 		else
401 			udata.au_cond = AUC_NOAUDIT;
402 		break;
403 
404 	case A_OLDSETCOND:
405 	case A_SETCOND:
406 		if (uap->length == sizeof(udata.au_cond64)) {
407 			if (udata.au_cond64 == AUC_NOAUDIT)
408 				audit_trail_suspended = 1;
409 			if (udata.au_cond64 == AUC_AUDITING)
410 				audit_trail_suspended = 0;
411 			if (udata.au_cond64 == AUC_DISABLED) {
412 				audit_trail_suspended = 1;
413 				audit_shutdown(NULL, 0);
414 			}
415 			audit_syscalls_enabled_update();
416 			break;
417 		}
418 		if (uap->length != sizeof(udata.au_cond))
419 			return (EINVAL);
420 		if (udata.au_cond == AUC_NOAUDIT)
421 			audit_trail_suspended = 1;
422 		if (udata.au_cond == AUC_AUDITING)
423 			audit_trail_suspended = 0;
424 		if (udata.au_cond == AUC_DISABLED) {
425 			audit_trail_suspended = 1;
426 			audit_shutdown(NULL, 0);
427 		}
428 		audit_syscalls_enabled_update();
429 		break;
430 
431 	case A_GETCLASS:
432 		if (uap->length != sizeof(udata.au_evclass))
433 			return (EINVAL);
434 		udata.au_evclass.ec_class = au_event_class(
435 		    udata.au_evclass.ec_number);
436 		break;
437 
438 	case A_GETEVENT:
439 		if (uap->length != sizeof(udata.au_evname))
440 			return (EINVAL);
441 		error = au_event_name(udata.au_evname.en_number,
442 		    udata.au_evname.en_name);
443 		if (error != 0)
444 			return (error);
445 		break;
446 
447 	case A_SETCLASS:
448 		if (uap->length != sizeof(udata.au_evclass))
449 			return (EINVAL);
450 		au_evclassmap_insert(udata.au_evclass.ec_number,
451 		    udata.au_evclass.ec_class);
452 		break;
453 
454 	case A_SETEVENT:
455 		if (uap->length != sizeof(udata.au_evname))
456 			return (EINVAL);
457 
458 		/* Ensure nul termination from userspace. */
459 		udata.au_evname.en_name[sizeof(udata.au_evname.en_name) - 1]
460 		    = 0;
461 		au_evnamemap_insert(udata.au_evname.en_number,
462 		    udata.au_evname.en_name);
463 		break;
464 
465 	case A_GETPINFO:
466 		if (uap->length != sizeof(udata.au_aupinfo))
467 			return (EINVAL);
468 		if (udata.au_aupinfo.ap_pid < 1)
469 			return (ESRCH);
470 		if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL)
471 			return (ESRCH);
472 		if ((error = p_cansee(td, tp)) != 0) {
473 			PROC_UNLOCK(tp);
474 			return (error);
475 		}
476 		cred = tp->p_ucred;
477 		if (cred->cr_audit.ai_termid.at_type == AU_IPv6) {
478 			PROC_UNLOCK(tp);
479 			return (EINVAL);
480 		}
481 		udata.au_aupinfo.ap_auid = cred->cr_audit.ai_auid;
482 		udata.au_aupinfo.ap_mask.am_success =
483 		    cred->cr_audit.ai_mask.am_success;
484 		udata.au_aupinfo.ap_mask.am_failure =
485 		    cred->cr_audit.ai_mask.am_failure;
486 		udata.au_aupinfo.ap_termid.machine =
487 		    cred->cr_audit.ai_termid.at_addr[0];
488 		udata.au_aupinfo.ap_termid.port =
489 		    (dev_t)cred->cr_audit.ai_termid.at_port;
490 		udata.au_aupinfo.ap_asid = cred->cr_audit.ai_asid;
491 		PROC_UNLOCK(tp);
492 		break;
493 
494 	case A_SETPMASK:
495 		if (uap->length != sizeof(udata.au_aupinfo))
496 			return (EINVAL);
497 		if (udata.au_aupinfo.ap_pid < 1)
498 			return (ESRCH);
499 		newcred = crget();
500 		if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) {
501 			crfree(newcred);
502 			return (ESRCH);
503 		}
504 		if ((error = p_cansee(td, tp)) != 0) {
505 			PROC_UNLOCK(tp);
506 			crfree(newcred);
507 			return (error);
508 		}
509 		oldcred = tp->p_ucred;
510 		crcopy(newcred, oldcred);
511 		newcred->cr_audit.ai_mask.am_success =
512 		    udata.au_aupinfo.ap_mask.am_success;
513 		newcred->cr_audit.ai_mask.am_failure =
514 		    udata.au_aupinfo.ap_mask.am_failure;
515 		proc_set_cred(tp, newcred);
516 		PROC_UNLOCK(tp);
517 		crfree(oldcred);
518 		break;
519 
520 	case A_SETFSIZE:
521 		if (uap->length != sizeof(udata.au_fstat))
522 			return (EINVAL);
523 		if ((udata.au_fstat.af_filesz != 0) &&
524 		   (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE))
525 			return (EINVAL);
526 		audit_fstat.af_filesz = udata.au_fstat.af_filesz;
527 		break;
528 
529 	case A_GETFSIZE:
530 		if (uap->length != sizeof(udata.au_fstat))
531 			return (EINVAL);
532 		udata.au_fstat.af_filesz = audit_fstat.af_filesz;
533 		udata.au_fstat.af_currsz = audit_fstat.af_currsz;
534 		break;
535 
536 	case A_GETPINFO_ADDR:
537 		if (uap->length != sizeof(udata.au_aupinfo_addr))
538 			return (EINVAL);
539 		if (udata.au_aupinfo_addr.ap_pid < 1)
540 			return (ESRCH);
541 		if ((tp = pfind(udata.au_aupinfo_addr.ap_pid)) == NULL)
542 			return (ESRCH);
543 		cred = tp->p_ucred;
544 		udata.au_aupinfo_addr.ap_auid = cred->cr_audit.ai_auid;
545 		udata.au_aupinfo_addr.ap_mask.am_success =
546 		    cred->cr_audit.ai_mask.am_success;
547 		udata.au_aupinfo_addr.ap_mask.am_failure =
548 		    cred->cr_audit.ai_mask.am_failure;
549 		udata.au_aupinfo_addr.ap_termid = cred->cr_audit.ai_termid;
550 		udata.au_aupinfo_addr.ap_asid = cred->cr_audit.ai_asid;
551 		PROC_UNLOCK(tp);
552 		break;
553 
554 	case A_GETKAUDIT:
555 		if (uap->length != sizeof(udata.au_kau_info))
556 			return (EINVAL);
557 		audit_get_kinfo(&udata.au_kau_info);
558 		break;
559 
560 	case A_SETKAUDIT:
561 		if (uap->length != sizeof(udata.au_kau_info))
562 			return (EINVAL);
563 		if (udata.au_kau_info.ai_termid.at_type != AU_IPv4 &&
564 		    udata.au_kau_info.ai_termid.at_type != AU_IPv6)
565 			return (EINVAL);
566 		audit_set_kinfo(&udata.au_kau_info);
567 		break;
568 
569 	case A_SENDTRIGGER:
570 		if (uap->length != sizeof(udata.au_trigger))
571 			return (EINVAL);
572 		if ((udata.au_trigger < AUDIT_TRIGGER_MIN) ||
573 		    (udata.au_trigger > AUDIT_TRIGGER_MAX))
574 			return (EINVAL);
575 		return (audit_send_trigger(udata.au_trigger));
576 
577 	default:
578 		return (EINVAL);
579 	}
580 
581 	/*
582 	 * Copy data back to userspace for the GET comands.
583 	 */
584 	switch (uap->cmd) {
585 	case A_GETPOLICY:
586 	case A_OLDGETPOLICY:
587 	case A_GETKMASK:
588 	case A_GETQCTRL:
589 	case A_OLDGETQCTRL:
590 	case A_GETCWD:
591 	case A_GETCAR:
592 	case A_GETSTAT:
593 	case A_GETCOND:
594 	case A_OLDGETCOND:
595 	case A_GETCLASS:
596 	case A_GETPINFO:
597 	case A_GETFSIZE:
598 	case A_GETPINFO_ADDR:
599 	case A_GETKAUDIT:
600 		error = copyout((void *)&udata, uap->data, uap->length);
601 		if (error)
602 			return (error);
603 		break;
604 	}
605 
606 	return (0);
607 }
608 
609 /*
610  * System calls to manage the user audit information.
611  */
612 /* ARGSUSED */
613 int
614 sys_getauid(struct thread *td, struct getauid_args *uap)
615 {
616 	int error;
617 
618 	error = audit_priv_check(td, PRIV_AUDIT_GETAUDIT);
619 	if (error)
620 		return (error);
621 	return (copyout(&td->td_ucred->cr_audit.ai_auid, uap->auid,
622 	    sizeof(td->td_ucred->cr_audit.ai_auid)));
623 }
624 
625 /* ARGSUSED */
626 int
627 sys_setauid(struct thread *td, struct setauid_args *uap)
628 {
629 	struct ucred *newcred, *oldcred;
630 	au_id_t id;
631 	int error;
632 
633 	error = copyin(uap->auid, &id, sizeof(id));
634 	if (error)
635 		return (error);
636 	audit_arg_auid(id);
637 	newcred = crget();
638 	PROC_LOCK(td->td_proc);
639 	oldcred = td->td_proc->p_ucred;
640 	crcopy(newcred, oldcred);
641 #ifdef MAC
642 	error = mac_cred_check_setauid(oldcred, id);
643 	if (error)
644 		goto fail;
645 #endif
646 	error = audit_priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT);
647 	if (error)
648 		goto fail;
649 	newcred->cr_audit.ai_auid = id;
650 	proc_set_cred(td->td_proc, newcred);
651 	PROC_UNLOCK(td->td_proc);
652 	crfree(oldcred);
653 	return (0);
654 fail:
655 	PROC_UNLOCK(td->td_proc);
656 	crfree(newcred);
657 	return (error);
658 }
659 
660 /*
661  * System calls to get and set process audit information.
662  */
663 /* ARGSUSED */
664 int
665 sys_getaudit(struct thread *td, struct getaudit_args *uap)
666 {
667 	struct auditinfo ai;
668 	struct ucred *cred;
669 	int error;
670 
671 	cred = td->td_ucred;
672 	error = audit_priv_check(td, PRIV_AUDIT_GETAUDIT);
673 	if (error)
674 		return (error);
675 	if (cred->cr_audit.ai_termid.at_type == AU_IPv6)
676 		return (E2BIG);
677 	bzero(&ai, sizeof(ai));
678 	ai.ai_auid = cred->cr_audit.ai_auid;
679 	ai.ai_mask = cred->cr_audit.ai_mask;
680 	ai.ai_asid = cred->cr_audit.ai_asid;
681 	ai.ai_termid.machine = cred->cr_audit.ai_termid.at_addr[0];
682 	ai.ai_termid.port = cred->cr_audit.ai_termid.at_port;
683 	return (copyout(&ai, uap->auditinfo, sizeof(ai)));
684 }
685 
686 /* ARGSUSED */
687 int
688 sys_setaudit(struct thread *td, struct setaudit_args *uap)
689 {
690 	struct ucred *newcred, *oldcred;
691 	struct auditinfo ai;
692 	int error;
693 
694 	error = copyin(uap->auditinfo, &ai, sizeof(ai));
695 	if (error)
696 		return (error);
697 	audit_arg_auditinfo(&ai);
698 	newcred = crget();
699 	PROC_LOCK(td->td_proc);
700 	oldcred = td->td_proc->p_ucred;
701 	crcopy(newcred, oldcred);
702 #ifdef MAC
703 	error = mac_cred_check_setaudit(oldcred, &ai);
704 	if (error)
705 		goto fail;
706 #endif
707 	error = audit_priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT);
708 	if (error)
709 		goto fail;
710 	bzero(&newcred->cr_audit, sizeof(newcred->cr_audit));
711 	newcred->cr_audit.ai_auid = ai.ai_auid;
712 	newcred->cr_audit.ai_mask = ai.ai_mask;
713 	newcred->cr_audit.ai_asid = ai.ai_asid;
714 	newcred->cr_audit.ai_termid.at_addr[0] = ai.ai_termid.machine;
715 	newcred->cr_audit.ai_termid.at_port = ai.ai_termid.port;
716 	newcred->cr_audit.ai_termid.at_type = AU_IPv4;
717 	proc_set_cred(td->td_proc, newcred);
718 	PROC_UNLOCK(td->td_proc);
719 	crfree(oldcred);
720 	return (0);
721 fail:
722 	PROC_UNLOCK(td->td_proc);
723 	crfree(newcred);
724 	return (error);
725 }
726 
727 /* ARGSUSED */
728 int
729 sys_getaudit_addr(struct thread *td, struct getaudit_addr_args *uap)
730 {
731 	int error;
732 
733 	if (uap->length < sizeof(*uap->auditinfo_addr))
734 		return (EOVERFLOW);
735 	error = audit_priv_check(td, PRIV_AUDIT_GETAUDIT);
736 	if (error)
737 		return (error);
738 	return (copyout(&td->td_ucred->cr_audit, uap->auditinfo_addr,
739 	    sizeof(*uap->auditinfo_addr)));
740 }
741 
742 /* ARGSUSED */
743 int
744 sys_setaudit_addr(struct thread *td, struct setaudit_addr_args *uap)
745 {
746 	struct ucred *newcred, *oldcred;
747 	struct auditinfo_addr aia;
748 	int error;
749 
750 	error = copyin(uap->auditinfo_addr, &aia, sizeof(aia));
751 	if (error)
752 		return (error);
753 	audit_arg_auditinfo_addr(&aia);
754 	if (aia.ai_termid.at_type != AU_IPv6 &&
755 	    aia.ai_termid.at_type != AU_IPv4)
756 		return (EINVAL);
757 	newcred = crget();
758 	PROC_LOCK(td->td_proc);
759 	oldcred = td->td_proc->p_ucred;
760 	crcopy(newcred, oldcred);
761 #ifdef MAC
762 	error = mac_cred_check_setaudit_addr(oldcred, &aia);
763 	if (error)
764 		goto fail;
765 #endif
766 	error = audit_priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT);
767 	if (error)
768 		goto fail;
769 	newcred->cr_audit = aia;
770 	proc_set_cred(td->td_proc, newcred);
771 	PROC_UNLOCK(td->td_proc);
772 	crfree(oldcred);
773 	return (0);
774 fail:
775 	PROC_UNLOCK(td->td_proc);
776 	crfree(newcred);
777 	return (error);
778 }
779 
780 /*
781  * Syscall to manage audit files.
782  */
783 /* ARGSUSED */
784 int
785 sys_auditctl(struct thread *td, struct auditctl_args *uap)
786 {
787 	struct nameidata nd;
788 	struct ucred *cred;
789 	struct vnode *vp;
790 	int error = 0;
791 	int flags;
792 
793 	if (jailed(td->td_ucred))
794 		return (ENOSYS);
795 	error = priv_check(td, PRIV_AUDIT_CONTROL);
796 	if (error)
797 		return (error);
798 
799 	vp = NULL;
800 	cred = NULL;
801 
802 	/*
803 	 * If a path is specified, open the replacement vnode, perform
804 	 * validity checks, and grab another reference to the current
805 	 * credential.
806 	 *
807 	 * On Darwin, a NULL path argument is also used to disable audit.
808 	 */
809 	if (uap->path == NULL)
810 		return (EINVAL);
811 
812 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE,
813 	    uap->path);
814 	flags = AUDIT_OPEN_FLAGS;
815 	error = vn_open(&nd, &flags, 0, NULL);
816 	if (error)
817 		return (error);
818 	vp = nd.ni_vp;
819 #ifdef MAC
820 	error = mac_system_check_auditctl(td->td_ucred, vp);
821 	VOP_UNLOCK(vp);
822 	if (error) {
823 		vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td);
824 		return (error);
825 	}
826 #else
827 	VOP_UNLOCK(vp);
828 #endif
829 	NDFREE_PNBUF(&nd);
830 	if (vp->v_type != VREG) {
831 		vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td);
832 		return (EINVAL);
833 	}
834 	cred = td->td_ucred;
835 	crhold(cred);
836 
837 	/*
838 	 * XXXAUDIT: Should audit_trail_suspended actually be cleared by
839 	 * audit_worker?
840 	 */
841 	audit_trail_suspended = 0;
842 	audit_syscalls_enabled_update();
843 
844 	audit_rotate_vnode(cred, vp);
845 
846 	return (error);
847 }
848 
849 #else /* !AUDIT */
850 
851 int
852 sys_audit(struct thread *td, struct audit_args *uap)
853 {
854 
855 	return (ENOSYS);
856 }
857 
858 int
859 sys_auditon(struct thread *td, struct auditon_args *uap)
860 {
861 
862 	return (ENOSYS);
863 }
864 
865 int
866 sys_getauid(struct thread *td, struct getauid_args *uap)
867 {
868 
869 	return (ENOSYS);
870 }
871 
872 int
873 sys_setauid(struct thread *td, struct setauid_args *uap)
874 {
875 
876 	return (ENOSYS);
877 }
878 
879 int
880 sys_getaudit(struct thread *td, struct getaudit_args *uap)
881 {
882 
883 	return (ENOSYS);
884 }
885 
886 int
887 sys_setaudit(struct thread *td, struct setaudit_args *uap)
888 {
889 
890 	return (ENOSYS);
891 }
892 
893 int
894 sys_getaudit_addr(struct thread *td, struct getaudit_addr_args *uap)
895 {
896 
897 	return (ENOSYS);
898 }
899 
900 int
901 sys_setaudit_addr(struct thread *td, struct setaudit_addr_args *uap)
902 {
903 
904 	return (ENOSYS);
905 }
906 
907 int
908 sys_auditctl(struct thread *td, struct auditctl_args *uap)
909 {
910 
911 	return (ENOSYS);
912 }
913 #endif /* AUDIT */
914