Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / crypto / io / cryptoadm.c
blobb832fc002be3e75c10369b0d589ae3561b13fb25
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * The ioctl interface for administrative commands.
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 <sys/disp.h>
53 * DDI entry points.
55 static int cryptoadm_attach(dev_info_t *, ddi_attach_cmd_t);
56 static int cryptoadm_detach(dev_info_t *, ddi_detach_cmd_t);
57 static int cryptoadm_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
58 static int cryptoadm_open(dev_t *, int, int, cred_t *);
59 static int cryptoadm_close(dev_t, int, int, cred_t *);
60 static int cryptoadm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
63 * Module linkage.
65 static struct cb_ops cbops = {
66 cryptoadm_open, /* cb_open */
67 cryptoadm_close, /* cb_close */
68 nodev, /* cb_strategy */
69 nodev, /* cb_print */
70 nodev, /* cb_dump */
71 nodev, /* cb_read */
72 nodev, /* cb_write */
73 cryptoadm_ioctl, /* cb_ioctl */
74 nodev, /* cb_devmap */
75 nodev, /* cb_mmap */
76 nodev, /* cb_segmap */
77 nochpoll, /* cb_chpoll */
78 ddi_prop_op, /* cb_prop_op */
79 NULL, /* cb_streamtab */
80 D_MP, /* cb_flag */
81 CB_REV, /* cb_rev */
82 nodev, /* cb_aread */
83 nodev, /* cb_awrite */
86 static struct dev_ops devops = {
87 DEVO_REV, /* devo_rev */
88 0, /* devo_refcnt */
89 cryptoadm_getinfo, /* devo_getinfo */
90 nulldev, /* devo_identify */
91 nulldev, /* devo_probe */
92 cryptoadm_attach, /* devo_attach */
93 cryptoadm_detach, /* devo_detach */
94 nodev, /* devo_reset */
95 &cbops, /* devo_cb_ops */
96 NULL, /* devo_bus_ops */
97 NULL, /* devo_power */
98 ddi_quiesce_not_needed, /* devo_quiesce */
101 static struct modldrv modldrv = {
102 &mod_driverops, /* drv_modops */
103 "Cryptographic Administrative Interface", /* drv_linkinfo */
104 &devops,
107 static struct modlinkage modlinkage = {
108 MODREV_1, /* ml_rev */
109 &modldrv, /* ml_linkage */
110 NULL
113 static dev_info_t *cryptoadm_dip = NULL;
116 * DDI entry points.
119 _init(void)
121 return (mod_install(&modlinkage));
125 _fini(void)
127 return (mod_remove(&modlinkage));
131 _info(struct modinfo *modinfop)
133 return (mod_info(&modlinkage, modinfop));
136 /* ARGSUSED */
137 static int
138 cryptoadm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
140 switch (cmd) {
141 case DDI_INFO_DEVT2DEVINFO:
142 *result = (void *)cryptoadm_dip;
143 return (DDI_SUCCESS);
145 case DDI_INFO_DEVT2INSTANCE:
146 *result = NULL;
147 return (DDI_SUCCESS);
149 return (DDI_FAILURE);
152 static int
153 cryptoadm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
155 if (cmd != DDI_ATTACH) {
156 return (DDI_FAILURE);
158 if (ddi_get_instance(dip) != 0) {
159 /* we only allow instance 0 to attach */
160 return (DDI_FAILURE);
163 /* create the minor node */
164 if (ddi_create_minor_node(dip, "cryptoadm", S_IFCHR, 0,
165 DDI_PSEUDO, 0) != DDI_SUCCESS) {
166 cmn_err(CE_WARN, "cryptoadm: failed creating minor node");
167 ddi_remove_minor_node(dip, NULL);
168 return (DDI_FAILURE);
171 cryptoadm_dip = dip;
173 return (DDI_SUCCESS);
176 static int
177 cryptoadm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
179 if (cmd != DDI_DETACH)
180 return (DDI_FAILURE);
182 cryptoadm_dip = NULL;
183 ddi_remove_minor_node(dip, NULL);
185 return (DDI_SUCCESS);
188 /* ARGSUSED */
189 static int
190 cryptoadm_open(dev_t *devp, int flag, int otyp, cred_t *credp)
192 if (otyp != OTYP_CHR || cryptoadm_dip == NULL)
193 return (ENXIO);
195 /* exclusive opens are not supported */
196 if (flag & FEXCL)
197 return (ENOTSUP);
199 *devp = makedevice(getmajor(*devp), 0);
201 kcf_sched_start();
203 return (0);
206 /* ARGSUSED */
207 static int
208 cryptoadm_close(dev_t dev, int flag, int otyp, cred_t *credp)
210 return (0);
214 * Returns TRUE if array of size MAXNAMELEN contains a '\0'
215 * termination character, otherwise, it returns FALSE.
217 static boolean_t
218 null_terminated(char *array)
220 int i;
222 for (i = 0; i < MAXNAMELEN; i++)
223 if (array[i] == '\0')
224 return (B_TRUE);
226 return (B_FALSE);
230 * This ioctl returns an array of hardware providers. Each entry
231 * contains a device name, device instance, and number of
232 * supported mechanisms.
234 /* ARGSUSED */
235 static int
236 get_dev_list(dev_t dev, caddr_t arg, int mode, int *rval)
238 crypto_get_dev_list_t dev_list;
239 crypto_dev_list_entry_t *entries;
240 size_t copyout_size;
241 uint_t count;
242 ulong_t offset;
244 if (copyin(arg, &dev_list, sizeof (dev_list)) != 0)
245 return (EFAULT);
247 /* get the list from the core module */
248 if (crypto_get_dev_list(&count, &entries) != 0) {
249 dev_list.dl_return_value = CRYPTO_FAILED;
250 if (copyout(&dev_list, arg, sizeof (dev_list)) != 0) {
251 return (EFAULT);
253 return (0);
256 /* check if buffer is too small */
257 if (count > dev_list.dl_dev_count) {
258 dev_list.dl_dev_count = count;
259 dev_list.dl_return_value = CRYPTO_BUFFER_TOO_SMALL;
260 crypto_free_dev_list(entries, count);
261 if (copyout(&dev_list, arg, sizeof (dev_list)) != 0) {
262 return (EFAULT);
264 return (0);
267 dev_list.dl_dev_count = count;
268 dev_list.dl_return_value = CRYPTO_SUCCESS;
270 copyout_size = count * sizeof (crypto_dev_list_entry_t);
272 /* copyout the first stuff */
273 if (copyout(&dev_list, arg, sizeof (dev_list)) != 0) {
274 crypto_free_dev_list(entries, count);
275 return (EFAULT);
278 /* copyout entries */
279 offset = offsetof(crypto_get_dev_list_t, dl_devs);
280 if (count > 0 && copyout(entries, arg + offset, copyout_size) != 0) {
281 crypto_free_dev_list(entries, count);
282 return (EFAULT);
284 crypto_free_dev_list(entries, count);
285 return (0);
289 * This ioctl returns a buffer containing the null terminated names
290 * of software providers.
292 /* ARGSUSED */
293 static int
294 get_soft_list(dev_t dev, caddr_t arg, int mode, int *rval)
296 STRUCT_DECL(crypto_get_soft_list, soft_list);
297 char *names;
298 size_t len;
299 uint_t count;
301 STRUCT_INIT(soft_list, mode);
303 if (copyin(arg, STRUCT_BUF(soft_list), STRUCT_SIZE(soft_list)) != 0)
304 return (EFAULT);
306 /* get the list from the core module */
307 if (crypto_get_soft_list(&count, &names, &len) != 0) {
308 STRUCT_FSET(soft_list, sl_return_value, CRYPTO_FAILED);
309 if (copyout(STRUCT_BUF(soft_list), arg,
310 STRUCT_SIZE(soft_list)) != 0) {
311 return (EFAULT);
313 return (0);
316 /* check if buffer is too small */
317 if (len > STRUCT_FGET(soft_list, sl_soft_len)) {
318 STRUCT_FSET(soft_list, sl_soft_count, count);
319 STRUCT_FSET(soft_list, sl_soft_len, len);
320 STRUCT_FSET(soft_list, sl_return_value,
321 CRYPTO_BUFFER_TOO_SMALL);
322 kmem_free(names, len);
323 if (copyout(STRUCT_BUF(soft_list), arg,
324 STRUCT_SIZE(soft_list)) != 0) {
325 return (EFAULT);
327 return (0);
330 STRUCT_FSET(soft_list, sl_soft_count, count);
331 STRUCT_FSET(soft_list, sl_soft_len, len);
332 STRUCT_FSET(soft_list, sl_return_value, CRYPTO_SUCCESS);
334 if (count > 0 && copyout(names,
335 STRUCT_FGETP(soft_list, sl_soft_names), len) != 0) {
336 kmem_free(names, len);
337 return (EFAULT);
339 kmem_free(names, len);
341 if (copyout(STRUCT_BUF(soft_list), arg, STRUCT_SIZE(soft_list)) != 0) {
342 return (EFAULT);
345 return (0);
349 * This ioctl returns an array of mechanisms supported by the
350 * specified device.
352 /* ARGSUSED */
353 static int
354 get_dev_info(dev_t dev, caddr_t arg, int mode, int *rval)
356 crypto_get_dev_info_t dev_info;
357 crypto_mech_name_t *entries;
358 size_t copyout_size;
359 uint_t count;
360 ulong_t offset;
361 char *dev_name;
362 int rv;
364 if (copyin(arg, &dev_info, sizeof (dev_info)) != 0)
365 return (EFAULT);
367 dev_name = dev_info.di_dev_name;
368 /* make sure the device name is null terminated */
369 if (!null_terminated(dev_name)) {
370 dev_info.di_return_value = CRYPTO_ARGUMENTS_BAD;
371 if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
372 return (EFAULT);
374 return (0);
377 /* get mechanism names from the core module */
378 if ((rv = crypto_get_dev_info(dev_name, dev_info.di_dev_instance,
379 &count, &entries)) != CRYPTO_SUCCESS) {
380 dev_info.di_return_value = rv;
381 if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
382 return (EFAULT);
384 return (0);
387 /* check if buffer is too small */
388 if (count > dev_info.di_count) {
389 dev_info.di_count = count;
390 dev_info.di_return_value = CRYPTO_BUFFER_TOO_SMALL;
391 crypto_free_mech_list(entries, count);
392 if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
393 return (EFAULT);
395 return (0);
398 dev_info.di_count = count;
399 dev_info.di_return_value = CRYPTO_SUCCESS;
401 copyout_size = count * sizeof (crypto_mech_name_t);
403 /* copyout the first stuff */
404 if (copyout(&dev_info, arg, sizeof (dev_info)) != 0) {
405 crypto_free_mech_list(entries, count);
406 return (EFAULT);
409 /* copyout entries */
410 offset = offsetof(crypto_get_dev_info_t, di_list);
411 if (copyout(entries, arg + offset, copyout_size) != 0) {
412 crypto_free_mech_list(entries, count);
413 return (EFAULT);
415 crypto_free_mech_list(entries, count);
416 return (0);
420 * This ioctl returns an array of mechanisms supported by the
421 * specified cryptographic module.
423 /* ARGSUSED */
424 static int
425 get_soft_info(dev_t dev, caddr_t arg, int mode, int *rval)
427 crypto_get_soft_info_t soft_info;
428 crypto_mech_name_t *entries;
429 size_t copyout_size;
430 uint_t count;
431 ulong_t offset;
432 char *name;
434 if (copyin(arg, &soft_info, sizeof (soft_info)) != 0)
435 return (EFAULT);
437 name = soft_info.si_name;
438 /* make sure the provider name is null terminated */
439 if (!null_terminated(name)) {
440 soft_info.si_return_value = CRYPTO_ARGUMENTS_BAD;
441 if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
442 return (EFAULT);
444 return (0);
447 /* get mechanism names from the core module */
448 if (crypto_get_soft_info(name, &count, &entries) != 0) {
449 soft_info.si_return_value = CRYPTO_FAILED;
450 if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
451 return (EFAULT);
453 return (0);
456 /* check if buffer is too small */
457 if (count > soft_info.si_count) {
458 soft_info.si_count = count;
459 soft_info.si_return_value = CRYPTO_BUFFER_TOO_SMALL;
460 crypto_free_mech_list(entries, count);
461 if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
462 return (EFAULT);
464 return (0);
467 soft_info.si_count = count;
468 soft_info.si_return_value = CRYPTO_SUCCESS;
469 copyout_size = count * sizeof (crypto_mech_name_t);
471 /* copyout the first stuff */
472 if (copyout(&soft_info, arg, sizeof (soft_info)) != 0) {
473 crypto_free_mech_list(entries, count);
474 return (EFAULT);
477 /* copyout entries */
478 offset = offsetof(crypto_get_soft_info_t, si_list);
479 if (copyout(entries, arg + offset, copyout_size) != 0) {
480 crypto_free_mech_list(entries, count);
481 return (EFAULT);
483 crypto_free_mech_list(entries, count);
484 return (0);
488 * This ioctl disables mechanisms supported by the specified device.
490 /* ARGSUSED */
491 static int
492 load_dev_disabled(dev_t dev, caddr_t arg, int mode, int *rval)
494 crypto_load_dev_disabled_t dev_disabled;
495 crypto_mech_name_t *entries;
496 size_t size;
497 ulong_t offset;
498 uint_t count;
499 uint_t instance;
500 char *dev_name;
501 uint32_t rv;
502 int error = 0;
504 if (copyin(arg, &dev_disabled, sizeof (dev_disabled)) != 0) {
505 error = EFAULT;
506 goto out2;
509 dev_name = dev_disabled.dd_dev_name;
510 /* make sure the device name is null terminated */
511 if (!null_terminated(dev_name)) {
512 rv = CRYPTO_ARGUMENTS_BAD;
513 goto out;
516 count = dev_disabled.dd_count;
517 instance = dev_disabled.dd_dev_instance;
518 if (count == 0) {
519 /* remove the entry */
520 if (crypto_load_dev_disabled(dev_name, instance, 0, NULL) != 0)
521 rv = CRYPTO_FAILED;
522 else
523 rv = CRYPTO_SUCCESS;
524 goto out;
527 if (count > KCF_MAXMECHS) {
528 rv = CRYPTO_ARGUMENTS_BAD;
529 goto out;
532 size = count * sizeof (crypto_mech_name_t);
533 entries = kmem_alloc(size, KM_SLEEP);
535 offset = offsetof(crypto_load_dev_disabled_t, dd_list);
536 if (copyin(arg + offset, entries, size) != 0) {
537 kmem_free(entries, size);
538 error = EFAULT;
539 goto out2;
542 /* 'entries' consumed (but not freed) by crypto_load_dev_disabled() */
543 if (crypto_load_dev_disabled(dev_name, instance, count, entries) != 0) {
544 kmem_free(entries, size);
545 rv = CRYPTO_FAILED;
546 goto out;
548 rv = CRYPTO_SUCCESS;
549 out:
550 dev_disabled.dd_return_value = rv;
552 if (copyout(&dev_disabled, arg, sizeof (dev_disabled)) != 0) {
553 error = EFAULT;
555 out2:
556 return (error);
560 * This ioctl disables mechanisms supported by the specified
561 * cryptographic module.
563 /* ARGSUSED */
564 static int
565 load_soft_disabled(dev_t dev, caddr_t arg, int mode, int *rval)
567 crypto_load_soft_disabled_t soft_disabled;
568 crypto_mech_name_t *entries;
569 size_t size;
570 uint_t count;
571 ulong_t offset;
572 char *name;
573 uint32_t rv;
574 int error = 0;
576 if (copyin(arg, &soft_disabled, sizeof (soft_disabled)) != 0) {
577 error = EFAULT;
578 goto out2;
581 name = soft_disabled.sd_name;
582 /* make sure the name is null terminated */
583 if (!null_terminated(name)) {
584 soft_disabled.sd_return_value = CRYPTO_ARGUMENTS_BAD;
585 if (copyout(&soft_disabled, arg, sizeof (soft_disabled)) != 0) {
586 return (EFAULT);
588 return (0);
591 count = soft_disabled.sd_count;
592 if (count == 0) {
593 /* remove the entry */
594 if (crypto_load_soft_disabled(name, 0, NULL) != 0) {
595 rv = CRYPTO_FAILED;
596 } else {
597 rv = CRYPTO_SUCCESS;
599 goto out;
602 if (count > KCF_MAXMECHS) {
603 rv = CRYPTO_ARGUMENTS_BAD;
604 goto out;
607 size = count * sizeof (crypto_mech_name_t);
608 entries = kmem_alloc(size, KM_SLEEP);
610 offset = offsetof(crypto_load_soft_disabled_t, sd_list);
611 if (copyin(arg + offset, entries, size) != 0) {
612 kmem_free(entries, size);
613 error = EFAULT;
614 goto out2;
617 /* 'entries' is consumed by crypto_load_soft_disabled() */
618 if (crypto_load_soft_disabled(name, count, entries) != 0) {
619 kmem_free(entries, size);
620 rv = CRYPTO_FAILED;
621 goto out;
623 rv = CRYPTO_SUCCESS;
624 out:
625 soft_disabled.sd_return_value = rv;
627 if (copyout(&soft_disabled, arg, sizeof (soft_disabled)) != 0) {
628 error = EFAULT;
630 out2:
631 return (error);
635 * This ioctl loads the supported mechanisms of the specfied cryptographic
636 * module. This is so, at boot time, all software providers do not
637 * have to be opened in order to cause them to register their
638 * supported mechanisms.
640 /* ARGSUSED */
641 static int
642 load_soft_config(dev_t dev, caddr_t arg, int mode, int *rval)
644 crypto_load_soft_config_t soft_config;
645 crypto_mech_name_t *entries;
646 size_t size;
647 uint_t count;
648 ulong_t offset;
649 char *name;
650 uint32_t rv;
651 int error = 0;
653 if (copyin(arg, &soft_config, sizeof (soft_config)) != 0) {
654 error = EFAULT;
655 goto out2;
658 name = soft_config.sc_name;
659 /* make sure the name is null terminated */
660 if (!null_terminated(name)) {
661 soft_config.sc_return_value = CRYPTO_ARGUMENTS_BAD;
662 if (copyout(&soft_config, arg, sizeof (soft_config)) != 0) {
663 return (EFAULT);
665 return (0);
668 count = soft_config.sc_count;
669 if (count == 0) {
670 if (crypto_load_soft_config(name, 0, NULL) != 0) {
671 rv = CRYPTO_FAILED;
672 } else {
673 rv = CRYPTO_SUCCESS;
675 goto out;
678 if (count > KCF_MAXMECHS) {
679 rv = CRYPTO_ARGUMENTS_BAD;
680 goto out;
683 size = count * sizeof (crypto_mech_name_t);
684 entries = kmem_alloc(size, KM_SLEEP);
686 offset = offsetof(crypto_load_soft_config_t, sc_list);
687 if (copyin(arg + offset, entries, size) != 0) {
688 kmem_free(entries, size);
689 error = EFAULT;
690 goto out2;
694 * 'entries' is consumed (but not freed) by
695 * crypto_load_soft_config()
697 if (crypto_load_soft_config(name, count, entries) != 0) {
698 kmem_free(entries, size);
699 rv = CRYPTO_FAILED;
700 goto out;
702 rv = CRYPTO_SUCCESS;
703 out:
704 soft_config.sc_return_value = rv;
706 if (copyout(&soft_config, arg, sizeof (soft_config)) != 0) {
707 error = EFAULT;
709 out2:
710 return (error);
714 * This ioctl unloads the specfied cryptographic module and removes
715 * its table of supported mechanisms.
717 /* ARGSUSED */
718 static int
719 unload_soft_module(dev_t dev, caddr_t arg, int mode, int *rval)
721 crypto_unload_soft_module_t unload_soft_module;
722 char *name;
723 uint32_t rv;
724 int error = 0;
726 if (copyin(arg, &unload_soft_module,
727 sizeof (unload_soft_module)) != 0) {
728 error = EFAULT;
729 goto out2;
732 name = unload_soft_module.sm_name;
733 /* make sure the name is null terminated */
734 if (!null_terminated(name)) {
735 unload_soft_module.sm_return_value = CRYPTO_ARGUMENTS_BAD;
736 if (copyout(&unload_soft_module, arg,
737 sizeof (unload_soft_module)) != 0) {
738 return (EFAULT);
740 return (0);
743 rv = crypto_unload_soft_module(name);
744 out:
745 unload_soft_module.sm_return_value = rv;
747 if (copyout(&unload_soft_module, arg,
748 sizeof (unload_soft_module)) != 0) {
749 error = EFAULT;
751 out2:
752 return (error);
755 static int
756 cryptoadm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *c,
757 int *rval)
759 int error;
760 #define ARG ((caddr_t)arg)
762 switch (cmd) {
763 case CRYPTO_LOAD_DEV_DISABLED:
764 case CRYPTO_LOAD_SOFT_DISABLED:
765 case CRYPTO_LOAD_SOFT_CONFIG:
766 case CRYPTO_UNLOAD_SOFT_MODULE:
767 case CRYPTO_LOAD_DOOR:
768 case CRYPTO_FIPS140_SET:
769 if ((error = drv_priv(c)) != 0)
770 return (error);
771 default:
772 break;
775 switch (cmd) {
776 case CRYPTO_GET_DEV_LIST:
777 return (get_dev_list(dev, ARG, mode, rval));
779 case CRYPTO_GET_DEV_INFO:
780 return (get_dev_info(dev, ARG, mode, rval));
782 case CRYPTO_GET_SOFT_LIST:
783 return (get_soft_list(dev, ARG, mode, rval));
785 case CRYPTO_GET_SOFT_INFO:
786 return (get_soft_info(dev, ARG, mode, rval));
788 case CRYPTO_LOAD_DEV_DISABLED:
789 return (load_dev_disabled(dev, ARG, mode, rval));
791 case CRYPTO_LOAD_SOFT_DISABLED:
792 return (load_soft_disabled(dev, ARG, mode, rval));
794 case CRYPTO_LOAD_SOFT_CONFIG:
795 return (load_soft_config(dev, ARG, mode, rval));
797 case CRYPTO_UNLOAD_SOFT_MODULE:
798 return (unload_soft_module(dev, ARG, mode, rval));
801 return (EINVAL);