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