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 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
180 /* Get the mechanism list for the kernel hardware provider */
181 if ((rc = get_dev_info(devname, inst_num, count, &pmechlist)) ==
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
302 /* If no mechanisms are to be disabled, return */
303 if (pent->dis_count == 0) {
304 free_entry(pent);
305 return (SUCCESS);
306 }
307
308 /* Update the config file with the new entry or the updated entry */
309 if (new_dev_entry) {
310 rc = update_kcfconf(pent, ADD_MODE);
311 } else {
312 rc = update_kcfconf(pent, MODIFY_MODE);
313 }
314
315 if (rc == FAILURE) {
316 free_entry(pent);
317 return (FAILURE);
318 }
319
320 /* Inform kernel about the new disabled mechanism list */
321 if ((pload_dev_dis = setup_dev_dis(pent)) == NULL) {
322 free_entry(pent);
323 return (FAILURE);
324 }
325 free_entry(pent);
326
327 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
328 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
329 ADMIN_IOCTL_DEVICE, strerror(errno));
330 free(pload_dev_dis);
331 return (FAILURE);
332 }
333
334 if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis) == -1) {
335 cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl failed: %s",
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,
675 gettext("failed to lock the configuration - %s"),
676 strerror(err));
677 free_entry(pent);
678 (void) fclose(pfile);
679 return (FAILURE);
680 }
681
682 /*
683 * Create a temporary file in the /etc/crypto directory.
684 */
685 (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
686 if (mkstemp(tmpfile_name) == -1) {
687 err = errno;
688 cryptoerror(LOG_STDERR,
689 gettext("failed to create a temporary file - %s"),
690 strerror(err));
691 free_entry(pent);
692 (void) fclose(pfile);
693 return (FAILURE);
694 }
695
696 if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
697 err = errno;
698 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
699 tmpfile_name, strerror(err));
700 free_entry(pent);
701 (void) fclose(pfile);
702 return (FAILURE);
703 }
704
705
706 /*
707 * Loop thru the config file. If the provider was reserved within a
708 * package bracket, just uncomment it. Otherwise, append it at
709 * the end. The resulting file will be saved in the temp file first.
710 */
711 found_count = 0;
712 rc = SUCCESS;
713 while (fgets(buffer, BUFSIZ, pfile) != NULL) {
714 found = B_FALSE;
715 if (buffer[0] == '#') {
716 (void) strlcpy(buffer2, buffer, BUFSIZ);
717 ptr = buffer2;
718 ptr++;
719 if ((name = strtok(ptr, SEP_COLON)) == NULL) {
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;
761 cryptoerror(LOG_STDERR, gettext(
762 "(Warning) failed to remove %s: %s"), tmpfile_name,
763 strerror(err));
764 }
765 free_entry(pent);
766 return (FAILURE);
767 }
768
769 if (found_count == 0) {
770 /*
771 * This libname was not in package before, append it to the
772 * end of the temp file.
773 */
774 if (fputs(str, pfile_tmp) == EOF) {
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) {
846 cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s",
847 strerror(errno));
848 free_entry(pent);
849 free(pload_soft_conf);
850 (void) close(fd);
851 return (FAILURE);
852 }
853
854 if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) {
855 cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed, "
856 "return_value = %d", pload_soft_conf->sc_return_value);
857 free_entry(pent);
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
1391 if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis) == -1) {
1392 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: %s",
1393 strerror(errno));
1394 free(pload_soft_dis);
1395 (void) close(fd);
1396 return (FAILURE);
1397 }
1398
1399 if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) {
1400 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl return_value = "
1401 "%d", pload_soft_dis->sd_return_value);
1402 free(pload_soft_dis);
1403 (void) close(fd);
1404 return (FAILURE);
1405 }
1406
1407 free(pload_soft_dis);
1408 (void) close(fd);
1409 return (SUCCESS);
1410 }
1411
1412
1413 /*
1414 * Check if a hardware provider is valid. If it is valid, returns its device
1415 * name, instance number and the number of mechanisms it supports.
1416 */
1417 static int
1418 check_hardware_provider(char *provname, char *pname, int *pnum, int *pcount)
1419 {
1420 crypto_get_dev_list_t *dev_list = NULL;
1421 int i;
1422
1423 if (provname == NULL) {
1424 return (FAILURE);
1425 }
1426
1427 /* First, get the device name and the instance number from provname */
1428 if (split_hw_provname(provname, pname, pnum) == FAILURE) {
1429 return (FAILURE);
1430 }
1431
1432 /*
1433 * Get the complete device list from kernel and check if this provider
1434 * is in the list.
1435 */
1436 if (get_dev_list(&dev_list) == FAILURE) {
1437 return (FAILURE);
1438 }
1439
1440 for (i = 0; i < dev_list->dl_dev_count; i++) {
1441 if ((strcmp(dev_list->dl_devs[i].le_dev_name, pname) == 0) &&
1442 (dev_list->dl_devs[i].le_dev_instance == *pnum)) {
1443 break;
1444 }
1445 }
1446
1447 if (i == dev_list->dl_dev_count) {
1448 /* didn't find this provider in the kernel device list */
1449 cryptoerror(LOG_STDERR, gettext("%s does not exist."),
1450 provname);
1451 free(dev_list);
1452 return (FAILURE);
1453 }
1454
1455 /* This provider is valid. Get its mechanism count */
1456 *pcount = dev_list->dl_devs[i].le_mechanism_count;
1457
1458 free(dev_list);
1459 return (SUCCESS);
1460 }