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 entries = NULL;
509 count = 0;
510 instance = 0;
511 rv = CRYPTO_SUCCESS;
512 if (copyin(arg, &dev_disabled, sizeof (dev_disabled)) != 0) {
513 error = EFAULT;
514 goto out2;
515 }
516
517 dev_name = dev_disabled.dd_dev_name;
518 /* make sure the device name is null terminated */
519 if (!null_terminated(dev_name)) {
520 rv = CRYPTO_ARGUMENTS_BAD;
521 goto out;
522 }
523
524 count = dev_disabled.dd_count;
525 instance = dev_disabled.dd_dev_instance;
526 if (count == 0) {
527 /* remove the entry */
528 if (crypto_load_dev_disabled(dev_name, instance, 0, NULL) != 0)
529 rv = CRYPTO_FAILED;
530 else
531 rv = CRYPTO_SUCCESS;
532 goto out;
533 }
534
535 if (count > KCF_MAXMECHS) {
536 rv = CRYPTO_ARGUMENTS_BAD;
537 goto out;
538 }
539
540 size = count * sizeof (crypto_mech_name_t);
541 entries = kmem_alloc(size, KM_SLEEP);
542
543 offset = offsetof(crypto_load_dev_disabled_t, dd_list);
544 if (copyin(arg + offset, entries, size) != 0) {
545 kmem_free(entries, size);
546 error = EFAULT;
547 goto out2;
548 }
549
550 /* 'entries' consumed (but not freed) by crypto_load_dev_disabled() */
551 if (crypto_load_dev_disabled(dev_name, instance, count, entries) != 0) {
552 kmem_free(entries, size);
553 rv = CRYPTO_FAILED;
554 goto out;
555 }
556 rv = CRYPTO_SUCCESS;
557 out:
558 dev_disabled.dd_return_value = rv;
559
560 if (copyout(&dev_disabled, arg, sizeof (dev_disabled)) != 0) {
561 error = EFAULT;
562 }
563 out2:
564 if (AU_AUDITING())
565 audit_cryptoadm(CRYPTO_LOAD_DEV_DISABLED, dev_name, entries,
566 count, instance, rv, error);
567 return (error);
568 }
569
570 /*
571 * This ioctl disables mechanisms supported by the specified
572 * cryptographic module.
573 */
574 /* ARGSUSED */
575 static int
load_soft_disabled(dev_t dev,caddr_t arg,int mode,int * rval)576 load_soft_disabled(dev_t dev, caddr_t arg, int mode, int *rval)
577 {
578 crypto_load_soft_disabled_t soft_disabled;
579 crypto_mech_name_t *entries;
580 size_t size;
581 uint_t count;
582 ulong_t offset;
583 char *name;
584 uint32_t rv;
585 int error = 0;
586
587 entries = NULL;
588 count = 0;
589 rv = CRYPTO_SUCCESS;
590 if (copyin(arg, &soft_disabled, sizeof (soft_disabled)) != 0) {
591 error = EFAULT;
592 goto out2;
593 }
594
595 name = soft_disabled.sd_name;
596 /* make sure the name is null terminated */
597 if (!null_terminated(name)) {
598 soft_disabled.sd_return_value = CRYPTO_ARGUMENTS_BAD;
599 if (copyout(&soft_disabled, arg, sizeof (soft_disabled)) != 0) {
600 return (EFAULT);
601 }
602 return (0);
603 }
604
605 count = soft_disabled.sd_count;
606 if (count == 0) {
607 /* remove the entry */
608 if (crypto_load_soft_disabled(name, 0, NULL) != 0) {
609 rv = CRYPTO_FAILED;
610 } else {
611 rv = CRYPTO_SUCCESS;
612 }
613 goto out;
614 }
615
616 if (count > KCF_MAXMECHS) {
617 rv = CRYPTO_ARGUMENTS_BAD;
618 goto out;
619 }
620
621 size = count * sizeof (crypto_mech_name_t);
622 entries = kmem_alloc(size, KM_SLEEP);
623
624 offset = offsetof(crypto_load_soft_disabled_t, sd_list);
625 if (copyin(arg + offset, entries, size) != 0) {
626 kmem_free(entries, size);
627 error = EFAULT;
628 goto out2;
629 }
630
631 /* 'entries' is consumed by crypto_load_soft_disabled() */
632 if (crypto_load_soft_disabled(name, count, entries) != 0) {
633 kmem_free(entries, size);
634 rv = CRYPTO_FAILED;
635 goto out;
636 }
637 rv = CRYPTO_SUCCESS;
638 out:
639 soft_disabled.sd_return_value = rv;
640
641 if (copyout(&soft_disabled, arg, sizeof (soft_disabled)) != 0) {
642 error = EFAULT;
643 }
644 out2:
645 if (AU_AUDITING())
646 audit_cryptoadm(CRYPTO_LOAD_SOFT_DISABLED, name, entries,
647 count, 0, rv, error);
648 return (error);
649 }
650
651 /*
652 * This ioctl loads the supported mechanisms of the specfied cryptographic
653 * module. This is so, at boot time, all software providers do not
654 * have to be opened in order to cause them to register their
655 * supported mechanisms.
656 */
657 /* ARGSUSED */
658 static int
load_soft_config(dev_t dev,caddr_t arg,int mode,int * rval)659 load_soft_config(dev_t dev, caddr_t arg, int mode, int *rval)
660 {
661 crypto_load_soft_config_t soft_config;
662 crypto_mech_name_t *entries;
663 size_t size;
664 uint_t count;
665 ulong_t offset;
666 char *name;
667 uint32_t rv;
668 int error = 0;
669
670 entries = NULL;
671 count = 0;
672 rv = CRYPTO_SUCCESS;
673 if (copyin(arg, &soft_config, sizeof (soft_config)) != 0) {
674 error = EFAULT;
675 goto out2;
676 }
677
678 name = soft_config.sc_name;
679 /* make sure the name is null terminated */
680 if (!null_terminated(name)) {
681 soft_config.sc_return_value = CRYPTO_ARGUMENTS_BAD;
682 if (copyout(&soft_config, arg, sizeof (soft_config)) != 0) {
683 return (EFAULT);
684 }
685 return (0);
686 }
687
688 count = soft_config.sc_count;
689 if (count == 0) {
690 if (crypto_load_soft_config(name, 0, NULL) != 0) {
691 rv = CRYPTO_FAILED;
692 } else {
693 rv = CRYPTO_SUCCESS;
694 }
695 goto out;
696 }
697
698 if (count > KCF_MAXMECHS) {
699 rv = CRYPTO_ARGUMENTS_BAD;
700 goto out;
701 }
702
703 size = count * sizeof (crypto_mech_name_t);
704 entries = kmem_alloc(size, KM_SLEEP);
705
706 offset = offsetof(crypto_load_soft_config_t, sc_list);
707 if (copyin(arg + offset, entries, size) != 0) {
708 kmem_free(entries, size);
709 error = EFAULT;
710 goto out2;
711 }
712
713 /*
714 * 'entries' is consumed (but not freed) by
715 * crypto_load_soft_config()
716 */
717 if (crypto_load_soft_config(name, count, entries) != 0) {
718 kmem_free(entries, size);
719 rv = CRYPTO_FAILED;
720 goto out;
721 }
722 rv = CRYPTO_SUCCESS;
723 out:
724 soft_config.sc_return_value = rv;
725
726 if (copyout(&soft_config, arg, sizeof (soft_config)) != 0) {
727 error = EFAULT;
728 }
729 out2:
730 if (AU_AUDITING())
731 audit_cryptoadm(CRYPTO_LOAD_SOFT_CONFIG, name, entries, count,
732 0, rv, error);
733 return (error);
734 }
735
736 /*
737 * This ioctl unloads the specfied cryptographic module and removes
738 * its table of supported mechanisms.
739 */
740 /* ARGSUSED */
741 static int
unload_soft_module(dev_t dev,caddr_t arg,int mode,int * rval)742 unload_soft_module(dev_t dev, caddr_t arg, int mode, int *rval)
743 {
744 crypto_unload_soft_module_t unload_soft_module;
745 char *name;
746 uint32_t rv;
747 int error = 0;
748
749 rv = CRYPTO_SUCCESS;
750 if (copyin(arg, &unload_soft_module,
751 sizeof (unload_soft_module)) != 0) {
752 error = EFAULT;
753 goto out;
754 }
755
756 name = unload_soft_module.sm_name;
757 /* make sure the name is null terminated */
758 if (!null_terminated(name)) {
759 unload_soft_module.sm_return_value = CRYPTO_ARGUMENTS_BAD;
760 if (copyout(&unload_soft_module, arg,
761 sizeof (unload_soft_module)) != 0) {
762 return (EFAULT);
763 }
764 return (0);
765 }
766
767 rv = crypto_unload_soft_module(name);
768 unload_soft_module.sm_return_value = rv;
769
770 if (copyout(&unload_soft_module, arg,
771 sizeof (unload_soft_module)) != 0) {
772 error = EFAULT;
773 }
774 out:
775 if (AU_AUDITING())
776 audit_cryptoadm(CRYPTO_UNLOAD_SOFT_MODULE, name, NULL, 0, 0,
777 rv, error);
778
779 return (error);
780 }
781
782 static int
cryptoadm_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * c,int * rval)783 cryptoadm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *c,
784 int *rval)
785 {
786 int error;
787 #define ARG ((caddr_t)arg)
788
789 switch (cmd) {
790 case CRYPTO_LOAD_DEV_DISABLED:
791 case CRYPTO_LOAD_SOFT_DISABLED:
792 case CRYPTO_LOAD_SOFT_CONFIG:
793 case CRYPTO_UNLOAD_SOFT_MODULE:
794 case CRYPTO_LOAD_DOOR:
795 case CRYPTO_FIPS140_SET:
796 if ((error = drv_priv(c)) != 0)
797 return (error);
798 default:
799 break;
800 }
801
802 switch (cmd) {
803 case CRYPTO_GET_DEV_LIST:
804 return (get_dev_list(dev, ARG, mode, rval));
805
806 case CRYPTO_GET_DEV_INFO:
807 return (get_dev_info(dev, ARG, mode, rval));
808
809 case CRYPTO_GET_SOFT_LIST:
810 return (get_soft_list(dev, ARG, mode, rval));
811
812 case CRYPTO_GET_SOFT_INFO:
813 return (get_soft_info(dev, ARG, mode, rval));
814
815 case CRYPTO_LOAD_DEV_DISABLED:
816 return (load_dev_disabled(dev, ARG, mode, rval));
817
818 case CRYPTO_LOAD_SOFT_DISABLED:
819 return (load_soft_disabled(dev, ARG, mode, rval));
820
821 case CRYPTO_LOAD_SOFT_CONFIG:
822 return (load_soft_config(dev, ARG, mode, rval));
823
824 case CRYPTO_UNLOAD_SOFT_MODULE:
825 return (unload_soft_module(dev, ARG, mode, rval));
826 }
827
828 return (EINVAL);
829 }
830