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 <errno.h>
27 #include <fcntl.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <strings.h>
31 #include <time.h>
32 #include <unistd.h>
33 #include <locale.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include "cryptoadm.h"
37
38 static int err; /* To store errno which may be overwritten by gettext() */
39 static int build_entrylist(entry_t *, entrylist_t **);
40 static entry_t *dup_entry(entry_t *);
41 static mechlist_t *dup_mechlist(mechlist_t *);
42 static entry_t *getent(char *, entrylist_t *);
43 static int interpret(char *, entry_t **);
44 static int parse_dislist(char *, entry_t *);
45
46
47 /*
48 * Duplicate the mechanism list. A null pointer is returned if the storage
49 * space available is insufficient or the input argument is NULL.
50 */
51 static mechlist_t *
52 dup_mechlist(mechlist_t *plist)
53 {
54 mechlist_t *pres = NULL;
55 mechlist_t *pcur;
56 mechlist_t *ptmp;
57 int rc = SUCCESS;
58
59 while (plist != NULL) {
60 if (!(ptmp = create_mech(plist->name))) {
61 rc = FAILURE;
62 break;
63 }
64
78
79 return (pres);
80 }
81
82
83 /*
84 * Get the number of mechanisms in the mechanism list.
85 */
86 int
87 get_mech_count(mechlist_t *plist)
88 {
89 int count = 0;
90
91 while (plist != NULL) {
92 count++;
93 plist = plist->next;
94 }
95 return (count);
96 }
97
98
99 /*
100 * Duplicate an entry. A null pointer is returned if the storage space
101 * available is insufficient or the input argument is NULL.
102 */
103 static entry_t *
104 dup_entry(entry_t *pent1)
105 {
106 entry_t *pent2 = NULL;
107
108 if (pent1 == NULL) {
109 return (NULL);
110 }
111
112 if ((pent2 = malloc(sizeof (entry_t))) == NULL) {
113 cryptodebug("out of memory.");
114 return (NULL);
115 }
116
117 (void) strlcpy(pent2->name, pent1->name, sizeof (pent2->name));
118 pent2->sup_count = pent1->sup_count;
119 pent2->dis_count = pent1->dis_count;
120 pent2->suplist = NULL;
121 pent2->dislist = NULL;
122 if (pent1->suplist != NULL) {
123 pent2->suplist = dup_mechlist(pent1->suplist);
124 if (pent2->suplist == NULL) {
125 free_entry(pent2);
126 return (NULL);
127 }
128 }
129 if (pent1->dislist != NULL) {
130 pent2->dislist = dup_mechlist(pent1->dislist);
131 if (pent2->dislist == NULL) {
132 free_entry(pent2);
133 return (NULL);
134 }
135 }
136
137 return (pent2);
138 }
139
140
141 /*
142 * This routine parses the disabledlist or the supportedlist of an entry
143 * in the kcf.conf configuration file.
144 *
145 * Arguments:
146 * buf: an input argument which is a char string with the format of
147 * "disabledlist=m1,m2,..." or "supportedlist=m1,m2,..."
148 * pent: the entry for the disabledlist. This is an IN/OUT argument.
149 *
150 * Return value: SUCCESS or FAILURE.
151 */
152 static int
153 parse_dislist(char *buf, entry_t *pent)
154 {
155 mechlist_t *pmech;
156 mechlist_t *phead;
157 char *next_token;
158 char *value;
159 int count;
160 int supflag = B_FALSE;
161 int disflag = B_FALSE;
162 int rc = SUCCESS;
163
164 if (strncmp(buf, EF_SUPPORTED, strlen(EF_SUPPORTED)) == 0) {
165 supflag = B_TRUE;
166 } else if (strncmp(buf, EF_DISABLED, strlen(EF_DISABLED)) == 0) {
167 disflag = B_TRUE;
168 } else {
169 /* should not come here */
170 return (FAILURE);
171 }
172
173 if (value = strpbrk(buf, SEP_EQUAL)) {
174 value++; /* get rid of = */
175 } else {
176 cryptodebug("failed to parse the kcf.conf file.");
202 count++;
203 phead->next = pmech;
204 phead = phead->next;
205 }
206 }
207
208 if (rc == SUCCESS) {
209 if (supflag) {
210 pent->sup_count = count;
211 } else if (disflag) {
212 pent->dis_count = count;
213 }
214 } else {
215 free_mechlist(phead);
216 }
217
218 return (rc);
219 }
220
221
222
223 /*
224 * This routine converts a char string into an entry_t structure
225 */
226 static int
227 interpret(char *buf, entry_t **ppent)
228 {
229 entry_t *pent;
230 char *token1;
231 char *token2;
232 char *token3;
233 int rc;
234
235 if ((token1 = strtok(buf, SEP_COLON)) == NULL) { /* buf is NULL */
236 return (FAILURE);
237 };
238
239 pent = malloc(sizeof (entry_t));
240 if (pent == NULL) {
241 cryptodebug("out of memory.");
242 return (FAILURE);
243 }
244 (void) strlcpy(pent->name, token1, sizeof (pent->name));
245 pent->suplist = NULL;
246 pent->dislist = NULL;
247 pent->sup_count = 0;
248 pent->dis_count = 0;
249
250 if ((token2 = strtok(NULL, SEP_SEMICOLON)) == NULL) {
251 /* The entry contains a provider name only */
252 free_entry(pent);
253 return (FAILURE);
254 }
255
256 /* need to get token3 first to satisfy nested strtok invocations */
257 token3 = strtok(NULL, SEP_SEMICOLON);
258
259 if (token2 && ((rc = parse_dislist(token2, pent)) != SUCCESS)) {
260 free_entry(pent);
261 return (rc);
262 }
263
264 if (token3 && ((rc = parse_dislist(token3, pent)) != SUCCESS)) {
265 free_entry(pent);
266 return (rc);
267 }
268
269 *ppent = pent;
270 return (SUCCESS);
271 }
272
273
274 /*
275 * Add an entry to the end of an entry list. If the entry list is NULL, will
276 * create an entry list with the pent.
277 */
278 static int
279 build_entrylist(entry_t *pent, entrylist_t **pplist)
280 {
281 entrylist_t *pentlist;
282 entrylist_t *pcur;
283
284 pentlist = malloc(sizeof (entrylist_t));
285 if (pentlist == NULL) {
286 cryptodebug("out of memory.");
287 return (FAILURE);
288 }
289 pentlist->pent = pent;
290 pentlist->next = NULL;
291
292 if (*pplist) {
293 pcur = *pplist;
294 while (pcur->next != NULL)
295 pcur = pcur->next;
296 pcur->next = pentlist;
297 } else { /* empty list */
298 *pplist = pentlist;
299 }
300
301 return (SUCCESS);
302 }
303
304
305
306 /*
307 * Find the entry with the "provname" name from the entry list and duplicate
308 * it.
309 */
310 static entry_t *
311 getent(char *provname, entrylist_t *entrylist)
312 {
313 boolean_t found = B_FALSE;
314 entry_t *pent1 = NULL;
315
316 if ((provname == NULL) || (entrylist == NULL)) {
317 return (NULL);
318 }
319
320 while (!found && entrylist) {
321 if (strcmp(entrylist->pent->name, provname) == 0) {
322 found = B_TRUE;
323 pent1 = entrylist->pent;
324 } else {
325 entrylist = entrylist->next;
326 }
327 }
328
329 if (!found) {
330 return (NULL);
331 }
332
333 /* duplicate the entry to be returned */
334 return (dup_entry(pent1));
335 }
336
337
338
339 void
340 free_entry(entry_t *pent)
341 {
342 if (pent == NULL) {
343 return;
344 } else {
345 free_mechlist(pent->suplist);
346 free_mechlist(pent->dislist);
347 free(pent);
348 }
349 }
350
351
352 void
353 free_entrylist(entrylist_t *entrylist)
354 {
355 entrylist_t *pnext;
356
357 while (entrylist != NULL) {
358 pnext = entrylist->next;
359 free_entry(entrylist->pent);
360 entrylist = pnext;
361 }
362 }
363
364
365 /*
366 * Convert an entry to a string. This routine builds a string for the entry
367 * to be inserted in the config file. Based on the content of each entry,
368 * the result string can be one of the 4 forms:
369 * - name
370 * - name:supportedlist=m1,m2,...,mj
371 * - name:disabledlist=m1,m2,...,mj
372 * - name:supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk
373 *
374 * Note that the caller is responsible for freeing the returned string.
375 */
376 char *
377 ent2str(entry_t *pent)
378 {
379 char *buf;
380 mechlist_t *phead;
381 boolean_t supflag = B_FALSE;
382
383
384 if (pent == NULL) {
385 return (NULL);
386 }
387
388 if ((buf = malloc(BUFSIZ)) == NULL) {
389 return (NULL);
390 }
391
392 /* convert the provider name */
393 if (strlcpy(buf, pent->name, BUFSIZ) >= BUFSIZ) {
394 free(buf);
395 return (NULL);
396 }
397
398 /* convert the supported list if any */
399 phead = pent->suplist;
400 if (phead != NULL) {
401 supflag = B_TRUE;
402
403 if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) {
404 free(buf);
405 return (NULL);
406 }
407
408 if (strlcat(buf, EF_SUPPORTED, BUFSIZ) >= BUFSIZ) {
409 free(buf);
410 return (NULL);
411 }
412
413 while (phead != NULL) {
414 if (strlcat(buf, phead->name, BUFSIZ) >= BUFSIZ) {
415 free(buf);
416 return (NULL);
417 }
418
419 phead = phead->next;
420 if (phead != NULL) {
421 if (strlcat(buf, SEP_COMMA, BUFSIZ)
422 >= BUFSIZ) {
423 free(buf);
424 return (NULL);
425 }
426 }
427 }
428 }
429
430 /* convert the disabled list if any */
431 phead = pent->dislist;
432 if (phead != NULL) {
433 if (supflag) {
434 if (strlcat(buf, ";disabledlist=", BUFSIZ) >= BUFSIZ) {
435 free(buf);
436 return (NULL);
437 }
438 } else {
439 if (strlcat(buf, ":disabledlist=", BUFSIZ) >= BUFSIZ) {
440 free(buf);
441 return (NULL);
442 }
443 }
444
445 while (phead != NULL) {
446 if (strlcat(buf, phead->name, BUFSIZ) >= BUFSIZ) {
447 free(buf);
448 return (NULL);
449 }
450
451 phead = phead->next;
452 if (phead != NULL) {
453 if (strlcat(buf, SEP_COMMA, BUFSIZ)
454 >= BUFSIZ) {
455 free(buf);
456 return (NULL);
457 }
458 }
459 }
460 }
461
462 if (strlcat(buf, "\n", BUFSIZ) >= BUFSIZ) {
463 free(buf);
464 return (NULL);
465 }
466
467 return (buf);
468 }
469
470
471 /*
472 * Enable the mechanisms for the provider pointed by *ppent. If allflag is
473 * TRUE, enable all. Otherwise, enable the mechanisms specified in the 3rd
474 * argument "mlist". The result will be stored in ppent also.
475 */
476 int
477 enable_mechs(entry_t **ppent, boolean_t allflag, mechlist_t *mlist)
478 {
479 entry_t *pent;
480 mechlist_t *phead; /* the current and resulting disabled list */
481 mechlist_t *ptr;
482 mechlist_t *pcur;
483 boolean_t found;
484
485 pent = *ppent;
486 if (pent == NULL) {
487 return (FAILURE);
488 }
489
490 if (allflag) {
491 free_mechlist(pent->dislist);
492 pent->dis_count = 0;
493 pent->dislist = NULL;
494 return (SUCCESS);
495 }
496
497 /*
498 * for each mechanism in the to-be-enabled mechanism list,
499 * - check if it is in the current disabled list
500 * - if found, delete it from the disabled list
501 * otherwise, give a warning.
502 */
523 }
524 pent->dis_count--;
525 } else {
526 cryptoerror(LOG_STDERR, gettext(
527 "(Warning) %1$s is either enabled already or not "
528 "a valid mechanism for %2$s"), ptr->name,
529 pent->name);
530 }
531 ptr = ptr->next;
532 }
533
534 if (pent->dis_count == 0) {
535 pent->dislist = NULL;
536 }
537
538 return (SUCCESS);
539
540 }
541
542
543 boolean_t
544 is_device(char *path)
545 {
546 if (strchr(path, SEP_SLASH) != NULL) {
547 return (B_TRUE);
548 } else {
549 return (B_FALSE);
550 }
551 }
552
553 /*
554 * Split a hardware provider name with the "name/inst_num" format into
555 * a name and a number.
556 */
557 int
558 split_hw_provname(char *provname, char *pname, int *inst_num)
559 {
560 char name[MAXNAMELEN];
561 char *inst_str;
562
563 if (provname == NULL) {
564 return (FAILURE);
565 }
566
567 (void) strlcpy(name, provname, MAXNAMELEN);
568 if (strtok(name, "/") == NULL) {
569 return (FAILURE);
570 }
571
572 if ((inst_str = strtok(NULL, "/")) == NULL) {
573 return (FAILURE);
574 }
575
576 (void) strlcpy(pname, name, MAXNAMELEN);
577 *inst_num = atoi(inst_str);
578
579 return (SUCCESS);
580 }
581
582
583 /*
584 * Retrieve information from kcf.conf and build a device entry list and
585 * a software entry list
586 */
587 int
588 get_kcfconf_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist)
589 {
590 FILE *pfile;
591 char buffer[BUFSIZ];
592 int len;
593 entry_t *pent = NULL;
594 int rc = SUCCESS;
595
596 if ((pfile = fopen(_PATH_KCF_CONF, "r")) == NULL) {
597 cryptodebug("failed to open the kcf.conf file for read only");
598 return (FAILURE);
599 }
600
601 *ppdevlist = NULL;
602 *ppsoftlist = NULL;
603 while (fgets(buffer, BUFSIZ, pfile) != NULL) {
604 if (buffer[0] == '#' || buffer[0] == ' ' ||
605 buffer[0] == '\n'|| buffer[0] == '\t') {
606 continue; /* ignore comment lines */
607 }
608
609 len = strlen(buffer);
610 if (buffer[len-1] == '\n') { /* get rid of trailing '\n' */
611 len--;
612 }
613 buffer[len] = '\0';
614
615 if ((rc = interpret(buffer, &pent)) == SUCCESS) {
616 if (is_device(pent->name)) {
617 rc = build_entrylist(pent, ppdevlist);
618 } else {
619 rc = build_entrylist(pent, ppsoftlist);
620 }
621 } else {
622 cryptoerror(LOG_STDERR, gettext(
623 "failed to parse configuration."));
624 }
625
626 if (rc != SUCCESS) {
627 free_entrylist(*ppdevlist);
628 free_entrylist(*ppsoftlist);
629 free_entry(pent);
630 break;
631 }
632 }
633
634 (void) fclose(pfile);
635 return (rc);
636 }
637
638 /*
639 * Retrieve information from admin device and build a device entry list and
640 * a software entry list. This is used where there is no kcf.conf, e.g.
641 * non-global zone.
642 */
643 int
644 get_admindev_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist)
645 {
646 crypto_get_dev_list_t *pdevlist_kernel = NULL;
647 crypto_get_soft_list_t *psoftlist_kernel = NULL;
648 char *devname;
649 int inst_num;
650 int mcount;
651 mechlist_t *pmech;
652 entry_t *pent = NULL;
653 int i;
654 char *psoftname;
655 entrylist_t *tmp_pdev = NULL;
656 entrylist_t *tmp_psoft = NULL;
657
658 if (get_dev_list(&pdevlist_kernel) != SUCCESS) {
659 cryptodebug("failed to get hardware provider list from kernel");
660 return (FAILURE);
661 }
662
663 for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) {
664 devname = pdevlist_kernel->dl_devs[i].le_dev_name;
665 inst_num = pdevlist_kernel->dl_devs[i].le_dev_instance;
666 mcount = pdevlist_kernel->dl_devs[i].le_mechanism_count;
667
668 pmech = NULL;
669 if (get_dev_info(devname, inst_num, mcount, &pmech) !=
670 SUCCESS) {
671 cryptodebug(
672 "failed to retrieve the mechanism list for %s/%d.",
673 devname, inst_num);
674 goto fail_out;
675 }
676
677 if ((pent = malloc(sizeof (entry_t))) == NULL) {
678 cryptodebug("out of memory.");
679 free_mechlist(pmech);
680 goto fail_out;
681 }
682
683 (void) strlcpy(pent->name, devname, MAXNAMELEN);
684 pent->suplist = pmech;
685 pent->sup_count = mcount;
686 pent->dislist = NULL;
687 pent->dis_count = 0;
688
689 if (build_entrylist(pent, &tmp_pdev) != SUCCESS) {
690 goto fail_out;
691 }
692
693 /* because incorporated in tmp_pdev */
694 pent = NULL;
695 }
696
697 free(pdevlist_kernel);
698 pdevlist_kernel = NULL;
699
700 if (get_soft_list(&psoftlist_kernel) != SUCCESS) {
701 cryptodebug("failed to get software provider list from kernel");
702 goto fail_out;
703 }
704
705 for (i = 0, psoftname = psoftlist_kernel->sl_soft_names;
706 i < psoftlist_kernel->sl_soft_count;
707 i++, psoftname = psoftname + strlen(psoftname) + 1) {
708 pmech = NULL;
709 if (get_soft_info(psoftname, &pmech) != SUCCESS) {
710 cryptodebug(
711 "failed to retrieve the mechanism list for %s.",
712 psoftname);
713 goto fail_out;
714 }
715
716 if ((pent = malloc(sizeof (entry_t))) == NULL) {
717 cryptodebug("out of memory.");
718 free_mechlist(pmech);
719 goto fail_out;
720 }
721
722 (void) strlcpy(pent->name, psoftname, MAXNAMELEN);
723 pent->suplist = pmech;
724 pent->sup_count = get_mech_count(pmech);
725 pent->dislist = NULL;
726 pent->dis_count = 0;
727
728 if (build_entrylist(pent, &tmp_psoft) != SUCCESS) {
729 goto fail_out;
730 }
731 }
732
733 free(psoftlist_kernel);
734 psoftlist_kernel = NULL;
735
736 *ppdevlist = tmp_pdev;
737 *ppsoftlist = tmp_psoft;
738
739 return (SUCCESS);
740
741 fail_out:
742 if (pent != NULL)
743 free_entry(pent);
744
745 free_entrylist(tmp_pdev);
746 free_entrylist(tmp_psoft);
747
748 if (pdevlist_kernel != NULL)
749 free(pdevlist_kernel);
750 if (psoftlist_kernel != NULL)
751 free(psoftlist_kernel);
752
753 return (FAILURE);
754 }
755
756 /*
757 * Find the entry in the "kcf.conf" file with "provname" as the provider name.
758 * Return the entry if found, otherwise return NULL.
759 */
760 entry_t *
761 getent_kef(char *provname)
762 {
763 entrylist_t *pdevlist = NULL;
764 entrylist_t *psoftlist = NULL;
765 entry_t *pent = NULL;
766
767 if (get_kcfconf_info(&pdevlist, &psoftlist) != SUCCESS) {
768 return (NULL);
769 }
770
771 if (is_device(provname)) {
772 pent = getent(provname, pdevlist);
773 } else {
774 pent = getent(provname, psoftlist);
775 }
776
777 free_entrylist(pdevlist);
778 free_entrylist(psoftlist);
779
780 return (pent);
781 }
782
783 /*
784 * Print out the provider name and the mechanism list.
785 */
786 void
787 print_mechlist(char *provname, mechlist_t *pmechlist)
788 {
789 mechlist_t *ptr;
790
791 if (provname == NULL) {
792 return;
793 }
794
795 (void) printf("%s: ", provname);
796 if (pmechlist == NULL) {
797 (void) printf(gettext("No mechanisms presented.\n"));
798 return;
799 }
800
801 ptr = pmechlist;
802 while (ptr != NULL) {
803 (void) printf("%s", ptr->name);
804 ptr = ptr->next;
805 if (ptr == NULL) {
806 (void) printf("\n");
807 } else {
808 (void) printf(",");
809 }
810 }
811 }
812
813
814 /*
815 * Update the kcf.conf file based on the specified entry and the update mode.
816 * - If update_mode is MODIFY_MODE or DELETE_MODE, the entry with the same
817 * provider name will be modified or deleted.
818 * - If update_mode is ADD_MODE, this must be a hardware provider without
819 * an entry in the kcf.conf file yet. Need to locate its driver package
820 * bracket and insert an entry into the bracket.
821 */
822 int
823 update_kcfconf(entry_t *pent, int update_mode)
824 {
825 boolean_t add_it = B_FALSE;
826 boolean_t delete_it = B_FALSE;
827 boolean_t found_package = B_FALSE;
828 boolean_t found_entry = B_FALSE;
829 FILE *pfile;
830 FILE *pfile_tmp;
831 char buffer[BUFSIZ];
832 char buffer2[BUFSIZ];
833 char devname[MAXNAMELEN];
834 char tmpfile_name[MAXPATHLEN];
835 char *name;
836 char *str;
837 char *new_str = NULL;
838 int inst_num;
839 int rc = SUCCESS;
840
841
842 if (pent == NULL) {
843 cryptoerror(LOG_STDERR, gettext("internal error."));
844 return (FAILURE);
845 }
846
847 /* Check the update_mode */
848 if (update_mode == ADD_MODE) {
849 add_it = B_TRUE;
850 /* Get the hardware provider name first */
851 if (split_hw_provname(pent->name, devname, &inst_num) ==
852 FAILURE) {
853 return (FAILURE);
854 }
855
856 /* Convert the entry to be a string */
857 if ((new_str = ent2str(pent)) == NULL) {
858 return (FAILURE);
859 }
860 } else if (update_mode == DELETE_MODE) {
861 delete_it = B_TRUE;
862 } else if (update_mode != MODIFY_MODE) {
863 cryptoerror(LOG_STDERR, gettext("internal error."));
864 return (FAILURE);
865 }
866
867
868 /* Open the kcf.conf file */
869 if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) {
870 err = errno;
871 cryptoerror(LOG_STDERR,
872 gettext("failed to update the configuration - %s"),
873 strerror(err));
874 cryptodebug("failed to open %s for write.", _PATH_KCF_CONF);
875 return (FAILURE);
876 }
877
878 /* Lock the kcf.conf file */
879 if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
880 err = errno;
881 cryptoerror(LOG_STDERR,
882 gettext("failed to update the configuration - %s"),
883 strerror(err));
884 (void) fclose(pfile);
885 return (FAILURE);
886 }
887
896 gettext("failed to create a temporary file - %s"),
897 strerror(err));
898 (void) fclose(pfile);
899 return (FAILURE);
900 }
901
902 if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
903 err = errno;
904 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
905 tmpfile_name, strerror(err));
906 (void) fclose(pfile);
907 return (FAILURE);
908 }
909
910 /*
911 * Loop thru the entire kcf.conf file, insert, modify or delete
912 * an entry.
913 */
914 while (fgets(buffer, BUFSIZ, pfile) != NULL) {
915 if (add_it) {
916 /* always keep the current line */
917 if (fputs(buffer, pfile_tmp) == EOF) {
918 err = errno;
919 cryptoerror(LOG_STDERR, gettext(
920 "failed to write to a temp file: %s."),
921 strerror(err));
922 rc = FAILURE;
923 break;
924 }
925
926 /*
927 * If the current position is the beginning of a driver
928 * package and if the driver name matches the hardware
929 * provider name, then we want to insert the entry
930 * here.
931 */
932 if ((strstr(buffer, HW_DRIVER_STRING) != NULL) &&
933 (strstr(buffer, devname) != NULL)) {
934 found_package = B_TRUE;
935 if (fputs(new_str, pfile_tmp) == EOF) {
936 err = errno;
937 cryptoerror(LOG_STDERR, gettext(
938 "failed to write to a temp file: "
939 "%s."), strerror(err));
940 rc = FAILURE;
941 break;
942 }
943 }
944 } else { /* modify or delete */
945 found_entry = B_FALSE;
946 if (!(buffer[0] == '#' || buffer[0] == ' ' ||
947 buffer[0] == '\n'|| buffer[0] == '\t')) {
948 /*
949 * Get the provider name from this line and
950 * check if this is the entry to be updated
951 * or deleted. Note: can not use "buffer"
952 * directly because strtok will change its
953 * value.
954 */
955 (void) strlcpy(buffer2, buffer, BUFSIZ);
956 if ((name = strtok(buffer2, SEP_COLON)) ==
957 NULL) {
958 rc = FAILURE;
959 break;
960 }
961
962 if (strcmp(pent->name, name) == 0) {
963 found_entry = B_TRUE;
964 }
965 }
966
967 if (found_entry && !delete_it) {
968 /*
969 * This is the entry to be updated; get the
970 * updated string and place into buffer.
971 */
972 if ((str = ent2str(pent)) == NULL) {
973 rc = FAILURE;
974 break;
975 } else {
976 (void) strlcpy(buffer, str, BUFSIZ);
977 free(str);
978 }
979 }
980
981 if (!(found_entry && delete_it)) {
982 /* This is the entry to be updated/reserved */
983 if (fputs(buffer, pfile_tmp) == EOF) {
984 err = errno;
985 cryptoerror(LOG_STDERR, gettext(
986 "failed to write to a temp file: "
987 "%s."), strerror(err));
988 rc = FAILURE;
989 break;
990 }
991 }
992 }
993 }
994
995 if (add_it) {
996 free(new_str);
997 }
998
999 if ((add_it && !found_package) || (rc == FAILURE)) {
1000 if (add_it && !found_package) {
1001 cryptoerror(LOG_STDERR,
1002 gettext("failed to update configuration - no "
1003 "driver package information."));
1004 }
1005
1006 (void) fclose(pfile);
1007 (void) fclose(pfile_tmp);
1008 if (unlink(tmpfile_name) != 0) {
1009 err = errno;
1010 cryptoerror(LOG_STDERR, gettext(
1011 "(Warning) failed to remove %s: %s"),
1012 tmpfile_name, strerror(err));
1013 }
1014 return (FAILURE);
1015 }
1016
1017 (void) fclose(pfile);
1018 if (fclose(pfile_tmp) != 0) {
1019 err = errno;
1020 cryptoerror(LOG_STDERR,
1021 gettext("failed to close %s: %s"), tmpfile_name,
1022 strerror(err));
1023 return (FAILURE);
1024 }
1025
1026 /* Copy the temporary file to the kcf.conf file */
1027 if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) {
1028 err = errno;
1029 cryptoerror(LOG_STDERR,
1030 gettext("failed to update the configuration - %s"),
1031 strerror(err));
1032 cryptodebug("failed to rename %s to %s: %s", tmpfile,
1033 _PATH_KCF_CONF, strerror(err));
1034 rc = FAILURE;
1035 } else if (chmod(_PATH_KCF_CONF,
1050 cryptoerror(LOG_STDERR, gettext(
1051 "(Warning) failed to remove %s: %s"),
1052 tmpfile_name, strerror(err));
1053 }
1054
1055 return (rc);
1056 }
1057
1058
1059 /*
1060 * Disable the mechanisms for the provider pointed by *ppent. If allflag is
1061 * TRUE, disable all. Otherwise, disable the mechanisms specified in the
1062 * dislist argument. The "infolist" argument contains the mechanism list
1063 * supported by this provider.
1064 */
1065 int
1066 disable_mechs(entry_t **ppent, mechlist_t *infolist, boolean_t allflag,
1067 mechlist_t *dislist)
1068 {
1069 entry_t *pent;
1070 mechlist_t *plist;
1071 mechlist_t *phead;
1072 mechlist_t *pmech;
1073 int rc = SUCCESS;
1074
1075 pent = *ppent;
1076 if (pent == NULL) {
1077 return (FAILURE);
1078 }
1079
1080 if (allflag) {
1081 free_mechlist(pent->dislist);
1082 pent->dis_count = get_mech_count(infolist);
1083 if (!(pent->dislist = dup_mechlist(infolist))) {
1084 return (FAILURE);
1085 } else {
1086 return (SUCCESS);
1087 }
1088 }
1089
1090 /*
1091 * Not disable all. Now loop thru the mechanisms specified in the
1092 * dislist. If the mechanism is not supported by the provider,
1155 cnt++;
1156 }
1157 }
1158
1159 /* Only one entry is present */
1160 if (cnt == 0)
1161 *pmechlist = NULL;
1162
1163 return (mech_present);
1164 }
1165
1166
1167
1168 /*
1169 * Print out the mechanism policy for a kernel provider that has an entry
1170 * in the kcf.conf file.
1171 *
1172 * The flag has_random is set to B_TRUE if the provider does random
1173 * numbers. The flag has_mechs is set by the caller to B_TRUE if the provider
1174 * has some mechanisms.
1175 */
1176 void
1177 print_kef_policy(entry_t *pent, boolean_t has_random, boolean_t has_mechs)
1178 {
1179 mechlist_t *ptr;
1180 boolean_t rnd_disabled = B_FALSE;
1181
1182 if (pent == NULL) {
1183 return;
1184 }
1185
1186 rnd_disabled = filter_mechlist(&pent->dislist, RANDOM);
1187 ptr = pent->dislist;
1188
1189 (void) printf("%s:", pent->name);
1190
1191 if (has_mechs == B_TRUE) {
1192 /*
1193 * TRANSLATION_NOTE
1194 * This code block may need to be modified a bit to avoid
1195 * constructing the text message on the fly.
1196 */
1197 (void) printf(gettext(" all mechanisms are enabled"));
1198 if (ptr != NULL)
1199 (void) printf(gettext(", except "));
1200 while (ptr != NULL) {
1201 (void) printf("%s", ptr->name);
1202 ptr = ptr->next;
1203 if (ptr != NULL)
1204 (void) printf(",");
1205 }
1206 if (ptr == NULL)
1207 (void) printf(".");
1208 }
1209
1210 /*
1211 * TRANSLATION_NOTE
1212 * "random" is a keyword and not to be translated.
1213 */
1214 if (rnd_disabled)
1215 (void) printf(gettext(" %s is disabled."), "random");
1216 else if (has_random)
1217 (void) printf(gettext(" %s is enabled."), "random");
1218 (void) printf("\n");
1219 }
1220
1221 /*
1222 * Check if a kernel software provider is in the kernel.
1223 */
1224 int
1225 check_active_for_soft(char *provname, boolean_t *is_active)
1226 {
1227 crypto_get_soft_list_t *psoftlist_kernel = NULL;
1228 char *ptr;
1229 int i;
1230
1231 if (provname == NULL) {
1232 cryptoerror(LOG_STDERR, gettext("internal error."));
1233 return (FAILURE);
1234 }
1235
1236 if (get_soft_list(&psoftlist_kernel) == FAILURE) {
1237 cryptodebug("failed to get the software provider list from"
1238 "kernel.");
1239 return (FAILURE);
1240 }
1241
1242 *is_active = B_FALSE;
1243 ptr = psoftlist_kernel->sl_soft_names;
1244 for (i = 0; i < psoftlist_kernel->sl_soft_count; i++) {
1245 if (strcmp(provname, ptr) == 0) {
1246 *is_active = B_TRUE;
1247 break;
1248 }
1249 ptr = ptr + strlen(ptr) + 1;
1250 }
1251 free(psoftlist_kernel);
1252
1253 return (SUCCESS);
1254 }
1255
1256
1257 /*
1258 * Check if a kernel hardware provider is in the kernel.
1259 */
1260 int
1261 check_active_for_hard(char *provname, boolean_t *is_active)
1262 {
1263 crypto_get_dev_list_t *pdevlist = NULL;
1264 char devname[MAXNAMELEN];
1265 int inst_num;
1266 int i;
1267
1268 if (provname == NULL) {
1269 cryptoerror(LOG_STDERR, gettext("internal error."));
1270 return (FAILURE);
1271 }
1272
1273 if (split_hw_provname(provname, devname, &inst_num) == FAILURE) {
1274 return (FAILURE);
1275 }
1276
1277 if (get_dev_list(&pdevlist) == FAILURE) {
1278 cryptoerror(LOG_STDERR, gettext("internal error."));
1279 return (FAILURE);
1280 }
1281
1282 *is_active = B_FALSE;
1283 for (i = 0; i < pdevlist->dl_dev_count; i++) {
1284 if ((strcmp(pdevlist->dl_devs[i].le_dev_name, devname) == 0) &&
1285 (pdevlist->dl_devs[i].le_dev_instance == inst_num)) {
1286 *is_active = B_TRUE;
1287 break;
1288 }
1289 }
1290 free(pdevlist);
1291
1292 return (SUCCESS);
1293 }
|
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 <errno.h>
27 #include <fcntl.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <strings.h>
31 #include <time.h>
32 #include <unistd.h>
33 #include <locale.h>
34 #include <sys/types.h>
35 #include <zone.h>
36 #include <sys/stat.h>
37 #include "cryptoadm.h"
38
39 static int err; /* To store errno which may be overwritten by gettext() */
40 static int build_entrylist(entry_t *, entrylist_t **);
41 static entry_t *dup_entry(entry_t *);
42 static mechlist_t *dup_mechlist(mechlist_t *);
43 static entry_t *getent(char *, entrylist_t *);
44 static int interpret(char *, entry_t **);
45 static int parse_sup_dis_list(char *, entry_t *);
46
47
48 /*
49 * Duplicate the mechanism list. A null pointer is returned if the storage
50 * space available is insufficient or the input argument is NULL.
51 */
52 static mechlist_t *
53 dup_mechlist(mechlist_t *plist)
54 {
55 mechlist_t *pres = NULL;
56 mechlist_t *pcur;
57 mechlist_t *ptmp;
58 int rc = SUCCESS;
59
60 while (plist != NULL) {
61 if (!(ptmp = create_mech(plist->name))) {
62 rc = FAILURE;
63 break;
64 }
65
79
80 return (pres);
81 }
82
83
84 /*
85 * Get the number of mechanisms in the mechanism list.
86 */
87 int
88 get_mech_count(mechlist_t *plist)
89 {
90 int count = 0;
91
92 while (plist != NULL) {
93 count++;
94 plist = plist->next;
95 }
96 return (count);
97 }
98
99 /*
100 * Create one item of type entry_t with the provider name.
101 * Return NULL if there's not enough memory or provname is NULL.
102 */
103 entry_t *
104 create_entry(char *provname)
105 {
106 entry_t *pent = NULL;
107
108 if (provname == NULL) {
109 return (NULL);
110 }
111
112 pent = calloc(1, sizeof (entry_t));
113 if (pent == NULL) {
114 cryptodebug("out of memory.");
115 return (NULL);
116 }
117
118 (void) strlcpy(pent->name, provname, MAXNAMELEN);
119 pent->suplist = NULL;
120 pent->sup_count = 0;
121 pent->dislist = NULL;
122 pent->dis_count = 0;
123 pent->load = B_TRUE;
124
125 return (pent);
126 }
127
128 /*
129 * Duplicate an entry for a provider from kcf.conf.
130 * Return NULL if memory is insufficient or the input argument is NULL.
131 * Called by getent().
132 */
133 static entry_t *
134 dup_entry(entry_t *pent1)
135 {
136 entry_t *pent2 = NULL;
137
138 if (pent1 == NULL) {
139 return (NULL);
140 }
141
142 if ((pent2 = create_entry(pent1->name)) == NULL) {
143 cryptodebug("out of memory.");
144 return (NULL);
145 }
146
147 pent2->sup_count = pent1->sup_count;
148 pent2->dis_count = pent1->dis_count;
149 pent2->load = pent1->load;
150 if (pent1->suplist != NULL) {
151 pent2->suplist = dup_mechlist(pent1->suplist);
152 if (pent2->suplist == NULL) {
153 free_entry(pent2);
154 return (NULL);
155 }
156 }
157 if (pent1->dislist != NULL) {
158 pent2->dislist = dup_mechlist(pent1->dislist);
159 if (pent2->dislist == NULL) {
160 free_entry(pent2);
161 return (NULL);
162 }
163 }
164
165 return (pent2);
166 }
167
168
169 /*
170 * This routine parses the disabledlist or the supportedlist of an entry
171 * in the kcf.conf configuration file.
172 *
173 * Arguments:
174 * buf: an input argument which is a char string with the format of
175 * "disabledlist=m1,m2,..." or "supportedlist=m1,m2,..."
176 * pent: the entry for the disabledlist. This is an IN/OUT argument.
177 *
178 * Return value: SUCCESS or FAILURE.
179 */
180 static int
181 parse_sup_dis_list(char *buf, entry_t *pent)
182 {
183 mechlist_t *pmech = NULL;
184 mechlist_t *phead = NULL;
185 char *next_token;
186 char *value;
187 int count;
188 int supflag = B_FALSE;
189 int disflag = B_FALSE;
190 int rc = SUCCESS;
191
192 if (strncmp(buf, EF_SUPPORTED, strlen(EF_SUPPORTED)) == 0) {
193 supflag = B_TRUE;
194 } else if (strncmp(buf, EF_DISABLED, strlen(EF_DISABLED)) == 0) {
195 disflag = B_TRUE;
196 } else {
197 /* should not come here */
198 return (FAILURE);
199 }
200
201 if (value = strpbrk(buf, SEP_EQUAL)) {
202 value++; /* get rid of = */
203 } else {
204 cryptodebug("failed to parse the kcf.conf file.");
230 count++;
231 phead->next = pmech;
232 phead = phead->next;
233 }
234 }
235
236 if (rc == SUCCESS) {
237 if (supflag) {
238 pent->sup_count = count;
239 } else if (disflag) {
240 pent->dis_count = count;
241 }
242 } else {
243 free_mechlist(phead);
244 }
245
246 return (rc);
247 }
248
249
250 /*
251 * Convert a char string containing a line about a provider
252 * from kcf.conf into an entry_t structure.
253 *
254 * See ent2str(), the reverse of this function, for the format of
255 * kcf.conf lines.
256 */
257 static int
258 interpret(char *buf, entry_t **ppent)
259 {
260 entry_t *pent = NULL;
261 char *token1;
262 char *token2;
263 char *token3;
264 int rc;
265
266 /* Get provider name */
267 if ((token1 = strtok(buf, SEP_COLON)) == NULL) { /* buf is NULL */
268 return (FAILURE);
269 };
270
271 pent = create_entry(token1);
272 if (pent == NULL) {
273 cryptodebug("out of memory.");
274 return (FAILURE);
275 }
276
277 if ((token2 = strtok(NULL, SEP_SEMICOLON)) == NULL) {
278 /* The entry contains a provider name only */
279 free_entry(pent);
280 return (FAILURE);
281 }
282
283 if (strncmp(token2, EF_UNLOAD, strlen(EF_UNLOAD)) == 0) {
284 pent->load = B_FALSE; /* cryptoadm unload */
285 if ((token2 = strtok(NULL, SEP_SEMICOLON)) == NULL) {
286 /* The entry contains a provider name:unload only */
287 free_entry(pent);
288 return (FAILURE);
289 }
290 }
291
292 /* need to get token3 first to satisfy nested strtok invocations */
293 token3 = strtok(NULL, SEP_SEMICOLON); /* optional */
294
295 /* parse supportedlist (or disabledlist if no supportedlist) */
296 if ((token2 != NULL) && ((rc = parse_sup_dis_list(token2, pent)) !=
297 SUCCESS)) {
298 free_entry(pent);
299 return (rc);
300 }
301
302 /* parse disabledlist (if there's a supportedlist) */
303 if ((token3 != NULL) && ((rc = parse_sup_dis_list(token3, pent)) !=
304 SUCCESS)) {
305 free_entry(pent);
306 return (rc);
307 }
308
309 *ppent = pent;
310 return (SUCCESS);
311 }
312
313
314 /*
315 * Add an entry about a provider from kcf.conf to the end of an entry list.
316 * If the entry list pplist is NULL, create the linked list with pent as the
317 * first element.
318 */
319 static int
320 build_entrylist(entry_t *pent, entrylist_t **pplist)
321 {
322 entrylist_t *pentlist;
323 entrylist_t *pcur = NULL;
324
325 pentlist = malloc(sizeof (entrylist_t));
326 if (pentlist == NULL) {
327 cryptodebug("out of memory.");
328 return (FAILURE);
329 }
330 pentlist->pent = pent;
331 pentlist->next = NULL;
332
333 if (*pplist) {
334 pcur = *pplist;
335 while (pcur->next != NULL)
336 pcur = pcur->next;
337 pcur->next = pentlist;
338 } else { /* empty list */
339 *pplist = pentlist;
340 }
341
342 return (SUCCESS);
343 }
344
345
346
347 /*
348 * Find the entry with the "provname" name from the entry list and duplicate
349 * it. Called by getent_kef().
350 */
351 static entry_t *
352 getent(char *provname, entrylist_t *entrylist)
353 {
354 boolean_t found = B_FALSE;
355 entry_t *pent1 = NULL;
356
357 if ((provname == NULL) || (entrylist == NULL)) {
358 return (NULL);
359 }
360
361 while (!found && entrylist) {
362 if (strcmp(entrylist->pent->name, provname) == 0) {
363 found = B_TRUE;
364 pent1 = entrylist->pent;
365 } else {
366 entrylist = entrylist->next;
367 }
368 }
369
370 if (!found) {
371 return (NULL);
372 }
373
374 /* duplicate the entry to be returned */
375 return (dup_entry(pent1));
376 }
377
378
379 /*
380 * Free memory in entry_t.
381 * That is, the supported and disabled lists for a provider
382 * from kcf.conf.
383 */
384 void
385 free_entry(entry_t *pent)
386 {
387 if (pent == NULL) {
388 return;
389 } else {
390 free_mechlist(pent->suplist);
391 free_mechlist(pent->dislist);
392 free(pent);
393 }
394 }
395
396
397 /*
398 * Free elements in a entrylist_t linked list,
399 * which lists providers in kcf.conf.
400 */
401 void
402 free_entrylist(entrylist_t *entrylist)
403 {
404 entrylist_t *pnext;
405
406 while (entrylist != NULL) {
407 pnext = entrylist->next;
408 free_entry(entrylist->pent);
409 entrylist = pnext;
410 }
411 }
412
413
414 /*
415 * Convert an entry to a string. This routine builds a string for the entry
416 * to be inserted in the kcf.conf file. Based on the content of each entry,
417 * the result string can be one of these 6 forms:
418 * - name:supportedlist=m1,m2,...,mj
419 * - name:disabledlist=m1,m2,...,mj
420 * - name:supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk
421 *
422 * - name:unload;supportedlist=m1,m2,...,mj
423 * - name:unload;disabledlist=m1,m2,...,mj
424 * - name:unload;supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk
425 *
426 * Note that the caller is responsible for freeing the returned string
427 * (with free_entry()).
428 * See interpret() for the reverse of this function: converting a string
429 * to an entry_t.
430 */
431 char *
432 ent2str(entry_t *pent)
433 {
434 char *buf;
435 mechlist_t *pcur = NULL;
436 boolean_t semicolon_separator = B_FALSE;
437
438
439 if (pent == NULL) {
440 return (NULL);
441 }
442
443 if ((buf = malloc(BUFSIZ)) == NULL) {
444 return (NULL);
445 }
446
447 /* convert the provider name */
448 if (strlcpy(buf, pent->name, BUFSIZ) >= BUFSIZ) {
449 free(buf);
450 return (NULL);
451 }
452
453 if (!pent->load) { /* add "unload" keyword */
454 if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) {
455 free(buf);
456 return (NULL);
457 }
458
459 if (strlcat(buf, EF_UNLOAD, BUFSIZ) >= BUFSIZ) {
460 free(buf);
461 return (NULL);
462 }
463
464 semicolon_separator = B_TRUE;
465 }
466
467 /* convert the supported list if any */
468 pcur = pent->suplist;
469 if (pcur != NULL) {
470 if (strlcat(buf,
471 semicolon_separator ? SEP_SEMICOLON : SEP_COLON,
472 BUFSIZ) >= BUFSIZ) {
473 free(buf);
474 return (NULL);
475 }
476
477 if (strlcat(buf, EF_SUPPORTED, BUFSIZ) >= BUFSIZ) {
478 free(buf);
479 return (NULL);
480 }
481
482 while (pcur != NULL) {
483 if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) {
484 free(buf);
485 return (NULL);
486 }
487
488 pcur = pcur->next;
489 if (pcur != NULL) {
490 if (strlcat(buf, SEP_COMMA, BUFSIZ)
491 >= BUFSIZ) {
492 free(buf);
493 return (NULL);
494 }
495 }
496 }
497 semicolon_separator = B_TRUE;
498 }
499
500 /* convert the disabled list if any */
501 pcur = pent->dislist;
502 if (pcur != NULL) {
503 if (strlcat(buf,
504 semicolon_separator ? SEP_SEMICOLON : SEP_COLON,
505 BUFSIZ) >= BUFSIZ) {
506 free(buf);
507 return (NULL);
508 }
509
510 if (strlcat(buf, EF_DISABLED, BUFSIZ) >= BUFSIZ) {
511 free(buf);
512 return (NULL);
513 }
514
515 while (pcur != NULL) {
516 if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) {
517 free(buf);
518 return (NULL);
519 }
520
521 pcur = pcur->next;
522 if (pcur != NULL) {
523 if (strlcat(buf, SEP_COMMA, BUFSIZ)
524 >= BUFSIZ) {
525 free(buf);
526 return (NULL);
527 }
528 }
529 }
530 semicolon_separator = B_TRUE;
531 }
532
533 if (strlcat(buf, "\n", BUFSIZ) >= BUFSIZ) {
534 free(buf);
535 return (NULL);
536 }
537
538 return (buf);
539 }
540
541
542 /*
543 * Enable the mechanisms for the provider pointed by *ppent. If allflag is
544 * TRUE, enable all. Otherwise, enable the mechanisms specified in the 3rd
545 * argument "mlist". The result will be stored in ppent also.
546 */
547 int
548 enable_mechs(entry_t **ppent, boolean_t allflag, mechlist_t *mlist)
549 {
550 entry_t *pent;
551 mechlist_t *phead; /* the current and resulting disabled list */
552 mechlist_t *ptr = NULL;
553 mechlist_t *pcur = NULL;
554 boolean_t found;
555
556 pent = *ppent;
557 if (pent == NULL) {
558 return (FAILURE);
559 }
560
561 if (allflag) {
562 free_mechlist(pent->dislist);
563 pent->dis_count = 0;
564 pent->dislist = NULL;
565 return (SUCCESS);
566 }
567
568 /*
569 * for each mechanism in the to-be-enabled mechanism list,
570 * - check if it is in the current disabled list
571 * - if found, delete it from the disabled list
572 * otherwise, give a warning.
573 */
594 }
595 pent->dis_count--;
596 } else {
597 cryptoerror(LOG_STDERR, gettext(
598 "(Warning) %1$s is either enabled already or not "
599 "a valid mechanism for %2$s"), ptr->name,
600 pent->name);
601 }
602 ptr = ptr->next;
603 }
604
605 if (pent->dis_count == 0) {
606 pent->dislist = NULL;
607 }
608
609 return (SUCCESS);
610
611 }
612
613
614 /*
615 * Determine if the kernel provider name, path, is a device
616 * (that is, it contains a slash character (e.g., "mca/0").
617 * If so, it is a hardware provider; otherwise it is a software provider.
618 */
619 boolean_t
620 is_device(char *path)
621 {
622 if (strchr(path, SEP_SLASH) != NULL) {
623 return (B_TRUE);
624 } else {
625 return (B_FALSE);
626 }
627 }
628
629 /*
630 * Split a hardware provider name with the "name/inst_num" format into
631 * a name and a number (e.g., split "mca/0" into "mca" instance 0).
632 */
633 int
634 split_hw_provname(char *provname, char *pname, int *inst_num)
635 {
636 char name[MAXNAMELEN];
637 char *inst_str;
638
639 if (provname == NULL) {
640 return (FAILURE);
641 }
642
643 (void) strlcpy(name, provname, MAXNAMELEN);
644 if (strtok(name, "/") == NULL) {
645 return (FAILURE);
646 }
647
648 if ((inst_str = strtok(NULL, "/")) == NULL) {
649 return (FAILURE);
650 }
651
652 (void) strlcpy(pname, name, MAXNAMELEN);
653 *inst_num = atoi(inst_str);
654
655 return (SUCCESS);
656 }
657
658
659 /*
660 * Retrieve information from kcf.conf and build a hardware device entry list
661 * and a software entry list of kernel crypto providers.
662 *
663 * This list is usually incomplete, as kernel crypto providers only have to
664 * be listed in kcf.conf if a mechanism is disabled (by cryptoadm) or
665 * if the kernel provider module is not one of the default kernel providers.
666 *
667 * The kcf.conf file is available only in the global zone.
668 */
669 int
670 get_kcfconf_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist)
671 {
672 FILE *pfile = NULL;
673 char buffer[BUFSIZ];
674 int len;
675 entry_t *pent = NULL;
676 int rc = SUCCESS;
677
678 if ((pfile = fopen(_PATH_KCF_CONF, "r")) == NULL) {
679 cryptodebug("failed to open the kcf.conf file for read only");
680 return (FAILURE);
681 }
682
683 *ppdevlist = NULL;
684 *ppsoftlist = NULL;
685 while (fgets(buffer, BUFSIZ, pfile) != NULL) {
686 if (buffer[0] == '#' || buffer[0] == ' ' ||
687 buffer[0] == '\n'|| buffer[0] == '\t') {
688 continue; /* ignore comment lines */
689 }
690
691 len = strlen(buffer);
692 if (buffer[len - 1] == '\n') { /* get rid of trailing '\n' */
693 len--;
694 }
695 buffer[len] = '\0';
696
697 if ((rc = interpret(buffer, &pent)) == SUCCESS) {
698 if (is_device(pent->name)) {
699 rc = build_entrylist(pent, ppdevlist);
700 } else {
701 rc = build_entrylist(pent, ppsoftlist);
702 }
703 } else {
704 cryptoerror(LOG_STDERR, gettext(
705 "failed to parse configuration."));
706 }
707
708 if (rc != SUCCESS) {
709 free_entrylist(*ppdevlist);
710 free_entrylist(*ppsoftlist);
711 free_entry(pent);
712 break;
713 }
714 }
715
716 (void) fclose(pfile);
717 return (rc);
718 }
719
720 /*
721 * Retrieve information from admin device and build a device entry list and
722 * a software entry list. This is used where there is no kcf.conf, e.g., the
723 * non-global zone.
724 */
725 int
726 get_admindev_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist)
727 {
728 crypto_get_dev_list_t *pdevlist_kernel = NULL;
729 crypto_get_soft_list_t *psoftlist_kernel = NULL;
730 char *devname;
731 int inst_num;
732 int mcount;
733 mechlist_t *pmech = NULL;
734 entry_t *pent_dev = NULL, *pent_soft = NULL;
735 int i;
736 char *psoftname;
737 entrylist_t *tmp_pdev = NULL;
738 entrylist_t *tmp_psoft = NULL;
739 entrylist_t *phardlist = NULL, *psoftlist = NULL;
740
741 /*
742 * Get hardware providers
743 */
744 if (get_dev_list(&pdevlist_kernel) != SUCCESS) {
745 cryptodebug("failed to get hardware provider list from kernel");
746 return (FAILURE);
747 }
748
749 for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) {
750 devname = pdevlist_kernel->dl_devs[i].le_dev_name;
751 inst_num = pdevlist_kernel->dl_devs[i].le_dev_instance;
752 mcount = pdevlist_kernel->dl_devs[i].le_mechanism_count;
753
754 pmech = NULL;
755 if (get_dev_info(devname, inst_num, mcount, &pmech) !=
756 SUCCESS) {
757 cryptodebug(
758 "failed to retrieve the mechanism list for %s/%d.",
759 devname, inst_num);
760 goto fail_out;
761 }
762
763 if ((pent_dev = create_entry(devname)) == NULL) {
764 cryptodebug("out of memory.");
765 free_mechlist(pmech);
766 goto fail_out;
767 }
768 pent_dev->suplist = pmech;
769 pent_dev->sup_count = mcount;
770
771 if (build_entrylist(pent_dev, &tmp_pdev) != SUCCESS) {
772 goto fail_out;
773 }
774 }
775
776 free(pdevlist_kernel);
777 pdevlist_kernel = NULL;
778
779 /*
780 * Get software providers
781 */
782 if (getzoneid() == GLOBAL_ZONEID) {
783 if (get_kcfconf_info(&phardlist, &psoftlist) != SUCCESS) {
784 goto fail_out;
785 }
786 }
787
788 if (get_soft_list(&psoftlist_kernel) != SUCCESS) {
789 cryptodebug("failed to get software provider list from kernel");
790 goto fail_out;
791 }
792
793 for (i = 0, psoftname = psoftlist_kernel->sl_soft_names;
794 i < psoftlist_kernel->sl_soft_count;
795 i++, psoftname = psoftname + strlen(psoftname) + 1) {
796 pmech = NULL;
797 if (get_soft_info(psoftname, &pmech, phardlist, psoftlist) !=
798 SUCCESS) {
799 cryptodebug(
800 "failed to retrieve the mechanism list for %s.",
801 psoftname);
802 goto fail_out;
803 }
804
805 if ((pent_soft = create_entry(psoftname)) == NULL) {
806 cryptodebug("out of memory.");
807 free_mechlist(pmech);
808 goto fail_out;
809 }
810 pent_soft->suplist = pmech;
811 pent_soft->sup_count = get_mech_count(pmech);
812
813 if (build_entrylist(pent_soft, &tmp_psoft) != SUCCESS) {
814 goto fail_out;
815 }
816 }
817
818 free(psoftlist_kernel);
819 psoftlist_kernel = NULL;
820
821 *ppdevlist = tmp_pdev;
822 *ppsoftlist = tmp_psoft;
823
824 return (SUCCESS);
825
826 fail_out:
827 if (pent_dev != NULL)
828 free_entry(pent_dev);
829 if (pent_soft != NULL)
830 free_entry(pent_soft);
831
832 free_entrylist(tmp_pdev);
833 free_entrylist(tmp_psoft);
834
835 if (pdevlist_kernel != NULL)
836 free(pdevlist_kernel);
837 if (psoftlist_kernel != NULL)
838 free(psoftlist_kernel);
839
840 return (FAILURE);
841 }
842
843 /*
844 * Return configuration information for a kernel provider from kcf.conf.
845 * For kernel software providers return a enabled list and disabled list.
846 * For kernel hardware providers return just a disabled list.
847 *
848 * Parameters phardlist and psoftlist are supplied by get_kcfconf_info().
849 * If NULL, this function calls get_kcfconf_info() internally.
850 */
851 entry_t *
852 getent_kef(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist)
853 {
854 entry_t *pent = NULL;
855 boolean_t memory_allocated = B_FALSE;
856
857 if ((phardlist == NULL) || (psoftlist == NULL)) {
858 if (get_kcfconf_info(&phardlist, &psoftlist) != SUCCESS) {
859 return (NULL);
860 }
861 memory_allocated = B_TRUE;
862 }
863
864 if (is_device(provname)) {
865 pent = getent(provname, phardlist);
866 } else {
867 pent = getent(provname, psoftlist);
868 }
869
870 if (memory_allocated) {
871 free_entrylist(phardlist);
872 free_entrylist(psoftlist);
873 }
874
875 return (pent);
876 }
877
878 /*
879 * Print out the provider name and the mechanism list.
880 */
881 void
882 print_mechlist(char *provname, mechlist_t *pmechlist)
883 {
884 mechlist_t *ptr = NULL;
885
886 if (provname == NULL) {
887 return;
888 }
889
890 (void) printf("%s: ", provname);
891 if (pmechlist == NULL) {
892 (void) printf(gettext("No mechanisms presented.\n"));
893 return;
894 }
895
896 ptr = pmechlist;
897 while (ptr != NULL) {
898 (void) printf("%s", ptr->name);
899 ptr = ptr->next;
900 if (ptr == NULL) {
901 (void) printf("\n");
902 } else {
903 (void) printf(",");
904 }
905 }
906 }
907
908
909 /*
910 * Update the kcf.conf file based on the update mode:
911 * - If update_mode is MODIFY_MODE, modify the entry with the same name.
912 * If not found, append a new entry to the kcf.conf file.
913 * - If update_mode is DELETE_MODE, delete the entry with the same name.
914 * - If update_mode is ADD_MODE, append a new entry to the kcf.conf file.
915 */
916 int
917 update_kcfconf(entry_t *pent, int update_mode)
918 {
919 boolean_t add_it = B_FALSE;
920 boolean_t delete_it = B_FALSE;
921 boolean_t found_entry = B_FALSE;
922 FILE *pfile = NULL;
923 FILE *pfile_tmp = NULL;
924 char buffer[BUFSIZ];
925 char buffer2[BUFSIZ];
926 char tmpfile_name[MAXPATHLEN];
927 char *name;
928 char *new_str = NULL;
929 int rc = SUCCESS;
930
931 if (pent == NULL) {
932 cryptoerror(LOG_STDERR, gettext("internal error."));
933 return (FAILURE);
934 }
935
936 /* Check the update_mode */
937 switch (update_mode) {
938 case ADD_MODE:
939 add_it = B_TRUE;
940 /* FALLTHROUGH */
941 case MODIFY_MODE:
942 /* Convert the entry a string to add to kcf.conf */
943 if ((new_str = ent2str(pent)) == NULL) {
944 return (FAILURE);
945 }
946 break;
947 case DELETE_MODE:
948 delete_it = B_TRUE;
949 break;
950 default:
951 cryptoerror(LOG_STDERR, gettext("internal error."));
952 return (FAILURE);
953 }
954
955 /* Open the kcf.conf file */
956 if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) {
957 err = errno;
958 cryptoerror(LOG_STDERR,
959 gettext("failed to update the configuration - %s"),
960 strerror(err));
961 cryptodebug("failed to open %s for write.", _PATH_KCF_CONF);
962 return (FAILURE);
963 }
964
965 /* Lock the kcf.conf file */
966 if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
967 err = errno;
968 cryptoerror(LOG_STDERR,
969 gettext("failed to update the configuration - %s"),
970 strerror(err));
971 (void) fclose(pfile);
972 return (FAILURE);
973 }
974
983 gettext("failed to create a temporary file - %s"),
984 strerror(err));
985 (void) fclose(pfile);
986 return (FAILURE);
987 }
988
989 if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
990 err = errno;
991 cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
992 tmpfile_name, strerror(err));
993 (void) fclose(pfile);
994 return (FAILURE);
995 }
996
997 /*
998 * Loop thru the entire kcf.conf file, insert, modify or delete
999 * an entry.
1000 */
1001 while (fgets(buffer, BUFSIZ, pfile) != NULL) {
1002 if (add_it) {
1003 if (fputs(buffer, pfile_tmp) == EOF) {
1004 err = errno;
1005 cryptoerror(LOG_STDERR, gettext(
1006 "failed to write to a temp file: %s."),
1007 strerror(err));
1008 rc = FAILURE;
1009 break;
1010 }
1011
1012 } else { /* modify or delete */
1013 found_entry = B_FALSE;
1014
1015 if (!(buffer[0] == '#' || buffer[0] == ' ' ||
1016 buffer[0] == '\n'|| buffer[0] == '\t')) {
1017 /*
1018 * Get the provider name from this line and
1019 * check if this is the entry to be updated
1020 * or deleted. Note: can not use "buffer"
1021 * directly because strtok will change its
1022 * value.
1023 */
1024 (void) strlcpy(buffer2, buffer, BUFSIZ);
1025 if ((name = strtok(buffer2, SEP_COLON)) ==
1026 NULL) {
1027 rc = FAILURE;
1028 break;
1029 }
1030
1031 if (strcmp(pent->name, name) == 0) {
1032 found_entry = B_TRUE;
1033 }
1034 }
1035
1036 if (found_entry && !delete_it) {
1037 /*
1038 * This is the entry to be updated; get the
1039 * updated string and place into buffer.
1040 */
1041 (void) strlcpy(buffer, new_str, BUFSIZ);
1042 free(new_str);
1043 }
1044
1045 if (!(found_entry && delete_it)) {
1046 /* This is the entry to be updated/reserved */
1047 if (fputs(buffer, pfile_tmp) == EOF) {
1048 err = errno;
1049 cryptoerror(LOG_STDERR, gettext(
1050 "failed to write to a temp file: "
1051 "%s."), strerror(err));
1052 rc = FAILURE;
1053 break;
1054 }
1055 }
1056 }
1057 }
1058
1059 if ((!delete_it) && (rc != FAILURE)) {
1060 if (add_it || !found_entry) {
1061 /* append new entry to end of file */
1062 if (fputs(new_str, pfile_tmp) == EOF) {
1063 err = errno;
1064 cryptoerror(LOG_STDERR, gettext(
1065 "failed to write to a temp file: %s."),
1066 strerror(err));
1067 rc = FAILURE;
1068 }
1069 free(new_str);
1070 }
1071 }
1072
1073 (void) fclose(pfile);
1074 if (fclose(pfile_tmp) != 0) {
1075 err = errno;
1076 cryptoerror(LOG_STDERR,
1077 gettext("failed to close %s: %s"), tmpfile_name,
1078 strerror(err));
1079 return (FAILURE);
1080 }
1081
1082 /* Copy the temporary file to the kcf.conf file */
1083 if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) {
1084 err = errno;
1085 cryptoerror(LOG_STDERR,
1086 gettext("failed to update the configuration - %s"),
1087 strerror(err));
1088 cryptodebug("failed to rename %s to %s: %s", tmpfile,
1089 _PATH_KCF_CONF, strerror(err));
1090 rc = FAILURE;
1091 } else if (chmod(_PATH_KCF_CONF,
1106 cryptoerror(LOG_STDERR, gettext(
1107 "(Warning) failed to remove %s: %s"),
1108 tmpfile_name, strerror(err));
1109 }
1110
1111 return (rc);
1112 }
1113
1114
1115 /*
1116 * Disable the mechanisms for the provider pointed by *ppent. If allflag is
1117 * TRUE, disable all. Otherwise, disable the mechanisms specified in the
1118 * dislist argument. The "infolist" argument contains the mechanism list
1119 * supported by this provider.
1120 */
1121 int
1122 disable_mechs(entry_t **ppent, mechlist_t *infolist, boolean_t allflag,
1123 mechlist_t *dislist)
1124 {
1125 entry_t *pent;
1126 mechlist_t *plist = NULL;
1127 mechlist_t *phead = NULL;
1128 mechlist_t *pmech = NULL;
1129 int rc = SUCCESS;
1130
1131 pent = *ppent;
1132 if (pent == NULL) {
1133 return (FAILURE);
1134 }
1135
1136 if (allflag) {
1137 free_mechlist(pent->dislist);
1138 pent->dis_count = get_mech_count(infolist);
1139 if (!(pent->dislist = dup_mechlist(infolist))) {
1140 return (FAILURE);
1141 } else {
1142 return (SUCCESS);
1143 }
1144 }
1145
1146 /*
1147 * Not disable all. Now loop thru the mechanisms specified in the
1148 * dislist. If the mechanism is not supported by the provider,
1211 cnt++;
1212 }
1213 }
1214
1215 /* Only one entry is present */
1216 if (cnt == 0)
1217 *pmechlist = NULL;
1218
1219 return (mech_present);
1220 }
1221
1222
1223
1224 /*
1225 * Print out the mechanism policy for a kernel provider that has an entry
1226 * in the kcf.conf file.
1227 *
1228 * The flag has_random is set to B_TRUE if the provider does random
1229 * numbers. The flag has_mechs is set by the caller to B_TRUE if the provider
1230 * has some mechanisms.
1231 *
1232 * If pent is NULL, the provider doesn't have a kcf.conf entry.
1233 */
1234 void
1235 print_kef_policy(char *provname, entry_t *pent, boolean_t has_random,
1236 boolean_t has_mechs)
1237 {
1238 mechlist_t *ptr = NULL;
1239 boolean_t rnd_disabled = B_FALSE;
1240
1241 if (pent != NULL) {
1242 rnd_disabled = filter_mechlist(&pent->dislist, RANDOM);
1243 ptr = pent->dislist;
1244 }
1245
1246 (void) printf("%s:", provname);
1247
1248 if (has_mechs == B_TRUE) {
1249 /*
1250 * TRANSLATION_NOTE
1251 * This code block may need to be modified a bit to avoid
1252 * constructing the text message on the fly.
1253 */
1254 (void) printf(gettext(" all mechanisms are enabled"));
1255 if (ptr != NULL)
1256 (void) printf(gettext(", except "));
1257 while (ptr != NULL) {
1258 (void) printf("%s", ptr->name);
1259 ptr = ptr->next;
1260 if (ptr != NULL)
1261 (void) printf(",");
1262 }
1263 if (ptr == NULL)
1264 (void) printf(".");
1265 }
1266
1267 /*
1268 * TRANSLATION_NOTE
1269 * "random" is a keyword and not to be translated.
1270 */
1271 if (rnd_disabled)
1272 (void) printf(gettext(" %s is disabled."), "random");
1273 else if (has_random)
1274 (void) printf(gettext(" %s is enabled."), "random");
1275 (void) printf("\n");
1276 }
1277
1278
1279 /*
1280 * Check if a kernel software provider is in the kernel.
1281 *
1282 * Parameters:
1283 * provname Provider name
1284 * psoftlist_kernel Optional software provider list. If NULL, it will be
1285 * obtained from get_soft_list().
1286 * in_kernel Set to B_TRUE if device is in the kernel, else B_FALSE
1287 */
1288 int
1289 check_kernel_for_soft(char *provname, crypto_get_soft_list_t *psoftlist_kernel,
1290 boolean_t *in_kernel)
1291 {
1292 char *ptr;
1293 int i;
1294 boolean_t psoftlist_allocated = B_FALSE;
1295
1296 if (provname == NULL) {
1297 cryptoerror(LOG_STDERR, gettext("internal error."));
1298 return (FAILURE);
1299 }
1300
1301 if (psoftlist_kernel == NULL) {
1302 if (get_soft_list(&psoftlist_kernel) == FAILURE) {
1303 cryptodebug("failed to get the software provider list"
1304 " from kernel.");
1305 return (FAILURE);
1306 }
1307 psoftlist_allocated = B_TRUE;
1308 }
1309
1310 *in_kernel = B_FALSE;
1311 ptr = psoftlist_kernel->sl_soft_names;
1312 for (i = 0; i < psoftlist_kernel->sl_soft_count; i++) {
1313 if (strcmp(provname, ptr) == 0) {
1314 *in_kernel = B_TRUE;
1315 break;
1316 }
1317 ptr = ptr + strlen(ptr) + 1;
1318 }
1319
1320 if (psoftlist_allocated)
1321 free(psoftlist_kernel);
1322
1323 return (SUCCESS);
1324 }
1325
1326
1327 /*
1328 * Check if a kernel hardware provider is in the kernel.
1329 *
1330 * Parameters:
1331 * provname Provider name
1332 * pdevlist Optional Hardware Crypto Device List. If NULL, it will be
1333 * obtained from get_dev_list().
1334 * in_kernel Set to B_TRUE if device is in the kernel, otherwise B_FALSE
1335 */
1336 int
1337 check_kernel_for_hard(char *provname,
1338 crypto_get_dev_list_t *pdevlist, boolean_t *in_kernel)
1339 {
1340 char devname[MAXNAMELEN];
1341 int inst_num;
1342 int i;
1343 boolean_t dev_list_allocated = B_FALSE;
1344
1345 if (provname == NULL) {
1346 cryptoerror(LOG_STDERR, gettext("internal error."));
1347 return (FAILURE);
1348 }
1349
1350 if (split_hw_provname(provname, devname, &inst_num) == FAILURE) {
1351 return (FAILURE);
1352 }
1353
1354 if (pdevlist == NULL) {
1355 if (get_dev_list(&pdevlist) == FAILURE) {
1356 cryptoerror(LOG_STDERR, gettext("internal error."));
1357 return (FAILURE);
1358 }
1359 dev_list_allocated = B_TRUE;
1360 }
1361
1362 *in_kernel = B_FALSE;
1363 for (i = 0; i < pdevlist->dl_dev_count; i++) {
1364 if ((strcmp(pdevlist->dl_devs[i].le_dev_name, devname) == 0) &&
1365 (pdevlist->dl_devs[i].le_dev_instance == inst_num)) {
1366 *in_kernel = B_TRUE;
1367 break;
1368 }
1369 }
1370
1371 if (dev_list_allocated)
1372 free(pdevlist);
1373
1374 return (SUCCESS);
1375 }
|