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