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 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
201 /* Get the mechanism list for the kernel hardware provider */
202 if ((rc = get_dev_info(devname, inst_num, count, &pmechlist)) ==
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
322 /* If no mechanisms are to be disabled, return */
323 if (pent->dis_count == 0) {
324 free_entry(pent);
325 return (SUCCESS);
326 }
327
328 /* Update the config file with the new entry or the updated entry */
329 if (new_dev_entry) {
330 rc = update_kcfconf(pent, ADD_MODE);
331 } else {
332 rc = update_kcfconf(pent, MODIFY_MODE);
333 }
334
335 if (rc == FAILURE) {
336 free_entry(pent);
337 return (FAILURE);
338 }
339
340 /* Inform kernel about the new disabled mechanism list */
341 if ((pload_dev_dis = setup_dev_dis(pent)) == NULL) {
342 free_entry(pent);
343 return (FAILURE);
344 }
345 free_entry(pent);
346
347 if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
348 cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
349 ADMIN_IOCTL_DEVICE, strerror(errno));
350 free(pload_dev_dis);
351 return (FAILURE);
352 }
353
354 if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis) == -1) {
355 cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl failed: %s",
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,
748 gettext("failed to lock the configuration - %s"),
749 strerror(err));
750 free_entry(pent);
751 (void) fclose(pfile);
752 return (FAILURE);
753 }
754
755 /*
756 * Create a temporary file in the /etc/crypto directory.
757 */
758 (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
759 if (mkstemp(tmpfile_name) == -1) {
760 err = errno;
761 cryptoerror(LOG_STDERR,
762 gettext("failed to create a temporary file - %s"),
763 strerror(err));
764 free_entry(pent);
765 (void) fclose(pfile);
766 return (FAILURE);
767 }
768
769 if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
770 err = errno;
771 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
772 tmpfile_name, strerror(err));
773 free_entry(pent);
774 (void) fclose(pfile);
775 return (FAILURE);
776 }
777
778
779 /*
780 * Loop thru the config file. If the provider was reserved within a
781 * package bracket, just uncomment it. Otherwise, append it at
782 * the end. The resulting file will be saved in the temp file first.
783 */
784 found_count = 0;
785 rc = SUCCESS;
786 while (fgets(buffer, BUFSIZ, pfile) != NULL) {
787 found = B_FALSE;
788 if (buffer[0] == '#') {
789 (void) strlcpy(buffer2, buffer, BUFSIZ);
790 ptr = buffer2;
791 ptr++;
792 if ((name = strtok(ptr, SEP_COLON)) == NULL) {
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;
834 cryptoerror(LOG_STDERR, gettext(
835 "(Warning) failed to remove %s: %s"), tmpfile_name,
836 strerror(err));
837 }
838 free_entry(pent);
839 return (FAILURE);
840 }
841
842 if (found_count == 0) {
843 /*
844 * This libname was not in package before, append it to the
845 * end of the temp file.
846 */
847 if (fputs(str, pfile_tmp) == EOF) {
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) {
921 cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s",
922 strerror(errno));
923 free_entry(pent);
924 free(pload_soft_conf);
925 (void) close(fd);
926 return (FAILURE);
927 }
928
929 if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) {
930 cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed, "
931 "return_value = %d", pload_soft_conf->sc_return_value);
932 free_entry(pent);
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
1293 if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis) == -1) {
1294 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: %s",
1295 strerror(errno));
1296 free(pload_soft_dis);
1297 (void) close(fd);
1298 return (FAILURE);
1299 }
1300
1301 if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) {
1302 cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl return_value = "
1303 "%d", pload_soft_dis->sd_return_value);
1304 free(pload_soft_dis);
1305 (void) close(fd);
1306 return (FAILURE);
1307 }
1308
1309 free(pload_soft_dis);
1310 (void) close(fd);
1311 return (SUCCESS);
1312 }
1313
1314
1315 /*
1316 * Check if a hardware provider is valid. If it is valid, returns its device
1317 * name, instance number and the number of mechanisms it supports.
1318 */
1319 static int
1320 check_hardware_provider(char *provname, char *pname, int *pnum, int *pcount)
1321 {
1322 crypto_get_dev_list_t *dev_list = NULL;
1323 int i;
1324
1325 if (provname == NULL) {
1326 return (FAILURE);
1327 }
1328
1329 /* First, get the device name and the instance number from provname */
1330 if (split_hw_provname(provname, pname, pnum) == FAILURE) {
1331 return (FAILURE);
1332 }
1333
1334 /*
1335 * Get the complete device list from kernel and check if this provider
1336 * is in the list.
1337 */
1338 if (get_dev_list(&dev_list) == FAILURE) {
1339 return (FAILURE);
1340 }
1341
1342 for (i = 0; i < dev_list->dl_dev_count; i++) {
1343 if ((strcmp(dev_list->dl_devs[i].le_dev_name, pname) == 0) &&
1344 (dev_list->dl_devs[i].le_dev_instance == *pnum)) {
1345 break;
1346 }
1347 }
1348
1349 if (i == dev_list->dl_dev_count) {
1350 /* didn't find this provider in the kernel device list */
1351 cryptoerror(LOG_STDERR, gettext("%s does not exist."),
1352 provname);
1353 free(dev_list);
1354 return (FAILURE);
1355 }
1356
1357 /* This provider is valid. Get its mechanism count */
1358 *pcount = dev_list->dl_devs[i].le_mechanism_count;
1359
1360 free(dev_list);
1361 return (SUCCESS);
1362 }