xref: /onnv-gate/usr/src/uts/common/crypto/io/cryptoadm.c (revision 11861:a63258283f8f)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55072Smcpowers  * Common Development and Distribution License (the "License").
65072Smcpowers  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*11861SMarek.Pospisil@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * The ioctl interface for administrative commands.
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/modctl.h>
330Sstevel@tonic-gate #include <sys/conf.h>
340Sstevel@tonic-gate #include <sys/stat.h>
350Sstevel@tonic-gate #include <sys/ddi.h>
360Sstevel@tonic-gate #include <sys/sunddi.h>
370Sstevel@tonic-gate #include <sys/kmem.h>
380Sstevel@tonic-gate #include <sys/errno.h>
390Sstevel@tonic-gate #include <sys/ksynch.h>
400Sstevel@tonic-gate #include <sys/file.h>
410Sstevel@tonic-gate #include <sys/open.h>
420Sstevel@tonic-gate #include <sys/cred.h>
430Sstevel@tonic-gate #include <sys/model.h>
440Sstevel@tonic-gate #include <sys/sysmacros.h>
450Sstevel@tonic-gate #include <sys/crypto/common.h>
460Sstevel@tonic-gate #include <sys/crypto/api.h>
470Sstevel@tonic-gate #include <sys/crypto/impl.h>
480Sstevel@tonic-gate #include <sys/crypto/sched_impl.h>
490Sstevel@tonic-gate #include <sys/crypto/ioctladmin.h>
500Sstevel@tonic-gate #include <c2/audit.h>
5110732SAnthony.Scarpino@Sun.COM #include <sys/disp.h>
520Sstevel@tonic-gate 
530Sstevel@tonic-gate /*
540Sstevel@tonic-gate  * DDI entry points.
550Sstevel@tonic-gate  */
560Sstevel@tonic-gate static int cryptoadm_attach(dev_info_t *, ddi_attach_cmd_t);
570Sstevel@tonic-gate static int cryptoadm_detach(dev_info_t *, ddi_detach_cmd_t);
580Sstevel@tonic-gate static int cryptoadm_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
590Sstevel@tonic-gate static int cryptoadm_open(dev_t *, int, int, cred_t *);
600Sstevel@tonic-gate static int cryptoadm_close(dev_t, int, int, cred_t *);
610Sstevel@tonic-gate static int cryptoadm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
620Sstevel@tonic-gate 
630Sstevel@tonic-gate extern void audit_cryptoadm(int, char *, crypto_mech_name_t *, uint_t,
640Sstevel@tonic-gate     uint_t, uint32_t, int);
6510500SHai-May.Chao@Sun.COM 
660Sstevel@tonic-gate /*
670Sstevel@tonic-gate  * Module linkage.
680Sstevel@tonic-gate  */
690Sstevel@tonic-gate static struct cb_ops cbops = {
700Sstevel@tonic-gate 	cryptoadm_open,		/* cb_open */
710Sstevel@tonic-gate 	cryptoadm_close,	/* cb_close */
720Sstevel@tonic-gate 	nodev,			/* cb_strategy */
730Sstevel@tonic-gate 	nodev,			/* cb_print */
740Sstevel@tonic-gate 	nodev,			/* cb_dump */
750Sstevel@tonic-gate 	nodev,			/* cb_read */
760Sstevel@tonic-gate 	nodev,			/* cb_write */
770Sstevel@tonic-gate 	cryptoadm_ioctl,	/* cb_ioctl */
780Sstevel@tonic-gate 	nodev,			/* cb_devmap */
790Sstevel@tonic-gate 	nodev,			/* cb_mmap */
800Sstevel@tonic-gate 	nodev,			/* cb_segmap */
810Sstevel@tonic-gate 	nochpoll,		/* cb_chpoll */
820Sstevel@tonic-gate 	ddi_prop_op,		/* cb_prop_op */
830Sstevel@tonic-gate 	NULL,			/* cb_streamtab */
840Sstevel@tonic-gate 	D_MP,			/* cb_flag */
850Sstevel@tonic-gate 	CB_REV,			/* cb_rev */
860Sstevel@tonic-gate 	nodev,			/* cb_aread */
870Sstevel@tonic-gate 	nodev,			/* cb_awrite */
880Sstevel@tonic-gate };
890Sstevel@tonic-gate 
900Sstevel@tonic-gate static struct dev_ops devops = {
910Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev */
920Sstevel@tonic-gate 	0,			/* devo_refcnt */
930Sstevel@tonic-gate 	cryptoadm_getinfo,	/* devo_getinfo */
940Sstevel@tonic-gate 	nulldev,		/* devo_identify */
950Sstevel@tonic-gate 	nulldev,		/* devo_probe */
960Sstevel@tonic-gate 	cryptoadm_attach,	/* devo_attach */
970Sstevel@tonic-gate 	cryptoadm_detach,	/* devo_detach */
980Sstevel@tonic-gate 	nodev,			/* devo_reset */
990Sstevel@tonic-gate 	&cbops,			/* devo_cb_ops */
1000Sstevel@tonic-gate 	NULL,			/* devo_bus_ops */
1010Sstevel@tonic-gate 	NULL,			/* devo_power */
1027656SSherry.Moore@Sun.COM 	ddi_quiesce_not_needed,		/* devo_quiesce */
1030Sstevel@tonic-gate };
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate static struct modldrv modldrv = {
1060Sstevel@tonic-gate 	&mod_driverops,					/* drv_modops */
1075072Smcpowers 	"Cryptographic Administrative Interface",	/* drv_linkinfo */
1080Sstevel@tonic-gate 	&devops,
1090Sstevel@tonic-gate };
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate static struct modlinkage modlinkage = {
1120Sstevel@tonic-gate 	MODREV_1,		/* ml_rev */
1130Sstevel@tonic-gate 	&modldrv,		/* ml_linkage */
1140Sstevel@tonic-gate 	NULL
1150Sstevel@tonic-gate };
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate static dev_info_t	*cryptoadm_dip = NULL;
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate /*
1200Sstevel@tonic-gate  * DDI entry points.
1210Sstevel@tonic-gate  */
1220Sstevel@tonic-gate int
_init(void)1230Sstevel@tonic-gate _init(void)
1240Sstevel@tonic-gate {
1250Sstevel@tonic-gate 	return (mod_install(&modlinkage));
1260Sstevel@tonic-gate }
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate int
_fini(void)1290Sstevel@tonic-gate _fini(void)
1300Sstevel@tonic-gate {
1310Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate int
_info(struct modinfo * modinfop)1350Sstevel@tonic-gate _info(struct modinfo *modinfop)
1360Sstevel@tonic-gate {
1370Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1380Sstevel@tonic-gate }
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate /* ARGSUSED */
1410Sstevel@tonic-gate static int
cryptoadm_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)1420Sstevel@tonic-gate cryptoadm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
1430Sstevel@tonic-gate {
1440Sstevel@tonic-gate 	switch (cmd) {
1450Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
1460Sstevel@tonic-gate 		*result = (void *)cryptoadm_dip;
1470Sstevel@tonic-gate 		return (DDI_SUCCESS);
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
1500Sstevel@tonic-gate 		*result = (void *)0;
1510Sstevel@tonic-gate 		return (DDI_SUCCESS);
1520Sstevel@tonic-gate 	}
1530Sstevel@tonic-gate 	return (DDI_FAILURE);
1540Sstevel@tonic-gate }
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate static int
cryptoadm_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1570Sstevel@tonic-gate cryptoadm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1580Sstevel@tonic-gate {
1590Sstevel@tonic-gate 	if (cmd != DDI_ATTACH) {
1600Sstevel@tonic-gate 		return (DDI_FAILURE);
1610Sstevel@tonic-gate 	}
1620Sstevel@tonic-gate 	if (ddi_get_instance(dip) != 0) {
1630Sstevel@tonic-gate 		/* we only allow instance 0 to attach */
1640Sstevel@tonic-gate 		return (DDI_FAILURE);
1650Sstevel@tonic-gate 	}
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	/* create the minor node */
1680Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, "cryptoadm", S_IFCHR, 0,
1690Sstevel@tonic-gate 	    DDI_PSEUDO, 0) != DDI_SUCCESS) {
1700Sstevel@tonic-gate 		cmn_err(CE_WARN, "cryptoadm: failed creating minor node");
1710Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
1720Sstevel@tonic-gate 		return (DDI_FAILURE);
1730Sstevel@tonic-gate 	}
1740Sstevel@tonic-gate 
17510500SHai-May.Chao@Sun.COM 	mutex_init(&fips140_mode_lock, NULL, MUTEX_DEFAULT, NULL);
1760Sstevel@tonic-gate 	cryptoadm_dip = dip;
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	return (DDI_SUCCESS);
1790Sstevel@tonic-gate }
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate static int
cryptoadm_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)1820Sstevel@tonic-gate cryptoadm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1830Sstevel@tonic-gate {
1840Sstevel@tonic-gate 	if (cmd != DDI_DETACH)
1850Sstevel@tonic-gate 		return (DDI_FAILURE);
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 	cryptoadm_dip = NULL;
1880Sstevel@tonic-gate 	ddi_remove_minor_node(dip, NULL);
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 	return (DDI_SUCCESS);
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate /* ARGSUSED */
1940Sstevel@tonic-gate static int
cryptoadm_open(dev_t * devp,int flag,int otyp,cred_t * credp)1950Sstevel@tonic-gate cryptoadm_open(dev_t *devp, int flag, int otyp, cred_t *credp)
1960Sstevel@tonic-gate {
1970Sstevel@tonic-gate 	if (otyp != OTYP_CHR || cryptoadm_dip == NULL)
1980Sstevel@tonic-gate 		return (ENXIO);
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	/* exclusive opens are not supported */
2010Sstevel@tonic-gate 	if (flag & FEXCL)
2020Sstevel@tonic-gate 		return (ENOTSUP);
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	*devp = makedevice(getmajor(*devp), 0);
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	kcf_sched_start();
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	return (0);
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate /* ARGSUSED */
2120Sstevel@tonic-gate static int
cryptoadm_close(dev_t dev,int flag,int otyp,cred_t * credp)2130Sstevel@tonic-gate cryptoadm_close(dev_t dev, int flag, int otyp, cred_t *credp)
2140Sstevel@tonic-gate {
2150Sstevel@tonic-gate 	return (0);
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate /*
2190Sstevel@tonic-gate  * Returns TRUE if array of size MAXNAMELEN contains a '\0'
2200Sstevel@tonic-gate  * termination character, otherwise, it returns FALSE.
2210Sstevel@tonic-gate  */
2220Sstevel@tonic-gate static boolean_t
null_terminated(char * array)2230Sstevel@tonic-gate null_terminated(char *array)
2240Sstevel@tonic-gate {
2250Sstevel@tonic-gate 	int i;
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	for (i = 0; i < MAXNAMELEN; i++)
2280Sstevel@tonic-gate 		if (array[i] == '\0')
2290Sstevel@tonic-gate 			return (B_TRUE);
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	return (B_FALSE);
2320Sstevel@tonic-gate }
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate /*
2350Sstevel@tonic-gate  * This ioctl returns an array of hardware providers.  Each entry
2360Sstevel@tonic-gate  * contains a device name, device instance, and number of
2370Sstevel@tonic-gate  * supported mechanisms.
2380Sstevel@tonic-gate  */
2390Sstevel@tonic-gate /* ARGSUSED */
2400Sstevel@tonic-gate static int
get_dev_list(dev_t dev,caddr_t arg,int mode,int * rval)2410Sstevel@tonic-gate get_dev_list(dev_t dev, caddr_t arg, int mode, int *rval)
2420Sstevel@tonic-gate {
2430Sstevel@tonic-gate 	crypto_get_dev_list_t dev_list;
2440Sstevel@tonic-gate 	crypto_dev_list_entry_t *entries;
2450Sstevel@tonic-gate 	size_t copyout_size;
2460Sstevel@tonic-gate 	uint_t count;
2470Sstevel@tonic-gate 	ulong_t offset;
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	if (copyin(arg, &dev_list, sizeof (dev_list)) != 0)
2500Sstevel@tonic-gate 		return (EFAULT);
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	/* get the list from the core module */
2530Sstevel@tonic-gate 	if (crypto_get_dev_list(&count, &entries) != 0) {
2540Sstevel@tonic-gate 		dev_list.dl_return_value = CRYPTO_FAILED;
2550Sstevel@tonic-gate 		if (copyout(&dev_list, arg, sizeof (dev_list)) != 0) {
2560Sstevel@tonic-gate 			return (EFAULT);
2570Sstevel@tonic-gate 		}
2580Sstevel@tonic-gate 		return (0);
2590Sstevel@tonic-gate 	}
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	/* check if buffer is too small */
2620Sstevel@tonic-gate 	if (count > dev_list.dl_dev_count) {
2630Sstevel@tonic-gate 		dev_list.dl_dev_count = count;
2640Sstevel@tonic-gate 		dev_list.dl_return_value = CRYPTO_BUFFER_TOO_SMALL;
2650Sstevel@tonic-gate 		crypto_free_dev_list(entries, count);
2660Sstevel@tonic-gate 		if (copyout(&dev_list, arg, sizeof (dev_list)) != 0) {
2670Sstevel@tonic-gate 			return (EFAULT);
2680Sstevel@tonic-gate 		}
2690Sstevel@tonic-gate 		return (0);
2700Sstevel@tonic-gate 	}
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	dev_list.dl_dev_count = count;
2730Sstevel@tonic-gate 	dev_list.dl_return_value = CRYPTO_SUCCESS;
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	copyout_size = count * sizeof (crypto_dev_list_entry_t);
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	/* copyout the first stuff */
2780Sstevel@tonic-gate 	if (copyout(&dev_list, arg, sizeof (dev_list)) != 0) {
2790Sstevel@tonic-gate 		crypto_free_dev_list(entries, count);
2800Sstevel@tonic-gate 		return (EFAULT);
2810Sstevel@tonic-gate 	}
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	/* copyout entries */
2840Sstevel@tonic-gate 	offset = offsetof(crypto_get_dev_list_t, dl_devs);
2850Sstevel@tonic-gate 	if (count > 0 && copyout(entries, arg + offset, copyout_size) != 0) {
2860Sstevel@tonic-gate 		crypto_free_dev_list(entries, count);
2870Sstevel@tonic-gate 		return (EFAULT);
2880Sstevel@tonic-gate 	}
2890Sstevel@tonic-gate 	crypto_free_dev_list(entries, count);
2900Sstevel@tonic-gate 	return (0);
2910Sstevel@tonic-gate }
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate /*
2940Sstevel@tonic-gate  * This ioctl returns a buffer containing the null terminated names
2950Sstevel@tonic-gate  * of software providers.
2960Sstevel@tonic-gate  */
2970Sstevel@tonic-gate /* ARGSUSED */
2980Sstevel@tonic-gate static int
get_soft_list(dev_t dev,caddr_t arg,int mode,int * rval)2990Sstevel@tonic-gate get_soft_list(dev_t dev, caddr_t arg, int mode, int *rval)
3000Sstevel@tonic-gate {
3010Sstevel@tonic-gate 	STRUCT_DECL(crypto_get_soft_list, soft_list);
3020Sstevel@tonic-gate 	char *names;
3030Sstevel@tonic-gate 	size_t len;
3040Sstevel@tonic-gate 	uint_t count;
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	STRUCT_INIT(soft_list, mode);
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	if (copyin(arg, STRUCT_BUF(soft_list), STRUCT_SIZE(soft_list)) != 0)
3090Sstevel@tonic-gate 		return (EFAULT);
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	/* get the list from the core module */
3120Sstevel@tonic-gate 	if (crypto_get_soft_list(&count, &names, &len) != 0) {
3130Sstevel@tonic-gate 		STRUCT_FSET(soft_list, sl_return_value, CRYPTO_FAILED);
3140Sstevel@tonic-gate 		if (copyout(STRUCT_BUF(soft_list), arg,
3150Sstevel@tonic-gate 		    STRUCT_SIZE(soft_list)) != 0) {
3160Sstevel@tonic-gate 			return (EFAULT);
3170Sstevel@tonic-gate 		}
3180Sstevel@tonic-gate 		return (0);
3190Sstevel@tonic-gate 	}
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	/* check if buffer is too small */
3220Sstevel@tonic-gate 	if (len > STRUCT_FGET(soft_list, sl_soft_len)) {
3230Sstevel@tonic-gate 		STRUCT_FSET(soft_list, sl_soft_count, count);
3240Sstevel@tonic-gate 		STRUCT_FSET(soft_list, sl_soft_len, len);
3250Sstevel@tonic-gate 		STRUCT_FSET(soft_list, sl_return_value,
3260Sstevel@tonic-gate 		    CRYPTO_BUFFER_TOO_SMALL);
3270Sstevel@tonic-gate 		kmem_free(names, len);
3280Sstevel@tonic-gate 		if (copyout(STRUCT_BUF(soft_list), arg,
3290Sstevel@tonic-gate 		    STRUCT_SIZE(soft_list)) != 0) {
3300Sstevel@tonic-gate 			return (EFAULT);
3310Sstevel@tonic-gate 		}
3320Sstevel@tonic-gate 		return (0);
3330Sstevel@tonic-gate 	}
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	STRUCT_FSET(soft_list, sl_soft_count, count);
3360Sstevel@tonic-gate 	STRUCT_FSET(soft_list, sl_soft_len, len);
3370Sstevel@tonic-gate 	STRUCT_FSET(soft_list, sl_return_value, CRYPTO_SUCCESS);
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	if (count > 0 && copyout(names,
3400Sstevel@tonic-gate 	    STRUCT_FGETP(soft_list, sl_soft_names), len) != 0) {
3410Sstevel@tonic-gate 		kmem_free(names, len);
3420Sstevel@tonic-gate 		return (EFAULT);
3430Sstevel@tonic-gate 	}
3440Sstevel@tonic-gate 	kmem_free(names, len);
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	if (copyout(STRUCT_BUF(soft_list), arg, STRUCT_SIZE(soft_list)) != 0) {
3470Sstevel@tonic-gate 		return (EFAULT);
3480Sstevel@tonic-gate 	}
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	return (0);
3510Sstevel@tonic-gate }
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate /*
3540Sstevel@tonic-gate  * This ioctl returns an array of mechanisms supported by the
3550Sstevel@tonic-gate  * specified device.
3560Sstevel@tonic-gate  */
3570Sstevel@tonic-gate /* ARGSUSED */
3580Sstevel@tonic-gate static int
get_dev_info(dev_t dev,caddr_t arg,int mode,int * rval)3590Sstevel@tonic-gate get_dev_info(dev_t dev, caddr_t arg, int mode, int *rval)
3600Sstevel@tonic-gate {
3610Sstevel@tonic-gate 	crypto_get_dev_info_t dev_info;
3620Sstevel@tonic-gate 	crypto_mech_name_t *entries;
3630Sstevel@tonic-gate 	size_t copyout_size;
3640Sstevel@tonic-gate 	uint_t count;
3650Sstevel@tonic-gate 	ulong_t offset;
3660Sstevel@tonic-gate 	char *dev_name;
3670Sstevel@tonic-gate 	int rv;
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	if (copyin(arg, &dev_info, sizeof (dev_info)) != 0)
3700Sstevel@tonic-gate 		return (EFAULT);
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 	dev_name = dev_info.di_dev_name;
3730Sstevel@tonic-gate 	/* make sure the device name is null terminated */
3740Sstevel@tonic-gate 	if (!null_terminated(dev_name)) {
3750Sstevel@tonic-gate 		dev_info.di_return_value = CRYPTO_ARGUMENTS_BAD;
3760Sstevel@tonic-gate 		if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
3770Sstevel@tonic-gate 			return (EFAULT);
3780Sstevel@tonic-gate 		}
3790Sstevel@tonic-gate 		return (0);
3800Sstevel@tonic-gate 	}
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	/* get mechanism names from the core module */
3830Sstevel@tonic-gate 	if ((rv = crypto_get_dev_info(dev_name, dev_info.di_dev_instance,
3840Sstevel@tonic-gate 	    &count, &entries)) != CRYPTO_SUCCESS) {
3850Sstevel@tonic-gate 		dev_info.di_return_value = rv;
3860Sstevel@tonic-gate 		if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
3870Sstevel@tonic-gate 			return (EFAULT);
3880Sstevel@tonic-gate 		}
3890Sstevel@tonic-gate 		return (0);
3900Sstevel@tonic-gate 	}
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	/* check if buffer is too small */
3930Sstevel@tonic-gate 	if (count > dev_info.di_count) {
3940Sstevel@tonic-gate 		dev_info.di_count = count;
3950Sstevel@tonic-gate 		dev_info.di_return_value = CRYPTO_BUFFER_TOO_SMALL;
3960Sstevel@tonic-gate 		crypto_free_mech_list(entries, count);
3970Sstevel@tonic-gate 		if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
3980Sstevel@tonic-gate 			return (EFAULT);
3990Sstevel@tonic-gate 		}
4000Sstevel@tonic-gate 		return (0);
4010Sstevel@tonic-gate 	}
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	dev_info.di_count = count;
4040Sstevel@tonic-gate 	dev_info.di_return_value = CRYPTO_SUCCESS;
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	copyout_size = count * sizeof (crypto_mech_name_t);
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	/* copyout the first stuff */
4090Sstevel@tonic-gate 	if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
4100Sstevel@tonic-gate 		crypto_free_mech_list(entries, count);
4110Sstevel@tonic-gate 		return (EFAULT);
4120Sstevel@tonic-gate 	}
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	/* copyout entries */
4150Sstevel@tonic-gate 	offset = offsetof(crypto_get_dev_info_t, di_list);
4160Sstevel@tonic-gate 	if (copyout(entries, arg + offset, copyout_size) != 0) {
4170Sstevel@tonic-gate 		crypto_free_mech_list(entries, count);
4180Sstevel@tonic-gate 		return (EFAULT);
4190Sstevel@tonic-gate 	}
4200Sstevel@tonic-gate 	crypto_free_mech_list(entries, count);
4210Sstevel@tonic-gate 	return (0);
4220Sstevel@tonic-gate }
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate /*
4250Sstevel@tonic-gate  * This ioctl returns an array of mechanisms supported by the
4260Sstevel@tonic-gate  * specified cryptographic module.
4270Sstevel@tonic-gate  */
4280Sstevel@tonic-gate /* ARGSUSED */
4290Sstevel@tonic-gate static int
get_soft_info(dev_t dev,caddr_t arg,int mode,int * rval)4300Sstevel@tonic-gate get_soft_info(dev_t dev, caddr_t arg, int mode, int *rval)
4310Sstevel@tonic-gate {
4320Sstevel@tonic-gate 	crypto_get_soft_info_t soft_info;
4330Sstevel@tonic-gate 	crypto_mech_name_t *entries;
4340Sstevel@tonic-gate 	size_t copyout_size;
4350Sstevel@tonic-gate 	uint_t count;
4360Sstevel@tonic-gate 	ulong_t offset;
4370Sstevel@tonic-gate 	char *name;
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	if (copyin(arg, &soft_info, sizeof (soft_info)) != 0)
4400Sstevel@tonic-gate 		return (EFAULT);
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	name = soft_info.si_name;
4430Sstevel@tonic-gate 	/* make sure the provider name is null terminated */
4440Sstevel@tonic-gate 	if (!null_terminated(name)) {
4450Sstevel@tonic-gate 		soft_info.si_return_value = CRYPTO_ARGUMENTS_BAD;
4460Sstevel@tonic-gate 		if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
4470Sstevel@tonic-gate 			return (EFAULT);
4480Sstevel@tonic-gate 		}
4490Sstevel@tonic-gate 		return (0);
4500Sstevel@tonic-gate 	}
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	/* get mechanism names from the core module */
4530Sstevel@tonic-gate 	if (crypto_get_soft_info(name, &count, &entries) != 0) {
4540Sstevel@tonic-gate 		soft_info.si_return_value = CRYPTO_FAILED;
4550Sstevel@tonic-gate 		if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
4560Sstevel@tonic-gate 			return (EFAULT);
4570Sstevel@tonic-gate 		}
4580Sstevel@tonic-gate 		return (0);
4590Sstevel@tonic-gate 	}
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 	/* check if buffer is too small */
4620Sstevel@tonic-gate 	if (count > soft_info.si_count) {
4630Sstevel@tonic-gate 		soft_info.si_count = count;
4640Sstevel@tonic-gate 		soft_info.si_return_value = CRYPTO_BUFFER_TOO_SMALL;
4650Sstevel@tonic-gate 		crypto_free_mech_list(entries, count);
4660Sstevel@tonic-gate 		if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
4670Sstevel@tonic-gate 			return (EFAULT);
4680Sstevel@tonic-gate 		}
4690Sstevel@tonic-gate 		return (0);
4700Sstevel@tonic-gate 	}
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	soft_info.si_count = count;
4730Sstevel@tonic-gate 	soft_info.si_return_value = CRYPTO_SUCCESS;
4740Sstevel@tonic-gate 	copyout_size = count * sizeof (crypto_mech_name_t);
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	/* copyout the first stuff */
4770Sstevel@tonic-gate 	if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
4780Sstevel@tonic-gate 		crypto_free_mech_list(entries, count);
4790Sstevel@tonic-gate 		return (EFAULT);
4800Sstevel@tonic-gate 	}
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	/* copyout entries */
4830Sstevel@tonic-gate 	offset = offsetof(crypto_get_soft_info_t, si_list);
4840Sstevel@tonic-gate 	if (copyout(entries, arg + offset, copyout_size) != 0) {
4850Sstevel@tonic-gate 		crypto_free_mech_list(entries, count);
4860Sstevel@tonic-gate 		return (EFAULT);
4870Sstevel@tonic-gate 	}
4880Sstevel@tonic-gate 	crypto_free_mech_list(entries, count);
4890Sstevel@tonic-gate 	return (0);
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate /*
4930Sstevel@tonic-gate  * This ioctl disables mechanisms supported by the specified device.
4940Sstevel@tonic-gate  */
4950Sstevel@tonic-gate /* ARGSUSED */
4960Sstevel@tonic-gate static int
load_dev_disabled(dev_t dev,caddr_t arg,int mode,int * rval)4970Sstevel@tonic-gate load_dev_disabled(dev_t dev, caddr_t arg, int mode, int *rval)
4980Sstevel@tonic-gate {
4990Sstevel@tonic-gate 	crypto_load_dev_disabled_t dev_disabled;
5000Sstevel@tonic-gate 	crypto_mech_name_t *entries;
5010Sstevel@tonic-gate 	size_t size;
5020Sstevel@tonic-gate 	ulong_t offset;
5030Sstevel@tonic-gate 	uint_t count;
5040Sstevel@tonic-gate 	uint_t instance;
5050Sstevel@tonic-gate 	char *dev_name;
5060Sstevel@tonic-gate 	uint32_t rv;
5070Sstevel@tonic-gate 	int error = 0;
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	if (copyin(arg, &dev_disabled, sizeof (dev_disabled)) != 0) {
5100Sstevel@tonic-gate 		error =  EFAULT;
5110Sstevel@tonic-gate 		goto out2;
5120Sstevel@tonic-gate 	}
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	dev_name = dev_disabled.dd_dev_name;
5150Sstevel@tonic-gate 	/* make sure the device name is null terminated */
5160Sstevel@tonic-gate 	if (!null_terminated(dev_name)) {
5170Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
5180Sstevel@tonic-gate 		goto out;
5190Sstevel@tonic-gate 	}
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	count = dev_disabled.dd_count;
5220Sstevel@tonic-gate 	instance = dev_disabled.dd_dev_instance;
5230Sstevel@tonic-gate 	if (count == 0) {
5240Sstevel@tonic-gate 		/* remove the entry */
5250Sstevel@tonic-gate 		if (crypto_load_dev_disabled(dev_name, instance, 0, NULL) != 0)
5260Sstevel@tonic-gate 			rv = CRYPTO_FAILED;
5270Sstevel@tonic-gate 		else
5280Sstevel@tonic-gate 			rv = CRYPTO_SUCCESS;
5290Sstevel@tonic-gate 		goto out;
5300Sstevel@tonic-gate 	}
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 	if (count > KCF_MAXMECHS) {
5330Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
5340Sstevel@tonic-gate 		goto out;
5350Sstevel@tonic-gate 	}
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	size = count * sizeof (crypto_mech_name_t);
5380Sstevel@tonic-gate 	entries = kmem_alloc(size, KM_SLEEP);
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	offset = offsetof(crypto_load_dev_disabled_t, dd_list);
5410Sstevel@tonic-gate 	if (copyin(arg + offset, entries, size) != 0) {
5420Sstevel@tonic-gate 		kmem_free(entries, size);
5430Sstevel@tonic-gate 		error = EFAULT;
5440Sstevel@tonic-gate 		goto out2;
5450Sstevel@tonic-gate 	}
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	/* 'entries' consumed (but not freed) by crypto_load_dev_disabled() */
5480Sstevel@tonic-gate 	if (crypto_load_dev_disabled(dev_name, instance, count, entries) != 0) {
5490Sstevel@tonic-gate 		kmem_free(entries, size);
5500Sstevel@tonic-gate 		rv = CRYPTO_FAILED;
5510Sstevel@tonic-gate 		goto out;
5520Sstevel@tonic-gate 	}
5530Sstevel@tonic-gate 	rv = CRYPTO_SUCCESS;
5540Sstevel@tonic-gate out:
5550Sstevel@tonic-gate 	dev_disabled.dd_return_value = rv;
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	if (copyout(&dev_disabled, arg, sizeof (dev_disabled)) != 0) {
5580Sstevel@tonic-gate 		error = EFAULT;
5590Sstevel@tonic-gate 	}
5600Sstevel@tonic-gate out2:
561*11861SMarek.Pospisil@Sun.COM 	if (AU_AUDITING())
5620Sstevel@tonic-gate 		audit_cryptoadm(CRYPTO_LOAD_DEV_DISABLED, dev_name, entries,
5630Sstevel@tonic-gate 		    count, instance, rv, error);
5640Sstevel@tonic-gate 	return (error);
5650Sstevel@tonic-gate }
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate /*
5680Sstevel@tonic-gate  * This ioctl disables mechanisms supported by the specified
5690Sstevel@tonic-gate  * cryptographic module.
5700Sstevel@tonic-gate  */
5710Sstevel@tonic-gate /* ARGSUSED */
5720Sstevel@tonic-gate static int
load_soft_disabled(dev_t dev,caddr_t arg,int mode,int * rval)5730Sstevel@tonic-gate load_soft_disabled(dev_t dev, caddr_t arg, int mode, int *rval)
5740Sstevel@tonic-gate {
5750Sstevel@tonic-gate 	crypto_load_soft_disabled_t soft_disabled;
5760Sstevel@tonic-gate 	crypto_mech_name_t *entries;
5770Sstevel@tonic-gate 	size_t size;
5780Sstevel@tonic-gate 	uint_t count;
5790Sstevel@tonic-gate 	ulong_t offset;
5800Sstevel@tonic-gate 	char *name;
5810Sstevel@tonic-gate 	uint32_t rv;
5820Sstevel@tonic-gate 	int error = 0;
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	if (copyin(arg, &soft_disabled, sizeof (soft_disabled)) != 0) {
5850Sstevel@tonic-gate 		error = EFAULT;
5860Sstevel@tonic-gate 		goto out2;
5870Sstevel@tonic-gate 	}
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	name = soft_disabled.sd_name;
5900Sstevel@tonic-gate 	/* make sure the name is null terminated */
5910Sstevel@tonic-gate 	if (!null_terminated(name)) {
5920Sstevel@tonic-gate 		soft_disabled.sd_return_value = CRYPTO_ARGUMENTS_BAD;
5930Sstevel@tonic-gate 		if (copyout(&soft_disabled, arg, sizeof (soft_disabled)) != 0) {
5940Sstevel@tonic-gate 			return (EFAULT);
5950Sstevel@tonic-gate 		}
5960Sstevel@tonic-gate 		return (0);
5970Sstevel@tonic-gate 	}
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	count = soft_disabled.sd_count;
6000Sstevel@tonic-gate 	if (count == 0) {
6010Sstevel@tonic-gate 		/* remove the entry */
6020Sstevel@tonic-gate 		if (crypto_load_soft_disabled(name, 0, NULL) != 0) {
6030Sstevel@tonic-gate 			rv = CRYPTO_FAILED;
6040Sstevel@tonic-gate 		} else {
6050Sstevel@tonic-gate 			rv = CRYPTO_SUCCESS;
6060Sstevel@tonic-gate 		}
6070Sstevel@tonic-gate 		goto out;
6080Sstevel@tonic-gate 	}
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	if (count > KCF_MAXMECHS) {
6110Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
6120Sstevel@tonic-gate 		goto out;
6130Sstevel@tonic-gate 	}
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	size = count * sizeof (crypto_mech_name_t);
6160Sstevel@tonic-gate 	entries = kmem_alloc(size, KM_SLEEP);
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	offset = offsetof(crypto_load_soft_disabled_t, sd_list);
6190Sstevel@tonic-gate 	if (copyin(arg + offset, entries, size) != 0) {
6200Sstevel@tonic-gate 		kmem_free(entries, size);
6210Sstevel@tonic-gate 		error = EFAULT;
6220Sstevel@tonic-gate 		goto out2;
6230Sstevel@tonic-gate 	}
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	/* 'entries' is consumed by crypto_load_soft_disabled() */
6260Sstevel@tonic-gate 	if (crypto_load_soft_disabled(name, count, entries) != 0) {
6270Sstevel@tonic-gate 		kmem_free(entries, size);
6280Sstevel@tonic-gate 		rv = CRYPTO_FAILED;
6290Sstevel@tonic-gate 		goto out;
6300Sstevel@tonic-gate 	}
6310Sstevel@tonic-gate 	rv = CRYPTO_SUCCESS;
6320Sstevel@tonic-gate out:
6330Sstevel@tonic-gate 	soft_disabled.sd_return_value = rv;
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 	if (copyout(&soft_disabled, arg, sizeof (soft_disabled)) != 0) {
6360Sstevel@tonic-gate 		error = EFAULT;
6370Sstevel@tonic-gate 	}
6380Sstevel@tonic-gate out2:
639*11861SMarek.Pospisil@Sun.COM 	if (AU_AUDITING())
6400Sstevel@tonic-gate 		audit_cryptoadm(CRYPTO_LOAD_SOFT_DISABLED, name, entries,
6410Sstevel@tonic-gate 		    count, 0, rv, error);
6420Sstevel@tonic-gate 	return (error);
6430Sstevel@tonic-gate }
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate /*
6460Sstevel@tonic-gate  * This ioctl loads the supported mechanisms of the specfied cryptographic
6470Sstevel@tonic-gate  * module.  This is so, at boot time, all software providers do not
6480Sstevel@tonic-gate  * have to be opened in order to cause them to register their
6490Sstevel@tonic-gate  * supported mechanisms.
6500Sstevel@tonic-gate  */
6510Sstevel@tonic-gate /* ARGSUSED */
6520Sstevel@tonic-gate static int
load_soft_config(dev_t dev,caddr_t arg,int mode,int * rval)6530Sstevel@tonic-gate load_soft_config(dev_t dev, caddr_t arg, int mode, int *rval)
6540Sstevel@tonic-gate {
6550Sstevel@tonic-gate 	crypto_load_soft_config_t soft_config;
6560Sstevel@tonic-gate 	crypto_mech_name_t *entries;
6570Sstevel@tonic-gate 	size_t size;
6580Sstevel@tonic-gate 	uint_t count;
6590Sstevel@tonic-gate 	ulong_t offset;
6600Sstevel@tonic-gate 	char *name;
6610Sstevel@tonic-gate 	uint32_t rv;
6620Sstevel@tonic-gate 	int error = 0;
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	if (copyin(arg, &soft_config, sizeof (soft_config)) != 0) {
6650Sstevel@tonic-gate 		error = EFAULT;
6660Sstevel@tonic-gate 		goto out2;
6670Sstevel@tonic-gate 	}
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 	name = soft_config.sc_name;
6700Sstevel@tonic-gate 	/* make sure the name is null terminated */
6710Sstevel@tonic-gate 	if (!null_terminated(name)) {
6720Sstevel@tonic-gate 		soft_config.sc_return_value = CRYPTO_ARGUMENTS_BAD;
6730Sstevel@tonic-gate 		if (copyout(&soft_config, arg, sizeof (soft_config)) != 0) {
6740Sstevel@tonic-gate 			return (EFAULT);
6750Sstevel@tonic-gate 		}
6760Sstevel@tonic-gate 		return (0);
6770Sstevel@tonic-gate 	}
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 	count = soft_config.sc_count;
6800Sstevel@tonic-gate 	if (count == 0) {
6810Sstevel@tonic-gate 		if (crypto_load_soft_config(name, 0, NULL) != 0) {
6820Sstevel@tonic-gate 			rv = CRYPTO_FAILED;
6830Sstevel@tonic-gate 		} else {
6840Sstevel@tonic-gate 			rv = CRYPTO_SUCCESS;
6850Sstevel@tonic-gate 		}
6860Sstevel@tonic-gate 		goto out;
6870Sstevel@tonic-gate 	}
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	if (count > KCF_MAXMECHS) {
6900Sstevel@tonic-gate 		rv = CRYPTO_ARGUMENTS_BAD;
6910Sstevel@tonic-gate 		goto out;
6920Sstevel@tonic-gate 	}
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	size = count * sizeof (crypto_mech_name_t);
6950Sstevel@tonic-gate 	entries = kmem_alloc(size, KM_SLEEP);
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	offset = offsetof(crypto_load_soft_config_t, sc_list);
6980Sstevel@tonic-gate 	if (copyin(arg + offset, entries, size) != 0) {
6990Sstevel@tonic-gate 		kmem_free(entries, size);
7000Sstevel@tonic-gate 		error = EFAULT;
7010Sstevel@tonic-gate 		goto out2;
7020Sstevel@tonic-gate 	}
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	/*
7050Sstevel@tonic-gate 	 * 'entries' is consumed (but not freed) by
7060Sstevel@tonic-gate 	 * crypto_load_soft_config()
7070Sstevel@tonic-gate 	 */
7080Sstevel@tonic-gate 	if (crypto_load_soft_config(name, count, entries) != 0) {
7090Sstevel@tonic-gate 		kmem_free(entries, size);
7100Sstevel@tonic-gate 		rv = CRYPTO_FAILED;
7110Sstevel@tonic-gate 		goto out;
7120Sstevel@tonic-gate 	}
7130Sstevel@tonic-gate 	rv = CRYPTO_SUCCESS;
7140Sstevel@tonic-gate out:
7150Sstevel@tonic-gate 	soft_config.sc_return_value = rv;
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	if (copyout(&soft_config, arg, sizeof (soft_config)) != 0) {
7180Sstevel@tonic-gate 		error = EFAULT;
7190Sstevel@tonic-gate 	}
7200Sstevel@tonic-gate out2:
721*11861SMarek.Pospisil@Sun.COM 	if (AU_AUDITING())
7220Sstevel@tonic-gate 		audit_cryptoadm(CRYPTO_LOAD_SOFT_CONFIG, name, entries, count,
7230Sstevel@tonic-gate 		    0, rv, error);
7240Sstevel@tonic-gate 	return (error);
7250Sstevel@tonic-gate }
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate /*
7280Sstevel@tonic-gate  * This ioctl unloads the specfied cryptographic module and removes
7290Sstevel@tonic-gate  * its table of supported mechanisms.
7300Sstevel@tonic-gate  */
7310Sstevel@tonic-gate /* ARGSUSED */
7320Sstevel@tonic-gate static int
unload_soft_module(dev_t dev,caddr_t arg,int mode,int * rval)7330Sstevel@tonic-gate unload_soft_module(dev_t dev, caddr_t arg, int mode, int *rval)
7340Sstevel@tonic-gate {
7350Sstevel@tonic-gate 	crypto_unload_soft_module_t unload_soft_module;
7360Sstevel@tonic-gate 	char *name;
7370Sstevel@tonic-gate 	uint32_t rv;
7380Sstevel@tonic-gate 	int error = 0;
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	if (copyin(arg, &unload_soft_module,
7410Sstevel@tonic-gate 	    sizeof (unload_soft_module)) != 0) {
7420Sstevel@tonic-gate 		error = EFAULT;
7430Sstevel@tonic-gate 		goto out2;
7440Sstevel@tonic-gate 	}
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	name = unload_soft_module.sm_name;
7470Sstevel@tonic-gate 	/* make sure the name is null terminated */
7480Sstevel@tonic-gate 	if (!null_terminated(name)) {
7490Sstevel@tonic-gate 		unload_soft_module.sm_return_value = CRYPTO_ARGUMENTS_BAD;
7500Sstevel@tonic-gate 		if (copyout(&unload_soft_module, arg,
7510Sstevel@tonic-gate 		    sizeof (unload_soft_module)) != 0) {
7520Sstevel@tonic-gate 			return (EFAULT);
7530Sstevel@tonic-gate 		}
7540Sstevel@tonic-gate 		return (0);
7550Sstevel@tonic-gate 	}
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	rv = crypto_unload_soft_module(name);
7580Sstevel@tonic-gate out:
7590Sstevel@tonic-gate 	unload_soft_module.sm_return_value = rv;
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	if (copyout(&unload_soft_module, arg,
7620Sstevel@tonic-gate 	    sizeof (unload_soft_module)) != 0) {
7630Sstevel@tonic-gate 		error = EFAULT;
7640Sstevel@tonic-gate 	}
7650Sstevel@tonic-gate out2:
766*11861SMarek.Pospisil@Sun.COM 	if (AU_AUDITING())
7670Sstevel@tonic-gate 		audit_cryptoadm(CRYPTO_UNLOAD_SOFT_MODULE, name, NULL, 0, 0,
7680Sstevel@tonic-gate 		    rv, error);
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	return (error);
7710Sstevel@tonic-gate }
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate /*
7740Sstevel@tonic-gate  * This ioctl loads a door descriptor into the  kernel.  The descriptor
7750Sstevel@tonic-gate  * is used for module verification.
7760Sstevel@tonic-gate  */
7770Sstevel@tonic-gate /* ARGSUSED */
7780Sstevel@tonic-gate static int
load_door(dev_t dev,caddr_t arg,int mode,int * rval)7790Sstevel@tonic-gate load_door(dev_t dev, caddr_t arg, int mode, int *rval)
7800Sstevel@tonic-gate {
7810Sstevel@tonic-gate 	crypto_load_door_t load_door;
7820Sstevel@tonic-gate 	uint32_t rv;
7830Sstevel@tonic-gate 	int error = 0;
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 	if (copyin(arg, &load_door, sizeof (crypto_load_door_t)) != 0) {
7860Sstevel@tonic-gate 		error = EFAULT;
7870Sstevel@tonic-gate 		goto out2;
7880Sstevel@tonic-gate 	}
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	if (crypto_load_door(load_door.ld_did) != 0) {
7910Sstevel@tonic-gate 		rv = CRYPTO_FAILED;
7920Sstevel@tonic-gate 		goto out;
7930Sstevel@tonic-gate 	}
7940Sstevel@tonic-gate 	rv = CRYPTO_SUCCESS;
7950Sstevel@tonic-gate out:
7960Sstevel@tonic-gate 	load_door.ld_return_value = rv;
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 	if (copyout(&load_door, arg, sizeof (crypto_load_door_t)) != 0)
7990Sstevel@tonic-gate 		error = EFAULT;
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate out2:
802*11861SMarek.Pospisil@Sun.COM 	if (AU_AUDITING())
8030Sstevel@tonic-gate 		audit_cryptoadm(CRYPTO_LOAD_DOOR, NULL, NULL,
8040Sstevel@tonic-gate 		    0, 0, rv, error);
8050Sstevel@tonic-gate 	return (error);
8060Sstevel@tonic-gate }
8070Sstevel@tonic-gate 
80810500SHai-May.Chao@Sun.COM /*
80910732SAnthony.Scarpino@Sun.COM  * This function enables/disables FIPS140 mode or gets the current
81010732SAnthony.Scarpino@Sun.COM  * FIPS 140 mode status.
81110500SHai-May.Chao@Sun.COM  *
81210732SAnthony.Scarpino@Sun.COM  * CRYPTO_FIPS140_STATUS: Returns back the value of global_fips140_mode.
81310732SAnthony.Scarpino@Sun.COM  * CRYPTO_FIPS140_SET: Recognizes 2 operations from userland:
81410732SAnthony.Scarpino@Sun.COM  *                     FIPS140_ENABLE or FIPS140_DISABLE. These can only be
81510732SAnthony.Scarpino@Sun.COM  *                     called when global_fips140_mode is FIPS140_MODE_UNSET
81610732SAnthony.Scarpino@Sun.COM  *                     as they are only operations that can be performed at
81710732SAnthony.Scarpino@Sun.COM  *                     bootup.
81810500SHai-May.Chao@Sun.COM  */
81910500SHai-May.Chao@Sun.COM /* ARGSUSED */
82010500SHai-May.Chao@Sun.COM static int
fips140_actions(dev_t dev,caddr_t arg,int mode,int * rval,int cmd)82110500SHai-May.Chao@Sun.COM fips140_actions(dev_t dev, caddr_t arg, int mode, int *rval, int cmd)
82210500SHai-May.Chao@Sun.COM {
82310500SHai-May.Chao@Sun.COM 	crypto_fips140_t fips140_info;
82410500SHai-May.Chao@Sun.COM 	uint32_t rv = CRYPTO_SUCCESS;
82510500SHai-May.Chao@Sun.COM 	int error = 0;
82610500SHai-May.Chao@Sun.COM 
82710500SHai-May.Chao@Sun.COM 	if (copyin(arg, &fips140_info, sizeof (crypto_fips140_t)) != 0)
82810500SHai-May.Chao@Sun.COM 		return (EFAULT);
82910500SHai-May.Chao@Sun.COM 
83010500SHai-May.Chao@Sun.COM 	switch (cmd) {
83110500SHai-May.Chao@Sun.COM 	case CRYPTO_FIPS140_STATUS:
83210500SHai-May.Chao@Sun.COM 		fips140_info.fips140_status = global_fips140_mode;
83310500SHai-May.Chao@Sun.COM 		break;
83410500SHai-May.Chao@Sun.COM 	case CRYPTO_FIPS140_SET:
83510732SAnthony.Scarpino@Sun.COM 		/* If the mode has been determined, there is nothing to set */
83610500SHai-May.Chao@Sun.COM 		mutex_enter(&fips140_mode_lock);
83710732SAnthony.Scarpino@Sun.COM 
83810732SAnthony.Scarpino@Sun.COM 		if (fips140_info.fips140_op == FIPS140_ENABLE &&
83910732SAnthony.Scarpino@Sun.COM 		    global_fips140_mode == FIPS140_MODE_UNSET) {
84010732SAnthony.Scarpino@Sun.COM 			/*
84110732SAnthony.Scarpino@Sun.COM 			 * If FIPS 140 is enabled, all approriate modules
84210732SAnthony.Scarpino@Sun.COM 			 * must be loaded and validated.  This can be done in
84310732SAnthony.Scarpino@Sun.COM 			 * the background as the rest of the OS comes up.
84410732SAnthony.Scarpino@Sun.COM 			 */
84510732SAnthony.Scarpino@Sun.COM 			global_fips140_mode = FIPS140_MODE_VALIDATING;
84610732SAnthony.Scarpino@Sun.COM 			(void) thread_create(NULL, 0, kcf_fips140_validate,
84710732SAnthony.Scarpino@Sun.COM 			    NULL, 0, &p0, TS_RUN, MAXCLSYSPRI);
84810732SAnthony.Scarpino@Sun.COM 			cv_signal(&cv_fips140);
84910732SAnthony.Scarpino@Sun.COM 
85010732SAnthony.Scarpino@Sun.COM 		} else if (fips140_info.fips140_op == FIPS140_DISABLE &&
85110732SAnthony.Scarpino@Sun.COM 		    global_fips140_mode == FIPS140_MODE_UNSET) {
85210732SAnthony.Scarpino@Sun.COM 			/*
85310732SAnthony.Scarpino@Sun.COM 			 * If FIPS 140 is not enabled, any modules that are
85410732SAnthony.Scarpino@Sun.COM 			 * waiting for validation must be released so they
85510732SAnthony.Scarpino@Sun.COM 			 * can be verified.
85610732SAnthony.Scarpino@Sun.COM 			 */
85710500SHai-May.Chao@Sun.COM 			global_fips140_mode = FIPS140_MODE_DISABLED;
85810732SAnthony.Scarpino@Sun.COM 			kcf_activate();
85910732SAnthony.Scarpino@Sun.COM 			cv_signal(&cv_fips140);
86010732SAnthony.Scarpino@Sun.COM 
86110732SAnthony.Scarpino@Sun.COM 		} else if (fips140_info.fips140_op != FIPS140_DISABLE &&
86210732SAnthony.Scarpino@Sun.COM 		    fips140_info.fips140_op != FIPS140_ENABLE) {
86310500SHai-May.Chao@Sun.COM 			rv = CRYPTO_ARGUMENTS_BAD;
86410500SHai-May.Chao@Sun.COM 		}
86510732SAnthony.Scarpino@Sun.COM 
86610500SHai-May.Chao@Sun.COM 		mutex_exit(&fips140_mode_lock);
86710500SHai-May.Chao@Sun.COM 		break;
86810732SAnthony.Scarpino@Sun.COM 
86910732SAnthony.Scarpino@Sun.COM 	default:
87010732SAnthony.Scarpino@Sun.COM 		rv = CRYPTO_ARGUMENTS_BAD;
87110500SHai-May.Chao@Sun.COM 	}
87210500SHai-May.Chao@Sun.COM 
87310500SHai-May.Chao@Sun.COM 	fips140_info.fips140_return_value = rv;
87410500SHai-May.Chao@Sun.COM 
87510500SHai-May.Chao@Sun.COM 	if (copyout(&fips140_info, arg, sizeof (crypto_fips140_t)) != 0)
87610500SHai-May.Chao@Sun.COM 		error = EFAULT;
87710500SHai-May.Chao@Sun.COM 
87810500SHai-May.Chao@Sun.COM 	return (error);
87910500SHai-May.Chao@Sun.COM }
88010500SHai-May.Chao@Sun.COM 
8810Sstevel@tonic-gate static int
cryptoadm_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * c,int * rval)8820Sstevel@tonic-gate cryptoadm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *c,
8830Sstevel@tonic-gate     int *rval)
8840Sstevel@tonic-gate {
885*11861SMarek.Pospisil@Sun.COM 	uint32_t auditing = AU_AUDITING();
8860Sstevel@tonic-gate 	int error;
8870Sstevel@tonic-gate #define	ARG	((caddr_t)arg)
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	switch (cmd) {
8900Sstevel@tonic-gate 	case CRYPTO_LOAD_DEV_DISABLED:
8910Sstevel@tonic-gate 	case CRYPTO_LOAD_SOFT_DISABLED:
8920Sstevel@tonic-gate 	case CRYPTO_LOAD_SOFT_CONFIG:
8930Sstevel@tonic-gate 	case CRYPTO_UNLOAD_SOFT_MODULE:
8940Sstevel@tonic-gate 	case CRYPTO_POOL_CREATE:
8950Sstevel@tonic-gate 	case CRYPTO_POOL_WAIT:
8960Sstevel@tonic-gate 	case CRYPTO_POOL_RUN:
8970Sstevel@tonic-gate 	case CRYPTO_LOAD_DOOR:
89810500SHai-May.Chao@Sun.COM 	case CRYPTO_FIPS140_SET:
8990Sstevel@tonic-gate 		if ((error = drv_priv(c)) != 0)
9000Sstevel@tonic-gate 			return (error);
9010Sstevel@tonic-gate 	default:
9020Sstevel@tonic-gate 		break;
9030Sstevel@tonic-gate 	}
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 	switch (cmd) {
9060Sstevel@tonic-gate 	case CRYPTO_GET_DEV_LIST:
9070Sstevel@tonic-gate 		return (get_dev_list(dev, ARG, mode, rval));
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	case CRYPTO_GET_DEV_INFO:
9100Sstevel@tonic-gate 		return (get_dev_info(dev, ARG, mode, rval));
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 	case CRYPTO_GET_SOFT_LIST:
9130Sstevel@tonic-gate 		return (get_soft_list(dev, ARG, mode, rval));
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 	case CRYPTO_GET_SOFT_INFO:
9160Sstevel@tonic-gate 		return (get_soft_info(dev, ARG, mode, rval));
9170Sstevel@tonic-gate 
9180Sstevel@tonic-gate 	case CRYPTO_LOAD_DEV_DISABLED:
9190Sstevel@tonic-gate 		return (load_dev_disabled(dev, ARG, mode, rval));
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 	case CRYPTO_LOAD_SOFT_DISABLED:
9220Sstevel@tonic-gate 		return (load_soft_disabled(dev, ARG, mode, rval));
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 	case CRYPTO_LOAD_SOFT_CONFIG:
9250Sstevel@tonic-gate 		return (load_soft_config(dev, ARG, mode, rval));
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	case CRYPTO_UNLOAD_SOFT_MODULE:
9280Sstevel@tonic-gate 		return (unload_soft_module(dev, ARG, mode, rval));
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 	case CRYPTO_POOL_CREATE:
9310Sstevel@tonic-gate 		/*
9320Sstevel@tonic-gate 		 * The framework allocates and initializes the pool.
9330Sstevel@tonic-gate 		 * So, this is a no op. We are keeping this ioctl around
9340Sstevel@tonic-gate 		 * to be used for any future threadpool related work.
9350Sstevel@tonic-gate 		 */
936*11861SMarek.Pospisil@Sun.COM 		if (auditing)
9370Sstevel@tonic-gate 			audit_cryptoadm(CRYPTO_POOL_CREATE, NULL, NULL,
9380Sstevel@tonic-gate 			    0, 0, 0, 0);
9390Sstevel@tonic-gate 		return (0);
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 	case CRYPTO_POOL_WAIT: {
9420Sstevel@tonic-gate 		int nthrs = 0, err;
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 		if ((err = kcf_svc_wait(&nthrs)) == 0) {
9450Sstevel@tonic-gate 			if (copyout((caddr_t)&nthrs, ARG, sizeof (int))
9460Sstevel@tonic-gate 			    == -1)
9470Sstevel@tonic-gate 				err = EFAULT;
9480Sstevel@tonic-gate 		}
949*11861SMarek.Pospisil@Sun.COM 		if (auditing)
9500Sstevel@tonic-gate 			audit_cryptoadm(CRYPTO_POOL_WAIT, NULL, NULL,
9510Sstevel@tonic-gate 			    0, 0, 0, err);
9520Sstevel@tonic-gate 		return (err);
9530Sstevel@tonic-gate 	}
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	case CRYPTO_POOL_RUN: {
9560Sstevel@tonic-gate 		int err;
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 		err = kcf_svc_do_run();
959*11861SMarek.Pospisil@Sun.COM 		if (auditing)
9600Sstevel@tonic-gate 			audit_cryptoadm(CRYPTO_POOL_RUN, NULL, NULL,
9610Sstevel@tonic-gate 			    0, 0, 0, err);
9620Sstevel@tonic-gate 		return (err);
9630Sstevel@tonic-gate 	}
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	case CRYPTO_LOAD_DOOR:
9660Sstevel@tonic-gate 		return (load_door(dev, ARG, mode, rval));
96710500SHai-May.Chao@Sun.COM 	case CRYPTO_FIPS140_STATUS:
96810500SHai-May.Chao@Sun.COM 		return (fips140_actions(dev, ARG, mode, rval, cmd));
96910500SHai-May.Chao@Sun.COM 	case CRYPTO_FIPS140_SET: {
97010500SHai-May.Chao@Sun.COM 		int err;
97110500SHai-May.Chao@Sun.COM 
97210500SHai-May.Chao@Sun.COM 		err = fips140_actions(dev, ARG, mode, rval, cmd);
973*11861SMarek.Pospisil@Sun.COM 		if (auditing)
97410500SHai-May.Chao@Sun.COM 			audit_cryptoadm(CRYPTO_FIPS140_SET, NULL, NULL,
97510500SHai-May.Chao@Sun.COM 			    0, 0, 0, err);
97610500SHai-May.Chao@Sun.COM 		return (err);
9770Sstevel@tonic-gate 	}
97810500SHai-May.Chao@Sun.COM 	}
97910500SHai-May.Chao@Sun.COM 
9800Sstevel@tonic-gate 	return (EINVAL);
9810Sstevel@tonic-gate }
982