audit_syscalls.c revision 176686
192986Sobrien/*
292986Sobrien * Copyright (c) 1999-2005 Apple Computer, Inc.
392986Sobrien * All rights reserved.
462856Sdcs *
562856Sdcs * Redistribution and use in source and binary forms, with or without
662856Sdcs * modification, are permitted provided that the following conditions
762856Sdcs * are met:
862856Sdcs * 1.  Redistributions of source code must retain the above copyright
962856Sdcs *     notice, this list of conditions and the following disclaimer.
1062856Sdcs * 2.  Redistributions in binary form must reproduce the above copyright
1162856Sdcs *     notice, this list of conditions and the following disclaimer in the
1262856Sdcs *     documentation and/or other materials provided with the distribution.
1362856Sdcs * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
1462856Sdcs *     its contributors may be used to endorse or promote products derived
1562856Sdcs *     from this software without specific prior written permission.
1662856Sdcs *
1762856Sdcs * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
1862856Sdcs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1962856Sdcs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2062856Sdcs * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
2162856Sdcs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2262856Sdcs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2362856Sdcs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2462856Sdcs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2592889Sobrien * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
2692889Sobrien * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2792889Sobrien * POSSIBILITY OF SUCH DAMAGE.
2892889Sobrien *
2962856Sdcs * $FreeBSD: head/sys/security/audit/audit_syscalls.c 176686 2008-03-01 11:04:04Z rwatson $
3062856Sdcs */
3162856Sdcs
3262856Sdcs#include "opt_mac.h"
3362856Sdcs
3462856Sdcs#include <sys/param.h>
3562856Sdcs#include <sys/mount.h>
3662856Sdcs#include <sys/namei.h>
3762856Sdcs#include <sys/priv.h>
3862856Sdcs#include <sys/proc.h>
3962856Sdcs#include <sys/sysproto.h>
4062856Sdcs#include <sys/systm.h>
4162856Sdcs#include <sys/vnode.h>
4262856Sdcs#include <sys/jail.h>
4362856Sdcs
4462856Sdcs#include <bsm/audit.h>
4562856Sdcs#include <bsm/audit_kevents.h>
4662856Sdcs
4762856Sdcs#include <security/audit/audit.h>
4862856Sdcs#include <security/audit/audit_private.h>
4962856Sdcs#include <security/mac/mac_framework.h>
5062856Sdcs
5162856Sdcs#ifdef AUDIT
5262856Sdcs
5362856Sdcs/*
5462856Sdcs * System call to allow a user space application to submit a BSM audit record
5562856Sdcs * to the kernel for inclusion in the audit log.  This function does little
5662856Sdcs * verification on the audit record that is submitted.
5762856Sdcs *
5862856Sdcs * XXXAUDIT: Audit preselection for user records does not currently work,
5962856Sdcs * since we pre-select only based on the AUE_audit event type, not the event
6062856Sdcs * type submitted as part of the user audit data.
6162856Sdcs */
6262856Sdcs/* ARGSUSED */
6362856Sdcsint
6462856Sdcsaudit(struct thread *td, struct audit_args *uap)
6562856Sdcs{
6662856Sdcs	int error;
6762856Sdcs	void * rec;
6862856Sdcs	struct kaudit_record *ar;
6962856Sdcs
7062856Sdcs	if (jailed(td->td_ucred))
7162856Sdcs		return (ENOSYS);
7262856Sdcs	error = priv_check(td, PRIV_AUDIT_SUBMIT);
7362856Sdcs	if (error)
7462856Sdcs		return (error);
7562856Sdcs
7662856Sdcs	if ((uap->length <= 0) || (uap->length > audit_qctrl.aq_bufsz))
7762856Sdcs		return (EINVAL);
7862856Sdcs
7962856Sdcs	ar = currecord();
8062856Sdcs
8162856Sdcs	/*
8262856Sdcs	 * If there's no current audit record (audit() itself not audited)
8362856Sdcs	 * commit the user audit record.
8462856Sdcs	 */
8562856Sdcs	if (ar == NULL) {
8662856Sdcs
8762856Sdcs		/*
8862856Sdcs		 * This is not very efficient; we're required to allocate a
8962856Sdcs		 * complete kernel audit record just so the user record can
9062856Sdcs		 * tag along.
9192889Sobrien		 *
9262856Sdcs		 * XXXAUDIT: Maybe AUE_AUDIT in the system call context and
9362856Sdcs		 * special pre-select handling?
9462856Sdcs		 */
9592889Sobrien		td->td_ar = audit_new(AUE_NULL, td);
9662856Sdcs		if (td->td_ar == NULL)
9762856Sdcs			return (ENOTSUP);
9892889Sobrien		ar = td->td_ar;
9992889Sobrien	}
10092889Sobrien
10192889Sobrien	if (uap->length > MAX_AUDIT_RECORD_SIZE)
10292889Sobrien		return (EINVAL);
10392889Sobrien
10492889Sobrien	rec = malloc(uap->length, M_AUDITDATA, M_WAITOK);
10592889Sobrien
10662856Sdcs	error = copyin(uap->record, rec, uap->length);
10762856Sdcs	if (error)
10862856Sdcs		goto free_out;
10962856Sdcs
11062856Sdcs	/* Verify the record. */
11162856Sdcs	if (bsm_rec_verify(rec) == 0) {
11262856Sdcs		error = EINVAL;
11362856Sdcs		goto free_out;
11462856Sdcs	}
11562856Sdcs
11662856Sdcs#ifdef MAC
11762856Sdcs	error = mac_system_check_audit(td->td_ucred, rec, uap->length);
11862856Sdcs	if (error)
11962856Sdcs		goto free_out;
12062856Sdcs#endif
12162856Sdcs
12262856Sdcs	/*
12362856Sdcs	 * Attach the user audit record to the kernel audit record.  Because
12462856Sdcs	 * this system call is an auditable event, we will write the user
12562856Sdcs	 * record along with the record for this audit event.
12662856Sdcs	 *
12762856Sdcs	 * XXXAUDIT: KASSERT appropriate starting values of k_udata, k_ulen,
12862856Sdcs	 * k_ar_commit & AR_COMMIT_USER?
12962856Sdcs	 */
13062856Sdcs	ar->k_udata = rec;
13162856Sdcs	ar->k_ulen  = uap->length;
13262856Sdcs	ar->k_ar_commit |= AR_COMMIT_USER;
13362856Sdcs
13462856Sdcs	/*
13562856Sdcs	 * Currently we assume that all preselection has been performed in
13662856Sdcs	 * userspace.  We unconditionally set these masks so that the records
13762856Sdcs	 * get committed both to the trail and pipe.  In the future we will
13862856Sdcs	 * want to setup kernel based preselection.
13962856Sdcs	 */
14062856Sdcs	ar->k_ar_commit |= (AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE);
14162856Sdcs	return (0);
14262856Sdcs
14362856Sdcsfree_out:
14462856Sdcs	/*
14562856Sdcs	 * audit_syscall_exit() will free the audit record on the thread even
14662856Sdcs	 * if we allocated it above.
14762856Sdcs	 */
14862856Sdcs	free(rec, M_AUDITDATA);
14962856Sdcs	return (error);
15062856Sdcs}
15162856Sdcs
15262856Sdcs/*
15362856Sdcs *  System call to manipulate auditing.
15462856Sdcs */
15562856Sdcs/* ARGSUSED */
15662856Sdcsint
15762856Sdcsauditon(struct thread *td, struct auditon_args *uap)
15862856Sdcs{
15962856Sdcs	struct ucred *newcred, *oldcred;
16062856Sdcs	int error;
16162856Sdcs	union auditon_udata udata;
16262856Sdcs	struct proc *tp;
16362856Sdcs
16462856Sdcs	if (jailed(td->td_ucred))
16562856Sdcs		return (ENOSYS);
16662856Sdcs	AUDIT_ARG(cmd, uap->cmd);
16762856Sdcs
16862856Sdcs#ifdef MAC
16962856Sdcs	error = mac_system_check_auditon(td->td_ucred, uap->cmd);
17062856Sdcs	if (error)
17162856Sdcs		return (error);
17262856Sdcs#endif
17362856Sdcs
17462856Sdcs	error = priv_check(td, PRIV_AUDIT_CONTROL);
17562856Sdcs	if (error)
17662856Sdcs		return (error);
17762856Sdcs
17862856Sdcs	if ((uap->length <= 0) || (uap->length > sizeof(union auditon_udata)))
17962856Sdcs		return (EINVAL);
18062856Sdcs
18162856Sdcs	memset((void *)&udata, 0, sizeof(udata));
18262856Sdcs
18362856Sdcs	/*
18462856Sdcs	 * Some of the GET commands use the arguments too.
18562856Sdcs	 */
18662856Sdcs	switch (uap->cmd) {
18762856Sdcs	case A_SETPOLICY:
18862856Sdcs	case A_SETKMASK:
18962856Sdcs	case A_SETQCTRL:
19062856Sdcs	case A_SETSTAT:
19162856Sdcs	case A_SETUMASK:
19262856Sdcs	case A_SETSMASK:
19362856Sdcs	case A_SETCOND:
19462856Sdcs	case A_SETCLASS:
19562856Sdcs	case A_SETPMASK:
19662856Sdcs	case A_SETFSIZE:
19762856Sdcs	case A_SETKAUDIT:
19862856Sdcs	case A_GETCLASS:
19962856Sdcs	case A_GETPINFO:
20062856Sdcs	case A_GETPINFO_ADDR:
20162856Sdcs	case A_SENDTRIGGER:
20262856Sdcs		error = copyin(uap->data, (void *)&udata, uap->length);
20362856Sdcs		if (error)
20462856Sdcs			return (error);
20562856Sdcs		AUDIT_ARG(auditon, &udata);
20662856Sdcs		break;
20762856Sdcs	}
20862856Sdcs
20962856Sdcs	/*
21062856Sdcs	 * XXXAUDIT: Locking?
21162856Sdcs	 */
21262856Sdcs	switch (uap->cmd) {
21362856Sdcs	case A_GETPOLICY:
21462856Sdcs		if (!audit_fail_stop)
21562856Sdcs			udata.au_policy |= AUDIT_CNT;
21662856Sdcs		if (audit_panic_on_write_fail)
21762856Sdcs			udata.au_policy |= AUDIT_AHLT;
21862856Sdcs		if (audit_argv)
21962856Sdcs			udata.au_policy |= AUDIT_ARGV;
22062856Sdcs		if (audit_arge)
22162856Sdcs			udata.au_policy |= AUDIT_ARGE;
22262856Sdcs		break;
22362856Sdcs
22462856Sdcs	case A_SETPOLICY:
22562856Sdcs		if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV|
22662856Sdcs		    AUDIT_ARGE))
22762856Sdcs			return (EINVAL);
22862856Sdcs		/*
22962856Sdcs		 * XXX - Need to wake up waiters if the policy relaxes?
23062856Sdcs		 */
23162856Sdcs		audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0);
23262856Sdcs		audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT);
23362856Sdcs		audit_argv = (udata.au_policy & AUDIT_ARGV);
23462856Sdcs		audit_arge = (udata.au_policy & AUDIT_ARGE);
23562856Sdcs		break;
23662856Sdcs
23762856Sdcs	case A_GETKMASK:
23862856Sdcs		udata.au_mask = audit_nae_mask;
23962856Sdcs		break;
24062856Sdcs
24162856Sdcs	case A_SETKMASK:
24262856Sdcs		audit_nae_mask = udata.au_mask;
24362856Sdcs		break;
24462856Sdcs
24562856Sdcs	case A_GETQCTRL:
246		udata.au_qctrl = audit_qctrl;
247		break;
248
249	case A_SETQCTRL:
250		if ((udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) ||
251		    (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) ||
252		    (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) ||
253		    (udata.au_qctrl.aq_minfree < 0) ||
254		    (udata.au_qctrl.aq_minfree > 100))
255			return (EINVAL);
256
257		audit_qctrl = udata.au_qctrl;
258		/* XXX The queue delay value isn't used with the kernel. */
259		audit_qctrl.aq_delay = -1;
260		break;
261
262	case A_GETCWD:
263		return (ENOSYS);
264		break;
265
266	case A_GETCAR:
267		return (ENOSYS);
268		break;
269
270	case A_GETSTAT:
271		return (ENOSYS);
272		break;
273
274	case A_SETSTAT:
275		return (ENOSYS);
276		break;
277
278	case A_SETUMASK:
279		return (ENOSYS);
280		break;
281
282	case A_SETSMASK:
283		return (ENOSYS);
284		break;
285
286	case A_GETCOND:
287		if (audit_enabled && !audit_suspended)
288			udata.au_cond = AUC_AUDITING;
289		else
290			udata.au_cond = AUC_NOAUDIT;
291		break;
292
293	case A_SETCOND:
294		if (udata.au_cond == AUC_NOAUDIT)
295			audit_suspended = 1;
296		if (udata.au_cond == AUC_AUDITING)
297			audit_suspended = 0;
298		if (udata.au_cond == AUC_DISABLED) {
299			audit_suspended = 1;
300			audit_shutdown(NULL, 0);
301		}
302		break;
303
304	case A_GETCLASS:
305		udata.au_evclass.ec_class = au_event_class(
306		    udata.au_evclass.ec_number);
307		break;
308
309	case A_SETCLASS:
310		au_evclassmap_insert(udata.au_evclass.ec_number,
311		    udata.au_evclass.ec_class);
312		break;
313
314	case A_GETPINFO:
315		if (udata.au_aupinfo.ap_pid < 1)
316			return (EINVAL);
317		if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL)
318			return (EINVAL);
319		if (p_cansee(td, tp) != 0) {
320			PROC_UNLOCK(tp);
321			return (EINVAL);
322		}
323		if (tp->p_ucred->cr_audit.ai_termid.at_type == AU_IPv6) {
324			PROC_UNLOCK(tp);
325			return (EINVAL);
326		}
327		udata.au_aupinfo.ap_auid =
328		    tp->p_ucred->cr_audit.ai_auid;
329		udata.au_aupinfo.ap_mask.am_success =
330		    tp->p_ucred->cr_audit.ai_mask.am_success;
331		udata.au_aupinfo.ap_mask.am_failure =
332		    tp->p_ucred->cr_audit.ai_mask.am_failure;
333		udata.au_aupinfo.ap_termid.machine =
334		    tp->p_ucred->cr_audit.ai_termid.at_addr[0];
335		udata.au_aupinfo.ap_termid.port =
336		    (dev_t)tp->p_ucred->cr_audit.ai_termid.at_port;
337		udata.au_aupinfo.ap_asid =
338		    tp->p_ucred->cr_audit.ai_asid;
339		PROC_UNLOCK(tp);
340		break;
341
342	case A_SETPMASK:
343		if (udata.au_aupinfo.ap_pid < 1)
344			return (EINVAL);
345		newcred = crget();
346		if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) {
347			crfree(newcred);
348			return (EINVAL);
349		}
350		if (p_cansee(td, tp) != 0) {
351			PROC_UNLOCK(tp);
352			crfree(newcred);
353			return (EINVAL);
354		}
355		oldcred = tp->p_ucred;
356		crcopy(newcred, oldcred);
357		newcred->cr_audit.ai_mask.am_success =
358		    udata.au_aupinfo.ap_mask.am_success;
359		newcred->cr_audit.ai_mask.am_failure =
360		    udata.au_aupinfo.ap_mask.am_failure;
361		td->td_proc->p_ucred = newcred;
362		PROC_UNLOCK(tp);
363		crfree(oldcred);
364		break;
365
366	case A_SETFSIZE:
367		if ((udata.au_fstat.af_filesz != 0) &&
368		   (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE))
369			return (EINVAL);
370		audit_fstat.af_filesz = udata.au_fstat.af_filesz;
371		break;
372
373	case A_GETFSIZE:
374		udata.au_fstat.af_filesz = audit_fstat.af_filesz;
375		udata.au_fstat.af_currsz = audit_fstat.af_currsz;
376		break;
377
378	case A_GETPINFO_ADDR:
379		if (udata.au_aupinfo_addr.ap_pid < 1)
380			return (EINVAL);
381		if ((tp = pfind(udata.au_aupinfo_addr.ap_pid)) == NULL)
382			return (EINVAL);
383		udata.au_aupinfo_addr.ap_auid =
384		    tp->p_ucred->cr_audit.ai_auid;
385		udata.au_aupinfo_addr.ap_mask.am_success =
386		    tp->p_ucred->cr_audit.ai_mask.am_success;
387		udata.au_aupinfo_addr.ap_mask.am_failure =
388		    tp->p_ucred->cr_audit.ai_mask.am_failure;
389		udata.au_aupinfo_addr.ap_termid =
390		    tp->p_ucred->cr_audit.ai_termid;
391		udata.au_aupinfo_addr.ap_asid =
392		    tp->p_ucred->cr_audit.ai_asid;
393		PROC_UNLOCK(tp);
394		break;
395
396	case A_GETKAUDIT:
397		return (ENOSYS);
398		break;
399
400	case A_SETKAUDIT:
401		return (ENOSYS);
402		break;
403
404	case A_SENDTRIGGER:
405		if ((udata.au_trigger < AUDIT_TRIGGER_MIN) ||
406		    (udata.au_trigger > AUDIT_TRIGGER_MAX))
407			return (EINVAL);
408		return (audit_send_trigger(udata.au_trigger));
409	}
410
411	/*
412	 * Copy data back to userspace for the GET comands.
413	 */
414	switch (uap->cmd) {
415	case A_GETPOLICY:
416	case A_GETKMASK:
417	case A_GETQCTRL:
418	case A_GETCWD:
419	case A_GETCAR:
420	case A_GETSTAT:
421	case A_GETCOND:
422	case A_GETCLASS:
423	case A_GETPINFO:
424	case A_GETFSIZE:
425	case A_GETPINFO_ADDR:
426	case A_GETKAUDIT:
427		error = copyout((void *)&udata, uap->data, uap->length);
428		if (error)
429			return (error);
430		break;
431	}
432
433	return (0);
434}
435
436/*
437 * System calls to manage the user audit information.
438 */
439/* ARGSUSED */
440int
441getauid(struct thread *td, struct getauid_args *uap)
442{
443	int error;
444
445	if (jailed(td->td_ucred))
446		return (ENOSYS);
447	error = priv_check(td, PRIV_AUDIT_GETAUDIT);
448	if (error)
449		return (error);
450	return (copyout(&td->td_ucred->cr_audit.ai_auid, uap->auid,
451	    sizeof(td->td_ucred->cr_audit.ai_auid)));
452}
453
454/* ARGSUSED */
455int
456setauid(struct thread *td, struct setauid_args *uap)
457{
458	struct ucred *newcred, *oldcred;
459	au_id_t id;
460	int error;
461
462	if (jailed(td->td_ucred))
463		return (ENOSYS);
464	error = copyin(uap->auid, &id, sizeof(id));
465	if (error)
466		return (error);
467	audit_arg_auid(id);
468	newcred = crget();
469	PROC_LOCK(td->td_proc);
470	oldcred = td->td_proc->p_ucred;
471	crcopy(newcred, oldcred);
472#ifdef MAC
473	error = mac_proc_check_setauid(oldcred, id);
474	if (error)
475		goto fail;
476#endif
477	error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0);
478	if (error)
479		goto fail;
480	newcred->cr_audit.ai_auid = id;
481	td->td_proc->p_ucred = newcred;
482	PROC_UNLOCK(td->td_proc);
483	crfree(oldcred);
484	return (0);
485fail:
486	PROC_UNLOCK(td->td_proc);
487	crfree(newcred);
488	return (error);
489}
490
491/*
492 * System calls to get and set process audit information.
493 */
494/* ARGSUSED */
495int
496getaudit(struct thread *td, struct getaudit_args *uap)
497{
498	struct auditinfo ai;
499	int error;
500
501	if (jailed(td->td_ucred))
502		return (ENOSYS);
503	error = priv_check(td, PRIV_AUDIT_GETAUDIT);
504	if (error)
505		return (error);
506	if (td->td_ucred->cr_audit.ai_termid.at_type == AU_IPv6)
507		return (E2BIG);
508	bzero(&ai, sizeof(ai));
509	ai.ai_auid = td->td_ucred->cr_audit.ai_auid;
510	ai.ai_mask = td->td_ucred->cr_audit.ai_mask;
511	ai.ai_asid = td->td_ucred->cr_audit.ai_asid;
512	ai.ai_termid.machine = td->td_ucred->cr_audit.ai_termid.at_addr[0];
513	ai.ai_termid.port = td->td_ucred->cr_audit.ai_termid.at_port;
514	return (copyout(&ai, uap->auditinfo, sizeof(ai)));
515}
516
517/* ARGSUSED */
518int
519setaudit(struct thread *td, struct setaudit_args *uap)
520{
521	struct ucred *newcred, *oldcred;
522	struct auditinfo ai;
523	int error;
524
525	if (jailed(td->td_ucred))
526		return (ENOSYS);
527	error = copyin(uap->auditinfo, &ai, sizeof(ai));
528	if (error)
529		return (error);
530	audit_arg_auditinfo(&ai);
531	newcred = crget();
532	PROC_LOCK(td->td_proc);
533	oldcred = td->td_proc->p_ucred;
534	crcopy(newcred, oldcred);
535#ifdef MAC
536	error = mac_proc_check_setaudit(oldcred, &ai);
537	if (error)
538		goto fail;
539#endif
540	error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0);
541	if (error)
542		goto fail;
543	bzero(&newcred->cr_audit, sizeof(newcred->cr_audit));
544	newcred->cr_audit.ai_auid = ai.ai_auid;
545	newcred->cr_audit.ai_mask = ai.ai_mask;
546	newcred->cr_audit.ai_asid = ai.ai_asid;
547	newcred->cr_audit.ai_termid.at_addr[0] = ai.ai_termid.machine;
548	newcred->cr_audit.ai_termid.at_port = ai.ai_termid.port;
549	newcred->cr_audit.ai_termid.at_type = AU_IPv4;
550	td->td_proc->p_ucred = newcred;
551	PROC_UNLOCK(td->td_proc);
552	crfree(oldcred);
553	return (0);
554fail:
555	PROC_UNLOCK(td->td_proc);
556	crfree(newcred);
557	return (error);
558}
559
560/* ARGSUSED */
561int
562getaudit_addr(struct thread *td, struct getaudit_addr_args *uap)
563{
564	int error;
565
566	if (jailed(td->td_ucred))
567		return (ENOSYS);
568	if (uap->length < sizeof(*uap->auditinfo_addr))
569		return (EOVERFLOW);
570	error = priv_check(td, PRIV_AUDIT_GETAUDIT);
571	if (error)
572		return (error);
573	return (copyout(&td->td_ucred->cr_audit, uap->auditinfo_addr,
574	    sizeof(*uap->auditinfo_addr)));
575}
576
577/* ARGSUSED */
578int
579setaudit_addr(struct thread *td, struct setaudit_addr_args *uap)
580{
581	struct ucred *newcred, *oldcred;
582	struct auditinfo_addr aia;
583	int error;
584
585	if (jailed(td->td_ucred))
586		return (ENOSYS);
587	error = copyin(uap->auditinfo_addr, &aia, sizeof(aia));
588	if (error)
589		return (error);
590	audit_arg_auditinfo_addr(&aia);
591	if (aia.ai_termid.at_type != AU_IPv6 &&
592	    aia.ai_termid.at_type != AU_IPv4)
593		return (EINVAL);
594	newcred = crget();
595	PROC_LOCK(td->td_proc);
596	oldcred = td->td_proc->p_ucred;
597	crcopy(newcred, oldcred);
598#ifdef MAC
599	error = mac_proc_check_setaudit_addr(oldcred, &aia);
600	if (error)
601		goto fail;
602#endif
603	error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0);
604	if (error)
605		goto fail;
606	newcred->cr_audit = aia;
607	td->td_proc->p_ucred = newcred;
608	PROC_UNLOCK(td->td_proc);
609	crfree(oldcred);
610	return (0);
611fail:
612	PROC_UNLOCK(td->td_proc);
613	crfree(newcred);
614	return (error);
615}
616
617/*
618 * Syscall to manage audit files.
619 */
620/* ARGSUSED */
621int
622auditctl(struct thread *td, struct auditctl_args *uap)
623{
624	struct nameidata nd;
625	struct ucred *cred;
626	struct vnode *vp;
627	int error = 0;
628	int flags, vfslocked;
629
630	if (jailed(td->td_ucred))
631		return (ENOSYS);
632	error = priv_check(td, PRIV_AUDIT_CONTROL);
633	if (error)
634		return (error);
635
636	vp = NULL;
637	cred = NULL;
638
639	/*
640	 * If a path is specified, open the replacement vnode, perform
641	 * validity checks, and grab another reference to the current
642	 * credential.
643	 *
644	 * On Darwin, a NULL path argument is also used to disable audit.
645	 */
646	if (uap->path == NULL)
647		return (EINVAL);
648
649	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
650	    UIO_USERSPACE, uap->path, td);
651	flags = AUDIT_OPEN_FLAGS;
652	error = vn_open(&nd, &flags, 0, NULL);
653	if (error)
654		return (error);
655	vfslocked = NDHASGIANT(&nd);
656	vp = nd.ni_vp;
657#ifdef MAC
658	error = mac_system_check_auditctl(td->td_ucred, vp);
659	VOP_UNLOCK(vp, 0);
660	if (error) {
661		vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td);
662		VFS_UNLOCK_GIANT(vfslocked);
663		return (error);
664	}
665#else
666	VOP_UNLOCK(vp, 0);
667#endif
668	NDFREE(&nd, NDF_ONLY_PNBUF);
669	if (vp->v_type != VREG) {
670		vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td);
671		VFS_UNLOCK_GIANT(vfslocked);
672		return (EINVAL);
673	}
674	VFS_UNLOCK_GIANT(vfslocked);
675	cred = td->td_ucred;
676	crhold(cred);
677
678	/*
679	 * XXXAUDIT: Should audit_suspended actually be cleared by
680	 * audit_worker?
681	 */
682	audit_suspended = 0;
683
684	audit_rotate_vnode(cred, vp);
685
686	return (error);
687}
688
689#else /* !AUDIT */
690
691int
692audit(struct thread *td, struct audit_args *uap)
693{
694
695	return (ENOSYS);
696}
697
698int
699auditon(struct thread *td, struct auditon_args *uap)
700{
701
702	return (ENOSYS);
703}
704
705int
706getauid(struct thread *td, struct getauid_args *uap)
707{
708
709	return (ENOSYS);
710}
711
712int
713setauid(struct thread *td, struct setauid_args *uap)
714{
715
716	return (ENOSYS);
717}
718
719int
720getaudit(struct thread *td, struct getaudit_args *uap)
721{
722
723	return (ENOSYS);
724}
725
726int
727setaudit(struct thread *td, struct setaudit_args *uap)
728{
729
730	return (ENOSYS);
731}
732
733int
734getaudit_addr(struct thread *td, struct getaudit_addr_args *uap)
735{
736
737	return (ENOSYS);
738}
739
740int
741setaudit_addr(struct thread *td, struct setaudit_addr_args *uap)
742{
743
744	return (ENOSYS);
745}
746
747int
748auditctl(struct thread *td, struct auditctl_args *uap)
749{
750
751	return (ENOSYS);
752}
753#endif /* AUDIT */
754