xref: /titanic_44/usr/src/uts/common/crypto/io/cryptoadm.c (revision 0ba2cbe97e0678a691742f98d2532caed0a2c4aa)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * The ioctl interface for administrative commands.
31  */
32 
33 #include <sys/types.h>
34 #include <sys/modctl.h>
35 #include <sys/conf.h>
36 #include <sys/stat.h>
37 #include <sys/ddi.h>
38 #include <sys/sunddi.h>
39 #include <sys/kmem.h>
40 #include <sys/errno.h>
41 #include <sys/ksynch.h>
42 #include <sys/file.h>
43 #include <sys/open.h>
44 #include <sys/cred.h>
45 #include <sys/model.h>
46 #include <sys/sysmacros.h>
47 #include <sys/crypto/common.h>
48 #include <sys/crypto/api.h>
49 #include <sys/crypto/impl.h>
50 #include <sys/crypto/sched_impl.h>
51 #include <sys/crypto/ioctladmin.h>
52 #include <c2/audit.h>
53 
54 /*
55  * DDI entry points.
56  */
57 static int cryptoadm_attach(dev_info_t *, ddi_attach_cmd_t);
58 static int cryptoadm_detach(dev_info_t *, ddi_detach_cmd_t);
59 static int cryptoadm_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
60 static int cryptoadm_open(dev_t *, int, int, cred_t *);
61 static int cryptoadm_close(dev_t, int, int, cred_t *);
62 static int cryptoadm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
63 
64 extern void audit_cryptoadm(int, char *, crypto_mech_name_t *, uint_t,
65     uint_t, uint32_t, int);
66 /*
67  * Module linkage.
68  */
69 static struct cb_ops cbops = {
70 	cryptoadm_open,		/* cb_open */
71 	cryptoadm_close,	/* cb_close */
72 	nodev,			/* cb_strategy */
73 	nodev,			/* cb_print */
74 	nodev,			/* cb_dump */
75 	nodev,			/* cb_read */
76 	nodev,			/* cb_write */
77 	cryptoadm_ioctl,	/* cb_ioctl */
78 	nodev,			/* cb_devmap */
79 	nodev,			/* cb_mmap */
80 	nodev,			/* cb_segmap */
81 	nochpoll,		/* cb_chpoll */
82 	ddi_prop_op,		/* cb_prop_op */
83 	NULL,			/* cb_streamtab */
84 	D_MP,			/* cb_flag */
85 	CB_REV,			/* cb_rev */
86 	nodev,			/* cb_aread */
87 	nodev,			/* cb_awrite */
88 };
89 
90 static struct dev_ops devops = {
91 	DEVO_REV,		/* devo_rev */
92 	0,			/* devo_refcnt */
93 	cryptoadm_getinfo,	/* devo_getinfo */
94 	nulldev,		/* devo_identify */
95 	nulldev,		/* devo_probe */
96 	cryptoadm_attach,	/* devo_attach */
97 	cryptoadm_detach,	/* devo_detach */
98 	nodev,			/* devo_reset */
99 	&cbops,			/* devo_cb_ops */
100 	NULL,			/* devo_bus_ops */
101 	NULL,			/* devo_power */
102 };
103 
104 static struct modldrv modldrv = {
105 	&mod_driverops,					/* drv_modops */
106 	"Cryptographic Administrative Interface v%I%",	/* drv_linkinfo */
107 	&devops,
108 };
109 
110 static struct modlinkage modlinkage = {
111 	MODREV_1,		/* ml_rev */
112 	&modldrv,		/* ml_linkage */
113 	NULL
114 };
115 
116 static dev_info_t	*cryptoadm_dip = NULL;
117 
118 /*
119  * DDI entry points.
120  */
121 int
122 _init(void)
123 {
124 	return (mod_install(&modlinkage));
125 }
126 
127 int
128 _fini(void)
129 {
130 	return (mod_remove(&modlinkage));
131 }
132 
133 int
134 _info(struct modinfo *modinfop)
135 {
136 	return (mod_info(&modlinkage, modinfop));
137 }
138 
139 /* ARGSUSED */
140 static int
141 cryptoadm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
142 {
143 	switch (cmd) {
144 	case DDI_INFO_DEVT2DEVINFO:
145 		*result = (void *)cryptoadm_dip;
146 		return (DDI_SUCCESS);
147 
148 	case DDI_INFO_DEVT2INSTANCE:
149 		*result = (void *)0;
150 		return (DDI_SUCCESS);
151 	}
152 	return (DDI_FAILURE);
153 }
154 
155 static int
156 cryptoadm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
157 {
158 	if (cmd != DDI_ATTACH) {
159 		return (DDI_FAILURE);
160 	}
161 	if (ddi_get_instance(dip) != 0) {
162 		/* we only allow instance 0 to attach */
163 		return (DDI_FAILURE);
164 	}
165 
166 	/* create the minor node */
167 	if (ddi_create_minor_node(dip, "cryptoadm", S_IFCHR, 0,
168 	    DDI_PSEUDO, 0) != DDI_SUCCESS) {
169 		cmn_err(CE_WARN, "cryptoadm: failed creating minor node");
170 		ddi_remove_minor_node(dip, NULL);
171 		return (DDI_FAILURE);
172 	}
173 
174 	cryptoadm_dip = dip;
175 
176 	return (DDI_SUCCESS);
177 }
178 
179 static int
180 cryptoadm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
181 {
182 	if (cmd != DDI_DETACH)
183 		return (DDI_FAILURE);
184 
185 	cryptoadm_dip = NULL;
186 	ddi_remove_minor_node(dip, NULL);
187 
188 	return (DDI_SUCCESS);
189 }
190 
191 /* ARGSUSED */
192 static int
193 cryptoadm_open(dev_t *devp, int flag, int otyp, cred_t *credp)
194 {
195 	if (otyp != OTYP_CHR || cryptoadm_dip == NULL)
196 		return (ENXIO);
197 
198 	/* exclusive opens are not supported */
199 	if (flag & FEXCL)
200 		return (ENOTSUP);
201 
202 	*devp = makedevice(getmajor(*devp), 0);
203 
204 	kcf_sched_start();
205 
206 	return (0);
207 }
208 
209 /* ARGSUSED */
210 static int
211 cryptoadm_close(dev_t dev, int flag, int otyp, cred_t *credp)
212 {
213 	return (0);
214 }
215 
216 /*
217  * Returns TRUE if array of size MAXNAMELEN contains a '\0'
218  * termination character, otherwise, it returns FALSE.
219  */
220 static boolean_t
221 null_terminated(char *array)
222 {
223 	int i;
224 
225 	for (i = 0; i < MAXNAMELEN; i++)
226 		if (array[i] == '\0')
227 			return (B_TRUE);
228 
229 	return (B_FALSE);
230 }
231 
232 /*
233  * This ioctl returns an array of hardware providers.  Each entry
234  * contains a device name, device instance, and number of
235  * supported mechanisms.
236  */
237 /* ARGSUSED */
238 static int
239 get_dev_list(dev_t dev, caddr_t arg, int mode, int *rval)
240 {
241 	crypto_get_dev_list_t dev_list;
242 	crypto_dev_list_entry_t *entries;
243 	size_t copyout_size;
244 	uint_t count;
245 	ulong_t offset;
246 
247 	if (copyin(arg, &dev_list, sizeof (dev_list)) != 0)
248 		return (EFAULT);
249 
250 	/* get the list from the core module */
251 	if (crypto_get_dev_list(&count, &entries) != 0) {
252 		dev_list.dl_return_value = CRYPTO_FAILED;
253 		if (copyout(&dev_list, arg, sizeof (dev_list)) != 0) {
254 			return (EFAULT);
255 		}
256 		return (0);
257 	}
258 
259 	/* check if buffer is too small */
260 	if (count > dev_list.dl_dev_count) {
261 		dev_list.dl_dev_count = count;
262 		dev_list.dl_return_value = CRYPTO_BUFFER_TOO_SMALL;
263 		crypto_free_dev_list(entries, count);
264 		if (copyout(&dev_list, arg, sizeof (dev_list)) != 0) {
265 			return (EFAULT);
266 		}
267 		return (0);
268 	}
269 
270 	dev_list.dl_dev_count = count;
271 	dev_list.dl_return_value = CRYPTO_SUCCESS;
272 
273 	copyout_size = count * sizeof (crypto_dev_list_entry_t);
274 
275 	/* copyout the first stuff */
276 	if (copyout(&dev_list, arg, sizeof (dev_list)) != 0) {
277 		crypto_free_dev_list(entries, count);
278 		return (EFAULT);
279 	}
280 
281 	/* copyout entries */
282 	offset = offsetof(crypto_get_dev_list_t, dl_devs);
283 	if (count > 0 && copyout(entries, arg + offset, copyout_size) != 0) {
284 		crypto_free_dev_list(entries, count);
285 		return (EFAULT);
286 	}
287 	crypto_free_dev_list(entries, count);
288 	return (0);
289 }
290 
291 /*
292  * This ioctl returns a buffer containing the null terminated names
293  * of software providers.
294  */
295 /* ARGSUSED */
296 static int
297 get_soft_list(dev_t dev, caddr_t arg, int mode, int *rval)
298 {
299 	STRUCT_DECL(crypto_get_soft_list, soft_list);
300 	char *names;
301 	size_t len;
302 	uint_t count;
303 
304 	STRUCT_INIT(soft_list, mode);
305 
306 	if (copyin(arg, STRUCT_BUF(soft_list), STRUCT_SIZE(soft_list)) != 0)
307 		return (EFAULT);
308 
309 	/* get the list from the core module */
310 	if (crypto_get_soft_list(&count, &names, &len) != 0) {
311 		STRUCT_FSET(soft_list, sl_return_value, CRYPTO_FAILED);
312 		if (copyout(STRUCT_BUF(soft_list), arg,
313 		    STRUCT_SIZE(soft_list)) != 0) {
314 			return (EFAULT);
315 		}
316 		return (0);
317 	}
318 
319 	/* check if buffer is too small */
320 	if (len > STRUCT_FGET(soft_list, sl_soft_len)) {
321 		STRUCT_FSET(soft_list, sl_soft_count, count);
322 		STRUCT_FSET(soft_list, sl_soft_len, len);
323 		STRUCT_FSET(soft_list, sl_return_value,
324 		    CRYPTO_BUFFER_TOO_SMALL);
325 		kmem_free(names, len);
326 		if (copyout(STRUCT_BUF(soft_list), arg,
327 		    STRUCT_SIZE(soft_list)) != 0) {
328 			return (EFAULT);
329 		}
330 		return (0);
331 	}
332 
333 	STRUCT_FSET(soft_list, sl_soft_count, count);
334 	STRUCT_FSET(soft_list, sl_soft_len, len);
335 	STRUCT_FSET(soft_list, sl_return_value, CRYPTO_SUCCESS);
336 
337 	if (count > 0 && copyout(names,
338 	    STRUCT_FGETP(soft_list, sl_soft_names), len) != 0) {
339 		kmem_free(names, len);
340 		return (EFAULT);
341 	}
342 	kmem_free(names, len);
343 
344 	if (copyout(STRUCT_BUF(soft_list), arg, STRUCT_SIZE(soft_list)) != 0) {
345 		return (EFAULT);
346 	}
347 
348 	return (0);
349 }
350 
351 /*
352  * This ioctl returns an array of mechanisms supported by the
353  * specified device.
354  */
355 /* ARGSUSED */
356 static int
357 get_dev_info(dev_t dev, caddr_t arg, int mode, int *rval)
358 {
359 	crypto_get_dev_info_t dev_info;
360 	crypto_mech_name_t *entries;
361 	size_t copyout_size;
362 	uint_t count;
363 	ulong_t offset;
364 	char *dev_name;
365 	int rv;
366 
367 	if (copyin(arg, &dev_info, sizeof (dev_info)) != 0)
368 		return (EFAULT);
369 
370 	dev_name = dev_info.di_dev_name;
371 	/* make sure the device name is null terminated */
372 	if (!null_terminated(dev_name)) {
373 		dev_info.di_return_value = CRYPTO_ARGUMENTS_BAD;
374 		if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
375 			return (EFAULT);
376 		}
377 		return (0);
378 	}
379 
380 	/* get mechanism names from the core module */
381 	if ((rv = crypto_get_dev_info(dev_name, dev_info.di_dev_instance,
382 	    &count, &entries)) != CRYPTO_SUCCESS) {
383 		dev_info.di_return_value = rv;
384 		if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
385 			return (EFAULT);
386 		}
387 		return (0);
388 	}
389 
390 	/* check if buffer is too small */
391 	if (count > dev_info.di_count) {
392 		dev_info.di_count = count;
393 		dev_info.di_return_value = CRYPTO_BUFFER_TOO_SMALL;
394 		crypto_free_mech_list(entries, count);
395 		if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
396 			return (EFAULT);
397 		}
398 		return (0);
399 	}
400 
401 	dev_info.di_count = count;
402 	dev_info.di_return_value = CRYPTO_SUCCESS;
403 
404 	copyout_size = count * sizeof (crypto_mech_name_t);
405 
406 	/* copyout the first stuff */
407 	if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
408 		crypto_free_mech_list(entries, count);
409 		return (EFAULT);
410 	}
411 
412 	/* copyout entries */
413 	offset = offsetof(crypto_get_dev_info_t, di_list);
414 	if (copyout(entries, arg + offset, copyout_size) != 0) {
415 		crypto_free_mech_list(entries, count);
416 		return (EFAULT);
417 	}
418 	crypto_free_mech_list(entries, count);
419 	return (0);
420 }
421 
422 /*
423  * This ioctl returns an array of mechanisms supported by the
424  * specified cryptographic module.
425  */
426 /* ARGSUSED */
427 static int
428 get_soft_info(dev_t dev, caddr_t arg, int mode, int *rval)
429 {
430 	crypto_get_soft_info_t soft_info;
431 	crypto_mech_name_t *entries;
432 	size_t copyout_size;
433 	uint_t count;
434 	ulong_t offset;
435 	char *name;
436 
437 	if (copyin(arg, &soft_info, sizeof (soft_info)) != 0)
438 		return (EFAULT);
439 
440 	name = soft_info.si_name;
441 	/* make sure the provider name is null terminated */
442 	if (!null_terminated(name)) {
443 		soft_info.si_return_value = CRYPTO_ARGUMENTS_BAD;
444 		if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
445 			return (EFAULT);
446 		}
447 		return (0);
448 	}
449 
450 	/* get mechanism names from the core module */
451 	if (crypto_get_soft_info(name, &count, &entries) != 0) {
452 		soft_info.si_return_value = CRYPTO_FAILED;
453 		if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
454 			return (EFAULT);
455 		}
456 		return (0);
457 	}
458 
459 	/* check if buffer is too small */
460 	if (count > soft_info.si_count) {
461 		soft_info.si_count = count;
462 		soft_info.si_return_value = CRYPTO_BUFFER_TOO_SMALL;
463 		crypto_free_mech_list(entries, count);
464 		if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
465 			return (EFAULT);
466 		}
467 		return (0);
468 	}
469 
470 	soft_info.si_count = count;
471 	soft_info.si_return_value = CRYPTO_SUCCESS;
472 	copyout_size = count * sizeof (crypto_mech_name_t);
473 
474 	/* copyout the first stuff */
475 	if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
476 		crypto_free_mech_list(entries, count);
477 		return (EFAULT);
478 	}
479 
480 	/* copyout entries */
481 	offset = offsetof(crypto_get_soft_info_t, si_list);
482 	if (copyout(entries, arg + offset, copyout_size) != 0) {
483 		crypto_free_mech_list(entries, count);
484 		return (EFAULT);
485 	}
486 	crypto_free_mech_list(entries, count);
487 	return (0);
488 }
489 
490 /*
491  * This ioctl disables mechanisms supported by the specified device.
492  */
493 /* ARGSUSED */
494 static int
495 load_dev_disabled(dev_t dev, caddr_t arg, int mode, int *rval)
496 {
497 	crypto_load_dev_disabled_t dev_disabled;
498 	crypto_mech_name_t *entries;
499 	size_t size;
500 	ulong_t offset;
501 	uint_t count;
502 	uint_t instance;
503 	char *dev_name;
504 	uint32_t rv;
505 	int error = 0;
506 
507 	if (copyin(arg, &dev_disabled, sizeof (dev_disabled)) != 0) {
508 		error =  EFAULT;
509 		goto out2;
510 	}
511 
512 	dev_name = dev_disabled.dd_dev_name;
513 	/* make sure the device name is null terminated */
514 	if (!null_terminated(dev_name)) {
515 		rv = CRYPTO_ARGUMENTS_BAD;
516 		goto out;
517 	}
518 
519 	count = dev_disabled.dd_count;
520 	instance = dev_disabled.dd_dev_instance;
521 	if (count == 0) {
522 		/* remove the entry */
523 		if (crypto_load_dev_disabled(dev_name, instance, 0, NULL) != 0)
524 			rv = CRYPTO_FAILED;
525 		else
526 			rv = CRYPTO_SUCCESS;
527 		goto out;
528 	}
529 
530 	if (count > KCF_MAXMECHS) {
531 		rv = CRYPTO_ARGUMENTS_BAD;
532 		goto out;
533 	}
534 
535 	size = count * sizeof (crypto_mech_name_t);
536 	entries = kmem_alloc(size, KM_SLEEP);
537 
538 	offset = offsetof(crypto_load_dev_disabled_t, dd_list);
539 	if (copyin(arg + offset, entries, size) != 0) {
540 		kmem_free(entries, size);
541 		error = EFAULT;
542 		goto out2;
543 	}
544 
545 	/* 'entries' consumed (but not freed) by crypto_load_dev_disabled() */
546 	if (crypto_load_dev_disabled(dev_name, instance, count, entries) != 0) {
547 		kmem_free(entries, size);
548 		rv = CRYPTO_FAILED;
549 		goto out;
550 	}
551 	rv = CRYPTO_SUCCESS;
552 out:
553 	dev_disabled.dd_return_value = rv;
554 
555 	if (copyout(&dev_disabled, arg, sizeof (dev_disabled)) != 0) {
556 		error = EFAULT;
557 	}
558 out2:
559 #ifdef C2_AUDIT
560 	if (audit_active)
561 		audit_cryptoadm(CRYPTO_LOAD_DEV_DISABLED, dev_name, entries,
562 		    count, instance, rv, error);
563 #endif
564 	return (error);
565 }
566 
567 /*
568  * This ioctl disables mechanisms supported by the specified
569  * cryptographic module.
570  */
571 /* ARGSUSED */
572 static int
573 load_soft_disabled(dev_t dev, caddr_t arg, int mode, int *rval)
574 {
575 	crypto_load_soft_disabled_t soft_disabled;
576 	crypto_mech_name_t *entries;
577 	size_t size;
578 	uint_t count;
579 	ulong_t offset;
580 	char *name;
581 	uint32_t rv;
582 	int error = 0;
583 
584 	if (copyin(arg, &soft_disabled, sizeof (soft_disabled)) != 0) {
585 		error = EFAULT;
586 		goto out2;
587 	}
588 
589 	name = soft_disabled.sd_name;
590 	/* make sure the name is null terminated */
591 	if (!null_terminated(name)) {
592 		soft_disabled.sd_return_value = CRYPTO_ARGUMENTS_BAD;
593 		if (copyout(&soft_disabled, arg, sizeof (soft_disabled)) != 0) {
594 			return (EFAULT);
595 		}
596 		return (0);
597 	}
598 
599 	count = soft_disabled.sd_count;
600 	if (count == 0) {
601 		/* remove the entry */
602 		if (crypto_load_soft_disabled(name, 0, NULL) != 0) {
603 			rv = CRYPTO_FAILED;
604 		} else {
605 			rv = CRYPTO_SUCCESS;
606 		}
607 		goto out;
608 	}
609 
610 	if (count > KCF_MAXMECHS) {
611 		rv = CRYPTO_ARGUMENTS_BAD;
612 		goto out;
613 	}
614 
615 	size = count * sizeof (crypto_mech_name_t);
616 	entries = kmem_alloc(size, KM_SLEEP);
617 
618 	offset = offsetof(crypto_load_soft_disabled_t, sd_list);
619 	if (copyin(arg + offset, entries, size) != 0) {
620 		kmem_free(entries, size);
621 		error = EFAULT;
622 		goto out2;
623 	}
624 
625 	/* 'entries' is consumed by crypto_load_soft_disabled() */
626 	if (crypto_load_soft_disabled(name, count, entries) != 0) {
627 		kmem_free(entries, size);
628 		rv = CRYPTO_FAILED;
629 		goto out;
630 	}
631 	rv = CRYPTO_SUCCESS;
632 out:
633 	soft_disabled.sd_return_value = rv;
634 
635 	if (copyout(&soft_disabled, arg, sizeof (soft_disabled)) != 0) {
636 		error = EFAULT;
637 	}
638 out2:
639 #ifdef C2_AUDIT
640 	if (audit_active)
641 		audit_cryptoadm(CRYPTO_LOAD_SOFT_DISABLED, name, entries,
642 		    count, 0, rv, error);
643 #endif
644 	return (error);
645 }
646 
647 /*
648  * This ioctl loads the supported mechanisms of the specfied cryptographic
649  * module.  This is so, at boot time, all software providers do not
650  * have to be opened in order to cause them to register their
651  * supported mechanisms.
652  */
653 /* ARGSUSED */
654 static int
655 load_soft_config(dev_t dev, caddr_t arg, int mode, int *rval)
656 {
657 	crypto_load_soft_config_t soft_config;
658 	crypto_mech_name_t *entries;
659 	size_t size;
660 	uint_t count;
661 	ulong_t offset;
662 	char *name;
663 	uint32_t rv;
664 	int error = 0;
665 
666 	if (copyin(arg, &soft_config, sizeof (soft_config)) != 0) {
667 		error = EFAULT;
668 		goto out2;
669 	}
670 
671 	name = soft_config.sc_name;
672 	/* make sure the name is null terminated */
673 	if (!null_terminated(name)) {
674 		soft_config.sc_return_value = CRYPTO_ARGUMENTS_BAD;
675 		if (copyout(&soft_config, arg, sizeof (soft_config)) != 0) {
676 			return (EFAULT);
677 		}
678 		return (0);
679 	}
680 
681 	count = soft_config.sc_count;
682 	if (count == 0) {
683 		if (crypto_load_soft_config(name, 0, NULL) != 0) {
684 			rv = CRYPTO_FAILED;
685 		} else {
686 			rv = CRYPTO_SUCCESS;
687 		}
688 		goto out;
689 	}
690 
691 	if (count > KCF_MAXMECHS) {
692 		rv = CRYPTO_ARGUMENTS_BAD;
693 		goto out;
694 	}
695 
696 	size = count * sizeof (crypto_mech_name_t);
697 	entries = kmem_alloc(size, KM_SLEEP);
698 
699 	offset = offsetof(crypto_load_soft_config_t, sc_list);
700 	if (copyin(arg + offset, entries, size) != 0) {
701 		kmem_free(entries, size);
702 		error = EFAULT;
703 		goto out2;
704 	}
705 
706 	/*
707 	 * 'entries' is consumed (but not freed) by
708 	 * crypto_load_soft_config()
709 	 */
710 	if (crypto_load_soft_config(name, count, entries) != 0) {
711 		kmem_free(entries, size);
712 		rv = CRYPTO_FAILED;
713 		goto out;
714 	}
715 	rv = CRYPTO_SUCCESS;
716 out:
717 	soft_config.sc_return_value = rv;
718 
719 	if (copyout(&soft_config, arg, sizeof (soft_config)) != 0) {
720 		error = EFAULT;
721 	}
722 out2:
723 #ifdef C2_AUDIT
724 	if (audit_active)
725 		audit_cryptoadm(CRYPTO_LOAD_SOFT_CONFIG, name, entries, count,
726 		    0, rv, error);
727 #endif
728 	return (error);
729 }
730 
731 /*
732  * This ioctl unloads the specfied cryptographic module and removes
733  * its table of supported mechanisms.
734  */
735 /* ARGSUSED */
736 static int
737 unload_soft_module(dev_t dev, caddr_t arg, int mode, int *rval)
738 {
739 	crypto_unload_soft_module_t unload_soft_module;
740 	char *name;
741 	uint32_t rv;
742 	int error = 0;
743 
744 	if (copyin(arg, &unload_soft_module,
745 	    sizeof (unload_soft_module)) != 0) {
746 		error = EFAULT;
747 		goto out2;
748 	}
749 
750 	name = unload_soft_module.sm_name;
751 	/* make sure the name is null terminated */
752 	if (!null_terminated(name)) {
753 		unload_soft_module.sm_return_value = CRYPTO_ARGUMENTS_BAD;
754 		if (copyout(&unload_soft_module, arg,
755 		    sizeof (unload_soft_module)) != 0) {
756 			return (EFAULT);
757 		}
758 		return (0);
759 	}
760 
761 	rv = crypto_unload_soft_module(name);
762 out:
763 	unload_soft_module.sm_return_value = rv;
764 
765 	if (copyout(&unload_soft_module, arg,
766 	    sizeof (unload_soft_module)) != 0) {
767 		error = EFAULT;
768 	}
769 out2:
770 #ifdef C2_AUDIT
771 	if (audit_active)
772 		audit_cryptoadm(CRYPTO_UNLOAD_SOFT_MODULE, name, NULL, 0, 0,
773 		    rv, error);
774 #endif
775 
776 	return (error);
777 }
778 
779 /*
780  * This ioctl loads a door descriptor into the  kernel.  The descriptor
781  * is used for module verification.
782  */
783 /* ARGSUSED */
784 static int
785 load_door(dev_t dev, caddr_t arg, int mode, int *rval)
786 {
787 	crypto_load_door_t load_door;
788 	uint32_t rv;
789 	int error = 0;
790 
791 	if (copyin(arg, &load_door, sizeof (crypto_load_door_t)) != 0) {
792 		error = EFAULT;
793 		goto out2;
794 	}
795 
796 	if (crypto_load_door(load_door.ld_did) != 0) {
797 		rv = CRYPTO_FAILED;
798 		goto out;
799 	}
800 	rv = CRYPTO_SUCCESS;
801 out:
802 	load_door.ld_return_value = rv;
803 
804 	if (copyout(&load_door, arg, sizeof (crypto_load_door_t)) != 0)
805 		error = EFAULT;
806 
807 out2:
808 #ifdef C2_AUDIT
809 	if (audit_active)
810 		audit_cryptoadm(CRYPTO_LOAD_DOOR, NULL, NULL,
811 		    0, 0, rv, error);
812 #endif
813 	return (error);
814 }
815 
816 static int
817 cryptoadm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *c,
818     int *rval)
819 {
820 	int error;
821 #define	ARG	((caddr_t)arg)
822 
823 	switch (cmd) {
824 	case CRYPTO_LOAD_DEV_DISABLED:
825 	case CRYPTO_LOAD_SOFT_DISABLED:
826 	case CRYPTO_LOAD_SOFT_CONFIG:
827 	case CRYPTO_UNLOAD_SOFT_MODULE:
828 	case CRYPTO_POOL_CREATE:
829 	case CRYPTO_POOL_WAIT:
830 	case CRYPTO_POOL_RUN:
831 	case CRYPTO_LOAD_DOOR:
832 		if ((error = drv_priv(c)) != 0)
833 			return (error);
834 	default:
835 		break;
836 	}
837 
838 	switch (cmd) {
839 	case CRYPTO_GET_DEV_LIST:
840 		return (get_dev_list(dev, ARG, mode, rval));
841 
842 	case CRYPTO_GET_DEV_INFO:
843 		return (get_dev_info(dev, ARG, mode, rval));
844 
845 	case CRYPTO_GET_SOFT_LIST:
846 		return (get_soft_list(dev, ARG, mode, rval));
847 
848 	case CRYPTO_GET_SOFT_INFO:
849 		return (get_soft_info(dev, ARG, mode, rval));
850 
851 	case CRYPTO_LOAD_DEV_DISABLED:
852 		return (load_dev_disabled(dev, ARG, mode, rval));
853 
854 	case CRYPTO_LOAD_SOFT_DISABLED:
855 		return (load_soft_disabled(dev, ARG, mode, rval));
856 
857 	case CRYPTO_LOAD_SOFT_CONFIG:
858 		return (load_soft_config(dev, ARG, mode, rval));
859 
860 	case CRYPTO_UNLOAD_SOFT_MODULE:
861 		return (unload_soft_module(dev, ARG, mode, rval));
862 
863 	case CRYPTO_POOL_CREATE:
864 		/*
865 		 * The framework allocates and initializes the pool.
866 		 * So, this is a no op. We are keeping this ioctl around
867 		 * to be used for any future threadpool related work.
868 		 */
869 #ifdef C2_AUDIT
870 		if (audit_active)
871 			audit_cryptoadm(CRYPTO_POOL_CREATE, NULL, NULL,
872 			    0, 0, 0, 0);
873 #endif
874 		return (0);
875 
876 	case CRYPTO_POOL_WAIT: {
877 		int nthrs = 0, err;
878 
879 		if ((err = kcf_svc_wait(&nthrs)) == 0) {
880 			if (copyout((caddr_t)&nthrs, ARG, sizeof (int))
881 			    == -1)
882 				err = EFAULT;
883 		}
884 #ifdef C2_AUDIT
885 		if (audit_active)
886 			audit_cryptoadm(CRYPTO_POOL_WAIT, NULL, NULL,
887 			    0, 0, 0, err);
888 #endif
889 		return (err);
890 	}
891 
892 	case CRYPTO_POOL_RUN: {
893 		int err;
894 
895 		err = kcf_svc_do_run();
896 #ifdef C2_AUDIT
897 		if (audit_active)
898 			audit_cryptoadm(CRYPTO_POOL_RUN, NULL, NULL,
899 			    0, 0, 0, err);
900 #endif
901 		return (err);
902 	}
903 
904 	case CRYPTO_LOAD_DOOR:
905 		return (load_door(dev, ARG, mode, rval));
906 	}
907 	return (EINVAL);
908 }
909