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