xref: /titanic_50/usr/src/uts/common/crypto/io/cryptoadm.c (revision 6ea3c0609e50782557505b88bb391b786bca32c9)
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 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 /*
28  * The ioctl interface for administrative commands.
29  */
30 
31 #include <sys/types.h>
32 #include <sys/modctl.h>
33 #include <sys/conf.h>
34 #include <sys/stat.h>
35 #include <sys/ddi.h>
36 #include <sys/sunddi.h>
37 #include <sys/kmem.h>
38 #include <sys/errno.h>
39 #include <sys/ksynch.h>
40 #include <sys/file.h>
41 #include <sys/open.h>
42 #include <sys/cred.h>
43 #include <sys/model.h>
44 #include <sys/sysmacros.h>
45 #include <sys/crypto/common.h>
46 #include <sys/crypto/api.h>
47 #include <sys/crypto/impl.h>
48 #include <sys/crypto/sched_impl.h>
49 #include <sys/crypto/ioctladmin.h>
50 #include <c2/audit.h>
51 #include <sys/disp.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 /*
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 	ddi_quiesce_not_needed,		/* devo_quiesce */
103 };
104 
105 static struct modldrv modldrv = {
106 	&mod_driverops,					/* drv_modops */
107 	"Cryptographic Administrative Interface",	/* drv_linkinfo */
108 	&devops,
109 };
110 
111 static struct modlinkage modlinkage = {
112 	MODREV_1,		/* ml_rev */
113 	&modldrv,		/* ml_linkage */
114 	NULL
115 };
116 
117 static dev_info_t	*cryptoadm_dip = NULL;
118 
119 /*
120  * DDI entry points.
121  */
122 int
_init(void)123 _init(void)
124 {
125 	return (mod_install(&modlinkage));
126 }
127 
128 int
_fini(void)129 _fini(void)
130 {
131 	return (mod_remove(&modlinkage));
132 }
133 
134 int
_info(struct modinfo * modinfop)135 _info(struct modinfo *modinfop)
136 {
137 	return (mod_info(&modlinkage, modinfop));
138 }
139 
140 /* ARGSUSED */
141 static int
cryptoadm_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)142 cryptoadm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
143 {
144 	switch (cmd) {
145 	case DDI_INFO_DEVT2DEVINFO:
146 		*result = (void *)cryptoadm_dip;
147 		return (DDI_SUCCESS);
148 
149 	case DDI_INFO_DEVT2INSTANCE:
150 		*result = (void *)0;
151 		return (DDI_SUCCESS);
152 	}
153 	return (DDI_FAILURE);
154 }
155 
156 static int
cryptoadm_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)157 cryptoadm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
158 {
159 	if (cmd != DDI_ATTACH) {
160 		return (DDI_FAILURE);
161 	}
162 	if (ddi_get_instance(dip) != 0) {
163 		/* we only allow instance 0 to attach */
164 		return (DDI_FAILURE);
165 	}
166 
167 	/* create the minor node */
168 	if (ddi_create_minor_node(dip, "cryptoadm", S_IFCHR, 0,
169 	    DDI_PSEUDO, 0) != DDI_SUCCESS) {
170 		cmn_err(CE_WARN, "cryptoadm: failed creating minor node");
171 		ddi_remove_minor_node(dip, NULL);
172 		return (DDI_FAILURE);
173 	}
174 
175 	cryptoadm_dip = dip;
176 
177 	return (DDI_SUCCESS);
178 }
179 
180 static int
cryptoadm_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)181 cryptoadm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
182 {
183 	if (cmd != DDI_DETACH)
184 		return (DDI_FAILURE);
185 
186 	cryptoadm_dip = NULL;
187 	ddi_remove_minor_node(dip, NULL);
188 
189 	return (DDI_SUCCESS);
190 }
191 
192 /* ARGSUSED */
193 static int
cryptoadm_open(dev_t * devp,int flag,int otyp,cred_t * credp)194 cryptoadm_open(dev_t *devp, int flag, int otyp, cred_t *credp)
195 {
196 	if (otyp != OTYP_CHR || cryptoadm_dip == NULL)
197 		return (ENXIO);
198 
199 	/* exclusive opens are not supported */
200 	if (flag & FEXCL)
201 		return (ENOTSUP);
202 
203 	*devp = makedevice(getmajor(*devp), 0);
204 
205 	kcf_sched_start();
206 
207 	return (0);
208 }
209 
210 /* ARGSUSED */
211 static int
cryptoadm_close(dev_t dev,int flag,int otyp,cred_t * credp)212 cryptoadm_close(dev_t dev, int flag, int otyp, cred_t *credp)
213 {
214 	return (0);
215 }
216 
217 /*
218  * Returns TRUE if array of size MAXNAMELEN contains a '\0'
219  * termination character, otherwise, it returns FALSE.
220  */
221 static boolean_t
null_terminated(char * array)222 null_terminated(char *array)
223 {
224 	int i;
225 
226 	for (i = 0; i < MAXNAMELEN; i++)
227 		if (array[i] == '\0')
228 			return (B_TRUE);
229 
230 	return (B_FALSE);
231 }
232 
233 /*
234  * This ioctl returns an array of hardware providers.  Each entry
235  * contains a device name, device instance, and number of
236  * supported mechanisms.
237  */
238 /* ARGSUSED */
239 static int
get_dev_list(dev_t dev,caddr_t arg,int mode,int * rval)240 get_dev_list(dev_t dev, caddr_t arg, int mode, int *rval)
241 {
242 	crypto_get_dev_list_t dev_list;
243 	crypto_dev_list_entry_t *entries;
244 	size_t copyout_size;
245 	uint_t count;
246 	ulong_t offset;
247 
248 	if (copyin(arg, &dev_list, sizeof (dev_list)) != 0)
249 		return (EFAULT);
250 
251 	/* get the list from the core module */
252 	if (crypto_get_dev_list(&count, &entries) != 0) {
253 		dev_list.dl_return_value = CRYPTO_FAILED;
254 		if (copyout(&dev_list, arg, sizeof (dev_list)) != 0) {
255 			return (EFAULT);
256 		}
257 		return (0);
258 	}
259 
260 	/* check if buffer is too small */
261 	if (count > dev_list.dl_dev_count) {
262 		dev_list.dl_dev_count = count;
263 		dev_list.dl_return_value = CRYPTO_BUFFER_TOO_SMALL;
264 		crypto_free_dev_list(entries, count);
265 		if (copyout(&dev_list, arg, sizeof (dev_list)) != 0) {
266 			return (EFAULT);
267 		}
268 		return (0);
269 	}
270 
271 	dev_list.dl_dev_count = count;
272 	dev_list.dl_return_value = CRYPTO_SUCCESS;
273 
274 	copyout_size = count * sizeof (crypto_dev_list_entry_t);
275 
276 	/* copyout the first stuff */
277 	if (copyout(&dev_list, arg, sizeof (dev_list)) != 0) {
278 		crypto_free_dev_list(entries, count);
279 		return (EFAULT);
280 	}
281 
282 	/* copyout entries */
283 	offset = offsetof(crypto_get_dev_list_t, dl_devs);
284 	if (count > 0 && copyout(entries, arg + offset, copyout_size) != 0) {
285 		crypto_free_dev_list(entries, count);
286 		return (EFAULT);
287 	}
288 	crypto_free_dev_list(entries, count);
289 	return (0);
290 }
291 
292 /*
293  * This ioctl returns a buffer containing the null terminated names
294  * of software providers.
295  */
296 /* ARGSUSED */
297 static int
get_soft_list(dev_t dev,caddr_t arg,int mode,int * rval)298 get_soft_list(dev_t dev, caddr_t arg, int mode, int *rval)
299 {
300 	STRUCT_DECL(crypto_get_soft_list, soft_list);
301 	char *names;
302 	size_t len;
303 	uint_t count;
304 
305 	STRUCT_INIT(soft_list, mode);
306 
307 	if (copyin(arg, STRUCT_BUF(soft_list), STRUCT_SIZE(soft_list)) != 0)
308 		return (EFAULT);
309 
310 	/* get the list from the core module */
311 	if (crypto_get_soft_list(&count, &names, &len) != 0) {
312 		STRUCT_FSET(soft_list, sl_return_value, CRYPTO_FAILED);
313 		if (copyout(STRUCT_BUF(soft_list), arg,
314 		    STRUCT_SIZE(soft_list)) != 0) {
315 			return (EFAULT);
316 		}
317 		return (0);
318 	}
319 
320 	/* check if buffer is too small */
321 	if (len > STRUCT_FGET(soft_list, sl_soft_len)) {
322 		STRUCT_FSET(soft_list, sl_soft_count, count);
323 		STRUCT_FSET(soft_list, sl_soft_len, len);
324 		STRUCT_FSET(soft_list, sl_return_value,
325 		    CRYPTO_BUFFER_TOO_SMALL);
326 		kmem_free(names, len);
327 		if (copyout(STRUCT_BUF(soft_list), arg,
328 		    STRUCT_SIZE(soft_list)) != 0) {
329 			return (EFAULT);
330 		}
331 		return (0);
332 	}
333 
334 	STRUCT_FSET(soft_list, sl_soft_count, count);
335 	STRUCT_FSET(soft_list, sl_soft_len, len);
336 	STRUCT_FSET(soft_list, sl_return_value, CRYPTO_SUCCESS);
337 
338 	if (count > 0 && copyout(names,
339 	    STRUCT_FGETP(soft_list, sl_soft_names), len) != 0) {
340 		kmem_free(names, len);
341 		return (EFAULT);
342 	}
343 	kmem_free(names, len);
344 
345 	if (copyout(STRUCT_BUF(soft_list), arg, STRUCT_SIZE(soft_list)) != 0) {
346 		return (EFAULT);
347 	}
348 
349 	return (0);
350 }
351 
352 /*
353  * This ioctl returns an array of mechanisms supported by the
354  * specified device.
355  */
356 /* ARGSUSED */
357 static int
get_dev_info(dev_t dev,caddr_t arg,int mode,int * rval)358 get_dev_info(dev_t dev, caddr_t arg, int mode, int *rval)
359 {
360 	crypto_get_dev_info_t dev_info;
361 	crypto_mech_name_t *entries;
362 	size_t copyout_size;
363 	uint_t count;
364 	ulong_t offset;
365 	char *dev_name;
366 	int rv;
367 
368 	if (copyin(arg, &dev_info, sizeof (dev_info)) != 0)
369 		return (EFAULT);
370 
371 	dev_name = dev_info.di_dev_name;
372 	/* make sure the device name is null terminated */
373 	if (!null_terminated(dev_name)) {
374 		dev_info.di_return_value = CRYPTO_ARGUMENTS_BAD;
375 		if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
376 			return (EFAULT);
377 		}
378 		return (0);
379 	}
380 
381 	/* get mechanism names from the core module */
382 	if ((rv = crypto_get_dev_info(dev_name, dev_info.di_dev_instance,
383 	    &count, &entries)) != CRYPTO_SUCCESS) {
384 		dev_info.di_return_value = rv;
385 		if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
386 			return (EFAULT);
387 		}
388 		return (0);
389 	}
390 
391 	/* check if buffer is too small */
392 	if (count > dev_info.di_count) {
393 		dev_info.di_count = count;
394 		dev_info.di_return_value = CRYPTO_BUFFER_TOO_SMALL;
395 		crypto_free_mech_list(entries, count);
396 		if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
397 			return (EFAULT);
398 		}
399 		return (0);
400 	}
401 
402 	dev_info.di_count = count;
403 	dev_info.di_return_value = CRYPTO_SUCCESS;
404 
405 	copyout_size = count * sizeof (crypto_mech_name_t);
406 
407 	/* copyout the first stuff */
408 	if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
409 		crypto_free_mech_list(entries, count);
410 		return (EFAULT);
411 	}
412 
413 	/* copyout entries */
414 	offset = offsetof(crypto_get_dev_info_t, di_list);
415 	if (copyout(entries, arg + offset, copyout_size) != 0) {
416 		crypto_free_mech_list(entries, count);
417 		return (EFAULT);
418 	}
419 	crypto_free_mech_list(entries, count);
420 	return (0);
421 }
422 
423 /*
424  * This ioctl returns an array of mechanisms supported by the
425  * specified cryptographic module.
426  */
427 /* ARGSUSED */
428 static int
get_soft_info(dev_t dev,caddr_t arg,int mode,int * rval)429 get_soft_info(dev_t dev, caddr_t arg, int mode, int *rval)
430 {
431 	crypto_get_soft_info_t soft_info;
432 	crypto_mech_name_t *entries;
433 	size_t copyout_size;
434 	uint_t count;
435 	ulong_t offset;
436 	char *name;
437 
438 	if (copyin(arg, &soft_info, sizeof (soft_info)) != 0)
439 		return (EFAULT);
440 
441 	name = soft_info.si_name;
442 	/* make sure the provider name is null terminated */
443 	if (!null_terminated(name)) {
444 		soft_info.si_return_value = CRYPTO_ARGUMENTS_BAD;
445 		if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
446 			return (EFAULT);
447 		}
448 		return (0);
449 	}
450 
451 	/* get mechanism names from the core module */
452 	if (crypto_get_soft_info(name, &count, &entries) != 0) {
453 		soft_info.si_return_value = CRYPTO_FAILED;
454 		if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
455 			return (EFAULT);
456 		}
457 		return (0);
458 	}
459 
460 	/* check if buffer is too small */
461 	if (count > soft_info.si_count) {
462 		soft_info.si_count = count;
463 		soft_info.si_return_value = CRYPTO_BUFFER_TOO_SMALL;
464 		crypto_free_mech_list(entries, count);
465 		if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
466 			return (EFAULT);
467 		}
468 		return (0);
469 	}
470 
471 	soft_info.si_count = count;
472 	soft_info.si_return_value = CRYPTO_SUCCESS;
473 	copyout_size = count * sizeof (crypto_mech_name_t);
474 
475 	/* copyout the first stuff */
476 	if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
477 		crypto_free_mech_list(entries, count);
478 		return (EFAULT);
479 	}
480 
481 	/* copyout entries */
482 	offset = offsetof(crypto_get_soft_info_t, si_list);
483 	if (copyout(entries, arg + offset, copyout_size) != 0) {
484 		crypto_free_mech_list(entries, count);
485 		return (EFAULT);
486 	}
487 	crypto_free_mech_list(entries, count);
488 	return (0);
489 }
490 
491 /*
492  * This ioctl disables mechanisms supported by the specified device.
493  */
494 /* ARGSUSED */
495 static int
load_dev_disabled(dev_t dev,caddr_t arg,int mode,int * rval)496 load_dev_disabled(dev_t dev, caddr_t arg, int mode, int *rval)
497 {
498 	crypto_load_dev_disabled_t dev_disabled;
499 	crypto_mech_name_t *entries;
500 	size_t size;
501 	ulong_t offset;
502 	uint_t count;
503 	uint_t instance;
504 	char *dev_name;
505 	uint32_t rv;
506 	int error = 0;
507 
508 	if (copyin(arg, &dev_disabled, sizeof (dev_disabled)) != 0) {
509 		error =  EFAULT;
510 		goto out2;
511 	}
512 
513 	dev_name = dev_disabled.dd_dev_name;
514 	/* make sure the device name is null terminated */
515 	if (!null_terminated(dev_name)) {
516 		rv = CRYPTO_ARGUMENTS_BAD;
517 		goto out;
518 	}
519 
520 	count = dev_disabled.dd_count;
521 	instance = dev_disabled.dd_dev_instance;
522 	if (count == 0) {
523 		/* remove the entry */
524 		if (crypto_load_dev_disabled(dev_name, instance, 0, NULL) != 0)
525 			rv = CRYPTO_FAILED;
526 		else
527 			rv = CRYPTO_SUCCESS;
528 		goto out;
529 	}
530 
531 	if (count > KCF_MAXMECHS) {
532 		rv = CRYPTO_ARGUMENTS_BAD;
533 		goto out;
534 	}
535 
536 	size = count * sizeof (crypto_mech_name_t);
537 	entries = kmem_alloc(size, KM_SLEEP);
538 
539 	offset = offsetof(crypto_load_dev_disabled_t, dd_list);
540 	if (copyin(arg + offset, entries, size) != 0) {
541 		kmem_free(entries, size);
542 		error = EFAULT;
543 		goto out2;
544 	}
545 
546 	/* 'entries' consumed (but not freed) by crypto_load_dev_disabled() */
547 	if (crypto_load_dev_disabled(dev_name, instance, count, entries) != 0) {
548 		kmem_free(entries, size);
549 		rv = CRYPTO_FAILED;
550 		goto out;
551 	}
552 	rv = CRYPTO_SUCCESS;
553 out:
554 	dev_disabled.dd_return_value = rv;
555 
556 	if (copyout(&dev_disabled, arg, sizeof (dev_disabled)) != 0) {
557 		error = EFAULT;
558 	}
559 out2:
560 	if (AU_AUDITING())
561 		audit_cryptoadm(CRYPTO_LOAD_DEV_DISABLED, dev_name, entries,
562 		    count, instance, rv, error);
563 	return (error);
564 }
565 
566 /*
567  * This ioctl disables mechanisms supported by the specified
568  * cryptographic module.
569  */
570 /* ARGSUSED */
571 static int
load_soft_disabled(dev_t dev,caddr_t arg,int mode,int * rval)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 	if (AU_AUDITING())
639 		audit_cryptoadm(CRYPTO_LOAD_SOFT_DISABLED, name, entries,
640 		    count, 0, rv, error);
641 	return (error);
642 }
643 
644 /*
645  * This ioctl loads the supported mechanisms of the specfied cryptographic
646  * module.  This is so, at boot time, all software providers do not
647  * have to be opened in order to cause them to register their
648  * supported mechanisms.
649  */
650 /* ARGSUSED */
651 static int
load_soft_config(dev_t dev,caddr_t arg,int mode,int * rval)652 load_soft_config(dev_t dev, caddr_t arg, int mode, int *rval)
653 {
654 	crypto_load_soft_config_t soft_config;
655 	crypto_mech_name_t *entries;
656 	size_t size;
657 	uint_t count;
658 	ulong_t offset;
659 	char *name;
660 	uint32_t rv;
661 	int error = 0;
662 
663 	if (copyin(arg, &soft_config, sizeof (soft_config)) != 0) {
664 		error = EFAULT;
665 		goto out2;
666 	}
667 
668 	name = soft_config.sc_name;
669 	/* make sure the name is null terminated */
670 	if (!null_terminated(name)) {
671 		soft_config.sc_return_value = CRYPTO_ARGUMENTS_BAD;
672 		if (copyout(&soft_config, arg, sizeof (soft_config)) != 0) {
673 			return (EFAULT);
674 		}
675 		return (0);
676 	}
677 
678 	count = soft_config.sc_count;
679 	if (count == 0) {
680 		if (crypto_load_soft_config(name, 0, NULL) != 0) {
681 			rv = CRYPTO_FAILED;
682 		} else {
683 			rv = CRYPTO_SUCCESS;
684 		}
685 		goto out;
686 	}
687 
688 	if (count > KCF_MAXMECHS) {
689 		rv = CRYPTO_ARGUMENTS_BAD;
690 		goto out;
691 	}
692 
693 	size = count * sizeof (crypto_mech_name_t);
694 	entries = kmem_alloc(size, KM_SLEEP);
695 
696 	offset = offsetof(crypto_load_soft_config_t, sc_list);
697 	if (copyin(arg + offset, entries, size) != 0) {
698 		kmem_free(entries, size);
699 		error = EFAULT;
700 		goto out2;
701 	}
702 
703 	/*
704 	 * 'entries' is consumed (but not freed) by
705 	 * crypto_load_soft_config()
706 	 */
707 	if (crypto_load_soft_config(name, count, entries) != 0) {
708 		kmem_free(entries, size);
709 		rv = CRYPTO_FAILED;
710 		goto out;
711 	}
712 	rv = CRYPTO_SUCCESS;
713 out:
714 	soft_config.sc_return_value = rv;
715 
716 	if (copyout(&soft_config, arg, sizeof (soft_config)) != 0) {
717 		error = EFAULT;
718 	}
719 out2:
720 	if (AU_AUDITING())
721 		audit_cryptoadm(CRYPTO_LOAD_SOFT_CONFIG, name, entries, count,
722 		    0, rv, error);
723 	return (error);
724 }
725 
726 /*
727  * This ioctl unloads the specfied cryptographic module and removes
728  * its table of supported mechanisms.
729  */
730 /* ARGSUSED */
731 static int
unload_soft_module(dev_t dev,caddr_t arg,int mode,int * rval)732 unload_soft_module(dev_t dev, caddr_t arg, int mode, int *rval)
733 {
734 	crypto_unload_soft_module_t unload_soft_module;
735 	char *name;
736 	uint32_t rv;
737 	int error = 0;
738 
739 	if (copyin(arg, &unload_soft_module,
740 	    sizeof (unload_soft_module)) != 0) {
741 		error = EFAULT;
742 		goto out2;
743 	}
744 
745 	name = unload_soft_module.sm_name;
746 	/* make sure the name is null terminated */
747 	if (!null_terminated(name)) {
748 		unload_soft_module.sm_return_value = CRYPTO_ARGUMENTS_BAD;
749 		if (copyout(&unload_soft_module, arg,
750 		    sizeof (unload_soft_module)) != 0) {
751 			return (EFAULT);
752 		}
753 		return (0);
754 	}
755 
756 	rv = crypto_unload_soft_module(name);
757 out:
758 	unload_soft_module.sm_return_value = rv;
759 
760 	if (copyout(&unload_soft_module, arg,
761 	    sizeof (unload_soft_module)) != 0) {
762 		error = EFAULT;
763 	}
764 out2:
765 	if (AU_AUDITING())
766 		audit_cryptoadm(CRYPTO_UNLOAD_SOFT_MODULE, name, NULL, 0, 0,
767 		    rv, error);
768 
769 	return (error);
770 }
771 
772 static int
cryptoadm_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * c,int * rval)773 cryptoadm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *c,
774     int *rval)
775 {
776 	int error;
777 #define	ARG	((caddr_t)arg)
778 
779 	switch (cmd) {
780 	case CRYPTO_LOAD_DEV_DISABLED:
781 	case CRYPTO_LOAD_SOFT_DISABLED:
782 	case CRYPTO_LOAD_SOFT_CONFIG:
783 	case CRYPTO_UNLOAD_SOFT_MODULE:
784 	case CRYPTO_LOAD_DOOR:
785 	case CRYPTO_FIPS140_SET:
786 		if ((error = drv_priv(c)) != 0)
787 			return (error);
788 	default:
789 		break;
790 	}
791 
792 	switch (cmd) {
793 	case CRYPTO_GET_DEV_LIST:
794 		return (get_dev_list(dev, ARG, mode, rval));
795 
796 	case CRYPTO_GET_DEV_INFO:
797 		return (get_dev_info(dev, ARG, mode, rval));
798 
799 	case CRYPTO_GET_SOFT_LIST:
800 		return (get_soft_list(dev, ARG, mode, rval));
801 
802 	case CRYPTO_GET_SOFT_INFO:
803 		return (get_soft_info(dev, ARG, mode, rval));
804 
805 	case CRYPTO_LOAD_DEV_DISABLED:
806 		return (load_dev_disabled(dev, ARG, mode, rval));
807 
808 	case CRYPTO_LOAD_SOFT_DISABLED:
809 		return (load_soft_disabled(dev, ARG, mode, rval));
810 
811 	case CRYPTO_LOAD_SOFT_CONFIG:
812 		return (load_soft_config(dev, ARG, mode, rval));
813 
814 	case CRYPTO_UNLOAD_SOFT_MODULE:
815 		return (unload_soft_module(dev, ARG, mode, rval));
816 	}
817 
818 	return (EINVAL);
819 }
820