20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <strings.h>
30 #include <unistd.h>
31 #include <locale.h>
32 #include <libgen.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <sys/crypto/ioctladmin.h>
36 #include <signal.h>
37 #include <sys/crypto/elfsign.h>
38 #include "cryptoadm.h"
39
40 static int err; /* to store the value of errno in case being overwritten */
41 static int check_hardware_provider(char *, char *, int *, int *);
42
43 /*
44 * Display the mechanism list for a kernel software provider.
45 */
46 int
47 list_mechlist_for_soft(char *provname)
48 {
49 mechlist_t *pmechlist;
50 int rc;
51
52 if (provname == NULL) {
53 return (FAILURE);
54 }
55
56 rc = get_soft_info(provname, &pmechlist);
57 if (rc == SUCCESS) {
58 (void) filter_mechlist(&pmechlist, RANDOM);
59 print_mechlist(provname, pmechlist);
60 free_mechlist(pmechlist);
61 } else {
62 cryptoerror(LOG_STDERR, gettext(
63 "failed to retrieve the mechanism list for %s."),
64 provname);
65 }
66
67 return (rc);
68
69 }
70
71 /*
72 * Display the mechanism list for a kernel hardware provider.
73 */
74 int
75 list_mechlist_for_hard(char *provname)
76 {
77 mechlist_t *pmechlist;
78 char devname[MAXNAMELEN];
79 int inst_num;
80 int count;
81 int rc = SUCCESS;
82
83 if (provname == NULL) {
84 return (FAILURE);
85 }
86
87 /*
88 * Check if the provider is valid. If it is valid, get the number of
89 * mechanisms also.
90 */
91 if (check_hardware_provider(provname, devname, &inst_num, &count) ==
92 FAILURE) {
93 return (FAILURE);
94 }
95
96 /* Get the mechanism list for the kernel hardware provider */
97 if ((rc = get_dev_info(devname, inst_num, count, &pmechlist)) ==
98 SUCCESS) {
99 (void) filter_mechlist(&pmechlist, RANDOM);
100 print_mechlist(provname, pmechlist);
101 free_mechlist(pmechlist);
102 }
103
104 return (rc);
105 }
106
107
108 /*
109 * Display the policy information for a kernel software provider.
110 */
111 int
112 list_policy_for_soft(char *provname)
113 {
114 int rc;
115 entry_t *pent = NULL;
116 mechlist_t *pmechlist;
117 boolean_t has_random = B_FALSE;
118 boolean_t has_mechs = B_FALSE;
119
120 if (provname == NULL) {
121 return (FAILURE);
122 }
123
124 if ((pent = getent_kef(provname)) == NULL) {
125 cryptoerror(LOG_STDERR, gettext("%s does not exist."),
126 provname);
127 return (FAILURE);
128 }
129
130 rc = get_soft_info(provname, &pmechlist);
131 if (rc == SUCCESS) {
132 has_random = filter_mechlist(&pmechlist, RANDOM);
133 if (pmechlist != NULL) {
134 has_mechs = B_TRUE;
135 free_mechlist(pmechlist);
136 }
137 } else {
138 cryptoerror(LOG_STDERR, gettext(
139 "failed to retrieve the mechanism list for %s."),
140 provname);
141 return (rc);
142 }
143
144 print_kef_policy(pent, has_random, has_mechs);
145 free_entry(pent);
146 return (SUCCESS);
147 }
148
149
150
151 /*
152 * Display the policy information for a kernel hardware provider.
153 */
154 int
155 list_policy_for_hard(char *provname)
156 {
157 entry_t *pent;
158 boolean_t is_active;
159 mechlist_t *pmechlist;
160 char devname[MAXNAMELEN];
161 int inst_num;
162 int count;
163 int rc = SUCCESS;
164 boolean_t has_random = B_FALSE;
165 boolean_t has_mechs = B_FALSE;
166
167 if (provname == NULL) {
168 return (FAILURE);
169 }
170
171 /*
172 * Check if the provider is valid. If it is valid, get the number of
173 * mechanisms also.
174 */
175 if (check_hardware_provider(provname, devname, &inst_num, &count) ==
176 FAILURE) {
177 return (FAILURE);
178 }
179
182 SUCCESS) {
183 has_random = filter_mechlist(&pmechlist, RANDOM);
184
185 if (pmechlist != NULL) {
186 has_mechs = B_TRUE;
187 free_mechlist(pmechlist);
188 }
189 } else {
190 cryptoerror(LOG_STDERR, gettext(
191 "failed to retrieve the mechanism list for %s."),
192 devname);
193 return (rc);
194 }
195
196 /*
197 * If the hardware provider has an entry in the kcf.conf file,
198 * some of its mechanisms must have been disabled. Print out
199 * the disabled list from the config file entry. Otherwise,
200 * if it is active, then all the mechanisms for it are enabled.
201 */
202 if ((pent = getent_kef(provname)) != NULL) {
203 print_kef_policy(pent, has_random, has_mechs);
204 free_entry(pent);
205 return (SUCCESS);
206 } else {
207 if (check_active_for_hard(provname, &is_active) ==
208 FAILURE) {
209 return (FAILURE);
210 } else if (is_active == B_TRUE) {
211 (void) printf(gettext(
212 "%s: all mechanisms are enabled."), provname);
213 if (has_random)
214 /*
215 * TRANSLATION_NOTE
216 * "random" is a keyword and not to be
217 * translated.
218 */
219 (void) printf(gettext(" %s is enabled.\n"),
220 "random");
221 else
222 (void) printf("\n");
223 return (SUCCESS);
224 } else {
225 cryptoerror(LOG_STDERR,
226 gettext("%s does not exist."), provname);
227 return (FAILURE);
228 }
229 }
230 }
231
232
233
234 int
235 disable_kef_hardware(char *provname, boolean_t rndflag, boolean_t allflag,
236 mechlist_t *dislist)
237 {
238 crypto_load_dev_disabled_t *pload_dev_dis;
239 mechlist_t *infolist;
240 entry_t *pent;
241 boolean_t new_dev_entry = B_FALSE;
242 char devname[MAXNAMELEN];
243 int inst_num;
244 int count;
245 int fd;
246 int rc = SUCCESS;
247
248 if (provname == NULL) {
249 return (FAILURE);
250 }
251
252 /*
253 * Check if the provider is valid. If it is valid, get the number of
254 * mechanisms also.
255 */
256 if (check_hardware_provider(provname, devname, &inst_num, &count)
257 == FAILURE) {
258 return (FAILURE);
259 }
260
261 /* Get the mechanism list for the kernel hardware provider */
262 if (get_dev_info(devname, inst_num, count, &infolist) == FAILURE) {
263 return (FAILURE);
264 }
265
266 /*
267 * Get the entry of this hardware provider from the config file.
268 * If there is no entry yet, create one for it.
269 */
270 if ((pent = getent_kef(provname)) == NULL) {
271 if ((pent = malloc(sizeof (entry_t))) == NULL) {
272 cryptoerror(LOG_STDERR, gettext("out of memory."));
273 free_mechlist(infolist);
274 return (FAILURE);
275 }
276 new_dev_entry = B_TRUE;
277 (void) strlcpy(pent->name, provname, MAXNAMELEN);
278 pent->suplist = NULL;
279 pent->sup_count = 0;
280 pent->dislist = NULL;
281 pent->dis_count = 0;
282 }
283
284 /*
285 * kCF treats random as an internal mechanism. So, we need to
286 * filter it from the mechanism list here, if we are NOT disabling
287 * or enabling the random feature. Note that we map random feature at
288 * cryptoadm(1M) level to the "random" mechanism in kCF.
289 */
290 if (!rndflag) {
291 (void) filter_mechlist(&dislist, RANDOM);
292 }
293
294 /* Calculate the new disabled list */
295 if (disable_mechs(&pent, infolist, allflag, dislist) == FAILURE) {
296 free_mechlist(infolist);
297 free_entry(pent);
298 return (FAILURE);
299 }
300 free_mechlist(infolist);
301
336 strerror(errno));
337 free(pload_dev_dis);
338 (void) close(fd);
339 return (FAILURE);
340 }
341
342 if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) {
343 cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl return_value = "
344 "%d", pload_dev_dis->dd_return_value);
345 free(pload_dev_dis);
346 (void) close(fd);
347 return (FAILURE);
348 }
349
350 free(pload_dev_dis);
351 (void) close(fd);
352 return (SUCCESS);
353 }
354
355
356
357 int
358 disable_kef_software(char *provname, boolean_t rndflag, boolean_t allflag,
359 mechlist_t *dislist)
360 {
361 crypto_load_soft_disabled_t *pload_soft_dis = NULL;
362 mechlist_t *infolist;
363 entry_t *pent;
364 boolean_t is_active;
365 int fd;
366
367 if (provname == NULL) {
368 return (FAILURE);
369 }
370
371 /* Get the entry of this provider from the config file. */
372 if ((pent = getent_kef(provname)) == NULL) {
373 cryptoerror(LOG_STDERR,
374 gettext("%s does not exist."), provname);
375 return (FAILURE);
376 }
377
378 /*
379 * Check if the kernel software provider is currently unloaded.
380 * If it is unloaded, return FAILURE, because the disable subcommand
381 * can not perform on inactive (unloaded) providers.
382 */
383 if (check_active_for_soft(provname, &is_active) == FAILURE) {
384 free_entry(pent);
385 return (FAILURE);
386 } else if (is_active == B_FALSE) {
387 /*
388 * TRANSLATION_NOTE
389 * "disable" is a keyword and not to be translated.
390 */
391 cryptoerror(LOG_STDERR,
392 gettext("can not do %1$s on an unloaded "
393 "kernel software provider -- %2$s."), "disable", provname);
394 free_entry(pent);
395 return (FAILURE);
396 }
397
398 /* Get the mechanism list for the software provider */
399 if (get_soft_info(provname, &infolist) == FAILURE) {
400 free(pent);
401 return (FAILURE);
402 }
403
404 /* See comments in disable_kef_hardware() */
405 if (!rndflag) {
406 (void) filter_mechlist(&infolist, RANDOM);
407 }
408
409 /* Calculate the new disabled list */
410 if (disable_mechs(&pent, infolist, allflag, dislist) == FAILURE) {
411 free_entry(pent);
412 free_mechlist(infolist);
413 return (FAILURE);
414 }
415
416 /* infolist is no longer needed; free it */
417 free_mechlist(infolist);
418
419 /* Update the kcf.conf file with the updated entry */
420 if (update_kcfconf(pent, MODIFY_MODE) == FAILURE) {
421 free_entry(pent);
422 return (FAILURE);
423 }
424
425 /* Inform kernel about the new disabled list. */
426 if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) {
427 free_entry(pent);
428 return (FAILURE);
429 }
430
431 /* pent is no longer needed; free it. */
432 free_entry(pent);
433
434 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
435 cryptoerror(LOG_STDERR,
436 gettext("failed to open %s for RW: %s"),
437 ADMIN_IOCTL_DEVICE, strerror(errno));
438 free(pload_soft_dis);
439 return (FAILURE);
440 }
441
442 if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis) == -1) {
443 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: %s",
444 strerror(errno));
445 free(pload_soft_dis);
446 (void) close(fd);
447 return (FAILURE);
448 }
449
450 if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) {
451 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl return_value = "
452 "%d", pload_soft_dis->sd_return_value);
453 free(pload_soft_dis);
454 (void) close(fd);
455 return (FAILURE);
456 }
457
458 free(pload_soft_dis);
459 (void) close(fd);
460 return (SUCCESS);
461 }
462
463
464 int
465 enable_kef(char *provname, boolean_t rndflag, boolean_t allflag,
466 mechlist_t *mlist)
467 {
468 crypto_load_soft_disabled_t *pload_soft_dis = NULL;
469 crypto_load_dev_disabled_t *pload_dev_dis = NULL;
470 entry_t *pent;
471 boolean_t redo_flag = B_FALSE;
472 int fd;
473 int rc = SUCCESS;
474
475
476 /* Get the entry with the provider name from the kcf.conf file */
477 pent = getent_kef(provname);
478
479 if (is_device(provname)) {
480 if (pent == NULL) {
481 /*
482 * This device doesn't have an entry in the config
483 * file, therefore nothing is disabled.
484 */
485 cryptoerror(LOG_STDERR, gettext(
486 "all mechanisms are enabled already for %s."),
487 provname);
488 return (SUCCESS);
489 }
490 } else { /* a software module */
491 if (pent == NULL) {
492 cryptoerror(LOG_STDERR,
493 gettext("%s does not exist."), provname);
494 return (FAILURE);
495 } else if (pent->dis_count == 0) {
496 /* nothing to be enabled. */
497 cryptoerror(LOG_STDERR, gettext(
498 "all mechanisms are enabled already for %s."),
499 provname);
500 free_entry(pent);
501 return (SUCCESS);
502 }
503 }
504
505 if (!rndflag) {
506 /* See comments in disable_kef_hardware() */
507 redo_flag = filter_mechlist(&pent->dislist, RANDOM);
508 if (redo_flag)
509 pent->dis_count--;
510 }
511
512 /* Update the entry by enabling mechanisms for this provider */
513 if ((rc = enable_mechs(&pent, allflag, mlist)) != SUCCESS) {
514 free_entry(pent);
515 return (rc);
516 }
517
518 if (redo_flag) {
519 mechlist_t *tmp;
520
521 if ((tmp = create_mech(RANDOM)) == NULL) {
522 free_entry(pent);
523 return (FAILURE);
524 }
525 tmp->next = pent->dislist;
526 pent->dislist = tmp;
527 pent->dis_count++;
528 }
529
530 /*
531 * Update the kcf.conf file with the updated entry.
532 * For a hardware provider, if there is no more disabled mechanism,
533 * the entire entry in the config file should be removed.
534 */
535 if (is_device(pent->name) && (pent->dis_count == 0)) {
536 rc = update_kcfconf(pent, DELETE_MODE);
537 } else {
538 rc = update_kcfconf(pent, MODIFY_MODE);
539 }
540
541 if (rc == FAILURE) {
542 free_entry(pent);
543 return (FAILURE);
544 }
545
546
547 /* Inform Kernel about the policy change */
548
549 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
550 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
551 ADMIN_IOCTL_DEVICE, strerror(errno));
552 return (FAILURE);
553 }
554
555 if (is_device(provname)) {
556 /* LOAD_DEV_DISABLED */
557 if ((pload_dev_dis = setup_dev_dis(pent)) == NULL) {
558 return (FAILURE);
559 }
560
561 if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis) == -1) {
562 cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl failed: "
563 "%s", strerror(errno));
564 free(pload_dev_dis);
565 (void) close(fd);
566 return (FAILURE);
567 }
568
569 if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) {
570 cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl "
571 "return_value = %d",
572 pload_dev_dis->dd_return_value);
573 free(pload_dev_dis);
574 (void) close(fd);
575 return (FAILURE);
576 }
577
578 } else {
579 /* LOAD_SOFT_DISABLED */
580 if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) {
581 return (FAILURE);
582 }
583
584 if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis)
585 == -1) {
586 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: "
587 "%s", strerror(errno));
588 free(pload_soft_dis);
589 (void) close(fd);
590 return (FAILURE);
591 }
592
593 if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) {
594 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl "
595 "return_value = %d",
596 pload_soft_dis->sd_return_value);
597 free(pload_soft_dis);
598 (void) close(fd);
599 return (FAILURE);
600 }
601 }
602
603 (void) close(fd);
604 return (SUCCESS);
605 }
606
607
608 /*
609 * Install a software module with the specified mechanism list into the system.
610 * This routine adds an entry into the config file for this software module
611 * first, then makes a CRYPTO_LOAD_SOFT_CONFIG ioctl call to inform kernel
612 * about the new addition.
613 */
614 int
615 install_kef(char *provname, mechlist_t *mlist)
616 {
617 crypto_load_soft_config_t *pload_soft_conf = NULL;
618 boolean_t found;
619 entry_t *pent;
620 FILE *pfile;
621 FILE *pfile_tmp;
622 char tmpfile_name[MAXPATHLEN];
623 char *ptr;
624 char *str;
625 char *name;
626 char buffer[BUFSIZ];
627 char buffer2[BUFSIZ];
628 int found_count;
629 int fd;
630 int rc = SUCCESS;
631
632 if ((provname == NULL) || (mlist == NULL)) {
633 return (FAILURE);
634 }
635
636 /* Check if the provider already exists */
637 if ((pent = getent_kef(provname)) != NULL) {
638 cryptoerror(LOG_STDERR, gettext("%s exists already."),
639 provname);
640 free_entry(pent);
641 return (FAILURE);
642 }
643
644 /* Create an entry with provname and mlist. */
645 if ((pent = malloc(sizeof (entry_t))) == NULL) {
646 cryptoerror(LOG_STDERR, gettext("out of memory."));
647 return (FAILURE);
648 }
649
650 (void) strlcpy(pent->name, provname, MAXNAMELEN);
651 pent->sup_count = get_mech_count(mlist);
652 pent->suplist = mlist;
653 pent->dis_count = 0;
654 pent->dislist = NULL;
655
656 /* Append an entry for this software module to the kcf.conf file. */
657 if ((str = ent2str(pent)) == NULL) {
658 free_entry(pent);
659 return (FAILURE);
660 }
661
662 if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) {
663 err = errno;
664 cryptoerror(LOG_STDERR,
665 gettext("failed to update the configuration - %s"),
666 strerror(err));
667 cryptodebug("failed to open %s for write.", _PATH_KCF_CONF);
668 free_entry(pent);
669 return (FAILURE);
670 }
671
672 if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
673 err = errno;
674 cryptoerror(LOG_STDERR,
720 rc = FAILURE;
721 break;
722 } else if (strcmp(provname, name) == 0) {
723 found = B_TRUE;
724 found_count++;
725 }
726 }
727
728 if (found == B_FALSE) {
729 if (fputs(buffer, pfile_tmp) == EOF) {
730 rc = FAILURE;
731 }
732 } else {
733 if (found_count == 1) {
734 if (fputs(str, pfile_tmp) == EOF) {
735 rc = FAILURE;
736 }
737 } else {
738 /*
739 * Found a second entry with #libname.
740 * Should not happen. The kcf.conf ffile
741 * is corrupted. Give a warning and skip
742 * this entry.
743 */
744 cryptoerror(LOG_STDERR, gettext(
745 "(Warning) Found an additional reserved "
746 "entry for %s."), provname);
747 }
748 }
749
750 if (rc == FAILURE) {
751 break;
752 }
753 }
754 (void) fclose(pfile);
755
756 if (rc == FAILURE) {
757 cryptoerror(LOG_STDERR, gettext("write error."));
758 (void) fclose(pfile_tmp);
759 if (unlink(tmpfile_name) != 0) {
760 err = errno;
775 cryptoerror(LOG_STDERR, gettext(
776 "failed to write to %s: %s"), tmpfile_name,
777 strerror(errno));
778 (void) fclose(pfile_tmp);
779 if (unlink(tmpfile_name) != 0) {
780 err = errno;
781 cryptoerror(LOG_STDERR, gettext(
782 "(Warning) failed to remove %s: %s"),
783 tmpfile_name, strerror(err));
784 }
785 free_entry(pent);
786 return (FAILURE);
787 }
788 }
789
790 if (fclose(pfile_tmp) != 0) {
791 err = errno;
792 cryptoerror(LOG_STDERR,
793 gettext("failed to close %s: %s"), tmpfile_name,
794 strerror(err));
795 return (FAILURE);
796 }
797
798 if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) {
799 err = errno;
800 cryptoerror(LOG_STDERR,
801 gettext("failed to update the configuration - %s"),
802 strerror(err));
803 cryptodebug("failed to rename %s to %s: %s", tmpfile_name,
804 _PATH_KCF_CONF, strerror(err));
805 rc = FAILURE;
806 } else if (chmod(_PATH_KCF_CONF,
807 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
808 err = errno;
809 cryptoerror(LOG_STDERR,
810 gettext("failed to update the configuration - %s"),
811 strerror(err));
812 cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF,
813 strerror(err));
814 rc = FAILURE;
815 } else {
816 rc = SUCCESS;
817 }
818
819 if (rc == FAILURE) {
820 if (unlink(tmpfile_name) != 0) {
821 err = errno;
822 cryptoerror(LOG_STDERR, gettext(
823 "(Warning) failed to remove %s: %s"),
824 tmpfile_name, strerror(err));
825 }
826 return (FAILURE);
827 }
828
829
830 /* Inform kernel of this new software module. */
831
832 if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) {
833 free_entry(pent);
834 return (FAILURE);
835 }
836
837 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
838 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
839 ADMIN_IOCTL_DEVICE, strerror(errno));
840 free_entry(pent);
841 free(pload_soft_conf);
842 return (FAILURE);
843 }
844
845 if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG, pload_soft_conf) == -1) {
858 free(pload_soft_conf);
859 (void) close(fd);
860 return (FAILURE);
861 }
862
863 free_entry(pent);
864 free(pload_soft_conf);
865 (void) close(fd);
866 return (SUCCESS);
867 }
868
869 /*
870 * Uninstall the software module. This routine first unloads the software
871 * module with 3 ioctl calls, then deletes its entry from the config file.
872 * Removing an entry from the config file needs to be done last to ensure
873 * that there is still an entry if the earlier unload failed for any reason.
874 */
875 int
876 uninstall_kef(char *provname)
877 {
878 entry_t *pent;
879 boolean_t is_active;
880 boolean_t in_package;
881 boolean_t found;
882 FILE *pfile;
883 FILE *pfile_tmp;
884 char tmpfile_name[MAXPATHLEN];
885 char *name;
886 char strbuf[BUFSIZ];
887 char buffer[BUFSIZ];
888 char buffer2[BUFSIZ];
889 char *str;
890 int len;
891 int rc = SUCCESS;
892
893
894 /* Check if it is in the kcf.conf file first. */
895 if ((pent = getent_kef(provname)) == NULL) {
896 cryptoerror(LOG_STDERR,
897 gettext("%s does not exist."), provname);
898 return (FAILURE);
899 }
900
901
902 /*
903 * Get rid of the disabled list for the provider and get the converted
904 * string for the entry. This is to prepare the string for a provider
905 * that is in a package.
906 */
907 free_mechlist(pent->dislist);
908 pent->dis_count = 0;
909 pent->dislist = NULL;
910 str = ent2str(pent);
911 free_entry(pent);
912 if (str == NULL) {
913 cryptoerror(LOG_STDERR, gettext("internal error."));
914 return (FAILURE);
915 }
916 (void) snprintf(strbuf, sizeof (strbuf), "%s%s", "#", str);
917 free(str);
918
919 /* If it is not loaded, unload it first */
920 if (check_active_for_soft(provname, &is_active) == FAILURE) {
921 return (FAILURE);
922 } else if ((is_active == B_TRUE) &&
923 (unload_kef_soft(provname, B_TRUE) == FAILURE)) {
924 cryptoerror(LOG_STDERR,
925 gettext("failed to uninstall %s.\n"), provname);
926 return (FAILURE);
927 }
928
929 /*
930 * Remove the entry from the config file. If the provider to be
931 * uninstalled is in a package, just comment it off.
932 */
933 if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) {
934 err = errno;
935 cryptoerror(LOG_STDERR,
936 gettext("failed to update the configuration - %s"),
937 strerror(err));
938 cryptodebug("failed to open %s for write.", _PATH_KCF_CONF);
939 return (FAILURE);
940 }
941
942 if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
943 err = errno;
944 cryptoerror(LOG_STDERR,
945 gettext("failed to lock the configuration - %s"),
946 strerror(err));
947 (void) fclose(pfile);
948 return (FAILURE);
949 }
950
951 /*
952 * Create a temporary file in the /etc/crypto directory to save
953 * the new configuration file first.
954 */
955 (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
956 if (mkstemp(tmpfile_name) == -1) {
957 err = errno;
958 cryptoerror(LOG_STDERR,
959 gettext("failed to create a temporary file - %s"),
960 strerror(err));
961 (void) fclose(pfile);
962 return (FAILURE);
963 }
964
965 if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
966 err = errno;
967 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
968 tmpfile_name, strerror(err));
969 if (unlink(tmpfile_name) != 0) {
970 err = errno;
971 cryptoerror(LOG_STDERR, gettext(
972 "(Warning) failed to remove %s: %s"), tmpfile_name,
973 strerror(err));
974 }
975 (void) fclose(pfile);
976 return (FAILURE);
977 }
978
979 /*
980 * Loop thru the config file. If the kernel software provider
981 * to be uninstalled is in a package, just comment it off.
982 */
983 in_package = B_FALSE;
984 while (fgets(buffer, BUFSIZ, pfile) != NULL) {
985 found = B_FALSE;
986 if (!(buffer[0] == ' ' || buffer[0] == '\n' ||
987 buffer[0] == '\t')) {
988 if (strstr(buffer, " Start ") != NULL) {
989 in_package = B_TRUE;
990 } else if (strstr(buffer, " End ") != NULL) {
991 in_package = B_FALSE;
992 } else if (buffer[0] != '#') {
993 (void) strlcpy(buffer2, buffer, BUFSIZ);
994
995 /* get rid of trailing '\n' */
996 len = strlen(buffer2);
997 if (buffer2[len-1] == '\n') {
998 len--;
999 }
1000 buffer2[len] = '\0';
1001
1002 if ((name = strtok(buffer2, SEP_COLON))
1003 == NULL) {
1004 rc = FAILURE;
1005 break;
1006 } else if (strcmp(provname, name) == 0) {
1007 found = B_TRUE;
1008 }
1009 }
1010 }
1011
1012 if (found) {
1013 if (in_package) {
1014 if (fputs(strbuf, pfile_tmp) == EOF) {
1015 rc = FAILURE;
1016 }
1017 }
1018 } else {
1019 if (fputs(buffer, pfile_tmp) == EOF) {
1020 rc = FAILURE;
1021 }
1022 }
1023
1024 if (rc == FAILURE) {
1025 break;
1026 }
1027 }
1028
1029 if (rc == FAILURE) {
1030 cryptoerror(LOG_STDERR, gettext("write error."));
1031 (void) fclose(pfile);
1032 (void) fclose(pfile_tmp);
1033 if (unlink(tmpfile_name) != 0) {
1034 err = errno;
1035 cryptoerror(LOG_STDERR, gettext(
1036 "(Warning) failed to remove %s: %s"), tmpfile_name,
1037 strerror(err));
1038 }
1039 return (FAILURE);
1040 }
1041
1042 (void) fclose(pfile);
1043 if (fclose(pfile_tmp) != 0) {
1044 err = errno;
1045 cryptoerror(LOG_STDERR,
1046 gettext("failed to close %s: %s"), tmpfile_name,
1047 strerror(err));
1048 return (FAILURE);
1049 }
1050
1051 /* Now update the real config file */
1052 if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) {
1053 err = errno;
1054 cryptoerror(LOG_STDERR,
1055 gettext("failed to update the configuration - %s"),
1056 strerror(err));
1057 cryptodebug("failed to rename %1$s to %2$s: %3$s", tmpfile,
1058 _PATH_KCF_CONF, strerror(err));
1059 rc = FAILURE;
1060 } else if (chmod(_PATH_KCF_CONF,
1061 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
1062 err = errno;
1063 cryptoerror(LOG_STDERR,
1064 gettext("failed to update the configuration - %s"),
1065 strerror(err));
1066 cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF,
1067 strerror(err));
1068 rc = FAILURE;
1069 } else {
1070 rc = SUCCESS;
1071 }
1072
1073 if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
1074 err = errno;
1075 cryptoerror(LOG_STDERR, gettext(
1076 "(Warning) failed to remove %s: %s"), tmpfile_name,
1077 strerror(err));
1078 }
1079
1080 return (rc);
1081
1082 }
1083
1084
1085 int
1086 refresh(void)
1087 {
1088 crypto_get_soft_list_t *psoftlist_kernel = NULL;
1089 crypto_load_soft_config_t *pload_soft_conf = NULL;
1090 crypto_load_soft_disabled_t *pload_soft_dis = NULL;
1091 crypto_load_dev_disabled_t *pload_dev_dis = NULL;
1092 entrylist_t *pdevlist = NULL;
1093 entrylist_t *psoftlist = NULL;
1094 entrylist_t *ptr;
1095 boolean_t found;
1096 char *psoftname;
1097 int fd;
1098 int rc = SUCCESS;
1099 int i;
1100
1101 if (get_soft_list(&psoftlist_kernel) == FAILURE) {
1102 cryptoerror(LOG_ERR, gettext("Failed to retrieve the "
1103 "software provider list from kernel."));
1104 return (FAILURE);
1105 }
1106
1107 if (get_kcfconf_info(&pdevlist, &psoftlist) == FAILURE) {
1108 cryptoerror(LOG_ERR, "failed to retrieve the providers' "
1109 "information from the configuration file - %s.",
1110 _PATH_KCF_CONF);
1111 return (FAILURE);
1112 }
1113
1114 /*
1115 * If a kernel software provider is in kernel, but it is not in the
1116 * kcf.conf file, it must have been pkgrm'ed and needs to be unloaded
1117 * now.
1118 */
1119 if (psoftlist_kernel->sl_soft_count > 0) {
1120 psoftname = psoftlist_kernel->sl_soft_names;
1121 for (i = 0; i < psoftlist_kernel->sl_soft_count; i++) {
1122 ptr = psoftlist;
1123 found = B_FALSE;
1124 while (ptr != NULL) {
1125 if (strcmp(psoftname, ptr->pent->name) == 0) {
1126 found = B_TRUE;
1127 break;
1128 }
1129 ptr = ptr->next;
1130 }
1131
1132 if (!found) {
1133 rc = unload_kef_soft(psoftname, B_FALSE);
1134 if (rc == FAILURE) {
1135 cryptoerror(LOG_ERR, gettext(
1136 "WARNING - the provider %s is "
1137 "still in kernel."), psoftname);
1138 }
1139 }
1140 psoftname = psoftname + strlen(psoftname) + 1;
1141 }
1142 }
1143 free(psoftlist_kernel);
1144
1145 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
1146 err = errno;
1147 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
1148 ADMIN_IOCTL_DEVICE, strerror(err));
1149 free(psoftlist);
1150 free(pdevlist);
1151 return (FAILURE);
1152 }
1153
1154 /*
1155 * For each software module, pass two sets of information to kernel
1156 * - the supported list and the disabled list
1157 */
1158 ptr = psoftlist;
1159 while (ptr != NULL) {
1160 /* load the supported list */
1161 if ((pload_soft_conf = setup_soft_conf(ptr->pent)) == NULL) {
1162 rc = FAILURE;
1163 break;
1164 }
1165
1166 if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG, pload_soft_conf)
1167 == -1) {
1168 cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s",
1169 strerror(errno));
1170 free(pload_soft_conf);
1171 rc = FAILURE;
1172 break;
1173 }
1174
1175 if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) {
1176 cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl "
1177 "return_value = %d",
1178 pload_soft_conf->sc_return_value);
1179 free(pload_soft_conf);
1180 rc = FAILURE;
1181 break;
1182 }
1183
1184 /* load the disabled list */
1185 if (ptr->pent->dis_count != 0) {
1186 pload_soft_dis = setup_soft_dis(ptr->pent);
1187 if (pload_soft_dis == NULL) {
1188 rc = FAILURE;
1189 break;
1190 }
1191
1192 if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED,
1193 pload_soft_dis) == -1) {
1194 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl "
1195 "failed: %s", strerror(errno));
1196 free(pload_soft_dis);
1197 rc = FAILURE;
1198 break;
1199 }
1200
1201 if (pload_soft_dis->sd_return_value !=
1202 CRYPTO_SUCCESS) {
1203 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl "
1204 "return_value = %d",
1205 pload_soft_dis->sd_return_value);
1206 free(pload_soft_dis);
1207 rc = FAILURE;
1208 break;
1209 }
1210 free(pload_soft_dis);
1211 }
1212
1213 free(pload_soft_conf);
1214 ptr = ptr->next;
1215 }
1216
1217 if (rc != SUCCESS) {
1218 (void) close(fd);
1219 return (rc);
1220 }
1221
1222
1223 /* Pass the disabledlist information for Device to kernel */
1224 ptr = pdevlist;
1225 while (ptr != NULL) {
1226 /* load the disabled list */
1227 if (ptr->pent->dis_count != 0) {
1228 pload_dev_dis = setup_dev_dis(ptr->pent);
1229 if (pload_dev_dis == NULL) {
1230 rc = FAILURE;
1231 break;
1232 }
1233
1234 if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis)
1235 == -1) {
1236 cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl "
1237 "failed: %s", strerror(errno));
1238 free(pload_dev_dis);
1239 rc = FAILURE;
1240 break;
1241 }
1242
1243 if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) {
1244 cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl "
1245 "return_value = %d",
1246 pload_dev_dis->dd_return_value);
1247 free(pload_dev_dis);
1248 rc = FAILURE;
1249 break;
1250 }
1251 free(pload_dev_dis);
1252 }
1253
1254 ptr = ptr->next;
1255 }
1256
1257 (void) close(fd);
1258 return (rc);
1259 }
1260
1261 /*
1262 * Unload the kernel software provider. Before calling this function, the
1263 * caller should check if the provider is in the config file and if it
1264 * is kernel. This routine makes 3 ioctl calls to remove it from kernel
1265 * completely. The argument do_check set to B_FALSE means that the
1266 * caller knows the provider is not the config file and hence the check
1267 * is skipped.
1268 */
1269 int
1270 unload_kef_soft(char *provname, boolean_t do_check)
1271 {
1272 crypto_unload_soft_module_t *punload_soft = NULL;
1273 crypto_load_soft_config_t *pload_soft_conf = NULL;
1274 crypto_load_soft_disabled_t *pload_soft_dis = NULL;
1275 entry_t *pent = NULL;
1276 int fd;
1277
1278 if (provname == NULL) {
1279 cryptoerror(LOG_STDERR, gettext("internal error."));
1280 return (FAILURE);
1281 }
1282
1283 if (!do_check) {
1284 /* Construct an entry using the provname */
1285 pent = calloc(1, sizeof (entry_t));
1286 if (pent == NULL) {
1287 cryptoerror(LOG_STDERR, gettext("out of memory."));
1288 return (FAILURE);
1289 }
1290 (void) strlcpy(pent->name, provname, MAXNAMELEN);
1291 } else if ((pent = getent_kef(provname)) == NULL) {
1292 cryptoerror(LOG_STDERR, gettext("%s does not exist."),
1293 provname);
1294 return (FAILURE);
1295 }
1296
1297 /* Open the admin_ioctl_device */
1298 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
1299 err = errno;
1300 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
1301 ADMIN_IOCTL_DEVICE, strerror(err));
1302 return (FAILURE);
1303 }
1304
1305 /* Inform kernel to unload this software module */
1306 if ((punload_soft = setup_unload_soft(pent)) == NULL) {
1307 (void) close(fd);
1308 return (FAILURE);
1309 }
1310
1311 if (ioctl(fd, CRYPTO_UNLOAD_SOFT_MODULE, punload_soft) == -1) {
1312 cryptodebug("CRYPTO_UNLOAD_SOFT_MODULE ioctl failed: %s",
1313 strerror(errno));
1314 free_entry(pent);
1315 free(punload_soft);
1316 (void) close(fd);
1317 return (FAILURE);
1318 }
1319
1320 if (punload_soft->sm_return_value != CRYPTO_SUCCESS) {
1321 cryptodebug("CRYPTO_UNLOAD_SOFT_MODULE ioctl return_value = "
1322 "%d", punload_soft->sm_return_value);
1323 /*
1324 * If the return value is CRYPTO_UNKNOWN_PROVIDER, it means
1325 * that the provider is not registered yet. Should just
1326 * continue.
1327 */
1328 if (punload_soft->sm_return_value != CRYPTO_UNKNOWN_PROVIDER) {
1329 free_entry(pent);
1330 free(punload_soft);
1331 (void) close(fd);
1332 return (FAILURE);
1333 }
1334 }
1335
1336 free(punload_soft);
1337
1338 /*
1339 * Inform kernel to remove the configuration of this software
1340 * module.
1341 */
1342 free_mechlist(pent->suplist);
1343 pent->suplist = NULL;
1344 pent->sup_count = 0;
1345 if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) {
1346 free_entry(pent);
1347 (void) close(fd);
1348 return (FAILURE);
1349 }
1350
1351 if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG, pload_soft_conf) == -1) {
1352 cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s",
1353 strerror(errno));
1354 free_entry(pent);
1355 free(pload_soft_conf);
1356 (void) close(fd);
1357 return (FAILURE);
1358 }
1359
1360 if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) {
1361 cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl return_value = "
1362 "%d", pload_soft_conf->sc_return_value);
1363 free_entry(pent);
1364 free(pload_soft_conf);
1365 (void) close(fd);
1366 return (FAILURE);
1367 }
1368
1369 free(pload_soft_conf);
1370
1371 /* Inform kernel to remove the disabled entries if any */
1372 if (pent->dis_count == 0) {
1373 free_entry(pent);
1374 (void) close(fd);
1375 return (SUCCESS);
1376 } else {
1377 free_mechlist(pent->dislist);
1378 pent->dislist = NULL;
1379 pent->dis_count = 0;
1380 }
1381
1382 if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) {
1383 free_entry(pent);
1384 (void) close(fd);
1385 return (FAILURE);
1386 }
1387
1388 /* pent is no longer needed; free it */
1389 free_entry(pent);
1390
|
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <strings.h>
30 #include <unistd.h>
31 #include <locale.h>
32 #include <libgen.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <sys/crypto/ioctladmin.h>
36 #include <signal.h>
37 #include <sys/crypto/elfsign.h>
38 #include "cryptoadm.h"
39
40 static int check_hardware_provider(char *, char *, int *, int *);
41
42 /*
43 * Display the mechanism list for a kernel software provider.
44 * This implements part of the "cryptoadm list -m" command.
45 *
46 * Parameters phardlist and psoftlist are supplied by get_kcfconf_info().
47 * If NULL, this function obtains it by calling get_kcfconf_info() internally.
48 */
49 int
50 list_mechlist_for_soft(char *provname,
51 entrylist_t *phardlist, entrylist_t *psoftlist)
52 {
53 mechlist_t *pmechlist = NULL;
54 int rc;
55
56 if (provname == NULL) {
57 return (FAILURE);
58 }
59
60 rc = get_soft_info(provname, &pmechlist, phardlist, psoftlist);
61 if (rc == SUCCESS) {
62 (void) filter_mechlist(&pmechlist, RANDOM);
63 print_mechlist(provname, pmechlist);
64 free_mechlist(pmechlist);
65 } else {
66 cryptoerror(LOG_STDERR, gettext(
67 "failed to retrieve the mechanism list for %s."),
68 provname);
69 }
70
71 return (rc);
72 }
73
74 /*
75 * Display the mechanism list for a kernel hardware provider.
76 * This implements part of the "cryptoadm list -m" command.
77 */
78 int
79 list_mechlist_for_hard(char *provname)
80 {
81 mechlist_t *pmechlist = NULL;
82 char devname[MAXNAMELEN];
83 int inst_num;
84 int count;
85 int rc = SUCCESS;
86
87 if (provname == NULL) {
88 return (FAILURE);
89 }
90
91 /*
92 * Check if the provider is valid. If it is valid, get the number of
93 * mechanisms also.
94 */
95 if (check_hardware_provider(provname, devname, &inst_num, &count) ==
96 FAILURE) {
97 return (FAILURE);
98 }
99
100 /* Get the mechanism list for the kernel hardware provider */
101 if ((rc = get_dev_info(devname, inst_num, count, &pmechlist)) ==
102 SUCCESS) {
103 (void) filter_mechlist(&pmechlist, RANDOM);
104 print_mechlist(provname, pmechlist);
105 free_mechlist(pmechlist);
106 }
107
108 return (rc);
109 }
110
111
112 /*
113 * Display the policy information for a kernel software provider.
114 * This implements part of the "cryptoadm list -p" command.
115 *
116 * Parameters phardlist and psoftlist are supplied by get_kcfconf_info().
117 * If NULL, this function obtains it by calling get_kcfconf_info() internally.
118 */
119 int
120 list_policy_for_soft(char *provname,
121 entrylist_t *phardlist, entrylist_t *psoftlist)
122 {
123 int rc;
124 entry_t *pent = NULL;
125 mechlist_t *pmechlist = NULL;
126 boolean_t has_random = B_FALSE;
127 boolean_t has_mechs = B_FALSE;
128 boolean_t in_kernel = B_FALSE;
129
130 if (provname == NULL) {
131 return (FAILURE);
132 }
133
134 if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) {
135 return (FAILURE);
136 } else if (in_kernel == B_FALSE) {
137 cryptoerror(LOG_STDERR, gettext("%s does not exist."),
138 provname);
139 return (FAILURE);
140 }
141 pent = getent_kef(provname, phardlist, psoftlist);
142
143 rc = get_soft_info(provname, &pmechlist, phardlist, psoftlist);
144 if (rc == SUCCESS) {
145 has_random = filter_mechlist(&pmechlist, RANDOM);
146 if (pmechlist != NULL) {
147 has_mechs = B_TRUE;
148 free_mechlist(pmechlist);
149 }
150 } else {
151 cryptoerror(LOG_STDERR, gettext(
152 "failed to retrieve the mechanism list for %s."),
153 provname);
154 return (rc);
155 }
156
157 print_kef_policy(provname, pent, has_random, has_mechs);
158 free_entry(pent);
159 return (SUCCESS);
160 }
161
162
163
164 /*
165 * Display the policy information for a kernel hardware provider.
166 * This implements part of the "cryptoadm list -p" command.
167 *
168 * Parameters phardlist and psoftlist are supplied by get_kcfconf_info().
169 * If NULL, this function obtains it by calling get_kcfconf_info() internally.
170 * Parameter pdevlist is supplied by get_dev_list().
171 * If NULL, this function obtains it by calling get_dev_list() internally.
172 */
173 int
174 list_policy_for_hard(char *provname,
175 entrylist_t *phardlist, entrylist_t *psoftlist,
176 crypto_get_dev_list_t *pdevlist)
177 {
178 entry_t *pent = NULL;
179 boolean_t in_kernel;
180 mechlist_t *pmechlist = NULL;
181 char devname[MAXNAMELEN];
182 int inst_num;
183 int count;
184 int rc = SUCCESS;
185 boolean_t has_random = B_FALSE;
186 boolean_t has_mechs = B_FALSE;
187
188 if (provname == NULL) {
189 return (FAILURE);
190 }
191
192 /*
193 * Check if the provider is valid. If it is valid, get the number of
194 * mechanisms also.
195 */
196 if (check_hardware_provider(provname, devname, &inst_num, &count) ==
197 FAILURE) {
198 return (FAILURE);
199 }
200
203 SUCCESS) {
204 has_random = filter_mechlist(&pmechlist, RANDOM);
205
206 if (pmechlist != NULL) {
207 has_mechs = B_TRUE;
208 free_mechlist(pmechlist);
209 }
210 } else {
211 cryptoerror(LOG_STDERR, gettext(
212 "failed to retrieve the mechanism list for %s."),
213 devname);
214 return (rc);
215 }
216
217 /*
218 * If the hardware provider has an entry in the kcf.conf file,
219 * some of its mechanisms must have been disabled. Print out
220 * the disabled list from the config file entry. Otherwise,
221 * if it is active, then all the mechanisms for it are enabled.
222 */
223 if ((pent = getent_kef(provname, phardlist, psoftlist)) != NULL) {
224 print_kef_policy(provname, pent, has_random, has_mechs);
225 free_entry(pent);
226 return (SUCCESS);
227 } else {
228 if (check_kernel_for_hard(provname, pdevlist,
229 &in_kernel) == FAILURE) {
230 return (FAILURE);
231 } else if (in_kernel == B_TRUE) {
232 (void) printf(gettext(
233 "%s: all mechanisms are enabled."), provname);
234 if (has_random)
235 /*
236 * TRANSLATION_NOTE
237 * "random" is a keyword and not to be
238 * translated.
239 */
240 (void) printf(gettext(" %s is enabled.\n"),
241 "random");
242 else
243 (void) printf("\n");
244 return (SUCCESS);
245 } else {
246 cryptoerror(LOG_STDERR,
247 gettext("%s does not exist."), provname);
248 return (FAILURE);
249 }
250 }
251 }
252
253
254 /*
255 * Disable a kernel hardware provider.
256 * This implements the "cryptoadm disable" command for
257 * kernel hardware providers.
258 */
259 int
260 disable_kef_hardware(char *provname, boolean_t rndflag, boolean_t allflag,
261 mechlist_t *dislist)
262 {
263 crypto_load_dev_disabled_t *pload_dev_dis = NULL;
264 mechlist_t *infolist = NULL;
265 entry_t *pent = NULL;
266 boolean_t new_dev_entry = B_FALSE;
267 char devname[MAXNAMELEN];
268 int inst_num;
269 int count;
270 int fd = -1;
271 int rc = SUCCESS;
272
273 if (provname == NULL) {
274 return (FAILURE);
275 }
276
277 /*
278 * Check if the provider is valid. If it is valid, get the number of
279 * mechanisms also.
280 */
281 if (check_hardware_provider(provname, devname, &inst_num, &count)
282 == FAILURE) {
283 return (FAILURE);
284 }
285
286 /* Get the mechanism list for the kernel hardware provider */
287 if (get_dev_info(devname, inst_num, count, &infolist) == FAILURE) {
288 return (FAILURE);
289 }
290
291 /*
292 * Get the entry of this hardware provider from the config file.
293 * If there is no entry yet, create one for it.
294 */
295 if ((pent = getent_kef(provname, NULL, NULL)) == NULL) {
296 if ((pent = create_entry(provname)) == NULL) {
297 cryptoerror(LOG_STDERR, gettext("out of memory."));
298 free_mechlist(infolist);
299 return (FAILURE);
300 }
301 new_dev_entry = B_TRUE;
302 }
303
304 /*
305 * kCF treats random as an internal mechanism. So, we need to
306 * filter it from the mechanism list here, if we are NOT disabling
307 * or enabling the random feature. Note that we map random feature at
308 * cryptoadm(1M) level to the "random" mechanism in kCF.
309 */
310 if (!rndflag) {
311 (void) filter_mechlist(&dislist, RANDOM);
312 }
313
314 /* Calculate the new disabled list */
315 if (disable_mechs(&pent, infolist, allflag, dislist) == FAILURE) {
316 free_mechlist(infolist);
317 free_entry(pent);
318 return (FAILURE);
319 }
320 free_mechlist(infolist);
321
356 strerror(errno));
357 free(pload_dev_dis);
358 (void) close(fd);
359 return (FAILURE);
360 }
361
362 if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) {
363 cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl return_value = "
364 "%d", pload_dev_dis->dd_return_value);
365 free(pload_dev_dis);
366 (void) close(fd);
367 return (FAILURE);
368 }
369
370 free(pload_dev_dis);
371 (void) close(fd);
372 return (SUCCESS);
373 }
374
375
376 /*
377 * Disable a kernel software provider.
378 * This implements the "cryptoadm disable" command for
379 * kernel software providers.
380 */
381 int
382 disable_kef_software(char *provname, boolean_t rndflag, boolean_t allflag,
383 mechlist_t *dislist)
384 {
385 crypto_load_soft_disabled_t *pload_soft_dis = NULL;
386 mechlist_t *infolist = NULL;
387 entry_t *pent = NULL;
388 entrylist_t *phardlist = NULL;
389 entrylist_t *psoftlist = NULL;
390 boolean_t in_kernel = B_FALSE;
391 int fd = -1;
392 int rc = SUCCESS;
393
394 if (provname == NULL) {
395 return (FAILURE);
396 }
397
398 /*
399 * Check if the kernel software provider is currently unloaded.
400 * If it is unloaded, return FAILURE, because the disable subcommand
401 * can not perform on inactive (unloaded) providers.
402 */
403 if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) {
404 return (FAILURE);
405 } else if (in_kernel == B_FALSE) {
406 cryptoerror(LOG_STDERR,
407 gettext("%s is not loaded or does not exist."),
408 provname);
409 return (FAILURE);
410 }
411
412 if (get_kcfconf_info(&phardlist, &psoftlist) == FAILURE) {
413 cryptoerror(LOG_ERR,
414 "failed to retrieve the providers' "
415 "information from the configuration file - %s.",
416 _PATH_KCF_CONF);
417 return (FAILURE);
418 }
419
420 /*
421 * Get the entry of this provider from the kcf.conf file, if any.
422 * Otherwise, create a new kcf.conf entry for writing back to the file.
423 */
424 pent = getent_kef(provname, phardlist, psoftlist);
425 if (pent == NULL) { /* create a new entry */
426 pent = create_entry(provname);
427 if (pent == NULL) {
428 cryptodebug("out of memory.");
429 rc = FAILURE;
430 goto out;
431 }
432 }
433
434 /* Get the mechanism list for the software provider from the kernel */
435 if (get_soft_info(provname, &infolist, phardlist, psoftlist) ==
436 FAILURE) {
437 rc = FAILURE;
438 goto out;
439 }
440
441 if ((infolist != NULL) && (infolist->name[0] != '\0')) {
442 /*
443 * Replace the supportedlist from kcf.conf with possibly
444 * more-up-to-date list from the kernel. This is the case
445 * for default software providers that had more mechanisms
446 * added in the current version of the kernel.
447 */
448 free_mechlist(pent->suplist);
449 pent->suplist = infolist;
450 }
451
452 /*
453 * kCF treats random as an internal mechanism. So, we need to
454 * filter it from the mechanism list here, if we are NOT disabling
455 * or enabling the random feature. Note that we map random feature at
456 * cryptoadm(1M) level to the "random" mechanism in kCF.
457 */
458 if (!rndflag) {
459 (void) filter_mechlist(&infolist, RANDOM);
460 }
461
462 /* Calculate the new disabled list */
463 if (disable_mechs(&pent, infolist, allflag, dislist) == FAILURE) {
464 rc = FAILURE;
465 goto out;
466 }
467
468 /* Update the kcf.conf file with the updated entry */
469 if (update_kcfconf(pent, MODIFY_MODE) == FAILURE) {
470 rc = FAILURE;
471 goto out;
472 }
473
474 /* Setup argument to inform kernel about the new disabled list. */
475 if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) {
476 rc = FAILURE;
477 goto out;
478 }
479
480 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
481 cryptoerror(LOG_STDERR,
482 gettext("failed to open %s for RW: %s"),
483 ADMIN_IOCTL_DEVICE, strerror(errno));
484 rc = FAILURE;
485 goto out;
486 }
487
488 /* Inform kernel about the new disabled list. */
489 if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis) == -1) {
490 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: %s",
491 strerror(errno));
492 rc = FAILURE;
493 goto out;
494 }
495
496 if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) {
497 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl return_value = "
498 "%d", pload_soft_dis->sd_return_value);
499 rc = FAILURE;
500 goto out;
501 }
502
503 out:
504 free_entrylist(phardlist);
505 free_entrylist(psoftlist);
506 free_mechlist(infolist);
507 free_entry(pent);
508 free(pload_soft_dis);
509 if (fd != -1)
510 (void) close(fd);
511 return (rc);
512 }
513
514
515 /*
516 * Enable a kernel software or hardware provider.
517 * This implements the "cryptoadm enable" command for kernel providers.
518 */
519 int
520 enable_kef(char *provname, boolean_t rndflag, boolean_t allflag,
521 mechlist_t *mlist)
522 {
523 crypto_load_soft_disabled_t *pload_soft_dis = NULL;
524 crypto_load_dev_disabled_t *pload_dev_dis = NULL;
525 entry_t *pent = NULL;
526 boolean_t redo_flag = B_FALSE;
527 boolean_t in_kernel = B_FALSE;
528 int fd = -1;
529 int rc = SUCCESS;
530
531
532 /* Get the entry of this provider from the kcf.conf file, if any. */
533 pent = getent_kef(provname, NULL, NULL);
534
535 if (is_device(provname)) {
536 if (pent == NULL) {
537 /*
538 * This device doesn't have an entry in the config
539 * file, therefore nothing is disabled.
540 */
541 cryptoerror(LOG_STDERR, gettext(
542 "all mechanisms are enabled already for %s."),
543 provname);
544 free_entry(pent);
545 return (SUCCESS);
546 }
547 } else { /* a software module */
548 if (check_kernel_for_soft(provname, NULL, &in_kernel) ==
549 FAILURE) {
550 free_entry(pent);
551 return (FAILURE);
552 } else if (in_kernel == B_FALSE) {
553 cryptoerror(LOG_STDERR, gettext("%s does not exist."),
554 provname);
555 free_entry(pent);
556 return (FAILURE);
557 } else if ((pent == NULL) || (pent->dis_count == 0)) {
558 /* nothing to be enabled. */
559 cryptoerror(LOG_STDERR, gettext(
560 "all mechanisms are enabled already for %s."),
561 provname);
562 free_entry(pent);
563 return (SUCCESS);
564 }
565 }
566
567 /*
568 * kCF treats random as an internal mechanism. So, we need to
569 * filter it from the mechanism list here, if we are NOT disabling
570 * or enabling the random feature. Note that we map random feature at
571 * cryptoadm(1M) level to the "random" mechanism in kCF.
572 */
573 if (!rndflag) {
574 redo_flag = filter_mechlist(&pent->dislist, RANDOM);
575 if (redo_flag)
576 pent->dis_count--;
577 }
578
579 /* Update the entry by enabling mechanisms for this provider */
580 if ((rc = enable_mechs(&pent, allflag, mlist)) != SUCCESS) {
581 free_entry(pent);
582 return (rc);
583 }
584
585 if (redo_flag) {
586 mechlist_t *tmp;
587
588 if ((tmp = create_mech(RANDOM)) == NULL) {
589 free_entry(pent);
590 return (FAILURE);
591 }
592 tmp->next = pent->dislist;
593 pent->dislist = tmp;
594 pent->dis_count++;
595 }
596
597 /*
598 * Update the kcf.conf file with the updated entry.
599 * For a hardware provider, if there is no more disabled mechanism,
600 * remove the entire kcf.conf entry.
601 */
602 if (is_device(pent->name) && (pent->dis_count == 0)) {
603 rc = update_kcfconf(pent, DELETE_MODE);
604 } else {
605 rc = update_kcfconf(pent, MODIFY_MODE);
606 }
607
608 if (rc == FAILURE) {
609 free_entry(pent);
610 return (FAILURE);
611 }
612
613
614 /* Inform Kernel about the policy change */
615
616 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
617 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
618 ADMIN_IOCTL_DEVICE, strerror(errno));
619 free_entry(pent);
620 return (FAILURE);
621 }
622
623 if (is_device(provname)) {
624 /* LOAD_DEV_DISABLED */
625 if ((pload_dev_dis = setup_dev_dis(pent)) == NULL) {
626 free_entry(pent);
627 return (FAILURE);
628 }
629
630 if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis) == -1) {
631 cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl failed: "
632 "%s", strerror(errno));
633 free_entry(pent);
634 free(pload_dev_dis);
635 (void) close(fd);
636 return (FAILURE);
637 }
638
639 if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) {
640 cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl "
641 "return_value = %d",
642 pload_dev_dis->dd_return_value);
643 free_entry(pent);
644 free(pload_dev_dis);
645 (void) close(fd);
646 return (FAILURE);
647 }
648
649 } else { /* a software module */
650 /* LOAD_SOFT_DISABLED */
651 if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) {
652 free_entry(pent);
653 return (FAILURE);
654 }
655
656 if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis)
657 == -1) {
658 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: "
659 "%s", strerror(errno));
660 free_entry(pent);
661 free(pload_soft_dis);
662 (void) close(fd);
663 return (FAILURE);
664 }
665
666 if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) {
667 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl "
668 "return_value = %d",
669 pload_soft_dis->sd_return_value);
670 free_entry(pent);
671 free(pload_soft_dis);
672 (void) close(fd);
673 return (FAILURE);
674 }
675 }
676
677 free_entry(pent);
678 free(pload_soft_dis);
679 (void) close(fd);
680 return (SUCCESS);
681 }
682
683
684 /*
685 * Install a software module with the specified mechanism list into the system.
686 * This routine adds an entry into the config file for this software module
687 * first, then makes a CRYPTO_LOAD_SOFT_CONFIG ioctl call to inform kernel
688 * about the new addition.
689 */
690 int
691 install_kef(char *provname, mechlist_t *mlist)
692 {
693 crypto_load_soft_config_t *pload_soft_conf = NULL;
694 boolean_t found;
695 entry_t *pent = NULL;
696 FILE *pfile = NULL;
697 FILE *pfile_tmp = NULL;
698 char tmpfile_name[MAXPATHLEN];
699 char *ptr;
700 char *str;
701 char *name;
702 char buffer[BUFSIZ];
703 char buffer2[BUFSIZ];
704 int found_count;
705 int fd = -1;
706 int rc = SUCCESS;
707 int err;
708
709 if ((provname == NULL) || (mlist == NULL)) {
710 return (FAILURE);
711 }
712
713 /* Check if the provider already exists */
714 if ((pent = getent_kef(provname, NULL, NULL)) != NULL) {
715 cryptoerror(LOG_STDERR, gettext("%s exists already."),
716 provname);
717 free_entry(pent);
718 return (FAILURE);
719 }
720
721 /* Create an entry with provname and mlist. */
722 if ((pent = create_entry(provname)) == NULL) {
723 cryptoerror(LOG_STDERR, gettext("out of memory."));
724 return (FAILURE);
725 }
726 pent->sup_count = get_mech_count(mlist);
727 pent->suplist = mlist;
728
729 /* Append an entry for this software module to the kcf.conf file. */
730 if ((str = ent2str(pent)) == NULL) {
731 free_entry(pent);
732 return (FAILURE);
733 }
734
735 if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) {
736 err = errno;
737 cryptoerror(LOG_STDERR,
738 gettext("failed to update the configuration - %s"),
739 strerror(err));
740 cryptodebug("failed to open %s for write.", _PATH_KCF_CONF);
741 free_entry(pent);
742 return (FAILURE);
743 }
744
745 if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
746 err = errno;
747 cryptoerror(LOG_STDERR,
793 rc = FAILURE;
794 break;
795 } else if (strcmp(provname, name) == 0) {
796 found = B_TRUE;
797 found_count++;
798 }
799 }
800
801 if (found == B_FALSE) {
802 if (fputs(buffer, pfile_tmp) == EOF) {
803 rc = FAILURE;
804 }
805 } else {
806 if (found_count == 1) {
807 if (fputs(str, pfile_tmp) == EOF) {
808 rc = FAILURE;
809 }
810 } else {
811 /*
812 * Found a second entry with #libname.
813 * Should not happen. The kcf.conf file
814 * is corrupted. Give a warning and skip
815 * this entry.
816 */
817 cryptoerror(LOG_STDERR, gettext(
818 "(Warning) Found an additional reserved "
819 "entry for %s."), provname);
820 }
821 }
822
823 if (rc == FAILURE) {
824 break;
825 }
826 }
827 (void) fclose(pfile);
828
829 if (rc == FAILURE) {
830 cryptoerror(LOG_STDERR, gettext("write error."));
831 (void) fclose(pfile_tmp);
832 if (unlink(tmpfile_name) != 0) {
833 err = errno;
848 cryptoerror(LOG_STDERR, gettext(
849 "failed to write to %s: %s"), tmpfile_name,
850 strerror(errno));
851 (void) fclose(pfile_tmp);
852 if (unlink(tmpfile_name) != 0) {
853 err = errno;
854 cryptoerror(LOG_STDERR, gettext(
855 "(Warning) failed to remove %s: %s"),
856 tmpfile_name, strerror(err));
857 }
858 free_entry(pent);
859 return (FAILURE);
860 }
861 }
862
863 if (fclose(pfile_tmp) != 0) {
864 err = errno;
865 cryptoerror(LOG_STDERR,
866 gettext("failed to close %s: %s"), tmpfile_name,
867 strerror(err));
868 free_entry(pent);
869 return (FAILURE);
870 }
871
872 if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) {
873 err = errno;
874 cryptoerror(LOG_STDERR,
875 gettext("failed to update the configuration - %s"),
876 strerror(err));
877 cryptodebug("failed to rename %s to %s: %s", tmpfile_name,
878 _PATH_KCF_CONF, strerror(err));
879 rc = FAILURE;
880 } else if (chmod(_PATH_KCF_CONF,
881 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
882 err = errno;
883 cryptoerror(LOG_STDERR,
884 gettext("failed to update the configuration - %s"),
885 strerror(err));
886 cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF,
887 strerror(err));
888 rc = FAILURE;
889 } else {
890 rc = SUCCESS;
891 }
892
893 if (rc == FAILURE) {
894 if (unlink(tmpfile_name) != 0) {
895 err = errno;
896 cryptoerror(LOG_STDERR, gettext(
897 "(Warning) failed to remove %s: %s"),
898 tmpfile_name, strerror(err));
899 }
900 free_entry(pent);
901 return (FAILURE);
902 }
903
904
905 /* Inform kernel of this new software module. */
906
907 if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) {
908 free_entry(pent);
909 return (FAILURE);
910 }
911
912 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
913 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
914 ADMIN_IOCTL_DEVICE, strerror(errno));
915 free_entry(pent);
916 free(pload_soft_conf);
917 return (FAILURE);
918 }
919
920 if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG, pload_soft_conf) == -1) {
933 free(pload_soft_conf);
934 (void) close(fd);
935 return (FAILURE);
936 }
937
938 free_entry(pent);
939 free(pload_soft_conf);
940 (void) close(fd);
941 return (SUCCESS);
942 }
943
944 /*
945 * Uninstall the software module. This routine first unloads the software
946 * module with 3 ioctl calls, then deletes its entry from the config file.
947 * Removing an entry from the config file needs to be done last to ensure
948 * that there is still an entry if the earlier unload failed for any reason.
949 */
950 int
951 uninstall_kef(char *provname)
952 {
953 entry_t *pent = NULL;
954 int rc = SUCCESS;
955 boolean_t in_kernel = B_FALSE;
956 boolean_t in_kcfconf = B_FALSE;
957 int fd = -1;
958 crypto_load_soft_config_t *pload_soft_conf = NULL;
959
960 /* Check to see if the provider exists first. */
961 if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) {
962 return (FAILURE);
963 } else if (in_kernel == B_FALSE) {
964 cryptoerror(LOG_STDERR, gettext("%s does not exist."),
965 provname);
966 return (FAILURE);
967 }
968
969 /*
970 * If it is loaded, unload it first. This does 2 ioctl calls:
971 * CRYPTO_UNLOAD_SOFT_MODULE and CRYPTO_LOAD_SOFT_DISABLED.
972 */
973 if (unload_kef_soft(provname) == FAILURE) {
974 cryptoerror(LOG_STDERR,
975 gettext("failed to unload %s during uninstall.\n"),
976 provname);
977 return (FAILURE);
978 }
979
980 /*
981 * Inform kernel to remove the configuration of this software module.
982 */
983
984 /* Setup ioctl() parameter */
985 pent = getent_kef(provname, NULL, NULL);
986 if (pent != NULL) { /* in kcf.conf */
987 in_kcfconf = B_TRUE;
988 free_mechlist(pent->suplist);
989 pent->suplist = NULL;
990 pent->sup_count = 0;
991 } else if ((pent = create_entry(provname)) == NULL) {
992 cryptoerror(LOG_STDERR, gettext("out of memory."));
993 return (FAILURE);
994 }
995 if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) {
996 free_entry(pent);
997 return (FAILURE);
998 }
999
1000 /* Open the /dev/cryptoadm device */
1001 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
1002 int err = errno;
1003 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
1004 ADMIN_IOCTL_DEVICE, strerror(err));
1005 free_entry(pent);
1006 free(pload_soft_conf);
1007 return (FAILURE);
1008 }
1009
1010 if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG,
1011 pload_soft_conf) == -1) {
1012 cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s",
1013 strerror(errno));
1014 free_entry(pent);
1015 free(pload_soft_conf);
1016 (void) close(fd);
1017 return (FAILURE);
1018 }
1019
1020 if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) {
1021 cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl = return_value = %d",
1022 pload_soft_conf->sc_return_value);
1023 free_entry(pent);
1024 free(pload_soft_conf);
1025 (void) close(fd);
1026 return (FAILURE);
1027 }
1028
1029 /* ioctl cleanup */
1030 free(pload_soft_conf);
1031 (void) close(fd);
1032
1033
1034 /* Finally, remove entry from kcf.conf, if present */
1035 if (in_kcfconf && (pent != NULL)) {
1036 rc = update_kcfconf(pent, DELETE_MODE);
1037 }
1038
1039 free_entry(pent);
1040 return (rc);
1041 }
1042
1043
1044 /*
1045 * Implement the "cryptoadm refresh" command for global zones.
1046 * That is, send the current contents of kcf.conf to the kernel via ioctl().
1047 */
1048 int
1049 refresh(void)
1050 {
1051 crypto_load_soft_config_t *pload_soft_conf = NULL;
1052 crypto_load_soft_disabled_t *pload_soft_dis = NULL;
1053 crypto_load_dev_disabled_t *pload_dev_dis = NULL;
1054 entrylist_t *pdevlist = NULL;
1055 entrylist_t *psoftlist = NULL;
1056 entrylist_t *ptr;
1057 int fd = -1;
1058 int rc = SUCCESS;
1059 int err;
1060
1061 if (get_kcfconf_info(&pdevlist, &psoftlist) == FAILURE) {
1062 cryptoerror(LOG_ERR, "failed to retrieve the providers' "
1063 "information from the configuration file - %s.",
1064 _PATH_KCF_CONF);
1065 return (FAILURE);
1066 }
1067
1068 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
1069 err = errno;
1070 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
1071 ADMIN_IOCTL_DEVICE, strerror(err));
1072 free(psoftlist);
1073 free(pdevlist);
1074 return (FAILURE);
1075 }
1076
1077 /*
1078 * For each software provider module, pass two sets of information to
1079 * the kernel: the supported list and the disabled list.
1080 */
1081 for (ptr = psoftlist; ptr != NULL; ptr = ptr->next) {
1082 entry_t *pent = ptr->pent;
1083
1084 /* load the supported list */
1085 if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) {
1086 cryptodebug("setup_soft_conf() failed");
1087 rc = FAILURE;
1088 break;
1089 }
1090
1091 if (!pent->load) { /* unloaded--mark as loaded */
1092 pent->load = B_TRUE;
1093 rc = update_kcfconf(pent, MODIFY_MODE);
1094 if (rc != SUCCESS) {
1095 free(pload_soft_conf);
1096 break;
1097 }
1098 }
1099
1100 if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG, pload_soft_conf)
1101 == -1) {
1102 cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s",
1103 strerror(errno));
1104 free(pload_soft_conf);
1105 rc = FAILURE;
1106 break;
1107 }
1108
1109 if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) {
1110 cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl "
1111 "return_value = %d",
1112 pload_soft_conf->sc_return_value);
1113 free(pload_soft_conf);
1114 rc = FAILURE;
1115 break;
1116 }
1117
1118 free(pload_soft_conf);
1119
1120 /* load the disabled list */
1121 if (ptr->pent->dis_count != 0) {
1122 pload_soft_dis = setup_soft_dis(ptr->pent);
1123 if (pload_soft_dis == NULL) {
1124 cryptodebug("setup_soft_dis() failed");
1125 free(pload_soft_dis);
1126 rc = FAILURE;
1127 break;
1128 }
1129
1130 if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED,
1131 pload_soft_dis) == -1) {
1132 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl "
1133 "failed: %s", strerror(errno));
1134 free(pload_soft_dis);
1135 rc = FAILURE;
1136 break;
1137 }
1138
1139 if (pload_soft_dis->sd_return_value !=
1140 CRYPTO_SUCCESS) {
1141 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl "
1142 "return_value = %d",
1143 pload_soft_dis->sd_return_value);
1144 free(pload_soft_dis);
1145 rc = FAILURE;
1146 break;
1147 }
1148 free(pload_soft_dis);
1149 }
1150 }
1151
1152 if (rc != SUCCESS) {
1153 (void) close(fd);
1154 return (rc);
1155 }
1156
1157
1158 /*
1159 * For each hardware provider module, pass the disabled list
1160 * information to the kernel.
1161 */
1162 for (ptr = pdevlist; ptr != NULL; ptr = ptr->next) {
1163 /* load the disabled list */
1164 if (ptr->pent->dis_count != 0) {
1165 pload_dev_dis = setup_dev_dis(ptr->pent);
1166 if (pload_dev_dis == NULL) {
1167 rc = FAILURE;
1168 break;
1169 }
1170
1171 if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis)
1172 == -1) {
1173 cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl "
1174 "failed: %s", strerror(errno));
1175 free(pload_dev_dis);
1176 rc = FAILURE;
1177 break;
1178 }
1179
1180 if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) {
1181 cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl "
1182 "return_value = %d",
1183 pload_dev_dis->dd_return_value);
1184 free(pload_dev_dis);
1185 rc = FAILURE;
1186 break;
1187 }
1188 free(pload_dev_dis);
1189 }
1190 }
1191
1192 (void) close(fd);
1193 return (rc);
1194 }
1195
1196 /*
1197 * Unload the kernel software provider. Before calling this function, the
1198 * caller should check to see if the provider is in the kernel.
1199 *
1200 * This routine makes 2 ioctl calls to remove it completely from the kernel:
1201 * CRYPTO_UNLOAD_SOFT_MODULE - does a modunload of the KCF module
1202 * CRYPTO_LOAD_SOFT_DISABLED - updates kernel disabled mechanism list
1203 *
1204 * This implements part of "cryptoadm unload" and "cryptoadm uninstall".
1205 */
1206 int
1207 unload_kef_soft(char *provname)
1208 {
1209 crypto_unload_soft_module_t *punload_soft = NULL;
1210 crypto_load_soft_disabled_t *pload_soft_dis = NULL;
1211 entry_t *pent = NULL;
1212 int fd = -1;
1213 int err;
1214
1215 if (provname == NULL) {
1216 cryptoerror(LOG_STDERR, gettext("internal error."));
1217 return (FAILURE);
1218 }
1219
1220 pent = getent_kef(provname, NULL, NULL);
1221 if (pent == NULL) { /* not in kcf.conf */
1222 /* Construct an entry using the provname */
1223 pent = create_entry(provname);
1224 if (pent == NULL) {
1225 cryptoerror(LOG_STDERR, gettext("out of memory."));
1226 return (FAILURE);
1227 }
1228 }
1229
1230 /* Open the admin_ioctl_device */
1231 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
1232 err = errno;
1233 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
1234 ADMIN_IOCTL_DEVICE, strerror(err));
1235 free_entry(pent);
1236 return (FAILURE);
1237 }
1238
1239 /* Inform kernel to unload this software module */
1240 if ((punload_soft = setup_unload_soft(pent)) == NULL) {
1241 free_entry(pent);
1242 (void) close(fd);
1243 return (FAILURE);
1244 }
1245
1246 if (ioctl(fd, CRYPTO_UNLOAD_SOFT_MODULE, punload_soft) == -1) {
1247 cryptodebug("CRYPTO_UNLOAD_SOFT_MODULE ioctl failed: %s",
1248 strerror(errno));
1249 free_entry(pent);
1250 free(punload_soft);
1251 (void) close(fd);
1252 return (FAILURE);
1253 }
1254
1255 if (punload_soft->sm_return_value != CRYPTO_SUCCESS) {
1256 cryptodebug("CRYPTO_UNLOAD_SOFT_MODULE ioctl return_value = "
1257 "%d", punload_soft->sm_return_value);
1258 /*
1259 * If the return value is CRYPTO_UNKNOWN_PROVIDER, it means
1260 * that the provider is not registered yet. Should just
1261 * continue.
1262 */
1263 if (punload_soft->sm_return_value != CRYPTO_UNKNOWN_PROVIDER) {
1264 free_entry(pent);
1265 free(punload_soft);
1266 (void) close(fd);
1267 return (FAILURE);
1268 }
1269 }
1270
1271 free(punload_soft);
1272
1273 /* Inform kernel to remove the disabled entries if any */
1274 if (pent->dis_count == 0) {
1275 free_entry(pent);
1276 (void) close(fd);
1277 return (SUCCESS);
1278 } else {
1279 free_mechlist(pent->dislist);
1280 pent->dislist = NULL;
1281 pent->dis_count = 0;
1282 }
1283
1284 if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) {
1285 free_entry(pent);
1286 (void) close(fd);
1287 return (FAILURE);
1288 }
1289
1290 /* pent is no longer needed; free it */
1291 free_entry(pent);
1292
|