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