17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54e5fbfedStz  * Common Development and Distribution License (the "License").
64e5fbfedStz  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
224e5fbfedStz  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * This file contains the auditing system call code.
287c478bd9Sstevel@tonic-gate  *
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <sys/param.h>
347c478bd9Sstevel@tonic-gate #include <sys/systm.h>
357c478bd9Sstevel@tonic-gate #include <sys/user.h>
367c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
377c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
387c478bd9Sstevel@tonic-gate #include <sys/session.h>	/* for session structure (auditctl(2) */
397c478bd9Sstevel@tonic-gate #include <sys/kmem.h>		/* for KM_SLEEP */
407c478bd9Sstevel@tonic-gate #include <sys/cred_impl.h>
417c478bd9Sstevel@tonic-gate #include <sys/types.h>
427c478bd9Sstevel@tonic-gate #include <sys/proc.h>
437c478bd9Sstevel@tonic-gate #include <sys/uio.h>
447c478bd9Sstevel@tonic-gate #include <sys/file.h>
457c478bd9Sstevel@tonic-gate #include <sys/stat.h>
467c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
477c478bd9Sstevel@tonic-gate #include <sys/acct.h>
487c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
497c478bd9Sstevel@tonic-gate #include <sys/exec.h>
507c478bd9Sstevel@tonic-gate #include <sys/thread.h>
517c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
527c478bd9Sstevel@tonic-gate #include <sys/debug.h>
537c478bd9Sstevel@tonic-gate #include <sys/disp.h>
547c478bd9Sstevel@tonic-gate #include <sys/kobj.h>
557c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
567c478bd9Sstevel@tonic-gate #include <sys/policy.h>
577c478bd9Sstevel@tonic-gate #include <sys/taskq.h>
587c478bd9Sstevel@tonic-gate #include <sys/zone.h>
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate #include <c2/audit.h>
617c478bd9Sstevel@tonic-gate #include <c2/audit_kernel.h>
627c478bd9Sstevel@tonic-gate #include <c2/audit_record.h>
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate #define	CLEAR_VAL	-1
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate #define	HEADER_SIZE64	1;
677c478bd9Sstevel@tonic-gate #define	HEADER_SIZE32	0;
687c478bd9Sstevel@tonic-gate #define	AU_MIN_FILE_SZ	0x80000	/* minumum audit file size */
697c478bd9Sstevel@tonic-gate #define	AUDIT_REC_SIZE	0x8000	/* maximum user audit record size */
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate extern kmutex_t pidlock;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate extern pri_t		minclsyspri;		/* priority for taskq */
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate extern int audit_load;		/* defined in audit_start.c */
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate int		au_auditstate = AUC_UNSET;	/* global audit state */
787c478bd9Sstevel@tonic-gate int		audit_policy;	/* global audit policies in force */
797c478bd9Sstevel@tonic-gate static clock_t	au_resid = 15;	/* wait .15 sec before droping a rec */
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate static int	getauid(caddr_t);
827c478bd9Sstevel@tonic-gate static int	setauid(caddr_t);
837c478bd9Sstevel@tonic-gate static int	getaudit(caddr_t);
847c478bd9Sstevel@tonic-gate static int	getaudit_addr(caddr_t, int);
857c478bd9Sstevel@tonic-gate static int	setaudit(caddr_t);
867c478bd9Sstevel@tonic-gate static int	setaudit_addr(caddr_t, int);
877c478bd9Sstevel@tonic-gate static int	auditdoor(int);
887c478bd9Sstevel@tonic-gate static int	auditsvc(int, int);
897c478bd9Sstevel@tonic-gate static int	auditctl(int, caddr_t, int);
907c478bd9Sstevel@tonic-gate static int	audit_modsysent(char *, int, int (*)());
917c478bd9Sstevel@tonic-gate static void	au_output_thread();
927c478bd9Sstevel@tonic-gate /*
937c478bd9Sstevel@tonic-gate  * This is the loadable module wrapper.
947c478bd9Sstevel@tonic-gate  */
957c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
967c478bd9Sstevel@tonic-gate #include "sys/syscall.h"
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate static struct sysent auditsysent = {
997c478bd9Sstevel@tonic-gate 	6,
1007c478bd9Sstevel@tonic-gate 	0,
1017c478bd9Sstevel@tonic-gate 	_auditsys
1027c478bd9Sstevel@tonic-gate };
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
1067c478bd9Sstevel@tonic-gate  */
1077c478bd9Sstevel@tonic-gate extern struct mod_ops mod_syscallops;
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate static struct modlsys modlsys = {
1107c478bd9Sstevel@tonic-gate 	&mod_syscallops, "C2 system call", &auditsysent
1117c478bd9Sstevel@tonic-gate };
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1147c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modlsys, 0
1157c478bd9Sstevel@tonic-gate };
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate int
1187c478bd9Sstevel@tonic-gate _init()
1197c478bd9Sstevel@tonic-gate {
1207c478bd9Sstevel@tonic-gate 	int retval;
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	if (audit_load == 0)
1237c478bd9Sstevel@tonic-gate 		return (-1);
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	/*
1267c478bd9Sstevel@tonic-gate 	 * We are going to do an ugly thing here.
1277c478bd9Sstevel@tonic-gate 	 *  Because auditsys is already defined as a regular
1287c478bd9Sstevel@tonic-gate 	 *  syscall we have to change the definition for syscall
1297c478bd9Sstevel@tonic-gate 	 *  auditsys. Basically or in the SE_LOADABLE flag for
1307c478bd9Sstevel@tonic-gate 	 *  auditsys. We no have a static loadable syscall. Also
1317c478bd9Sstevel@tonic-gate 	 *  create an rw_lock.
1327c478bd9Sstevel@tonic-gate 	 */
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	if ((audit_modsysent("c2audit",
1357c478bd9Sstevel@tonic-gate 		SE_LOADABLE|SE_NOUNLOAD,
1367c478bd9Sstevel@tonic-gate 		_auditsys)) == -1)
1377c478bd9Sstevel@tonic-gate 		return (-1);
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	if ((retval = mod_install(&modlinkage)) != 0)
1407c478bd9Sstevel@tonic-gate 		return (retval);
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	return (0);
1437c478bd9Sstevel@tonic-gate }
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate int
1467c478bd9Sstevel@tonic-gate _fini()
1477c478bd9Sstevel@tonic-gate {
1487c478bd9Sstevel@tonic-gate 	return (EBUSY);
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate int
1527c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1537c478bd9Sstevel@tonic-gate {
1547c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1557c478bd9Sstevel@tonic-gate }
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate /*
1587c478bd9Sstevel@tonic-gate  * when auditing is updated to allow enable/disable without
1597c478bd9Sstevel@tonic-gate  * reboot (and when the audit stubs are removed) *most* of these
1607c478bd9Sstevel@tonic-gate  * calls should return an error when auditing is off -- some
1617c478bd9Sstevel@tonic-gate  * for local zones only.
1627c478bd9Sstevel@tonic-gate  */
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate int
1657c478bd9Sstevel@tonic-gate _auditsys(struct auditcalls *uap, rval_t *rvp)
1667c478bd9Sstevel@tonic-gate {
1677c478bd9Sstevel@tonic-gate 	int result = 0;
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	switch (uap->code) {
1707c478bd9Sstevel@tonic-gate 	case BSM_GETAUID:
1717c478bd9Sstevel@tonic-gate 		result = getauid((caddr_t)uap->a1);
1727c478bd9Sstevel@tonic-gate 		break;
1737c478bd9Sstevel@tonic-gate 	case BSM_SETAUID:
1747c478bd9Sstevel@tonic-gate 		result = setauid((caddr_t)uap->a1);
1757c478bd9Sstevel@tonic-gate 		break;
1767c478bd9Sstevel@tonic-gate 	case BSM_GETAUDIT:
1777c478bd9Sstevel@tonic-gate 		result = getaudit((caddr_t)uap->a1);
1787c478bd9Sstevel@tonic-gate 		break;
1797c478bd9Sstevel@tonic-gate 	case BSM_GETAUDIT_ADDR:
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 		result = getaudit_addr((caddr_t)uap->a1, (int)uap->a2);
1827c478bd9Sstevel@tonic-gate 		break;
1837c478bd9Sstevel@tonic-gate 	case BSM_SETAUDIT:
1847c478bd9Sstevel@tonic-gate 		result = setaudit((caddr_t)uap->a1);
1857c478bd9Sstevel@tonic-gate 		break;
1867c478bd9Sstevel@tonic-gate 	case BSM_SETAUDIT_ADDR:
1877c478bd9Sstevel@tonic-gate 		result = setaudit_addr((caddr_t)uap->a1, (int)uap->a2);
1887c478bd9Sstevel@tonic-gate 		break;
1897c478bd9Sstevel@tonic-gate 	case BSM_AUDIT:
1907c478bd9Sstevel@tonic-gate 		result = audit((caddr_t)uap->a1, (int)uap->a2);
1917c478bd9Sstevel@tonic-gate 		break;
1927c478bd9Sstevel@tonic-gate 	case BSM_AUDITSVC:
1937c478bd9Sstevel@tonic-gate 		result = auditsvc((int)uap->a1, (int)uap->a2);
1947c478bd9Sstevel@tonic-gate 		break;
1957c478bd9Sstevel@tonic-gate 	case BSM_AUDITDOOR:
1967c478bd9Sstevel@tonic-gate 		result = auditdoor((int)uap->a1);
1977c478bd9Sstevel@tonic-gate 		break;
1987c478bd9Sstevel@tonic-gate 	case BSM_AUDITON:
1997c478bd9Sstevel@tonic-gate 	case BSM_AUDITCTL:
2007c478bd9Sstevel@tonic-gate 		result = auditctl((int)uap->a1, (caddr_t)uap->a2, (int)uap->a3);
2017c478bd9Sstevel@tonic-gate 		break;
2027c478bd9Sstevel@tonic-gate 	default:
2037c478bd9Sstevel@tonic-gate 		result = EINVAL;
2047c478bd9Sstevel@tonic-gate 	}
2057c478bd9Sstevel@tonic-gate 	rvp->r_vals = result;
2067c478bd9Sstevel@tonic-gate 	return (result);
2077c478bd9Sstevel@tonic-gate }
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate /*
2107c478bd9Sstevel@tonic-gate  * Return the audit user ID for the current process.  Currently only
2117c478bd9Sstevel@tonic-gate  * the privileged processes may see the audit id.  That may change.
2127c478bd9Sstevel@tonic-gate  * If copyout is unsucessful return EFAULT.
2137c478bd9Sstevel@tonic-gate  */
2147c478bd9Sstevel@tonic-gate static int
2157c478bd9Sstevel@tonic-gate getauid(caddr_t auid_p)
2167c478bd9Sstevel@tonic-gate {
2177c478bd9Sstevel@tonic-gate 	const auditinfo_addr_t	*ainfo;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	if (secpolicy_audit_getattr(CRED()) != 0)
2207c478bd9Sstevel@tonic-gate 		return (EPERM);
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	ainfo = crgetauinfo(CRED());
2237c478bd9Sstevel@tonic-gate 	if (ainfo == NULL)
2247c478bd9Sstevel@tonic-gate 		return (EINVAL);
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	if (copyout(&ainfo->ai_auid, auid_p, sizeof (au_id_t)))
2277c478bd9Sstevel@tonic-gate 		return (EFAULT);
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	return (0);
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate /*
2337c478bd9Sstevel@tonic-gate  * Set the audit userid, for a process.  This can only be changed by
2347c478bd9Sstevel@tonic-gate  * privileged processes.  The audit userid is inherited across forks & execs.
2357c478bd9Sstevel@tonic-gate  * Passed in is a pointer to the au_id_t; if copyin unsuccessful return EFAULT.
2367c478bd9Sstevel@tonic-gate  */
2377c478bd9Sstevel@tonic-gate static int
2387c478bd9Sstevel@tonic-gate setauid(caddr_t auid_p)
2397c478bd9Sstevel@tonic-gate {
2407c478bd9Sstevel@tonic-gate 	proc_t *p;
2417c478bd9Sstevel@tonic-gate 	au_id_t	auid;
2427c478bd9Sstevel@tonic-gate 	cred_t *newcred;
2437c478bd9Sstevel@tonic-gate 	auditinfo_addr_t *auinfo;
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	if (secpolicy_audit_config(CRED()) != 0)
2467c478bd9Sstevel@tonic-gate 		return (EPERM);
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	if (copyin(auid_p, &auid, sizeof (au_id_t))) {
2497c478bd9Sstevel@tonic-gate 		return (EFAULT);
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	newcred = cralloc();
2537c478bd9Sstevel@tonic-gate 	if ((auinfo = crgetauinfo_modifiable(newcred)) == NULL) {
2547c478bd9Sstevel@tonic-gate 		crfree(newcred);
2557c478bd9Sstevel@tonic-gate 		return (EINVAL);
2567c478bd9Sstevel@tonic-gate 	}
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	/* grab p_crlock and switch to new cred */
2597c478bd9Sstevel@tonic-gate 	p = curproc;
2607c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
2617c478bd9Sstevel@tonic-gate 	crcopy_to(p->p_cred, newcred);
2627c478bd9Sstevel@tonic-gate 	p->p_cred = newcred;
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	auinfo->ai_auid = auid;			/* update the auid */
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	/* unlock and broadcast the cred changes */
2677c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
2687c478bd9Sstevel@tonic-gate 	crset(p, newcred);
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	return (0);
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate /*
2747c478bd9Sstevel@tonic-gate  * Get the audit state information from the current process.
2757c478bd9Sstevel@tonic-gate  * Return EFAULT if copyout fails.
2767c478bd9Sstevel@tonic-gate  */
2777c478bd9Sstevel@tonic-gate static int
2787c478bd9Sstevel@tonic-gate getaudit(caddr_t info_p)
2797c478bd9Sstevel@tonic-gate {
2807c478bd9Sstevel@tonic-gate 	STRUCT_DECL(auditinfo, info);
2817c478bd9Sstevel@tonic-gate 	const auditinfo_addr_t	*ainfo;
2827c478bd9Sstevel@tonic-gate 	model_t	model;
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	if (secpolicy_audit_getattr(CRED()) != 0)
2857c478bd9Sstevel@tonic-gate 		return (EPERM);
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	model = get_udatamodel();
2887c478bd9Sstevel@tonic-gate 	STRUCT_INIT(info, model);
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	ainfo = crgetauinfo(CRED());
2917c478bd9Sstevel@tonic-gate 	if (ainfo == NULL)
2927c478bd9Sstevel@tonic-gate 		return (EINVAL);
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	/* trying to read a process with an IPv6 address? */
2957c478bd9Sstevel@tonic-gate 	if (ainfo->ai_termid.at_type == AU_IPv6)
2967c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_auid, ainfo->ai_auid);
2997c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_mask, ainfo->ai_mask);
3007c478bd9Sstevel@tonic-gate #ifdef _LP64
3017c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_ILP32) {
3027c478bd9Sstevel@tonic-gate 		dev32_t dev;
3037c478bd9Sstevel@tonic-gate 		/* convert internal 64 bit form to 32 bit version */
3047c478bd9Sstevel@tonic-gate 		if (cmpldev(&dev, ainfo->ai_termid.at_port) == 0) {
3057c478bd9Sstevel@tonic-gate 			return (EOVERFLOW);
3067c478bd9Sstevel@tonic-gate 		}
3077c478bd9Sstevel@tonic-gate 		STRUCT_FSET(info, ai_termid.port, dev);
3087c478bd9Sstevel@tonic-gate 	} else
3097c478bd9Sstevel@tonic-gate 		STRUCT_FSET(info, ai_termid.port, ainfo->ai_termid.at_port);
3107c478bd9Sstevel@tonic-gate #else
3117c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_termid.port, ainfo->ai_termid.at_port);
3127c478bd9Sstevel@tonic-gate #endif
3137c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_termid.machine, ainfo->ai_termid.at_addr[0]);
3147c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_asid, ainfo->ai_asid);
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(info), info_p, STRUCT_SIZE(info)))
3177c478bd9Sstevel@tonic-gate 		return (EFAULT);
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	return (0);
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate /*
3237c478bd9Sstevel@tonic-gate  * Get the audit state information from the current process.
3247c478bd9Sstevel@tonic-gate  * Return EFAULT if copyout fails.
3257c478bd9Sstevel@tonic-gate  */
3267c478bd9Sstevel@tonic-gate static int
3277c478bd9Sstevel@tonic-gate getaudit_addr(caddr_t info_p, int len)
3287c478bd9Sstevel@tonic-gate {
3297c478bd9Sstevel@tonic-gate 	STRUCT_DECL(auditinfo_addr, info);
3307c478bd9Sstevel@tonic-gate 	const auditinfo_addr_t	*ainfo;
3317c478bd9Sstevel@tonic-gate 	model_t	model;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	if (secpolicy_audit_getattr(CRED()) != 0)
3347c478bd9Sstevel@tonic-gate 		return (EPERM);
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	model = get_udatamodel();
3377c478bd9Sstevel@tonic-gate 	STRUCT_INIT(info, model);
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	if (len < STRUCT_SIZE(info))
3407c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	ainfo = crgetauinfo(CRED());
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	if (ainfo == NULL)
3457c478bd9Sstevel@tonic-gate 		return (EINVAL);
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_auid, ainfo->ai_auid);
3487c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_mask, ainfo->ai_mask);
3497c478bd9Sstevel@tonic-gate #ifdef _LP64
3507c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_ILP32) {
3517c478bd9Sstevel@tonic-gate 		dev32_t dev;
3527c478bd9Sstevel@tonic-gate 		/* convert internal 64 bit form to 32 bit version */
3537c478bd9Sstevel@tonic-gate 		if (cmpldev(&dev, ainfo->ai_termid.at_port) == 0) {
3547c478bd9Sstevel@tonic-gate 			return (EOVERFLOW);
3557c478bd9Sstevel@tonic-gate 		}
3567c478bd9Sstevel@tonic-gate 		STRUCT_FSET(info, ai_termid.at_port, dev);
3577c478bd9Sstevel@tonic-gate 	} else
3587c478bd9Sstevel@tonic-gate 		STRUCT_FSET(info, ai_termid.at_port, ainfo->ai_termid.at_port);
3597c478bd9Sstevel@tonic-gate #else
3607c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_termid.at_port, ainfo->ai_termid.at_port);
3617c478bd9Sstevel@tonic-gate #endif
3627c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_termid.at_type, ainfo->ai_termid.at_type);
3637c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_termid.at_addr[0], ainfo->ai_termid.at_addr[0]);
3647c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_termid.at_addr[1], ainfo->ai_termid.at_addr[1]);
3657c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_termid.at_addr[2], ainfo->ai_termid.at_addr[2]);
3667c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_termid.at_addr[3], ainfo->ai_termid.at_addr[3]);
3677c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_asid, ainfo->ai_asid);
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(info), info_p, STRUCT_SIZE(info)))
3707c478bd9Sstevel@tonic-gate 		return (EFAULT);
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	return (0);
3737c478bd9Sstevel@tonic-gate }
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate /*
3767c478bd9Sstevel@tonic-gate  * Set the audit state information for the current process.
3777c478bd9Sstevel@tonic-gate  * Return EFAULT if copyout fails.
3787c478bd9Sstevel@tonic-gate  */
3797c478bd9Sstevel@tonic-gate static int
3807c478bd9Sstevel@tonic-gate setaudit(caddr_t info_p)
3817c478bd9Sstevel@tonic-gate {
3827c478bd9Sstevel@tonic-gate 	STRUCT_DECL(auditinfo, info);
3837c478bd9Sstevel@tonic-gate 	proc_t *p;
3847c478bd9Sstevel@tonic-gate 	cred_t	*newcred;
3857c478bd9Sstevel@tonic-gate 	model_t	model;
3867c478bd9Sstevel@tonic-gate 	auditinfo_addr_t *ainfo;
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	if (secpolicy_audit_config(CRED()) != 0)
3897c478bd9Sstevel@tonic-gate 		return (EPERM);
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	model = get_udatamodel();
3927c478bd9Sstevel@tonic-gate 	STRUCT_INIT(info, model);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	if (copyin(info_p, STRUCT_BUF(info), STRUCT_SIZE(info)))
3957c478bd9Sstevel@tonic-gate 		return (EFAULT);
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	newcred = cralloc();
3987c478bd9Sstevel@tonic-gate 	if ((ainfo = crgetauinfo_modifiable(newcred)) == NULL) {
3997c478bd9Sstevel@tonic-gate 		crfree(newcred);
4007c478bd9Sstevel@tonic-gate 		return (EINVAL);
4017c478bd9Sstevel@tonic-gate 	}
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	/* grab p_crlock and switch to new cred */
4047c478bd9Sstevel@tonic-gate 	p = curproc;
4057c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
4067c478bd9Sstevel@tonic-gate 	crcopy_to(p->p_cred, newcred);
4077c478bd9Sstevel@tonic-gate 	p->p_cred = newcred;
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	/* Set audit mask, id, termid and session id as specified */
4107c478bd9Sstevel@tonic-gate 	ainfo->ai_auid = STRUCT_FGET(info, ai_auid);
4117c478bd9Sstevel@tonic-gate #ifdef _LP64
4127c478bd9Sstevel@tonic-gate 	/* only convert to 64 bit if coming from a 32 bit binary */
4137c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_ILP32)
4147c478bd9Sstevel@tonic-gate 		ainfo->ai_termid.at_port =
4157c478bd9Sstevel@tonic-gate 			DEVEXPL(STRUCT_FGET(info, ai_termid.port));
4167c478bd9Sstevel@tonic-gate 	else
4177c478bd9Sstevel@tonic-gate 		ainfo->ai_termid.at_port = STRUCT_FGET(info, ai_termid.port);
4187c478bd9Sstevel@tonic-gate #else
4197c478bd9Sstevel@tonic-gate 	ainfo->ai_termid.at_port = STRUCT_FGET(info, ai_termid.port);
4207c478bd9Sstevel@tonic-gate #endif
4217c478bd9Sstevel@tonic-gate 	ainfo->ai_termid.at_type = AU_IPv4;
4227c478bd9Sstevel@tonic-gate 	ainfo->ai_termid.at_addr[0] = STRUCT_FGET(info, ai_termid.machine);
4237c478bd9Sstevel@tonic-gate 	ainfo->ai_asid = STRUCT_FGET(info, ai_asid);
4247c478bd9Sstevel@tonic-gate 	ainfo->ai_mask = STRUCT_FGET(info, ai_mask);
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	/* unlock and broadcast the cred changes */
4277c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
4287c478bd9Sstevel@tonic-gate 	crset(p, newcred);
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	return (0);
4317c478bd9Sstevel@tonic-gate }
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate /*
4347c478bd9Sstevel@tonic-gate  * Set the audit state information for the current process.
4357c478bd9Sstevel@tonic-gate  * Return EFAULT if copyin fails.
4367c478bd9Sstevel@tonic-gate  */
4377c478bd9Sstevel@tonic-gate static int
4387c478bd9Sstevel@tonic-gate setaudit_addr(caddr_t info_p, int len)
4397c478bd9Sstevel@tonic-gate {
4407c478bd9Sstevel@tonic-gate 	STRUCT_DECL(auditinfo_addr, info);
4417c478bd9Sstevel@tonic-gate 	proc_t *p;
4427c478bd9Sstevel@tonic-gate 	cred_t	*newcred;
4437c478bd9Sstevel@tonic-gate 	model_t	model;
4447c478bd9Sstevel@tonic-gate 	int i;
4457c478bd9Sstevel@tonic-gate 	int type;
4467c478bd9Sstevel@tonic-gate 	auditinfo_addr_t *ainfo;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	if (secpolicy_audit_config(CRED()) != 0)
4497c478bd9Sstevel@tonic-gate 		return (EPERM);
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	model = get_udatamodel();
4527c478bd9Sstevel@tonic-gate 	STRUCT_INIT(info, model);
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	if (len < STRUCT_SIZE(info))
4557c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	if (copyin(info_p, STRUCT_BUF(info), STRUCT_SIZE(info)))
4587c478bd9Sstevel@tonic-gate 		return (EFAULT);
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	type = STRUCT_FGET(info, ai_termid.at_type);
4617c478bd9Sstevel@tonic-gate 	if ((type != AU_IPv4) && (type != AU_IPv6))
4627c478bd9Sstevel@tonic-gate 		return (EINVAL);
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	newcred = cralloc();
4657c478bd9Sstevel@tonic-gate 	if ((ainfo = crgetauinfo_modifiable(newcred)) == NULL) {
4667c478bd9Sstevel@tonic-gate 		crfree(newcred);
4677c478bd9Sstevel@tonic-gate 		return (EINVAL);
4687c478bd9Sstevel@tonic-gate 	}
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	/* grab p_crlock and switch to new cred */
4717c478bd9Sstevel@tonic-gate 	p = curproc;
4727c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
4737c478bd9Sstevel@tonic-gate 	crcopy_to(p->p_cred, newcred);
4747c478bd9Sstevel@tonic-gate 	p->p_cred = newcred;
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	/* Set audit mask, id, termid and session id as specified */
4777c478bd9Sstevel@tonic-gate 	ainfo->ai_auid = STRUCT_FGET(info, ai_auid);
4787c478bd9Sstevel@tonic-gate 	ainfo->ai_mask = STRUCT_FGET(info, ai_mask);
4797c478bd9Sstevel@tonic-gate #ifdef _LP64
4807c478bd9Sstevel@tonic-gate 	/* only convert to 64 bit if coming from a 32 bit binary */
4817c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_ILP32)
4827c478bd9Sstevel@tonic-gate 		ainfo->ai_termid.at_port =
4837c478bd9Sstevel@tonic-gate 			DEVEXPL(STRUCT_FGET(info, ai_termid.at_port));
4847c478bd9Sstevel@tonic-gate 	else
4857c478bd9Sstevel@tonic-gate 		ainfo->ai_termid.at_port = STRUCT_FGET(info, ai_termid.at_port);
4867c478bd9Sstevel@tonic-gate #else
4877c478bd9Sstevel@tonic-gate 	ainfo->ai_termid.at_port = STRUCT_FGET(info, ai_termid.at_port);
4887c478bd9Sstevel@tonic-gate #endif
4897c478bd9Sstevel@tonic-gate 	ainfo->ai_termid.at_type = type;
4907c478bd9Sstevel@tonic-gate 	bzero(&ainfo->ai_termid.at_addr[0], sizeof (ainfo->ai_termid.at_addr));
4917c478bd9Sstevel@tonic-gate 	for (i = 0; i < (type/sizeof (int)); i++)
4927c478bd9Sstevel@tonic-gate 		ainfo->ai_termid.at_addr[i] =
4937c478bd9Sstevel@tonic-gate 			STRUCT_FGET(info, ai_termid.at_addr[i]);
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	if (ainfo->ai_termid.at_type == AU_IPv6 &&
4967c478bd9Sstevel@tonic-gate 	    IN6_IS_ADDR_V4MAPPED(((in6_addr_t *)ainfo->ai_termid.at_addr))) {
4977c478bd9Sstevel@tonic-gate 		ainfo->ai_termid.at_type = AU_IPv4;
4987c478bd9Sstevel@tonic-gate 		ainfo->ai_termid.at_addr[0] = ainfo->ai_termid.at_addr[3];
4997c478bd9Sstevel@tonic-gate 		ainfo->ai_termid.at_addr[1] = 0;
5007c478bd9Sstevel@tonic-gate 		ainfo->ai_termid.at_addr[2] = 0;
5017c478bd9Sstevel@tonic-gate 		ainfo->ai_termid.at_addr[3] = 0;
5027c478bd9Sstevel@tonic-gate 	}
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	ainfo->ai_asid = STRUCT_FGET(info, ai_asid);
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	/* unlock and broadcast the cred changes */
5077c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
5087c478bd9Sstevel@tonic-gate 	crset(p, newcred);
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	return (0);
5117c478bd9Sstevel@tonic-gate }
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate /*
5147c478bd9Sstevel@tonic-gate  * The audit system call. Trust what the user has sent down and save it
5157c478bd9Sstevel@tonic-gate  * away in the audit file. User passes a complete audit record and its
5167c478bd9Sstevel@tonic-gate  * length.  We will fill in the time stamp, check the header and the length
5177c478bd9Sstevel@tonic-gate  * Put a trailer and a sequence token if policy requires.
5187c478bd9Sstevel@tonic-gate  * In the future length might become size_t instead of an int.
5197c478bd9Sstevel@tonic-gate  *
5207c478bd9Sstevel@tonic-gate  * The call is valid whether or not AUDIT_PERZONE is set (think of
5217c478bd9Sstevel@tonic-gate  * login to a zone).  When the local audit state (auk_auditstate) is
5227c478bd9Sstevel@tonic-gate  * AUC_INIT_AUDIT, records are accepted even though auditd isn't
5237c478bd9Sstevel@tonic-gate  * running.
5247c478bd9Sstevel@tonic-gate  */
5257c478bd9Sstevel@tonic-gate int
5267c478bd9Sstevel@tonic-gate audit(caddr_t record, int length)
5277c478bd9Sstevel@tonic-gate {
5287c478bd9Sstevel@tonic-gate 	char	c;
5297c478bd9Sstevel@tonic-gate 	int	count, l;
5307c478bd9Sstevel@tonic-gate 	token_t	*m, *n, *s, *ad;
5317c478bd9Sstevel@tonic-gate 	int	hdrlen, delta;
5327c478bd9Sstevel@tonic-gate 	adr_t	hadr;
5337c478bd9Sstevel@tonic-gate 	adr_t	sadr;
5347c478bd9Sstevel@tonic-gate 	int	size;	/* 0: 32 bit utility  1: 64 bit utility */
5357c478bd9Sstevel@tonic-gate 	int	host_len;
5367c478bd9Sstevel@tonic-gate 	size_t	zlen;
5377c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx = SET_KCTX_PZ;
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	ASSERT(kctx != NULL);
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	/* if auditing not enabled, then don't generate an audit record */
5427c478bd9Sstevel@tonic-gate 	if (kctx->auk_auditstate != AUC_AUDITING &&
5437c478bd9Sstevel@tonic-gate 	    kctx->auk_auditstate != AUC_INIT_AUDIT)
5447c478bd9Sstevel@tonic-gate 		return (0);
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	/* Only privileged processes can audit */
5477c478bd9Sstevel@tonic-gate 	if (secpolicy_audit_modify(CRED()) != 0)
5487c478bd9Sstevel@tonic-gate 		return (EPERM);
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	/* Max user record size is 32K */
5517c478bd9Sstevel@tonic-gate 	if (length > AUDIT_REC_SIZE)
5527c478bd9Sstevel@tonic-gate 		return (E2BIG);
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	/*
5557c478bd9Sstevel@tonic-gate 	 * The specified length must be at least as big as the smallest
5567c478bd9Sstevel@tonic-gate 	 * possible header token. Later after beginning to scan the
5577c478bd9Sstevel@tonic-gate 	 * header we'll determine the true minimum length according to
5587c478bd9Sstevel@tonic-gate 	 * the header type and attributes.
5597c478bd9Sstevel@tonic-gate 	 */
5607c478bd9Sstevel@tonic-gate #define	AU_MIN_HEADER_LEN	(sizeof (char) + sizeof (int32_t) + \
5617c478bd9Sstevel@tonic-gate 	sizeof (char) + sizeof (short) + sizeof (short) + \
5627c478bd9Sstevel@tonic-gate 	(sizeof (int32_t) * 2))
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	if (length < AU_MIN_HEADER_LEN)
5657c478bd9Sstevel@tonic-gate 		return (EINVAL);
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	/* Read in user's audit record */
5687c478bd9Sstevel@tonic-gate 	count = length;
5697c478bd9Sstevel@tonic-gate 	m = n = s = ad = NULL;
5707c478bd9Sstevel@tonic-gate 	while (count) {
5717c478bd9Sstevel@tonic-gate 		m = au_getclr();
5727c478bd9Sstevel@tonic-gate 		if (!s)
5737c478bd9Sstevel@tonic-gate 			s = n = m;
5747c478bd9Sstevel@tonic-gate 		else {
5757c478bd9Sstevel@tonic-gate 			n->next_buf = m;
5767c478bd9Sstevel@tonic-gate 			n = m;
5777c478bd9Sstevel@tonic-gate 		}
5787c478bd9Sstevel@tonic-gate 		l = MIN(count, AU_BUFSIZE);
5797c478bd9Sstevel@tonic-gate 		if (copyin(record, memtod(m, caddr_t),
5807c478bd9Sstevel@tonic-gate 			(size_t)l)) {
5817c478bd9Sstevel@tonic-gate 				/* copyin failed release au_membuf */
5827c478bd9Sstevel@tonic-gate 				au_free_rec(s);
5837c478bd9Sstevel@tonic-gate 				return (EFAULT);
5847c478bd9Sstevel@tonic-gate 		}
5857c478bd9Sstevel@tonic-gate 		record += l;
5867c478bd9Sstevel@tonic-gate 		count -= l;
5877c478bd9Sstevel@tonic-gate 		m->len = (uchar_t)l;
5887c478bd9Sstevel@tonic-gate 	}
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	/* Now attach the entire thing to ad */
5917c478bd9Sstevel@tonic-gate 	au_write((caddr_t *)&(ad), s);
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	/* validate header token type. trust everything following it */
5947c478bd9Sstevel@tonic-gate 	adr_start(&hadr, memtod(s, char *));
5957c478bd9Sstevel@tonic-gate 	(void) adr_getchar(&hadr, &c);
5967c478bd9Sstevel@tonic-gate 	switch (c) {
5977c478bd9Sstevel@tonic-gate 	case AUT_HEADER32:
5987c478bd9Sstevel@tonic-gate 		/* size vers+event_ID+event_modifier fields */
5997c478bd9Sstevel@tonic-gate 		delta = 1 + 2 + 2;
6007c478bd9Sstevel@tonic-gate 		hdrlen = 1 + 4 + delta + (sizeof (int32_t) * 2);
6017c478bd9Sstevel@tonic-gate 		size = HEADER_SIZE32;
6027c478bd9Sstevel@tonic-gate 		break;
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate #ifdef _LP64
6057c478bd9Sstevel@tonic-gate 	case AUT_HEADER64:
6067c478bd9Sstevel@tonic-gate 		/* size vers+event_ID+event_modifier fields */
6077c478bd9Sstevel@tonic-gate 		delta = 1 + 2 + 2;
6087c478bd9Sstevel@tonic-gate 		hdrlen = 1 + 4 + delta + (sizeof (int64_t) * 2);
6097c478bd9Sstevel@tonic-gate 		size = HEADER_SIZE64;
6107c478bd9Sstevel@tonic-gate 		break;
6117c478bd9Sstevel@tonic-gate #endif
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	case AUT_HEADER32_EX:
6147c478bd9Sstevel@tonic-gate 		/*
6157c478bd9Sstevel@tonic-gate 		 * Skip over the length/version/type/mod fields and
6167c478bd9Sstevel@tonic-gate 		 * grab the host address type (length), then rewind.
6177c478bd9Sstevel@tonic-gate 		 * This is safe per the previous minimum length check.
6187c478bd9Sstevel@tonic-gate 		 */
6197c478bd9Sstevel@tonic-gate 		hadr.adr_now += 9;
6207c478bd9Sstevel@tonic-gate 		(void) adr_getint32(&hadr, &host_len);
6217c478bd9Sstevel@tonic-gate 		hadr.adr_now -= 9 + sizeof (int32_t);
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 		/* size: vers+event_ID+event_modifier+IP_type+IP_addr_array */
6247c478bd9Sstevel@tonic-gate 		delta = 1 + 2 + 2 + 4 + host_len;
6257c478bd9Sstevel@tonic-gate 		hdrlen = 1 + 4 + delta + (sizeof (int32_t) * 2);
6267c478bd9Sstevel@tonic-gate 		size = HEADER_SIZE32;
6277c478bd9Sstevel@tonic-gate 		break;
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate #ifdef _LP64
6307c478bd9Sstevel@tonic-gate 	case AUT_HEADER64_EX:
6317c478bd9Sstevel@tonic-gate 		/*
6327c478bd9Sstevel@tonic-gate 		 * Skip over the length/version/type/mod fields and grab
6337c478bd9Sstevel@tonic-gate 		 * the host address type (length), then rewind.
6347c478bd9Sstevel@tonic-gate 		 * This is safe per the previous minimum length check.
6357c478bd9Sstevel@tonic-gate 		 */
6367c478bd9Sstevel@tonic-gate 		hadr.adr_now += 9;
6377c478bd9Sstevel@tonic-gate 		(void) adr_getint32(&hadr, &host_len);
6387c478bd9Sstevel@tonic-gate 		hadr.adr_now -= 9 + sizeof (int32_t);
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 		/* size: vers+event_ID+event_modifier+IP_type+IP_addr_array */
6417c478bd9Sstevel@tonic-gate 		delta = 1 + 2 + 2 + 4 + host_len;
6427c478bd9Sstevel@tonic-gate 		hdrlen = 1 + 4 + delta + (sizeof (int64_t) * 2);
6437c478bd9Sstevel@tonic-gate 		size = HEADER_SIZE64;
6447c478bd9Sstevel@tonic-gate 		break;
6457c478bd9Sstevel@tonic-gate #endif
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	default:
6487c478bd9Sstevel@tonic-gate 		/* Header is wrong, reject message */
6497c478bd9Sstevel@tonic-gate 		au_free_rec(s);
6507c478bd9Sstevel@tonic-gate 		return (EINVAL);
6517c478bd9Sstevel@tonic-gate 	}
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	if (length < hdrlen) {
6547c478bd9Sstevel@tonic-gate 		au_free_rec(s);
6557c478bd9Sstevel@tonic-gate 		return (0);
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	/* advance over header token length field */
6597c478bd9Sstevel@tonic-gate 	hadr.adr_now += 4;
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 	/* validate version */
6627c478bd9Sstevel@tonic-gate 	(void) adr_getchar(&hadr, &c);
6637c478bd9Sstevel@tonic-gate 	if (c != TOKEN_VERSION) {
6647c478bd9Sstevel@tonic-gate 		/* version is wrong, reject message */
6657c478bd9Sstevel@tonic-gate 		au_free_rec(s);
6667c478bd9Sstevel@tonic-gate 		return (EINVAL);
6677c478bd9Sstevel@tonic-gate 	}
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	/* backup to header length field (including version field) */
6707c478bd9Sstevel@tonic-gate 	hadr.adr_now -= 5;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	/*
6737c478bd9Sstevel@tonic-gate 	 * add on the zonename token if policy AUDIT_ZONENAME is set
6747c478bd9Sstevel@tonic-gate 	 */
6757c478bd9Sstevel@tonic-gate 	if (kctx->auk_policy & AUDIT_ZONENAME) {
676*1d7bfecdStz 		zlen = au_zonename_length(NULL);
6777c478bd9Sstevel@tonic-gate 		if (zlen > 0) {
6787c478bd9Sstevel@tonic-gate 			length += zlen;
679*1d7bfecdStz 			m = au_to_zonename(zlen, NULL);
6807c478bd9Sstevel@tonic-gate 			(void) au_append_rec(ad, m, AU_PACK);
6817c478bd9Sstevel@tonic-gate 		}
6827c478bd9Sstevel@tonic-gate 	}
6837c478bd9Sstevel@tonic-gate 	/* Add an (optional) sequence token. NULL offset if none */
6847c478bd9Sstevel@tonic-gate 	if (kctx->auk_policy & AUDIT_SEQ) {
6857c478bd9Sstevel@tonic-gate 		/* get the sequnce token */
6867c478bd9Sstevel@tonic-gate 		m = au_to_seq();
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 		/* sequence token 5 bytes long */
6897c478bd9Sstevel@tonic-gate 		length += 5;
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 		/* link to audit record (i.e. don't pack the data) */
6927c478bd9Sstevel@tonic-gate 		(void) au_append_rec(ad, m, AU_LINK);
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 		/* advance to count field of token */
6957c478bd9Sstevel@tonic-gate 		adr_start(&sadr, memtod(m, char *));
6967c478bd9Sstevel@tonic-gate 		sadr.adr_now += 1;
6977c478bd9Sstevel@tonic-gate 	} else
6987c478bd9Sstevel@tonic-gate 		sadr.adr_now = (char *)NULL;
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	/* add the (optional) trailer token */
7017c478bd9Sstevel@tonic-gate 	if (kctx->auk_policy & AUDIT_TRAIL) {
7027c478bd9Sstevel@tonic-gate 		/* trailer token is 7 bytes long */
7037c478bd9Sstevel@tonic-gate 		length += 7;
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 		/* append to audit record */
7067c478bd9Sstevel@tonic-gate 		(void) au_append_rec(ad, au_to_trailer(length), AU_PACK);
7077c478bd9Sstevel@tonic-gate 	}
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	/* audit record completely assembled. set the length */
7107c478bd9Sstevel@tonic-gate 	adr_int32(&hadr, (int32_t *)&length, 1);
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 	/* advance to date/time field of header */
7137c478bd9Sstevel@tonic-gate 	hadr.adr_now += delta;
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	/* We are done  put it on the queue */
7167c478bd9Sstevel@tonic-gate 	AS_INC(as_generated, 1, kctx);
7177c478bd9Sstevel@tonic-gate 	AS_INC(as_audit, 1, kctx);
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	au_enqueue(kctx, s, &hadr, &sadr, size, 0);
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	AS_INC(as_totalsize, length, kctx);
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 	return (0);
7247c478bd9Sstevel@tonic-gate }
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate static void
7277c478bd9Sstevel@tonic-gate audit_dont_stop(void *kctx)
7287c478bd9Sstevel@tonic-gate {
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 	if ((((au_kcontext_t *)kctx)->auk_valid != AUK_VALID) ||
7317c478bd9Sstevel@tonic-gate 	    (((au_kcontext_t *)kctx)->auk_auditstate == AUC_NOAUDIT))
7327c478bd9Sstevel@tonic-gate 		return;
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 	mutex_enter(&(((au_kcontext_t *)kctx)->auk_queue.lock));
7357c478bd9Sstevel@tonic-gate 	cv_broadcast(&(((au_kcontext_t *)kctx)->auk_queue.write_cv));
7367c478bd9Sstevel@tonic-gate 	mutex_exit(&(((au_kcontext_t *)kctx)->auk_queue.lock));
7377c478bd9Sstevel@tonic-gate }
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate /*
7407c478bd9Sstevel@tonic-gate  * auditdoor starts a kernel thread to generate output from the audit
7417c478bd9Sstevel@tonic-gate  * queue.  The thread terminates when it detects auditing being turned
7427c478bd9Sstevel@tonic-gate  * off, such as when auditd exits with a SIGTERM.  If a subsequent
7437c478bd9Sstevel@tonic-gate  * auditdoor arrives while the thread is running, the door descriptor
7447c478bd9Sstevel@tonic-gate  * of the last auditdoor in will be used for output.  auditd is responsible
7457c478bd9Sstevel@tonic-gate  * for insuring that multiple copies are not running.
7467c478bd9Sstevel@tonic-gate  */
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate static int
7497c478bd9Sstevel@tonic-gate auditdoor(int fd)
7507c478bd9Sstevel@tonic-gate {
7517c478bd9Sstevel@tonic-gate 	struct file	*fp;
7527c478bd9Sstevel@tonic-gate 	struct vnode	*vp;
7537c478bd9Sstevel@tonic-gate 	int		error = 0;
7547c478bd9Sstevel@tonic-gate 	int		do_create = 0;
7557c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx;
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	if (secpolicy_audit_config(CRED()) != 0)
7587c478bd9Sstevel@tonic-gate 		return (EPERM);
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 	if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc))
7617c478bd9Sstevel@tonic-gate 		return (EINVAL);
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	kctx = SET_KCTX_LZ;
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	/*
7667c478bd9Sstevel@tonic-gate 	 * Prevent a second audit daemon from running this code.
7677c478bd9Sstevel@tonic-gate 	 * auk_svc_busy == 2 until the output thread terminates.
7687c478bd9Sstevel@tonic-gate 	 * Multiple calls to auditdoor() are valid but a call
7697c478bd9Sstevel@tonic-gate 	 * to auditsvc() while au_output_thread() is running
7707c478bd9Sstevel@tonic-gate 	 * or a call to auditdoor() while auditsvc is running
7717c478bd9Sstevel@tonic-gate 	 * is blocked.
7727c478bd9Sstevel@tonic-gate 	 */
7737c478bd9Sstevel@tonic-gate 	mutex_enter(&(kctx->auk_svc_lock));
7747c478bd9Sstevel@tonic-gate 	if (kctx->auk_svc_busy == 1) {		/* active auditsvc? */
7757c478bd9Sstevel@tonic-gate 		mutex_exit(&(kctx->auk_svc_lock));
7767c478bd9Sstevel@tonic-gate 		return (EBUSY);
7777c478bd9Sstevel@tonic-gate 	}
7787c478bd9Sstevel@tonic-gate 	kctx->auk_svc_busy = 2;
7797c478bd9Sstevel@tonic-gate 	mutex_exit(&(kctx->auk_svc_lock));
7807c478bd9Sstevel@tonic-gate 	/*
7817c478bd9Sstevel@tonic-gate 	 * convert file pointer to file descriptor
7827c478bd9Sstevel@tonic-gate 	 *   Note: fd ref count incremented here.
7837c478bd9Sstevel@tonic-gate 	 */
7847c478bd9Sstevel@tonic-gate 	if ((fp = (struct file *)getf(fd)) == NULL) {
7857c478bd9Sstevel@tonic-gate 		error = EBADF;
7867c478bd9Sstevel@tonic-gate 		goto svc_exit;
7877c478bd9Sstevel@tonic-gate 	}
7887c478bd9Sstevel@tonic-gate 	vp = fp->f_vnode;
7897c478bd9Sstevel@tonic-gate 	if (vp->v_type != VDOOR) {
7907c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
7917c478bd9Sstevel@tonic-gate 		    "auditdoor() did not get the expected door descriptor\n");
7927c478bd9Sstevel@tonic-gate 		error = EINVAL;
7937c478bd9Sstevel@tonic-gate 		releasef(fd);
7947c478bd9Sstevel@tonic-gate 		goto svc_exit;
7957c478bd9Sstevel@tonic-gate 	}
7967c478bd9Sstevel@tonic-gate 	/*
7977c478bd9Sstevel@tonic-gate 	 * If the output thread is already running, then replace the
7987c478bd9Sstevel@tonic-gate 	 * door descriptor with the new one and continue; otherwise
7997c478bd9Sstevel@tonic-gate 	 * create the thread too.  Since au_output_thread makes a call
8007c478bd9Sstevel@tonic-gate 	 * to au_doorio() which also does
8017c478bd9Sstevel@tonic-gate 	 * mutex_lock(&(kctx->auk_svc_lock)), the create/dispatch is
8027c478bd9Sstevel@tonic-gate 	 * done after the unlock...
8037c478bd9Sstevel@tonic-gate 	 */
8047c478bd9Sstevel@tonic-gate 	mutex_enter(&(kctx->auk_svc_lock));
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	if (kctx->auk_current_vp != NULL)
8077c478bd9Sstevel@tonic-gate 		VN_RELE(kctx->auk_current_vp);
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 	kctx->auk_current_vp = vp;
8107c478bd9Sstevel@tonic-gate 	VN_HOLD(kctx->auk_current_vp);
8117c478bd9Sstevel@tonic-gate 	releasef(fd);
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	if (!kctx->auk_output_active) {
8147c478bd9Sstevel@tonic-gate 		kctx->auk_output_active = 1;
8157c478bd9Sstevel@tonic-gate 		do_create = 1;
8167c478bd9Sstevel@tonic-gate 	}
8177c478bd9Sstevel@tonic-gate 	mutex_exit(&(kctx->auk_svc_lock));
8187c478bd9Sstevel@tonic-gate 	if (do_create) {
8197c478bd9Sstevel@tonic-gate 		kctx->auk_taskq =
8207c478bd9Sstevel@tonic-gate 		    taskq_create("output_master", 1, minclsyspri, 1, 1, 0);
8217c478bd9Sstevel@tonic-gate 		(void) taskq_dispatch(kctx->auk_taskq,
8227c478bd9Sstevel@tonic-gate 		    (task_func_t *)au_output_thread,
8237c478bd9Sstevel@tonic-gate 		    kctx, TQ_SLEEP);
8247c478bd9Sstevel@tonic-gate 	}
8257c478bd9Sstevel@tonic-gate svc_exit:
8267c478bd9Sstevel@tonic-gate 	if (error) {
8277c478bd9Sstevel@tonic-gate 		mutex_enter(&(kctx->auk_svc_lock));
8287c478bd9Sstevel@tonic-gate 		kctx->auk_svc_busy = 2;
8297c478bd9Sstevel@tonic-gate 		mutex_exit(&(kctx->auk_svc_lock));
8307c478bd9Sstevel@tonic-gate 	}
8317c478bd9Sstevel@tonic-gate 	return (error);
8327c478bd9Sstevel@tonic-gate }
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate /*
8357c478bd9Sstevel@tonic-gate  * au_queue_kick -- wake up the output queue after delay ticks
8367c478bd9Sstevel@tonic-gate  */
8377c478bd9Sstevel@tonic-gate static void
8387c478bd9Sstevel@tonic-gate au_queue_kick(void *kctx)
8397c478bd9Sstevel@tonic-gate {
8407c478bd9Sstevel@tonic-gate 	/*
8417c478bd9Sstevel@tonic-gate 	 * wakeup reader if its not running and there is something
8427c478bd9Sstevel@tonic-gate 	 * to do.  It also helps that kctx still be valid...
8437c478bd9Sstevel@tonic-gate 	 */
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	if ((((au_kcontext_t *)kctx)->auk_valid != AUK_VALID) ||
8467c478bd9Sstevel@tonic-gate 	    (((au_kcontext_t *)kctx)->auk_auditstate == AUC_NOAUDIT))
8477c478bd9Sstevel@tonic-gate 		return;
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	if (((au_kcontext_t *)kctx)->auk_queue.cnt &&
8507c478bd9Sstevel@tonic-gate 	    ((au_kcontext_t *)kctx)->auk_queue.rd_block)
8517c478bd9Sstevel@tonic-gate 		cv_broadcast(&((au_kcontext_t *)kctx)->auk_queue.read_cv);
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	/* fire off timeout event to kick audit queue awake */
8547c478bd9Sstevel@tonic-gate 	(void) timeout(au_queue_kick, kctx,
8557c478bd9Sstevel@tonic-gate 	    ((au_kcontext_t *)kctx)->auk_queue.delay);
8567c478bd9Sstevel@tonic-gate }
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate /*
8597c478bd9Sstevel@tonic-gate  * output thread
8607c478bd9Sstevel@tonic-gate  *
8617c478bd9Sstevel@tonic-gate  * this runs "forever" where "forever" means until either auk_auditstate
8627c478bd9Sstevel@tonic-gate  * changes from AUC_AUDITING or if the door descriptor becomes invalid.
8637c478bd9Sstevel@tonic-gate  *
8647c478bd9Sstevel@tonic-gate  * there is one thread per active zone if AUC_PERZONE is set.  Since
8657c478bd9Sstevel@tonic-gate  * there is the possibility that a zone may go down without auditd
8667c478bd9Sstevel@tonic-gate  * terminating properly, a zone shutdown kills its au_output_thread()
8677c478bd9Sstevel@tonic-gate  * via taskq_destroy().
8687c478bd9Sstevel@tonic-gate  */
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate static void
8717c478bd9Sstevel@tonic-gate au_output_thread(au_kcontext_t *kctx)
8727c478bd9Sstevel@tonic-gate {
8737c478bd9Sstevel@tonic-gate 	int		error = 0;
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	(void) timeout(au_queue_kick, kctx, kctx->auk_queue.delay);
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	/*
8787c478bd9Sstevel@tonic-gate 	 * Wait for work, until a signal arrives,
8797c478bd9Sstevel@tonic-gate 	 * or until auditing is disabled.
8807c478bd9Sstevel@tonic-gate 	 */
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	while (!error) {
8837c478bd9Sstevel@tonic-gate 	    if (kctx->auk_auditstate == AUC_AUDITING) {
8847c478bd9Sstevel@tonic-gate 		mutex_enter(&(kctx->auk_queue.lock));
8857c478bd9Sstevel@tonic-gate 		while (kctx->auk_queue.head == NULL) {
8867c478bd9Sstevel@tonic-gate 		    /* safety check. kick writer awake */
8877c478bd9Sstevel@tonic-gate 		    if (kctx->auk_queue.wt_block)
8887c478bd9Sstevel@tonic-gate 			cv_broadcast(&(kctx->auk_queue.write_cv));
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 		    kctx->auk_queue.rd_block = 1;
8917c478bd9Sstevel@tonic-gate 		    AS_INC(as_rblocked, 1, kctx);
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 		    cv_wait(&(kctx->auk_queue.read_cv),
8947c478bd9Sstevel@tonic-gate 			&(kctx->auk_queue.lock));
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 		    kctx->auk_queue.rd_block = 0;
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 		    if (kctx->auk_auditstate != AUC_AUDITING) {
8997c478bd9Sstevel@tonic-gate 			mutex_exit(&(kctx->auk_queue.lock));
9007c478bd9Sstevel@tonic-gate 			(void) timeout(audit_dont_stop, kctx, au_resid);
9017c478bd9Sstevel@tonic-gate 			goto output_exit;
9027c478bd9Sstevel@tonic-gate 		    }
9037c478bd9Sstevel@tonic-gate 		    kctx->auk_queue.rd_block = 0;
9047c478bd9Sstevel@tonic-gate 		}
9057c478bd9Sstevel@tonic-gate 		mutex_exit(&(kctx->auk_queue.lock));
9067c478bd9Sstevel@tonic-gate 		/*
9077c478bd9Sstevel@tonic-gate 		 * au_doorio() calls au_door_upcall which holds auk_svc_lock;
9087c478bd9Sstevel@tonic-gate 		 * au_doorio empties the queue before returning.
9097c478bd9Sstevel@tonic-gate 		 */
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 		error = au_doorio(kctx);
9127c478bd9Sstevel@tonic-gate 	    } else	/* auditing turned off while we slept */
9137c478bd9Sstevel@tonic-gate 		break;
9147c478bd9Sstevel@tonic-gate 	}
9157c478bd9Sstevel@tonic-gate output_exit:
9167c478bd9Sstevel@tonic-gate 	mutex_enter(&(kctx->auk_svc_lock));
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	VN_RELE(kctx->auk_current_vp);
9197c478bd9Sstevel@tonic-gate 	kctx->auk_current_vp = NULL;
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 	kctx->auk_output_active = 0;
9227c478bd9Sstevel@tonic-gate 	kctx->auk_svc_busy = 0;
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 	mutex_exit(&(kctx->auk_svc_lock));
9257c478bd9Sstevel@tonic-gate }
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate /*
9297c478bd9Sstevel@tonic-gate  * Get the global policy flag
9307c478bd9Sstevel@tonic-gate  */
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate static int
9337c478bd9Sstevel@tonic-gate getpolicy(caddr_t data)
9347c478bd9Sstevel@tonic-gate {
9357c478bd9Sstevel@tonic-gate 	int	policy;
9367c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx = SET_KCTX_PZ;
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	policy = audit_policy | kctx->auk_policy;
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 	if (copyout(&policy, data, sizeof (int)))
9417c478bd9Sstevel@tonic-gate 		return (EFAULT);
9427c478bd9Sstevel@tonic-gate 	return (0);
9437c478bd9Sstevel@tonic-gate }
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate /*
9467c478bd9Sstevel@tonic-gate  * Set the global and local policy flags
9477c478bd9Sstevel@tonic-gate  *
9487c478bd9Sstevel@tonic-gate  * The global flags only make sense from the global zone;
9497c478bd9Sstevel@tonic-gate  * the local flags depend on the AUDIT_PERZONE policy:
9507c478bd9Sstevel@tonic-gate  * if the perzone policy is set, then policy is set separately
9517c478bd9Sstevel@tonic-gate  * per zone, else held only in the global zone.
9527c478bd9Sstevel@tonic-gate  *
9537c478bd9Sstevel@tonic-gate  * The initial value of a local zone's policy flag is determined
9547c478bd9Sstevel@tonic-gate  * by the value of the global zone's flags at the time the
9557c478bd9Sstevel@tonic-gate  * local zone is created.
9567c478bd9Sstevel@tonic-gate  *
9577c478bd9Sstevel@tonic-gate  * While auditconfig(1M) allows setting and unsetting policies one bit
9587c478bd9Sstevel@tonic-gate  * at a time, the mask passed in from auditconfig() is created by a
9597c478bd9Sstevel@tonic-gate  * syscall to getpolicy and then modified based on the auditconfig()
9607c478bd9Sstevel@tonic-gate  * cmd line, so the input policy value is used to replace the existing
9617c478bd9Sstevel@tonic-gate  * policy.
9627c478bd9Sstevel@tonic-gate  */
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate static int
9667c478bd9Sstevel@tonic-gate setpolicy(caddr_t data)
9677c478bd9Sstevel@tonic-gate {
9687c478bd9Sstevel@tonic-gate 	int	policy;
9697c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx;
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	if (copyin(data, &policy, sizeof (int)))
9727c478bd9Sstevel@tonic-gate 		return (EFAULT);
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 	kctx = SET_KCTX_LZ;
9757c478bd9Sstevel@tonic-gate 	ASSERT(kctx != NULL);
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 	if (INGLOBALZONE(curproc)) {
9787c478bd9Sstevel@tonic-gate 		if (policy & ~(AUDIT_GLOBAL | AUDIT_LOCAL))
9797c478bd9Sstevel@tonic-gate 			return (EINVAL);
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 		audit_policy = policy & AUDIT_GLOBAL;
9827c478bd9Sstevel@tonic-gate 	} else {
9837c478bd9Sstevel@tonic-gate 		if (!(audit_policy & AUDIT_PERZONE))
9847c478bd9Sstevel@tonic-gate 			return (EINVAL);
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 		if (policy & ~AUDIT_LOCAL)	/* global bits are a no-no */
9877c478bd9Sstevel@tonic-gate 			return (EINVAL);
9887c478bd9Sstevel@tonic-gate 	}
9897c478bd9Sstevel@tonic-gate 	kctx->auk_policy = policy & AUDIT_LOCAL;
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 	/*
9927c478bd9Sstevel@tonic-gate 	 * auk_current_vp is NULL before auditd starts (or during early
9937c478bd9Sstevel@tonic-gate 	 * auditd starup) or if auditd is halted; in either case,
9947c478bd9Sstevel@tonic-gate 	 * notification of a policy change is not needed, since auditd
9957c478bd9Sstevel@tonic-gate 	 * reads policy as it comes up.  The error return from au_doormsg()
9967c478bd9Sstevel@tonic-gate 	 * is ignored to avoid a race condition -- for example if auditd
9977c478bd9Sstevel@tonic-gate 	 * segv's, the audit state may be "auditing" but the door may
9987c478bd9Sstevel@tonic-gate 	 * be closed.  Returning an error if the door is open makes it
9997c478bd9Sstevel@tonic-gate 	 * impossible for Greenline to restart auditd.
10007c478bd9Sstevel@tonic-gate 	 */
10017c478bd9Sstevel@tonic-gate 	if (kctx->auk_current_vp != NULL)
10027c478bd9Sstevel@tonic-gate 		(void) au_doormsg(kctx, AU_DBUF_POLICY, &policy);
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 	/*
10057c478bd9Sstevel@tonic-gate 	 * Wake up anyone who might have blocked on full audit
10067c478bd9Sstevel@tonic-gate 	 * partitions. audit daemons need to set AUDIT_FULL when no
10077c478bd9Sstevel@tonic-gate 	 * space so we can tell if we should start dropping records.
10087c478bd9Sstevel@tonic-gate 	 */
10097c478bd9Sstevel@tonic-gate 	mutex_enter(&(kctx->auk_queue.lock));
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 	if ((policy & (AUDIT_CNT | AUDIT_SCNT) &&
10127c478bd9Sstevel@tonic-gate 	    (kctx->auk_queue.cnt >= kctx->auk_queue.hiwater)))
10137c478bd9Sstevel@tonic-gate 		cv_broadcast(&(kctx->auk_queue.write_cv));
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	mutex_exit(&(kctx->auk_queue.lock));
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 	return (0);
10187c478bd9Sstevel@tonic-gate }
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate static int
10217c478bd9Sstevel@tonic-gate getkmask(caddr_t data)
10227c478bd9Sstevel@tonic-gate {
10237c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx;
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 	kctx = SET_KCTX_PZ;
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	if (copyout(&kctx->auk_info.ai_mask, data, sizeof (au_mask_t)))
10287c478bd9Sstevel@tonic-gate 		return (EFAULT);
10297c478bd9Sstevel@tonic-gate 	return (0);
10307c478bd9Sstevel@tonic-gate }
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate static int
10337c478bd9Sstevel@tonic-gate setkmask(caddr_t data)
10347c478bd9Sstevel@tonic-gate {
10357c478bd9Sstevel@tonic-gate 	au_mask_t	mask;
10367c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx;
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 	if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc))
10397c478bd9Sstevel@tonic-gate 		return (EINVAL);
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 	kctx = SET_KCTX_LZ;
10427c478bd9Sstevel@tonic-gate 
10437c478bd9Sstevel@tonic-gate 	if (copyin(data, &mask, sizeof (au_mask_t)))
10447c478bd9Sstevel@tonic-gate 		return (EFAULT);
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate 	kctx->auk_info.ai_mask = mask;
10477c478bd9Sstevel@tonic-gate 	return (0);
10487c478bd9Sstevel@tonic-gate }
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate static int
10517c478bd9Sstevel@tonic-gate getkaudit(caddr_t info_p, int len)
10527c478bd9Sstevel@tonic-gate {
10537c478bd9Sstevel@tonic-gate 	STRUCT_DECL(auditinfo_addr, info);
10547c478bd9Sstevel@tonic-gate 	model_t model;
10557c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx = SET_KCTX_PZ;
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	model = get_udatamodel();
10587c478bd9Sstevel@tonic-gate 	STRUCT_INIT(info, model);
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 	if (len < STRUCT_SIZE(info))
10617c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_auid, kctx->auk_info.ai_auid);
10647c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_mask, kctx->auk_info.ai_mask);
10657c478bd9Sstevel@tonic-gate #ifdef _LP64
10667c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_ILP32) {
10677c478bd9Sstevel@tonic-gate 		dev32_t dev;
10687c478bd9Sstevel@tonic-gate 		/* convert internal 64 bit form to 32 bit version */
10697c478bd9Sstevel@tonic-gate 		if (cmpldev(&dev, kctx->auk_info.ai_termid.at_port) == 0) {
10707c478bd9Sstevel@tonic-gate 			return (EOVERFLOW);
10717c478bd9Sstevel@tonic-gate 		}
10727c478bd9Sstevel@tonic-gate 		STRUCT_FSET(info, ai_termid.at_port, dev);
10737c478bd9Sstevel@tonic-gate 	} else
10747c478bd9Sstevel@tonic-gate 		STRUCT_FSET(info, ai_termid.at_port,
10757c478bd9Sstevel@tonic-gate 			kctx->auk_info.ai_termid.at_port);
10767c478bd9Sstevel@tonic-gate #else
10777c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_termid.at_port,
10787c478bd9Sstevel@tonic-gate 		kctx->auk_info.ai_termid.at_port);
10797c478bd9Sstevel@tonic-gate #endif
10807c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_termid.at_type,
10817c478bd9Sstevel@tonic-gate 	    kctx->auk_info.ai_termid.at_type);
10827c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_termid.at_addr[0],
10837c478bd9Sstevel@tonic-gate 	    kctx->auk_info.ai_termid.at_addr[0]);
10847c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_termid.at_addr[1],
10857c478bd9Sstevel@tonic-gate 	    kctx->auk_info.ai_termid.at_addr[1]);
10867c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_termid.at_addr[2],
10877c478bd9Sstevel@tonic-gate 	    kctx->auk_info.ai_termid.at_addr[2]);
10887c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_termid.at_addr[3],
10897c478bd9Sstevel@tonic-gate 	    kctx->auk_info.ai_termid.at_addr[3]);
10907c478bd9Sstevel@tonic-gate 	STRUCT_FSET(info, ai_asid, kctx->auk_info.ai_asid);
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(info), info_p, STRUCT_SIZE(info)))
10937c478bd9Sstevel@tonic-gate 		return (EFAULT);
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 	return (0);
10967c478bd9Sstevel@tonic-gate }
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate /*
10997c478bd9Sstevel@tonic-gate  * the host address for AUDIT_PERZONE == 0 is that of the global
11007c478bd9Sstevel@tonic-gate  * zone and for local zones it is of the current zone.
11017c478bd9Sstevel@tonic-gate  */
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate static int
11047c478bd9Sstevel@tonic-gate setkaudit(caddr_t info_p, int len)
11057c478bd9Sstevel@tonic-gate {
11067c478bd9Sstevel@tonic-gate 	STRUCT_DECL(auditinfo_addr, info);
11077c478bd9Sstevel@tonic-gate 	model_t model;
11087c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx;
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 	if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc))
11117c478bd9Sstevel@tonic-gate 		return (EINVAL);
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 	kctx = SET_KCTX_LZ;
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 	model = get_udatamodel();
11167c478bd9Sstevel@tonic-gate 	STRUCT_INIT(info, model);
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	if (len < STRUCT_SIZE(info))
11197c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 	if (copyin(info_p, STRUCT_BUF(info), STRUCT_SIZE(info)))
11227c478bd9Sstevel@tonic-gate 		return (EFAULT);
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate 	if ((STRUCT_FGET(info, ai_termid.at_type) != AU_IPv4) &&
11257c478bd9Sstevel@tonic-gate 	    (STRUCT_FGET(info, ai_termid.at_type) != AU_IPv6))
11267c478bd9Sstevel@tonic-gate 		return (EINVAL);
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 	/* Set audit mask, termid and session id as specified */
11297c478bd9Sstevel@tonic-gate 	kctx->auk_info.ai_auid = STRUCT_FGET(info, ai_auid);
11307c478bd9Sstevel@tonic-gate 	kctx->auk_info.ai_mask = STRUCT_FGET(info, ai_mask);
11317c478bd9Sstevel@tonic-gate #ifdef _LP64
11327c478bd9Sstevel@tonic-gate 	/* only convert to 64 bit if coming from a 32 bit binary */
11337c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_ILP32)
11347c478bd9Sstevel@tonic-gate 		kctx->auk_info.ai_termid.at_port =
11357c478bd9Sstevel@tonic-gate 			DEVEXPL(STRUCT_FGET(info, ai_termid.at_port));
11367c478bd9Sstevel@tonic-gate 	else
11377c478bd9Sstevel@tonic-gate 		kctx->auk_info.ai_termid.at_port =
11387c478bd9Sstevel@tonic-gate 			STRUCT_FGET(info, ai_termid.at_port);
11397c478bd9Sstevel@tonic-gate #else
11407c478bd9Sstevel@tonic-gate 	kctx->auk_info.ai_termid.at_port = STRUCT_FGET(info, ai_termid.at_port);
11417c478bd9Sstevel@tonic-gate #endif
11427c478bd9Sstevel@tonic-gate 	kctx->auk_info.ai_termid.at_type = STRUCT_FGET(info, ai_termid.at_type);
11437c478bd9Sstevel@tonic-gate 	bzero(&kctx->auk_info.ai_termid.at_addr[0],
11447c478bd9Sstevel@tonic-gate 		sizeof (kctx->auk_info.ai_termid.at_addr));
11457c478bd9Sstevel@tonic-gate 	kctx->auk_info.ai_termid.at_addr[0] =
11467c478bd9Sstevel@tonic-gate 	    STRUCT_FGET(info, ai_termid.at_addr[0]);
11477c478bd9Sstevel@tonic-gate 	kctx->auk_info.ai_termid.at_addr[1] =
11487c478bd9Sstevel@tonic-gate 	    STRUCT_FGET(info, ai_termid.at_addr[1]);
11497c478bd9Sstevel@tonic-gate 	kctx->auk_info.ai_termid.at_addr[2] =
11507c478bd9Sstevel@tonic-gate 	    STRUCT_FGET(info, ai_termid.at_addr[2]);
11517c478bd9Sstevel@tonic-gate 	kctx->auk_info.ai_termid.at_addr[3] =
11527c478bd9Sstevel@tonic-gate 	    STRUCT_FGET(info, ai_termid.at_addr[3]);
11537c478bd9Sstevel@tonic-gate 	kctx->auk_info.ai_asid = STRUCT_FGET(info, ai_asid);
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 	if (kctx->auk_info.ai_termid.at_type == AU_IPv6 &&
11567c478bd9Sstevel@tonic-gate 	    IN6_IS_ADDR_V4MAPPED(
11577c478bd9Sstevel@tonic-gate 	    ((in6_addr_t *)kctx->auk_info.ai_termid.at_addr))) {
11587c478bd9Sstevel@tonic-gate 		kctx->auk_info.ai_termid.at_type = AU_IPv4;
11597c478bd9Sstevel@tonic-gate 		kctx->auk_info.ai_termid.at_addr[0] =
11607c478bd9Sstevel@tonic-gate 		    kctx->auk_info.ai_termid.at_addr[3];
11617c478bd9Sstevel@tonic-gate 		kctx->auk_info.ai_termid.at_addr[1] = 0;
11627c478bd9Sstevel@tonic-gate 		kctx->auk_info.ai_termid.at_addr[2] = 0;
11637c478bd9Sstevel@tonic-gate 		kctx->auk_info.ai_termid.at_addr[3] = 0;
11647c478bd9Sstevel@tonic-gate 	}
11657c478bd9Sstevel@tonic-gate 	if (kctx->auk_info.ai_termid.at_type == AU_IPv6)
11667c478bd9Sstevel@tonic-gate 		kctx->auk_hostaddr_valid = IN6_IS_ADDR_UNSPECIFIED(
11677c478bd9Sstevel@tonic-gate 		    (in6_addr_t *)kctx->auk_info.ai_termid.at_addr) ? 0 : 1;
11687c478bd9Sstevel@tonic-gate 	else
11697c478bd9Sstevel@tonic-gate 		kctx->auk_hostaddr_valid =
11707c478bd9Sstevel@tonic-gate 		    (kctx->auk_info.ai_termid.at_addr[0] ==
11717c478bd9Sstevel@tonic-gate 		    htonl(INADDR_ANY)) ? 0 : 1;
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 	return (0);
11747c478bd9Sstevel@tonic-gate }
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate static int
11777c478bd9Sstevel@tonic-gate getqctrl(caddr_t data)
11787c478bd9Sstevel@tonic-gate {
11797c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx = SET_KCTX_PZ;
11807c478bd9Sstevel@tonic-gate 	STRUCT_DECL(au_qctrl, qctrl);
11817c478bd9Sstevel@tonic-gate 	STRUCT_INIT(qctrl, get_udatamodel());
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	mutex_enter(&(kctx->auk_queue.lock));
11847c478bd9Sstevel@tonic-gate 	STRUCT_FSET(qctrl, aq_hiwater, kctx->auk_queue.hiwater);
11857c478bd9Sstevel@tonic-gate 	STRUCT_FSET(qctrl, aq_lowater, kctx->auk_queue.lowater);
11867c478bd9Sstevel@tonic-gate 	STRUCT_FSET(qctrl, aq_bufsz, kctx->auk_queue.bufsz);
11877c478bd9Sstevel@tonic-gate 	STRUCT_FSET(qctrl, aq_delay, kctx->auk_queue.delay);
11887c478bd9Sstevel@tonic-gate 	mutex_exit(&(kctx->auk_queue.lock));
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(qctrl), data, STRUCT_SIZE(qctrl)))
11917c478bd9Sstevel@tonic-gate 		return (EFAULT);
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 	return (0);
11947c478bd9Sstevel@tonic-gate }
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate static int
11977c478bd9Sstevel@tonic-gate setqctrl(caddr_t data)
11987c478bd9Sstevel@tonic-gate {
11997c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx;
12007c478bd9Sstevel@tonic-gate 	struct au_qctrl qctrl_tmp;
12017c478bd9Sstevel@tonic-gate 	STRUCT_DECL(au_qctrl, qctrl);
12027c478bd9Sstevel@tonic-gate 	STRUCT_INIT(qctrl, get_udatamodel());
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 	if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc))
12057c478bd9Sstevel@tonic-gate 		return (EINVAL);
12067c478bd9Sstevel@tonic-gate 	kctx = SET_KCTX_LZ;
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate 	if (copyin(data, STRUCT_BUF(qctrl), STRUCT_SIZE(qctrl)))
12097c478bd9Sstevel@tonic-gate 		return (EFAULT);
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 	qctrl_tmp.aq_hiwater = (size_t)STRUCT_FGET(qctrl, aq_hiwater);
12127c478bd9Sstevel@tonic-gate 	qctrl_tmp.aq_lowater = (size_t)STRUCT_FGET(qctrl, aq_lowater);
12137c478bd9Sstevel@tonic-gate 	qctrl_tmp.aq_bufsz = (size_t)STRUCT_FGET(qctrl, aq_bufsz);
12147c478bd9Sstevel@tonic-gate 	qctrl_tmp.aq_delay = (clock_t)STRUCT_FGET(qctrl, aq_delay);
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 	/* enforce sane values */
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 	if (qctrl_tmp.aq_hiwater <= qctrl_tmp.aq_lowater)
12197c478bd9Sstevel@tonic-gate 		return (EINVAL);
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 	if (qctrl_tmp.aq_hiwater < AQ_LOWATER)
12227c478bd9Sstevel@tonic-gate 		return (EINVAL);
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 	if (qctrl_tmp.aq_hiwater > AQ_MAXHIGH)
12257c478bd9Sstevel@tonic-gate 		return (EINVAL);
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	if (qctrl_tmp.aq_bufsz < AQ_BUFSZ)
12287c478bd9Sstevel@tonic-gate 		return (EINVAL);
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 	if (qctrl_tmp.aq_bufsz > AQ_MAXBUFSZ)
12317c478bd9Sstevel@tonic-gate 		return (EINVAL);
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	if (qctrl_tmp.aq_delay == 0)
12347c478bd9Sstevel@tonic-gate 		return (EINVAL);
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 	if (qctrl_tmp.aq_delay > AQ_MAXDELAY)
12377c478bd9Sstevel@tonic-gate 		return (EINVAL);
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate 	/* update everything at once so things are consistant */
12407c478bd9Sstevel@tonic-gate 	mutex_enter(&(kctx->auk_queue.lock));
12417c478bd9Sstevel@tonic-gate 	kctx->auk_queue.hiwater = qctrl_tmp.aq_hiwater;
12427c478bd9Sstevel@tonic-gate 	kctx->auk_queue.lowater = qctrl_tmp.aq_lowater;
12437c478bd9Sstevel@tonic-gate 	kctx->auk_queue.bufsz = qctrl_tmp.aq_bufsz;
12447c478bd9Sstevel@tonic-gate 	kctx->auk_queue.delay = qctrl_tmp.aq_delay;
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 	if (kctx->auk_queue.rd_block &&
12477c478bd9Sstevel@tonic-gate 	    kctx->auk_queue.cnt > kctx->auk_queue.lowater)
12487c478bd9Sstevel@tonic-gate 		cv_broadcast(&(kctx->auk_queue.read_cv));
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate 	if (kctx->auk_queue.wt_block &&
12517c478bd9Sstevel@tonic-gate 	    kctx->auk_queue.cnt < kctx->auk_queue.hiwater)
12527c478bd9Sstevel@tonic-gate 		cv_broadcast(&(kctx->auk_queue.write_cv));
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 	mutex_exit(&(kctx->auk_queue.lock));
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	return (0);
12577c478bd9Sstevel@tonic-gate }
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate static int
12607c478bd9Sstevel@tonic-gate getcwd(caddr_t data, int length)
12617c478bd9Sstevel@tonic-gate {
12627c478bd9Sstevel@tonic-gate 	struct p_audit_data	*pad;
12637c478bd9Sstevel@tonic-gate 	struct audit_path	*app;
12647c478bd9Sstevel@tonic-gate 	int	pathlen;
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate 	pad = P2A(curproc);
12677c478bd9Sstevel@tonic-gate 	ASSERT(pad != NULL);
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 	mutex_enter(&(pad->pad_lock));
12707c478bd9Sstevel@tonic-gate 	app = pad->pad_cwd;
12717c478bd9Sstevel@tonic-gate 	au_pathhold(app);
12727c478bd9Sstevel@tonic-gate 	mutex_exit(&(pad->pad_lock));
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 	pathlen = app->audp_sect[1] - app->audp_sect[0];
12757c478bd9Sstevel@tonic-gate 	if (pathlen > length) {
12767c478bd9Sstevel@tonic-gate 		au_pathrele(app);
12777c478bd9Sstevel@tonic-gate 		return (E2BIG);
12787c478bd9Sstevel@tonic-gate 	}
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate 	if (copyout(app->audp_sect[0], data, pathlen)) {
12817c478bd9Sstevel@tonic-gate 		au_pathrele(app);
12827c478bd9Sstevel@tonic-gate 		return (EFAULT);
12837c478bd9Sstevel@tonic-gate 	}
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 	au_pathrele(app);
12867c478bd9Sstevel@tonic-gate 	return (0);
12877c478bd9Sstevel@tonic-gate }
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate static int
12907c478bd9Sstevel@tonic-gate getcar(caddr_t data, int length)
12917c478bd9Sstevel@tonic-gate {
12927c478bd9Sstevel@tonic-gate 	struct p_audit_data	*pad;
12937c478bd9Sstevel@tonic-gate 	struct audit_path	*app;
12947c478bd9Sstevel@tonic-gate 	int	pathlen;
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate 	pad = P2A(curproc);
12977c478bd9Sstevel@tonic-gate 	ASSERT(pad != NULL);
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 	mutex_enter(&(pad->pad_lock));
13007c478bd9Sstevel@tonic-gate 	app = pad->pad_root;
13017c478bd9Sstevel@tonic-gate 	au_pathhold(app);
13027c478bd9Sstevel@tonic-gate 	mutex_exit(&(pad->pad_lock));
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 	pathlen = app->audp_sect[1] - app->audp_sect[0];
13057c478bd9Sstevel@tonic-gate 	if (pathlen > length) {
13067c478bd9Sstevel@tonic-gate 		au_pathrele(app);
13077c478bd9Sstevel@tonic-gate 		return (E2BIG);
13087c478bd9Sstevel@tonic-gate 	}
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate 	if (copyout(app->audp_sect[0], data, pathlen)) {
13117c478bd9Sstevel@tonic-gate 		au_pathrele(app);
13127c478bd9Sstevel@tonic-gate 		return (EFAULT);
13137c478bd9Sstevel@tonic-gate 	}
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 	au_pathrele(app);
13167c478bd9Sstevel@tonic-gate 	return (0);
13177c478bd9Sstevel@tonic-gate }
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate static int
13207c478bd9Sstevel@tonic-gate getstat(caddr_t data)
13217c478bd9Sstevel@tonic-gate {
13227c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx = SET_KCTX_PZ;
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 	membar_consumer();
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 	if (copyout((caddr_t)&(kctx->auk_statistics), data, sizeof (au_stat_t)))
13277c478bd9Sstevel@tonic-gate 		return (EFAULT);
13287c478bd9Sstevel@tonic-gate 	return (0);
13297c478bd9Sstevel@tonic-gate }
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate static int
13337c478bd9Sstevel@tonic-gate setstat(caddr_t data)
13347c478bd9Sstevel@tonic-gate {
13357c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx = SET_KCTX_PZ;
13367c478bd9Sstevel@tonic-gate 	au_stat_t au_stat;
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate 	if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc))
13397c478bd9Sstevel@tonic-gate 		return (EINVAL);
13407c478bd9Sstevel@tonic-gate 
13417c478bd9Sstevel@tonic-gate 	if (copyin(data, &au_stat, sizeof (au_stat_t)))
13427c478bd9Sstevel@tonic-gate 		return (EFAULT);
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate 	if (au_stat.as_generated == CLEAR_VAL)
13457c478bd9Sstevel@tonic-gate 		kctx->auk_statistics.as_generated = 0;
13467c478bd9Sstevel@tonic-gate 	if (au_stat.as_nonattrib == CLEAR_VAL)
13477c478bd9Sstevel@tonic-gate 		kctx->auk_statistics.as_nonattrib = 0;
13487c478bd9Sstevel@tonic-gate 	if (au_stat.as_kernel == CLEAR_VAL)
13497c478bd9Sstevel@tonic-gate 		kctx->auk_statistics.as_kernel = 0;
13507c478bd9Sstevel@tonic-gate 	if (au_stat.as_audit == CLEAR_VAL)
13517c478bd9Sstevel@tonic-gate 		kctx->auk_statistics.as_audit = 0;
13527c478bd9Sstevel@tonic-gate 	if (au_stat.as_auditctl == CLEAR_VAL)
13537c478bd9Sstevel@tonic-gate 		kctx->auk_statistics.as_auditctl = 0;
13547c478bd9Sstevel@tonic-gate 	if (au_stat.as_enqueue == CLEAR_VAL)
13557c478bd9Sstevel@tonic-gate 		kctx->auk_statistics.as_enqueue = 0;
13567c478bd9Sstevel@tonic-gate 	if (au_stat.as_written == CLEAR_VAL)
13577c478bd9Sstevel@tonic-gate 		kctx->auk_statistics.as_written = 0;
13587c478bd9Sstevel@tonic-gate 	if (au_stat.as_wblocked == CLEAR_VAL)
13597c478bd9Sstevel@tonic-gate 		kctx->auk_statistics.as_wblocked = 0;
13607c478bd9Sstevel@tonic-gate 	if (au_stat.as_rblocked == CLEAR_VAL)
13617c478bd9Sstevel@tonic-gate 		kctx->auk_statistics.as_rblocked = 0;
13627c478bd9Sstevel@tonic-gate 	if (au_stat.as_dropped == CLEAR_VAL)
13637c478bd9Sstevel@tonic-gate 		kctx->auk_statistics.as_dropped = 0;
13647c478bd9Sstevel@tonic-gate 	if (au_stat.as_totalsize == CLEAR_VAL)
13657c478bd9Sstevel@tonic-gate 		kctx->auk_statistics.as_totalsize = 0;
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 	membar_producer();
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 	return (0);
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate }
13727c478bd9Sstevel@tonic-gate 
13737c478bd9Sstevel@tonic-gate static int
13747c478bd9Sstevel@tonic-gate setumask(caddr_t data)
13757c478bd9Sstevel@tonic-gate {
13767c478bd9Sstevel@tonic-gate 	STRUCT_DECL(auditinfo, user_info);
13777c478bd9Sstevel@tonic-gate 	struct proc *p;
13787c478bd9Sstevel@tonic-gate 	const auditinfo_addr_t	*ainfo;
13797c478bd9Sstevel@tonic-gate 	model_t	model;
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 	model = get_udatamodel();
13827c478bd9Sstevel@tonic-gate 	STRUCT_INIT(user_info, model);
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate 	if (copyin(data, STRUCT_BUF(user_info), STRUCT_SIZE(user_info)))
13857c478bd9Sstevel@tonic-gate 		return (EFAULT);
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate 	mutex_enter(&pidlock);	/* lock the process queue against updates */
13887c478bd9Sstevel@tonic-gate 	for (p = practive; p != NULL; p = p->p_next) {
13897c478bd9Sstevel@tonic-gate 		cred_t	*cr;
13907c478bd9Sstevel@tonic-gate 
13917c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);	/* so process doesn't go away */
13927c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_crlock);
13937c478bd9Sstevel@tonic-gate 		crhold(cr = p->p_cred);
13947c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_crlock);
13957c478bd9Sstevel@tonic-gate 		ainfo = crgetauinfo(cr);
13967c478bd9Sstevel@tonic-gate 		if (ainfo == NULL) {
13977c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
13987c478bd9Sstevel@tonic-gate 			crfree(cr);
13997c478bd9Sstevel@tonic-gate 			continue;
14007c478bd9Sstevel@tonic-gate 		}
14017c478bd9Sstevel@tonic-gate 
14027c478bd9Sstevel@tonic-gate 		if (ainfo->ai_auid == STRUCT_FGET(user_info, ai_auid)) {
14037c478bd9Sstevel@tonic-gate 			au_mask_t	mask;
14047c478bd9Sstevel@tonic-gate 			int		err;
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate 			/*
14077c478bd9Sstevel@tonic-gate 			 * Here's a process which matches the specified auid.
14087c478bd9Sstevel@tonic-gate 			 * If its mask doesn't already match the new mask,
14097c478bd9Sstevel@tonic-gate 			 * save the new mask in the pad, to be picked up
14107c478bd9Sstevel@tonic-gate 			 * next syscall.
14117c478bd9Sstevel@tonic-gate 			 */
14127c478bd9Sstevel@tonic-gate 			mask = STRUCT_FGET(user_info, ai_mask);
14137c478bd9Sstevel@tonic-gate 			err = bcmp(&mask, &ainfo->ai_mask, sizeof (au_mask_t));
14147c478bd9Sstevel@tonic-gate 			crfree(cr);
14157c478bd9Sstevel@tonic-gate 			if (err != 0) {
14167c478bd9Sstevel@tonic-gate 				struct p_audit_data *pad = P2A(p);
14177c478bd9Sstevel@tonic-gate 				ASSERT(pad != NULL);
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate 				mutex_enter(&(pad->pad_lock));
14207c478bd9Sstevel@tonic-gate 				pad->pad_flags |= PAD_SETMASK;
14217c478bd9Sstevel@tonic-gate 				pad->pad_newmask = mask;
14227c478bd9Sstevel@tonic-gate 				mutex_exit(&(pad->pad_lock));
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 				/*
14257c478bd9Sstevel@tonic-gate 				 * No need to call set_proc_pre_sys(), since
14267c478bd9Sstevel@tonic-gate 				 * t_pre_sys is ALWAYS on when audit is
14277c478bd9Sstevel@tonic-gate 				 * enabled...due to syscall auditing.
14287c478bd9Sstevel@tonic-gate 				 */
14297c478bd9Sstevel@tonic-gate 			}
14307c478bd9Sstevel@tonic-gate 		} else {
14317c478bd9Sstevel@tonic-gate 			crfree(cr);
14327c478bd9Sstevel@tonic-gate 		}
14337c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
14347c478bd9Sstevel@tonic-gate 	}
14357c478bd9Sstevel@tonic-gate 	mutex_exit(&pidlock);
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 	return (0);
14387c478bd9Sstevel@tonic-gate }
14397c478bd9Sstevel@tonic-gate 
14407c478bd9Sstevel@tonic-gate static int
14417c478bd9Sstevel@tonic-gate setsmask(caddr_t data)
14427c478bd9Sstevel@tonic-gate {
14437c478bd9Sstevel@tonic-gate 	STRUCT_DECL(auditinfo, user_info);
14447c478bd9Sstevel@tonic-gate 	struct proc *p;
14457c478bd9Sstevel@tonic-gate 	const auditinfo_addr_t	*ainfo;
14467c478bd9Sstevel@tonic-gate 	model_t	model;
14477c478bd9Sstevel@tonic-gate 
14487c478bd9Sstevel@tonic-gate 	model = get_udatamodel();
14497c478bd9Sstevel@tonic-gate 	STRUCT_INIT(user_info, model);
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 	if (copyin(data, STRUCT_BUF(user_info), STRUCT_SIZE(user_info)))
14527c478bd9Sstevel@tonic-gate 		return (EFAULT);
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate 	mutex_enter(&pidlock);	/* lock the process queue against updates */
14557c478bd9Sstevel@tonic-gate 	for (p = practive; p != NULL; p = p->p_next) {
14567c478bd9Sstevel@tonic-gate 		cred_t	*cr;
14577c478bd9Sstevel@tonic-gate 
14587c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);	/* so process doesn't go away */
14597c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_crlock);
14607c478bd9Sstevel@tonic-gate 		crhold(cr = p->p_cred);
14617c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_crlock);
14627c478bd9Sstevel@tonic-gate 		ainfo = crgetauinfo(cr);
14637c478bd9Sstevel@tonic-gate 		if (ainfo == NULL) {
14647c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
14657c478bd9Sstevel@tonic-gate 			crfree(cr);
14667c478bd9Sstevel@tonic-gate 			continue;
14677c478bd9Sstevel@tonic-gate 		}
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate 		if (ainfo->ai_asid == STRUCT_FGET(user_info, ai_asid)) {
14707c478bd9Sstevel@tonic-gate 			au_mask_t	mask;
14717c478bd9Sstevel@tonic-gate 			int		err;
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate 			/*
14747c478bd9Sstevel@tonic-gate 			 * Here's a process which matches the specified asid.
14757c478bd9Sstevel@tonic-gate 			 * If its mask doesn't already match the new mask,
14767c478bd9Sstevel@tonic-gate 			 * save the new mask in the pad, to be picked up
14777c478bd9Sstevel@tonic-gate 			 * next syscall.
14787c478bd9Sstevel@tonic-gate 			 */
14797c478bd9Sstevel@tonic-gate 			mask = STRUCT_FGET(user_info, ai_mask);
14807c478bd9Sstevel@tonic-gate 			err = bcmp(&mask, &ainfo->ai_mask, sizeof (au_mask_t));
14817c478bd9Sstevel@tonic-gate 			crfree(cr);
14827c478bd9Sstevel@tonic-gate 			if (err != 0) {
14837c478bd9Sstevel@tonic-gate 				struct p_audit_data *pad = P2A(p);
14847c478bd9Sstevel@tonic-gate 				ASSERT(pad != NULL);
14857c478bd9Sstevel@tonic-gate 
14867c478bd9Sstevel@tonic-gate 				mutex_enter(&(pad->pad_lock));
14877c478bd9Sstevel@tonic-gate 				pad->pad_flags |= PAD_SETMASK;
14887c478bd9Sstevel@tonic-gate 				pad->pad_newmask = mask;
14897c478bd9Sstevel@tonic-gate 				mutex_exit(&(pad->pad_lock));
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate 				/*
14927c478bd9Sstevel@tonic-gate 				 * No need to call set_proc_pre_sys(), since
14937c478bd9Sstevel@tonic-gate 				 * t_pre_sys is ALWAYS on when audit is
14947c478bd9Sstevel@tonic-gate 				 * enabled...due to syscall auditing.
14957c478bd9Sstevel@tonic-gate 				 */
14967c478bd9Sstevel@tonic-gate 			}
14977c478bd9Sstevel@tonic-gate 		} else {
14987c478bd9Sstevel@tonic-gate 			crfree(cr);
14997c478bd9Sstevel@tonic-gate 		}
15007c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
15017c478bd9Sstevel@tonic-gate 	}
15027c478bd9Sstevel@tonic-gate 	mutex_exit(&pidlock);
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate 	return (0);
15057c478bd9Sstevel@tonic-gate }
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate /*
15087c478bd9Sstevel@tonic-gate  * Get the current audit state of the system
15097c478bd9Sstevel@tonic-gate  */
15107c478bd9Sstevel@tonic-gate static int
15117c478bd9Sstevel@tonic-gate getcond(caddr_t data)
15127c478bd9Sstevel@tonic-gate {
15137c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx;
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 	if (au_auditstate == AUC_DISABLED)
15167c478bd9Sstevel@tonic-gate 		if (copyout(&au_auditstate, data, sizeof (int)))
15177c478bd9Sstevel@tonic-gate 			return (EFAULT);
15187c478bd9Sstevel@tonic-gate 
15197c478bd9Sstevel@tonic-gate 	kctx = SET_KCTX_PZ;
15207c478bd9Sstevel@tonic-gate 
15217c478bd9Sstevel@tonic-gate 	if (copyout(&(kctx->auk_auditstate), data, sizeof (int)))
15227c478bd9Sstevel@tonic-gate 		return (EFAULT);
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate 	return (0);
15257c478bd9Sstevel@tonic-gate }
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate /*
15287c478bd9Sstevel@tonic-gate  * Set the current audit state of the system to on (AUC_AUDITING) or
15297c478bd9Sstevel@tonic-gate  * off (AUC_NOAUDIT).
15307c478bd9Sstevel@tonic-gate  */
15317c478bd9Sstevel@tonic-gate /* ARGSUSED */
15327c478bd9Sstevel@tonic-gate static int
15337c478bd9Sstevel@tonic-gate setcond(caddr_t data)
15347c478bd9Sstevel@tonic-gate {
15357c478bd9Sstevel@tonic-gate 	int	auditstate;
15367c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx;
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate 	if (!(audit_policy & AUDIT_PERZONE) && (!INGLOBALZONE(curproc)))
15397c478bd9Sstevel@tonic-gate 		return (EINVAL);
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate 	kctx = SET_KCTX_LZ;
15427c478bd9Sstevel@tonic-gate 
15437c478bd9Sstevel@tonic-gate 	if (copyin(data, &auditstate, sizeof (int)))
15447c478bd9Sstevel@tonic-gate 		return (EFAULT);
15457c478bd9Sstevel@tonic-gate 
15467c478bd9Sstevel@tonic-gate 	switch (auditstate) {
15477c478bd9Sstevel@tonic-gate 	case AUC_AUDITING:		/* Turn auditing on */
15487c478bd9Sstevel@tonic-gate 		kctx->auk_auditstate = AUC_AUDITING;
15497c478bd9Sstevel@tonic-gate 		au_auditstate = AUC_ENABLED;
15507c478bd9Sstevel@tonic-gate 		break;
15517c478bd9Sstevel@tonic-gate 
15527c478bd9Sstevel@tonic-gate 	case AUC_NOAUDIT:		/* Turn auditing off */
15537c478bd9Sstevel@tonic-gate 		if (kctx->auk_auditstate == AUC_NOAUDIT)
15547c478bd9Sstevel@tonic-gate 			break;
15557c478bd9Sstevel@tonic-gate 		kctx->auk_auditstate = AUC_NOAUDIT;
15567c478bd9Sstevel@tonic-gate 
15577c478bd9Sstevel@tonic-gate 		/* clear out the audit queue */
15587c478bd9Sstevel@tonic-gate 
15597c478bd9Sstevel@tonic-gate 		mutex_enter(&(kctx->auk_queue.lock));
15607c478bd9Sstevel@tonic-gate 		if (kctx->auk_queue.wt_block)
15617c478bd9Sstevel@tonic-gate 			cv_broadcast(&(kctx->auk_queue.write_cv));
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate 		/* unblock au_output_thread */
15647c478bd9Sstevel@tonic-gate 		cv_broadcast(&(kctx->auk_queue.read_cv));
15657c478bd9Sstevel@tonic-gate 
15667c478bd9Sstevel@tonic-gate 		mutex_exit(&(kctx->auk_queue.lock));
15677c478bd9Sstevel@tonic-gate 		break;
15687c478bd9Sstevel@tonic-gate 
15697c478bd9Sstevel@tonic-gate 	default:
15707c478bd9Sstevel@tonic-gate 		return (EINVAL);
15717c478bd9Sstevel@tonic-gate 	}
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 	return (0);
15747c478bd9Sstevel@tonic-gate }
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate static int
15777c478bd9Sstevel@tonic-gate getclass(caddr_t data)
15787c478bd9Sstevel@tonic-gate {
15797c478bd9Sstevel@tonic-gate 	au_evclass_map_t event;
15807c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx = SET_KCTX_PZ;
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate 	if (copyin(data, &event, sizeof (au_evclass_map_t)))
15837c478bd9Sstevel@tonic-gate 		return (EFAULT);
15847c478bd9Sstevel@tonic-gate 
15857c478bd9Sstevel@tonic-gate 	if (event.ec_number < 0 || event.ec_number > (au_naevent - 1))
15867c478bd9Sstevel@tonic-gate 		return (EINVAL);
15877c478bd9Sstevel@tonic-gate 
15887c478bd9Sstevel@tonic-gate 	event.ec_class = kctx->auk_ets[event.ec_number];
15897c478bd9Sstevel@tonic-gate 
15907c478bd9Sstevel@tonic-gate 	if (copyout(&event, data, sizeof (au_evclass_map_t)))
15917c478bd9Sstevel@tonic-gate 		return (EFAULT);
15927c478bd9Sstevel@tonic-gate 
15937c478bd9Sstevel@tonic-gate 	return (0);
15947c478bd9Sstevel@tonic-gate }
15957c478bd9Sstevel@tonic-gate 
15967c478bd9Sstevel@tonic-gate static int
15977c478bd9Sstevel@tonic-gate setclass(caddr_t data)
15987c478bd9Sstevel@tonic-gate {
15997c478bd9Sstevel@tonic-gate 	au_evclass_map_t event;
16007c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx;
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 	if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc))
16037c478bd9Sstevel@tonic-gate 		return (EINVAL);
16047c478bd9Sstevel@tonic-gate 
16057c478bd9Sstevel@tonic-gate 	kctx = SET_KCTX_LZ;
16067c478bd9Sstevel@tonic-gate 
16077c478bd9Sstevel@tonic-gate 	if (copyin(data, &event, sizeof (au_evclass_map_t)))
16087c478bd9Sstevel@tonic-gate 		return (EFAULT);
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate 	if (event.ec_number < 0 || event.ec_number > (au_naevent - 1))
16117c478bd9Sstevel@tonic-gate 		return (EINVAL);
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate 	kctx->auk_ets[event.ec_number] = event.ec_class;
16147c478bd9Sstevel@tonic-gate 
16157c478bd9Sstevel@tonic-gate 	return (0);
16167c478bd9Sstevel@tonic-gate }
16177c478bd9Sstevel@tonic-gate 
16187c478bd9Sstevel@tonic-gate static int
16197c478bd9Sstevel@tonic-gate getpinfo(caddr_t data)
16207c478bd9Sstevel@tonic-gate {
16217c478bd9Sstevel@tonic-gate 	STRUCT_DECL(auditpinfo, apinfo);
16227c478bd9Sstevel@tonic-gate 	proc_t *proc;
16237c478bd9Sstevel@tonic-gate 	const auditinfo_addr_t	*ainfo;
16247c478bd9Sstevel@tonic-gate 	model_t	model;
16257c478bd9Sstevel@tonic-gate 	cred_t	*cr, *newcred;
16267c478bd9Sstevel@tonic-gate 
16277c478bd9Sstevel@tonic-gate 	model = get_udatamodel();
16287c478bd9Sstevel@tonic-gate 	STRUCT_INIT(apinfo, model);
16297c478bd9Sstevel@tonic-gate 
16307c478bd9Sstevel@tonic-gate 	if (copyin(data, STRUCT_BUF(apinfo), STRUCT_SIZE(apinfo)))
16317c478bd9Sstevel@tonic-gate 		return (EFAULT);
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate 	newcred = cralloc();
16347c478bd9Sstevel@tonic-gate 
16357c478bd9Sstevel@tonic-gate 	mutex_enter(&pidlock);
16367c478bd9Sstevel@tonic-gate 	if ((proc = prfind(STRUCT_FGET(apinfo, ap_pid))) == NULL) {
16377c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
16387c478bd9Sstevel@tonic-gate 		crfree(newcred);
16397c478bd9Sstevel@tonic-gate 		return (ESRCH);		/* no such process */
16407c478bd9Sstevel@tonic-gate 	}
16417c478bd9Sstevel@tonic-gate 	mutex_enter(&proc->p_lock);	/* so process doesn't go away */
16427c478bd9Sstevel@tonic-gate 	mutex_exit(&pidlock);
16437c478bd9Sstevel@tonic-gate 
16447c478bd9Sstevel@tonic-gate 	audit_update_context(proc, newcred);	/* make sure it's up-to-date */
16457c478bd9Sstevel@tonic-gate 
16467c478bd9Sstevel@tonic-gate 	mutex_enter(&proc->p_crlock);
16477c478bd9Sstevel@tonic-gate 	crhold(cr = proc->p_cred);
16487c478bd9Sstevel@tonic-gate 	mutex_exit(&proc->p_crlock);
16497c478bd9Sstevel@tonic-gate 	mutex_exit(&proc->p_lock);
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 	ainfo = crgetauinfo(cr);
16527c478bd9Sstevel@tonic-gate 	if (ainfo == NULL) {
16537c478bd9Sstevel@tonic-gate 		crfree(cr);
16547c478bd9Sstevel@tonic-gate 		return (EINVAL);
16557c478bd9Sstevel@tonic-gate 	}
16567c478bd9Sstevel@tonic-gate 
16577c478bd9Sstevel@tonic-gate 	/* designated process has an ipv6 address? */
16587c478bd9Sstevel@tonic-gate 	if (ainfo->ai_termid.at_type == AU_IPv6) {
16597c478bd9Sstevel@tonic-gate 		crfree(cr);
16607c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
16617c478bd9Sstevel@tonic-gate 	}
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 	STRUCT_FSET(apinfo, ap_auid, ainfo->ai_auid);
16647c478bd9Sstevel@tonic-gate 	STRUCT_FSET(apinfo, ap_asid, ainfo->ai_asid);
16657c478bd9Sstevel@tonic-gate #ifdef _LP64
16667c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_ILP32) {
16677c478bd9Sstevel@tonic-gate 		dev32_t dev;
16687c478bd9Sstevel@tonic-gate 		/* convert internal 64 bit form to 32 bit version */
16697c478bd9Sstevel@tonic-gate 		if (cmpldev(&dev, ainfo->ai_termid.at_port) == 0) {
16707c478bd9Sstevel@tonic-gate 			crfree(cr);
16717c478bd9Sstevel@tonic-gate 			return (EOVERFLOW);
16727c478bd9Sstevel@tonic-gate 		}
16737c478bd9Sstevel@tonic-gate 		STRUCT_FSET(apinfo, ap_termid.port, dev);
16747c478bd9Sstevel@tonic-gate 	} else
16757c478bd9Sstevel@tonic-gate 		STRUCT_FSET(apinfo, ap_termid.port, ainfo->ai_termid.at_port);
16767c478bd9Sstevel@tonic-gate #else
16777c478bd9Sstevel@tonic-gate 	STRUCT_FSET(apinfo, ap_termid.port, ainfo->ai_termid.at_port);
16787c478bd9Sstevel@tonic-gate #endif
16797c478bd9Sstevel@tonic-gate 	STRUCT_FSET(apinfo, ap_termid.machine, ainfo->ai_termid.at_addr[0]);
16807c478bd9Sstevel@tonic-gate 	STRUCT_FSET(apinfo, ap_mask, ainfo->ai_mask);
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 	crfree(cr);
16837c478bd9Sstevel@tonic-gate 
16847c478bd9Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(apinfo), data, STRUCT_SIZE(apinfo)))
16857c478bd9Sstevel@tonic-gate 		return (EFAULT);
16867c478bd9Sstevel@tonic-gate 
16877c478bd9Sstevel@tonic-gate 	return (0);
16887c478bd9Sstevel@tonic-gate }
16897c478bd9Sstevel@tonic-gate 
16907c478bd9Sstevel@tonic-gate static int
16917c478bd9Sstevel@tonic-gate getpinfo_addr(caddr_t data, int len)
16927c478bd9Sstevel@tonic-gate {
16937c478bd9Sstevel@tonic-gate 	STRUCT_DECL(auditpinfo_addr, apinfo);
16947c478bd9Sstevel@tonic-gate 	proc_t *proc;
16957c478bd9Sstevel@tonic-gate 	const auditinfo_addr_t	*ainfo;
16967c478bd9Sstevel@tonic-gate 	model_t	model;
16977c478bd9Sstevel@tonic-gate 	cred_t	*cr, *newcred;
16987c478bd9Sstevel@tonic-gate 
16997c478bd9Sstevel@tonic-gate 	model = get_udatamodel();
17007c478bd9Sstevel@tonic-gate 	STRUCT_INIT(apinfo, model);
17017c478bd9Sstevel@tonic-gate 
17027c478bd9Sstevel@tonic-gate 	if (len < STRUCT_SIZE(apinfo))
17037c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 	if (copyin(data, STRUCT_BUF(apinfo), STRUCT_SIZE(apinfo)))
17067c478bd9Sstevel@tonic-gate 		return (EFAULT);
17077c478bd9Sstevel@tonic-gate 
17087c478bd9Sstevel@tonic-gate 	newcred = cralloc();
17097c478bd9Sstevel@tonic-gate 
17107c478bd9Sstevel@tonic-gate 	mutex_enter(&pidlock);
17117c478bd9Sstevel@tonic-gate 	if ((proc = prfind(STRUCT_FGET(apinfo, ap_pid))) == NULL) {
17127c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
17137c478bd9Sstevel@tonic-gate 		crfree(newcred);
17147c478bd9Sstevel@tonic-gate 		return (ESRCH);
17157c478bd9Sstevel@tonic-gate 	}
17167c478bd9Sstevel@tonic-gate 	mutex_enter(&proc->p_lock);	/* so process doesn't go away */
17177c478bd9Sstevel@tonic-gate 	mutex_exit(&pidlock);
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate 	audit_update_context(proc, newcred);	/* make sure it's up-to-date */
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate 	mutex_enter(&proc->p_crlock);
17227c478bd9Sstevel@tonic-gate 	crhold(cr = proc->p_cred);
17237c478bd9Sstevel@tonic-gate 	mutex_exit(&proc->p_crlock);
17247c478bd9Sstevel@tonic-gate 	mutex_exit(&proc->p_lock);
17257c478bd9Sstevel@tonic-gate 
17267c478bd9Sstevel@tonic-gate 	ainfo = crgetauinfo(cr);
17277c478bd9Sstevel@tonic-gate 	if (ainfo == NULL) {
17287c478bd9Sstevel@tonic-gate 		crfree(cr);
17297c478bd9Sstevel@tonic-gate 		return (EINVAL);
17307c478bd9Sstevel@tonic-gate 	}
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate 	STRUCT_FSET(apinfo, ap_auid, ainfo->ai_auid);
17337c478bd9Sstevel@tonic-gate 	STRUCT_FSET(apinfo, ap_asid, ainfo->ai_asid);
17347c478bd9Sstevel@tonic-gate #ifdef _LP64
17357c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_ILP32) {
17367c478bd9Sstevel@tonic-gate 		dev32_t dev;
17377c478bd9Sstevel@tonic-gate 		/* convert internal 64 bit form to 32 bit version */
17387c478bd9Sstevel@tonic-gate 		if (cmpldev(&dev, ainfo->ai_termid.at_port) == 0) {
17397c478bd9Sstevel@tonic-gate 			crfree(cr);
17407c478bd9Sstevel@tonic-gate 			return (EOVERFLOW);
17417c478bd9Sstevel@tonic-gate 		}
17427c478bd9Sstevel@tonic-gate 		STRUCT_FSET(apinfo, ap_termid.at_port, dev);
17437c478bd9Sstevel@tonic-gate 	} else
17447c478bd9Sstevel@tonic-gate 		STRUCT_FSET(apinfo, ap_termid.at_port,
17457c478bd9Sstevel@tonic-gate 		    ainfo->ai_termid.at_port);
17467c478bd9Sstevel@tonic-gate #else
17477c478bd9Sstevel@tonic-gate 	STRUCT_FSET(apinfo, ap_termid.at_port, ainfo->ai_termid.at_port);
17487c478bd9Sstevel@tonic-gate #endif
17497c478bd9Sstevel@tonic-gate 	STRUCT_FSET(apinfo, ap_termid.at_type, ainfo->ai_termid.at_type);
17507c478bd9Sstevel@tonic-gate 	STRUCT_FSET(apinfo, ap_termid.at_addr[0], ainfo->ai_termid.at_addr[0]);
17517c478bd9Sstevel@tonic-gate 	STRUCT_FSET(apinfo, ap_termid.at_addr[1], ainfo->ai_termid.at_addr[1]);
17527c478bd9Sstevel@tonic-gate 	STRUCT_FSET(apinfo, ap_termid.at_addr[2], ainfo->ai_termid.at_addr[2]);
17537c478bd9Sstevel@tonic-gate 	STRUCT_FSET(apinfo, ap_termid.at_addr[3], ainfo->ai_termid.at_addr[3]);
17547c478bd9Sstevel@tonic-gate 	STRUCT_FSET(apinfo, ap_mask, ainfo->ai_mask);
17557c478bd9Sstevel@tonic-gate 
17567c478bd9Sstevel@tonic-gate 	crfree(cr);
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(apinfo), data, STRUCT_SIZE(apinfo)))
17597c478bd9Sstevel@tonic-gate 		return (EFAULT);
17607c478bd9Sstevel@tonic-gate 
17617c478bd9Sstevel@tonic-gate 	return (0);
17627c478bd9Sstevel@tonic-gate }
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate static int
17657c478bd9Sstevel@tonic-gate setpmask(caddr_t data)
17667c478bd9Sstevel@tonic-gate {
17677c478bd9Sstevel@tonic-gate 	STRUCT_DECL(auditpinfo, apinfo);
17687c478bd9Sstevel@tonic-gate 	proc_t *proc;
17697c478bd9Sstevel@tonic-gate 	cred_t	*newcred;
17707c478bd9Sstevel@tonic-gate 	auditinfo_addr_t	*ainfo;
17717c478bd9Sstevel@tonic-gate 	struct p_audit_data	*pad;
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 	model_t	model;
17747c478bd9Sstevel@tonic-gate 
17757c478bd9Sstevel@tonic-gate 	model = get_udatamodel();
17767c478bd9Sstevel@tonic-gate 	STRUCT_INIT(apinfo, model);
17777c478bd9Sstevel@tonic-gate 
17787c478bd9Sstevel@tonic-gate 	if (copyin(data, STRUCT_BUF(apinfo), STRUCT_SIZE(apinfo)))
17797c478bd9Sstevel@tonic-gate 		return (EFAULT);
17807c478bd9Sstevel@tonic-gate 
17817c478bd9Sstevel@tonic-gate 	mutex_enter(&pidlock);
17827c478bd9Sstevel@tonic-gate 	if ((proc = prfind(STRUCT_FGET(apinfo, ap_pid))) == NULL) {
17837c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
17847c478bd9Sstevel@tonic-gate 		return (ESRCH);
17857c478bd9Sstevel@tonic-gate 	}
17867c478bd9Sstevel@tonic-gate 	mutex_enter(&proc->p_lock);	/* so process doesn't go away */
17877c478bd9Sstevel@tonic-gate 	mutex_exit(&pidlock);
17887c478bd9Sstevel@tonic-gate 
17897c478bd9Sstevel@tonic-gate 	newcred = cralloc();
17907c478bd9Sstevel@tonic-gate 	if ((ainfo = crgetauinfo_modifiable(newcred)) == NULL) {
17917c478bd9Sstevel@tonic-gate 		mutex_exit(&proc->p_lock);
17927c478bd9Sstevel@tonic-gate 		crfree(newcred);
17937c478bd9Sstevel@tonic-gate 		return (EINVAL);
17947c478bd9Sstevel@tonic-gate 	}
17957c478bd9Sstevel@tonic-gate 
17967c478bd9Sstevel@tonic-gate 	mutex_enter(&proc->p_crlock);
17977c478bd9Sstevel@tonic-gate 	crcopy_to(proc->p_cred, newcred);
17987c478bd9Sstevel@tonic-gate 	proc->p_cred = newcred;
17997c478bd9Sstevel@tonic-gate 
18007c478bd9Sstevel@tonic-gate 	ainfo->ai_mask = STRUCT_FGET(apinfo, ap_mask);
18017c478bd9Sstevel@tonic-gate 
18027c478bd9Sstevel@tonic-gate 	/*
18037c478bd9Sstevel@tonic-gate 	 * Unlock. No need to broadcast changes via set_proc_pre_sys(),
18047c478bd9Sstevel@tonic-gate 	 * since t_pre_sys is ALWAYS on when audit is enabled... due to
18057c478bd9Sstevel@tonic-gate 	 * syscall auditing.
18067c478bd9Sstevel@tonic-gate 	 */
18077c478bd9Sstevel@tonic-gate 	crfree(newcred);
18087c478bd9Sstevel@tonic-gate 	mutex_exit(&proc->p_crlock);
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate 	/* Reset flag for any previous pending mask change; this supercedes */
18117c478bd9Sstevel@tonic-gate 	pad = P2A(proc);
18127c478bd9Sstevel@tonic-gate 	ASSERT(pad != NULL);
18137c478bd9Sstevel@tonic-gate 	mutex_enter(&(pad->pad_lock));
18147c478bd9Sstevel@tonic-gate 	pad->pad_flags &= ~PAD_SETMASK;
18157c478bd9Sstevel@tonic-gate 	mutex_exit(&(pad->pad_lock));
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate 	mutex_exit(&proc->p_lock);
18187c478bd9Sstevel@tonic-gate 
18197c478bd9Sstevel@tonic-gate 	return (0);
18207c478bd9Sstevel@tonic-gate }
18217c478bd9Sstevel@tonic-gate 
18227c478bd9Sstevel@tonic-gate static int
18237c478bd9Sstevel@tonic-gate getfsize(caddr_t data)
18247c478bd9Sstevel@tonic-gate {
18257c478bd9Sstevel@tonic-gate 	au_fstat_t fstat;
18267c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx = SET_KCTX_PZ;
18277c478bd9Sstevel@tonic-gate 
18287c478bd9Sstevel@tonic-gate 	mutex_enter(&(kctx->auk_fstat_lock));
18297c478bd9Sstevel@tonic-gate 	fstat.af_filesz = kctx->auk_file_stat.af_filesz;
18307c478bd9Sstevel@tonic-gate 	fstat.af_currsz = kctx->auk_file_stat.af_currsz;
18317c478bd9Sstevel@tonic-gate 	mutex_exit(&(kctx->auk_fstat_lock));
18327c478bd9Sstevel@tonic-gate 
18337c478bd9Sstevel@tonic-gate 	if (copyout(&fstat, data, sizeof (au_fstat_t)))
18347c478bd9Sstevel@tonic-gate 		return (EFAULT);
18357c478bd9Sstevel@tonic-gate 
18367c478bd9Sstevel@tonic-gate 	return (0);
18377c478bd9Sstevel@tonic-gate }
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate static int
18407c478bd9Sstevel@tonic-gate setfsize(caddr_t data)
18417c478bd9Sstevel@tonic-gate {
18427c478bd9Sstevel@tonic-gate 	au_fstat_t fstat;
18437c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx;
18447c478bd9Sstevel@tonic-gate 
18457c478bd9Sstevel@tonic-gate 	if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc))
18467c478bd9Sstevel@tonic-gate 		return (EINVAL);
18477c478bd9Sstevel@tonic-gate 
18487c478bd9Sstevel@tonic-gate 	kctx = SET_KCTX_LZ;
18497c478bd9Sstevel@tonic-gate 
18507c478bd9Sstevel@tonic-gate 	if (copyin(data, &fstat, sizeof (au_fstat_t)))
18517c478bd9Sstevel@tonic-gate 		return (EFAULT);
18527c478bd9Sstevel@tonic-gate 
18537c478bd9Sstevel@tonic-gate 	if ((fstat.af_filesz != 0) && (fstat.af_filesz < AU_MIN_FILE_SZ))
18547c478bd9Sstevel@tonic-gate 		return (EINVAL);
18557c478bd9Sstevel@tonic-gate 
18567c478bd9Sstevel@tonic-gate 	mutex_enter(&(kctx->auk_fstat_lock));
18577c478bd9Sstevel@tonic-gate 	kctx->auk_file_stat.af_filesz = fstat.af_filesz;
18587c478bd9Sstevel@tonic-gate 	mutex_exit(&(kctx->auk_fstat_lock));
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 	return (0);
18617c478bd9Sstevel@tonic-gate }
18627c478bd9Sstevel@tonic-gate /*
18637c478bd9Sstevel@tonic-gate  * The out of control system call
18647c478bd9Sstevel@tonic-gate  * This is audit kitchen sink aka auditadm, aka auditon
18657c478bd9Sstevel@tonic-gate  */
18667c478bd9Sstevel@tonic-gate static int
18677c478bd9Sstevel@tonic-gate auditctl(
18687c478bd9Sstevel@tonic-gate 	int	cmd,
18697c478bd9Sstevel@tonic-gate 	caddr_t data,
18707c478bd9Sstevel@tonic-gate 	int	length)
18717c478bd9Sstevel@tonic-gate {
18727c478bd9Sstevel@tonic-gate 	int result;
18737c478bd9Sstevel@tonic-gate 
18747c478bd9Sstevel@tonic-gate 	if (!audit_active)
18757c478bd9Sstevel@tonic-gate 		return (EINVAL);
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate 	switch (cmd) {
18787c478bd9Sstevel@tonic-gate 	case A_GETCOND:
18797c478bd9Sstevel@tonic-gate 	case A_GETCAR:
18807c478bd9Sstevel@tonic-gate 	case A_GETCLASS:
18817c478bd9Sstevel@tonic-gate 	case A_GETCWD:
18827c478bd9Sstevel@tonic-gate 	case A_GETFSIZE:
18837c478bd9Sstevel@tonic-gate 	case A_GETKAUDIT:
18847c478bd9Sstevel@tonic-gate 	case A_GETKMASK:
18857c478bd9Sstevel@tonic-gate 	case A_GETPINFO:
18867c478bd9Sstevel@tonic-gate 	case A_GETPINFO_ADDR:
18877c478bd9Sstevel@tonic-gate 	case A_GETPOLICY:
18887c478bd9Sstevel@tonic-gate 	case A_GETQCTRL:
18897c478bd9Sstevel@tonic-gate 	case A_GETSTAT:
18907c478bd9Sstevel@tonic-gate 		if (secpolicy_audit_getattr(CRED()) != 0)
18917c478bd9Sstevel@tonic-gate 			return (EPERM);
18927c478bd9Sstevel@tonic-gate 		break;
18937c478bd9Sstevel@tonic-gate 	default:
18947c478bd9Sstevel@tonic-gate 		if (secpolicy_audit_config(CRED()) != 0)
18957c478bd9Sstevel@tonic-gate 			return (EPERM);
18967c478bd9Sstevel@tonic-gate 		break;
18977c478bd9Sstevel@tonic-gate 	}
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 	switch (cmd) {
19007c478bd9Sstevel@tonic-gate 	case A_GETPOLICY:
19017c478bd9Sstevel@tonic-gate 		result = getpolicy(data);
19027c478bd9Sstevel@tonic-gate 		break;
19037c478bd9Sstevel@tonic-gate 	case A_SETPOLICY:
19047c478bd9Sstevel@tonic-gate 		result = setpolicy(data);
19057c478bd9Sstevel@tonic-gate 		break;
19067c478bd9Sstevel@tonic-gate 	case A_GETKMASK:
19077c478bd9Sstevel@tonic-gate 		result = getkmask(data);
19087c478bd9Sstevel@tonic-gate 		break;
19097c478bd9Sstevel@tonic-gate 	case A_SETKMASK:
19107c478bd9Sstevel@tonic-gate 		result = setkmask(data);
19117c478bd9Sstevel@tonic-gate 		break;
19127c478bd9Sstevel@tonic-gate 	case A_GETKAUDIT:
19137c478bd9Sstevel@tonic-gate 		result = getkaudit(data, length);
19147c478bd9Sstevel@tonic-gate 		break;
19157c478bd9Sstevel@tonic-gate 	case A_SETKAUDIT:
19167c478bd9Sstevel@tonic-gate 		result = setkaudit(data, length);
19177c478bd9Sstevel@tonic-gate 		break;
19187c478bd9Sstevel@tonic-gate 	case A_GETQCTRL:
19197c478bd9Sstevel@tonic-gate 		result = getqctrl(data);
19207c478bd9Sstevel@tonic-gate 		break;
19217c478bd9Sstevel@tonic-gate 	case A_SETQCTRL:
19227c478bd9Sstevel@tonic-gate 		result = setqctrl(data);
19237c478bd9Sstevel@tonic-gate 		break;
19247c478bd9Sstevel@tonic-gate 	case A_GETCWD:
19257c478bd9Sstevel@tonic-gate 		result = getcwd(data, length);
19267c478bd9Sstevel@tonic-gate 		break;
19277c478bd9Sstevel@tonic-gate 	case A_GETCAR:
19287c478bd9Sstevel@tonic-gate 		result = getcar(data, length);
19297c478bd9Sstevel@tonic-gate 		break;
19307c478bd9Sstevel@tonic-gate 	case A_GETSTAT:
19317c478bd9Sstevel@tonic-gate 		result = getstat(data);
19327c478bd9Sstevel@tonic-gate 		break;
19337c478bd9Sstevel@tonic-gate 	case A_SETSTAT:
19347c478bd9Sstevel@tonic-gate 		result = setstat(data);
19357c478bd9Sstevel@tonic-gate 		break;
19367c478bd9Sstevel@tonic-gate 	case A_SETUMASK:
19377c478bd9Sstevel@tonic-gate 		result = setumask(data);
19387c478bd9Sstevel@tonic-gate 		break;
19397c478bd9Sstevel@tonic-gate 	case A_SETSMASK:
19407c478bd9Sstevel@tonic-gate 		result = setsmask(data);
19417c478bd9Sstevel@tonic-gate 		break;
19427c478bd9Sstevel@tonic-gate 	case A_GETCOND:
19437c478bd9Sstevel@tonic-gate 		result = getcond(data);
19447c478bd9Sstevel@tonic-gate 		break;
19457c478bd9Sstevel@tonic-gate 	case A_SETCOND:
19467c478bd9Sstevel@tonic-gate 		result = setcond(data);
19477c478bd9Sstevel@tonic-gate 		break;
19487c478bd9Sstevel@tonic-gate 	case A_GETCLASS:
19497c478bd9Sstevel@tonic-gate 		result = getclass(data);
19507c478bd9Sstevel@tonic-gate 		break;
19517c478bd9Sstevel@tonic-gate 	case A_SETCLASS:
19527c478bd9Sstevel@tonic-gate 		result = setclass(data);
19537c478bd9Sstevel@tonic-gate 		break;
19547c478bd9Sstevel@tonic-gate 	case A_GETPINFO:
19557c478bd9Sstevel@tonic-gate 		result = getpinfo(data);
19567c478bd9Sstevel@tonic-gate 		break;
19577c478bd9Sstevel@tonic-gate 	case A_GETPINFO_ADDR:
19587c478bd9Sstevel@tonic-gate 		result = getpinfo_addr(data, length);
19597c478bd9Sstevel@tonic-gate 		break;
19607c478bd9Sstevel@tonic-gate 	case A_SETPMASK:
19617c478bd9Sstevel@tonic-gate 		result = setpmask(data);
19627c478bd9Sstevel@tonic-gate 		break;
19637c478bd9Sstevel@tonic-gate 	case A_SETFSIZE:
19647c478bd9Sstevel@tonic-gate 		result = setfsize(data);
19657c478bd9Sstevel@tonic-gate 		break;
19667c478bd9Sstevel@tonic-gate 	case A_GETFSIZE:
19677c478bd9Sstevel@tonic-gate 		result = getfsize(data);
19687c478bd9Sstevel@tonic-gate 		break;
19697c478bd9Sstevel@tonic-gate 	default:
19707c478bd9Sstevel@tonic-gate 		result = EINVAL;
19717c478bd9Sstevel@tonic-gate 		break;
19727c478bd9Sstevel@tonic-gate 	}
19737c478bd9Sstevel@tonic-gate 	return (result);
19747c478bd9Sstevel@tonic-gate }
19757c478bd9Sstevel@tonic-gate 
19767c478bd9Sstevel@tonic-gate /*
19777c478bd9Sstevel@tonic-gate  * auditsvc was EOL'd effective Sol 10
19787c478bd9Sstevel@tonic-gate  */
19797c478bd9Sstevel@tonic-gate static int
19807c478bd9Sstevel@tonic-gate auditsvc(int fd, int limit)
19817c478bd9Sstevel@tonic-gate {
19827c478bd9Sstevel@tonic-gate 	struct file *fp;
19837c478bd9Sstevel@tonic-gate 	struct vnode *vp;
19847c478bd9Sstevel@tonic-gate 	int error = 0;
19857c478bd9Sstevel@tonic-gate 	au_kcontext_t	*kctx;
19867c478bd9Sstevel@tonic-gate 
19877c478bd9Sstevel@tonic-gate 	if (secpolicy_audit_config(CRED()) != 0)
19887c478bd9Sstevel@tonic-gate 		return (EPERM);
19897c478bd9Sstevel@tonic-gate 
19907c478bd9Sstevel@tonic-gate 	if (!INGLOBALZONE(curproc))
19917c478bd9Sstevel@tonic-gate 		return (EINVAL);
19927c478bd9Sstevel@tonic-gate 
19937c478bd9Sstevel@tonic-gate 	kctx = SET_KCTX_GZ;
19947c478bd9Sstevel@tonic-gate 
19957c478bd9Sstevel@tonic-gate 	if (limit < 0 ||
19967c478bd9Sstevel@tonic-gate 	    (!(kctx->auk_auditstate == AUC_AUDITING ||
19977c478bd9Sstevel@tonic-gate 	    kctx->auk_auditstate == AUC_NOSPACE)))
19987c478bd9Sstevel@tonic-gate 		return (EINVAL);
19997c478bd9Sstevel@tonic-gate 
20007c478bd9Sstevel@tonic-gate 	/*
20017c478bd9Sstevel@tonic-gate 	 * Prevent a second audit daemon from running this code
20027c478bd9Sstevel@tonic-gate 	 */
20037c478bd9Sstevel@tonic-gate 	mutex_enter(&(kctx->auk_svc_lock));
20047c478bd9Sstevel@tonic-gate 	if (kctx->auk_svc_busy) {
20057c478bd9Sstevel@tonic-gate 		mutex_exit(&(kctx->auk_svc_lock));
20067c478bd9Sstevel@tonic-gate 		return (EBUSY);
20077c478bd9Sstevel@tonic-gate 	}
20087c478bd9Sstevel@tonic-gate 	kctx->auk_svc_busy = 1;
20097c478bd9Sstevel@tonic-gate 	mutex_exit(&(kctx->auk_svc_lock));
20107c478bd9Sstevel@tonic-gate 
20117c478bd9Sstevel@tonic-gate 	/*
20127c478bd9Sstevel@tonic-gate 	 * convert file pointer to file descriptor
20137c478bd9Sstevel@tonic-gate 	 *   Note: fd ref count incremented here.
20147c478bd9Sstevel@tonic-gate 	 */
20157c478bd9Sstevel@tonic-gate 	if ((fp = (struct file *)getf(fd)) == NULL) {
20167c478bd9Sstevel@tonic-gate 		mutex_enter(&(kctx->auk_svc_lock));
20177c478bd9Sstevel@tonic-gate 		kctx->auk_svc_busy = 0;
20187c478bd9Sstevel@tonic-gate 		mutex_exit(&(kctx->auk_svc_lock));
20197c478bd9Sstevel@tonic-gate 		return (EBADF);
20207c478bd9Sstevel@tonic-gate 	}
20217c478bd9Sstevel@tonic-gate 
20227c478bd9Sstevel@tonic-gate 	vp = fp->f_vnode;
20237c478bd9Sstevel@tonic-gate 
20247c478bd9Sstevel@tonic-gate 	kctx->auk_file_stat.af_currsz = 0;
20257c478bd9Sstevel@tonic-gate 
20267c478bd9Sstevel@tonic-gate 	/*
20277c478bd9Sstevel@tonic-gate 	 * Wait for work, until a signal arrives,
20287c478bd9Sstevel@tonic-gate 	 * or until auditing is disabled.
20297c478bd9Sstevel@tonic-gate 	 */
20307c478bd9Sstevel@tonic-gate 	while (!error) {
20317c478bd9Sstevel@tonic-gate 	    if (kctx->auk_auditstate == AUC_AUDITING) {
20327c478bd9Sstevel@tonic-gate 		mutex_enter(&(kctx->auk_queue.lock));
20337c478bd9Sstevel@tonic-gate 		    /* nothing on the audit queue */
20347c478bd9Sstevel@tonic-gate 		while (kctx->auk_queue.head == NULL) {
20357c478bd9Sstevel@tonic-gate 			/* safety check. kick writer awake */
20367c478bd9Sstevel@tonic-gate 		    if (kctx->auk_queue.wt_block)
20377c478bd9Sstevel@tonic-gate 			cv_broadcast(&(kctx->auk_queue.write_cv));
20387c478bd9Sstevel@tonic-gate 			/* sleep waiting for things to to */
20397c478bd9Sstevel@tonic-gate 		    kctx->auk_queue.rd_block = 1;
20407c478bd9Sstevel@tonic-gate 		    AS_INC(as_rblocked, 1, kctx);
20417c478bd9Sstevel@tonic-gate 		    if (!cv_wait_sig(&(kctx->auk_queue.read_cv),
20427c478bd9Sstevel@tonic-gate 			&(kctx->auk_queue.lock))) {
20437c478bd9Sstevel@tonic-gate 				/* interrupted system call */
20447c478bd9Sstevel@tonic-gate 			kctx->auk_queue.rd_block = 0;
20457c478bd9Sstevel@tonic-gate 			mutex_exit(&(kctx->auk_queue.lock));
20467c478bd9Sstevel@tonic-gate 			error = ((kctx->auk_auditstate == AUC_AUDITING) ||
20477c478bd9Sstevel@tonic-gate 			    (kctx->auk_auditstate == AUC_NOSPACE)) ?
20487c478bd9Sstevel@tonic-gate 			    EINTR : EINVAL;
20497c478bd9Sstevel@tonic-gate 			mutex_enter(&(kctx->auk_svc_lock));
20507c478bd9Sstevel@tonic-gate 			kctx->auk_svc_busy = 0;
20517c478bd9Sstevel@tonic-gate 			mutex_exit(&(kctx->auk_svc_lock));
20527c478bd9Sstevel@tonic-gate 
20537c478bd9Sstevel@tonic-gate 		/* decrement file descriptor reference count */
20547c478bd9Sstevel@tonic-gate 			releasef(fd);
20557c478bd9Sstevel@tonic-gate 			(void) timeout(audit_dont_stop, kctx, au_resid);
20567c478bd9Sstevel@tonic-gate 			return (error);
20577c478bd9Sstevel@tonic-gate 		    }
20587c478bd9Sstevel@tonic-gate 		    kctx->auk_queue.rd_block = 0;
20597c478bd9Sstevel@tonic-gate 		}
20607c478bd9Sstevel@tonic-gate 		mutex_exit(&(kctx->auk_queue.lock));
20617c478bd9Sstevel@tonic-gate 
20627c478bd9Sstevel@tonic-gate 			/* do as much as we can */
20637c478bd9Sstevel@tonic-gate 		error = au_doio(vp, limit);
20647c478bd9Sstevel@tonic-gate 
20657c478bd9Sstevel@tonic-gate 		/* if we ran out of space, be sure to fire off timeout */
20667c478bd9Sstevel@tonic-gate 		if (error == ENOSPC)
20677c478bd9Sstevel@tonic-gate 			(void) timeout(audit_dont_stop, kctx, au_resid);
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 	    } else	/* auditing turned off while we slept */
20707c478bd9Sstevel@tonic-gate 		    break;
20717c478bd9Sstevel@tonic-gate 	}
20727c478bd9Sstevel@tonic-gate 
20737c478bd9Sstevel@tonic-gate 	/*
20747c478bd9Sstevel@tonic-gate 	 * decrement file descriptor reference count
20757c478bd9Sstevel@tonic-gate 	 */
20767c478bd9Sstevel@tonic-gate 	releasef(fd);
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate 	/*
20797c478bd9Sstevel@tonic-gate 	 * If auditing has been disabled quit processing
20807c478bd9Sstevel@tonic-gate 	 */
20817c478bd9Sstevel@tonic-gate 	if (!(kctx->auk_auditstate == AUC_AUDITING ||
20827c478bd9Sstevel@tonic-gate 	    kctx->auk_auditstate == AUC_NOSPACE))
20837c478bd9Sstevel@tonic-gate 		error = EINVAL;
20847c478bd9Sstevel@tonic-gate 
20857c478bd9Sstevel@tonic-gate 	mutex_enter(&(kctx->auk_svc_lock));
20867c478bd9Sstevel@tonic-gate 	kctx->auk_svc_busy = 0;
20877c478bd9Sstevel@tonic-gate 	mutex_exit(&(kctx->auk_svc_lock));
20887c478bd9Sstevel@tonic-gate 
20897c478bd9Sstevel@tonic-gate 	return (error);
20907c478bd9Sstevel@tonic-gate }
20917c478bd9Sstevel@tonic-gate 
20927c478bd9Sstevel@tonic-gate static int
20937c478bd9Sstevel@tonic-gate audit_modsysent(char *modname, int flags, int (*func)())
20947c478bd9Sstevel@tonic-gate {
20957c478bd9Sstevel@tonic-gate 	struct sysent *sysp;
20967c478bd9Sstevel@tonic-gate 	int sysnum;
20977c478bd9Sstevel@tonic-gate 	krwlock_t *kl;
20987c478bd9Sstevel@tonic-gate 
20997c478bd9Sstevel@tonic-gate 	if ((sysnum = mod_getsysnum(modname)) == -1) {
21007c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "system call missing from bind file");
21017c478bd9Sstevel@tonic-gate 		return (-1);
21027c478bd9Sstevel@tonic-gate 	}
21037c478bd9Sstevel@tonic-gate 
21047c478bd9Sstevel@tonic-gate 	kl = (krwlock_t *)kobj_zalloc(sizeof (krwlock_t), KM_SLEEP);
21057c478bd9Sstevel@tonic-gate 
21067c478bd9Sstevel@tonic-gate 	sysp = &sysent[sysnum];
21077c478bd9Sstevel@tonic-gate 	sysp->sy_narg = auditsysent.sy_narg;
21087c478bd9Sstevel@tonic-gate #ifdef _LP64
21097c478bd9Sstevel@tonic-gate 	sysp->sy_flags = (unsigned short)flags;
21107c478bd9Sstevel@tonic-gate #else
21117c478bd9Sstevel@tonic-gate 	sysp->sy_flags = (unsigned char)flags;
21127c478bd9Sstevel@tonic-gate #endif
21137c478bd9Sstevel@tonic-gate 	sysp->sy_call = func;
21147c478bd9Sstevel@tonic-gate 	sysp->sy_lock = kl;
21157c478bd9Sstevel@tonic-gate 
21167c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
21177c478bd9Sstevel@tonic-gate 	sysp = &sysent32[sysnum];
21187c478bd9Sstevel@tonic-gate 	sysp->sy_narg = auditsysent.sy_narg;
21197c478bd9Sstevel@tonic-gate 	sysp->sy_flags = (unsigned short)flags;
21207c478bd9Sstevel@tonic-gate 	sysp->sy_call = func;
21217c478bd9Sstevel@tonic-gate 	sysp->sy_lock = kl;
21227c478bd9Sstevel@tonic-gate #endif
21237c478bd9Sstevel@tonic-gate 
21247c478bd9Sstevel@tonic-gate 	rw_init(sysp->sy_lock, NULL, RW_DEFAULT, NULL);
21257c478bd9Sstevel@tonic-gate 
21267c478bd9Sstevel@tonic-gate 	return (0);
21277c478bd9Sstevel@tonic-gate }
2128