xref: /titanic_44/usr/src/uts/common/crypto/io/cryptoadm.c (revision 22eb7cb54d8a6bcf6fe2674cb4b1f0cf2d85cfb6)
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 	if (audit_active)
559 		audit_cryptoadm(CRYPTO_LOAD_DEV_DISABLED, dev_name, entries,
560 		    count, instance, rv, error);
561 	return (error);
562 }
563 
564 /*
565  * This ioctl disables mechanisms supported by the specified
566  * cryptographic module.
567  */
568 /* ARGSUSED */
569 static int
570 load_soft_disabled(dev_t dev, caddr_t arg, int mode, int *rval)
571 {
572 	crypto_load_soft_disabled_t soft_disabled;
573 	crypto_mech_name_t *entries;
574 	size_t size;
575 	uint_t count;
576 	ulong_t offset;
577 	char *name;
578 	uint32_t rv;
579 	int error = 0;
580 
581 	if (copyin(arg, &soft_disabled, sizeof (soft_disabled)) != 0) {
582 		error = EFAULT;
583 		goto out2;
584 	}
585 
586 	name = soft_disabled.sd_name;
587 	/* make sure the name is null terminated */
588 	if (!null_terminated(name)) {
589 		soft_disabled.sd_return_value = CRYPTO_ARGUMENTS_BAD;
590 		if (copyout(&soft_disabled, arg, sizeof (soft_disabled)) != 0) {
591 			return (EFAULT);
592 		}
593 		return (0);
594 	}
595 
596 	count = soft_disabled.sd_count;
597 	if (count == 0) {
598 		/* remove the entry */
599 		if (crypto_load_soft_disabled(name, 0, NULL) != 0) {
600 			rv = CRYPTO_FAILED;
601 		} else {
602 			rv = CRYPTO_SUCCESS;
603 		}
604 		goto out;
605 	}
606 
607 	if (count > KCF_MAXMECHS) {
608 		rv = CRYPTO_ARGUMENTS_BAD;
609 		goto out;
610 	}
611 
612 	size = count * sizeof (crypto_mech_name_t);
613 	entries = kmem_alloc(size, KM_SLEEP);
614 
615 	offset = offsetof(crypto_load_soft_disabled_t, sd_list);
616 	if (copyin(arg + offset, entries, size) != 0) {
617 		kmem_free(entries, size);
618 		error = EFAULT;
619 		goto out2;
620 	}
621 
622 	/* 'entries' is consumed by crypto_load_soft_disabled() */
623 	if (crypto_load_soft_disabled(name, count, entries) != 0) {
624 		kmem_free(entries, size);
625 		rv = CRYPTO_FAILED;
626 		goto out;
627 	}
628 	rv = CRYPTO_SUCCESS;
629 out:
630 	soft_disabled.sd_return_value = rv;
631 
632 	if (copyout(&soft_disabled, arg, sizeof (soft_disabled)) != 0) {
633 		error = EFAULT;
634 	}
635 out2:
636 	if (audit_active)
637 		audit_cryptoadm(CRYPTO_LOAD_SOFT_DISABLED, name, entries,
638 		    count, 0, rv, error);
639 	return (error);
640 }
641 
642 /*
643  * This ioctl loads the supported mechanisms of the specfied cryptographic
644  * module.  This is so, at boot time, all software providers do not
645  * have to be opened in order to cause them to register their
646  * supported mechanisms.
647  */
648 /* ARGSUSED */
649 static int
650 load_soft_config(dev_t dev, caddr_t arg, int mode, int *rval)
651 {
652 	crypto_load_soft_config_t soft_config;
653 	crypto_mech_name_t *entries;
654 	size_t size;
655 	uint_t count;
656 	ulong_t offset;
657 	char *name;
658 	uint32_t rv;
659 	int error = 0;
660 
661 	if (copyin(arg, &soft_config, sizeof (soft_config)) != 0) {
662 		error = EFAULT;
663 		goto out2;
664 	}
665 
666 	name = soft_config.sc_name;
667 	/* make sure the name is null terminated */
668 	if (!null_terminated(name)) {
669 		soft_config.sc_return_value = CRYPTO_ARGUMENTS_BAD;
670 		if (copyout(&soft_config, arg, sizeof (soft_config)) != 0) {
671 			return (EFAULT);
672 		}
673 		return (0);
674 	}
675 
676 	count = soft_config.sc_count;
677 	if (count == 0) {
678 		if (crypto_load_soft_config(name, 0, NULL) != 0) {
679 			rv = CRYPTO_FAILED;
680 		} else {
681 			rv = CRYPTO_SUCCESS;
682 		}
683 		goto out;
684 	}
685 
686 	if (count > KCF_MAXMECHS) {
687 		rv = CRYPTO_ARGUMENTS_BAD;
688 		goto out;
689 	}
690 
691 	size = count * sizeof (crypto_mech_name_t);
692 	entries = kmem_alloc(size, KM_SLEEP);
693 
694 	offset = offsetof(crypto_load_soft_config_t, sc_list);
695 	if (copyin(arg + offset, entries, size) != 0) {
696 		kmem_free(entries, size);
697 		error = EFAULT;
698 		goto out2;
699 	}
700 
701 	/*
702 	 * 'entries' is consumed (but not freed) by
703 	 * crypto_load_soft_config()
704 	 */
705 	if (crypto_load_soft_config(name, count, entries) != 0) {
706 		kmem_free(entries, size);
707 		rv = CRYPTO_FAILED;
708 		goto out;
709 	}
710 	rv = CRYPTO_SUCCESS;
711 out:
712 	soft_config.sc_return_value = rv;
713 
714 	if (copyout(&soft_config, arg, sizeof (soft_config)) != 0) {
715 		error = EFAULT;
716 	}
717 out2:
718 	if (audit_active)
719 		audit_cryptoadm(CRYPTO_LOAD_SOFT_CONFIG, name, entries, count,
720 		    0, rv, error);
721 	return (error);
722 }
723 
724 /*
725  * This ioctl unloads the specfied cryptographic module and removes
726  * its table of supported mechanisms.
727  */
728 /* ARGSUSED */
729 static int
730 unload_soft_module(dev_t dev, caddr_t arg, int mode, int *rval)
731 {
732 	crypto_unload_soft_module_t unload_soft_module;
733 	char *name;
734 	uint32_t rv;
735 	int error = 0;
736 
737 	if (copyin(arg, &unload_soft_module,
738 	    sizeof (unload_soft_module)) != 0) {
739 		error = EFAULT;
740 		goto out2;
741 	}
742 
743 	name = unload_soft_module.sm_name;
744 	/* make sure the name is null terminated */
745 	if (!null_terminated(name)) {
746 		unload_soft_module.sm_return_value = CRYPTO_ARGUMENTS_BAD;
747 		if (copyout(&unload_soft_module, arg,
748 		    sizeof (unload_soft_module)) != 0) {
749 			return (EFAULT);
750 		}
751 		return (0);
752 	}
753 
754 	rv = crypto_unload_soft_module(name);
755 out:
756 	unload_soft_module.sm_return_value = rv;
757 
758 	if (copyout(&unload_soft_module, arg,
759 	    sizeof (unload_soft_module)) != 0) {
760 		error = EFAULT;
761 	}
762 out2:
763 	if (audit_active)
764 		audit_cryptoadm(CRYPTO_UNLOAD_SOFT_MODULE, name, NULL, 0, 0,
765 		    rv, error);
766 
767 	return (error);
768 }
769 
770 /*
771  * This ioctl loads a door descriptor into the  kernel.  The descriptor
772  * is used for module verification.
773  */
774 /* ARGSUSED */
775 static int
776 load_door(dev_t dev, caddr_t arg, int mode, int *rval)
777 {
778 	crypto_load_door_t load_door;
779 	uint32_t rv;
780 	int error = 0;
781 
782 	if (copyin(arg, &load_door, sizeof (crypto_load_door_t)) != 0) {
783 		error = EFAULT;
784 		goto out2;
785 	}
786 
787 	if (crypto_load_door(load_door.ld_did) != 0) {
788 		rv = CRYPTO_FAILED;
789 		goto out;
790 	}
791 	rv = CRYPTO_SUCCESS;
792 out:
793 	load_door.ld_return_value = rv;
794 
795 	if (copyout(&load_door, arg, sizeof (crypto_load_door_t)) != 0)
796 		error = EFAULT;
797 
798 out2:
799 	if (audit_active)
800 		audit_cryptoadm(CRYPTO_LOAD_DOOR, NULL, NULL,
801 		    0, 0, rv, error);
802 	return (error);
803 }
804 
805 static int
806 cryptoadm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *c,
807     int *rval)
808 {
809 	int error;
810 #define	ARG	((caddr_t)arg)
811 
812 	switch (cmd) {
813 	case CRYPTO_LOAD_DEV_DISABLED:
814 	case CRYPTO_LOAD_SOFT_DISABLED:
815 	case CRYPTO_LOAD_SOFT_CONFIG:
816 	case CRYPTO_UNLOAD_SOFT_MODULE:
817 	case CRYPTO_POOL_CREATE:
818 	case CRYPTO_POOL_WAIT:
819 	case CRYPTO_POOL_RUN:
820 	case CRYPTO_LOAD_DOOR:
821 		if ((error = drv_priv(c)) != 0)
822 			return (error);
823 	default:
824 		break;
825 	}
826 
827 	switch (cmd) {
828 	case CRYPTO_GET_DEV_LIST:
829 		return (get_dev_list(dev, ARG, mode, rval));
830 
831 	case CRYPTO_GET_DEV_INFO:
832 		return (get_dev_info(dev, ARG, mode, rval));
833 
834 	case CRYPTO_GET_SOFT_LIST:
835 		return (get_soft_list(dev, ARG, mode, rval));
836 
837 	case CRYPTO_GET_SOFT_INFO:
838 		return (get_soft_info(dev, ARG, mode, rval));
839 
840 	case CRYPTO_LOAD_DEV_DISABLED:
841 		return (load_dev_disabled(dev, ARG, mode, rval));
842 
843 	case CRYPTO_LOAD_SOFT_DISABLED:
844 		return (load_soft_disabled(dev, ARG, mode, rval));
845 
846 	case CRYPTO_LOAD_SOFT_CONFIG:
847 		return (load_soft_config(dev, ARG, mode, rval));
848 
849 	case CRYPTO_UNLOAD_SOFT_MODULE:
850 		return (unload_soft_module(dev, ARG, mode, rval));
851 
852 	case CRYPTO_POOL_CREATE:
853 		/*
854 		 * The framework allocates and initializes the pool.
855 		 * So, this is a no op. We are keeping this ioctl around
856 		 * to be used for any future threadpool related work.
857 		 */
858 		if (audit_active)
859 			audit_cryptoadm(CRYPTO_POOL_CREATE, NULL, NULL,
860 			    0, 0, 0, 0);
861 		return (0);
862 
863 	case CRYPTO_POOL_WAIT: {
864 		int nthrs = 0, err;
865 
866 		if ((err = kcf_svc_wait(&nthrs)) == 0) {
867 			if (copyout((caddr_t)&nthrs, ARG, sizeof (int))
868 			    == -1)
869 				err = EFAULT;
870 		}
871 		if (audit_active)
872 			audit_cryptoadm(CRYPTO_POOL_WAIT, NULL, NULL,
873 			    0, 0, 0, err);
874 		return (err);
875 	}
876 
877 	case CRYPTO_POOL_RUN: {
878 		int err;
879 
880 		err = kcf_svc_do_run();
881 		if (audit_active)
882 			audit_cryptoadm(CRYPTO_POOL_RUN, NULL, NULL,
883 			    0, 0, 0, err);
884 		return (err);
885 	}
886 
887 	case CRYPTO_LOAD_DOOR:
888 		return (load_door(dev, ARG, mode, rval));
889 	}
890 	return (EINVAL);
891 }
892