1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <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
65 if (pres == NULL) {
66 pres = pcur = ptmp;
67 } else {
68 pcur->next = ptmp;
69 pcur = pcur->next;
70 }
71 plist = plist->next;
72 }
73
74 if (rc != SUCCESS) {
75 free_mechlist(pres);
76 return (NULL);
77 }
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.");
177 return (FAILURE);
178 }
179
180 if ((next_token = strtok(value, SEP_COMMA)) == NULL) {
181 cryptodebug("failed to parse the kcf.conf file.");
182 return (FAILURE);
183 }
184
185 if ((pmech = create_mech(next_token)) == NULL) {
186 return (FAILURE);
187 }
188
189 if (supflag) {
190 pent->suplist = phead = pmech;
191 } else if (disflag) {
192 pent->dislist = phead = pmech;
193 }
194
195 count = 1;
196 while (next_token) {
197 if (next_token = strtok(NULL, SEP_COMMA)) {
198 if ((pmech = create_mech(next_token)) == NULL) {
199 rc = FAILURE;
200 break;
201 }
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 */
503 ptr = mlist;
504 while (ptr != NULL) {
505 found = B_FALSE;
506 phead = pcur = pent->dislist;
507 while (!found && pcur) {
508 if (strcmp(pcur->name, ptr->name) == 0) {
509 found = B_TRUE;
510 } else {
511 phead = pcur;
512 pcur = pcur->next;
513 }
514 }
515
516 if (found) {
517 if (phead == pcur) {
518 pent->dislist = pent->dislist->next;
519 free(pcur);
520 } else {
521 phead->next = pcur->next;
522 free(pcur);
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
888 /*
889 * Create a temporary file in the /etc/crypto directory to save
890 * updated configuration file first.
891 */
892 (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
893 if (mkstemp(tmpfile_name) == -1) {
894 err = errno;
895 cryptoerror(LOG_STDERR,
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,
1036 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
1037 err = errno;
1038 cryptoerror(LOG_STDERR,
1039 gettext("failed to update the configuration - %s"),
1040 strerror(err));
1041 cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF,
1042 strerror(err));
1043 rc = FAILURE;
1044 } else {
1045 rc = SUCCESS;
1046 }
1047
1048 if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
1049 err = errno;
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,
1093 * ignore it with a warning. If the mechanism is disabled already,
1094 * do nothing. Otherwise, prepend it to the beginning of the disabled
1095 * list of the provider.
1096 */
1097 plist = dislist;
1098 while (plist != NULL) {
1099 if (!is_in_list(plist->name, infolist)) {
1100 cryptoerror(LOG_STDERR, gettext("(Warning) "
1101 "%1$s is not a valid mechanism for %2$s."),
1102 plist->name, pent->name);
1103 } else if (!is_in_list(plist->name, pent->dislist)) {
1104 /* Add this mechanism into the disabled list */
1105 if ((pmech = create_mech(plist->name)) == NULL) {
1106 rc = FAILURE;
1107 break;
1108 }
1109
1110 if (pent->dislist == NULL) {
1111 pent->dislist = pmech;
1112 } else {
1113 phead = pent->dislist;
1114 pent->dislist = pmech;
1115 pmech->next = phead;
1116 }
1117 pent->dis_count++;
1118 }
1119 plist = plist->next;
1120 }
1121
1122 return (rc);
1123 }
1124
1125 /*
1126 * Remove the mechanism passed, specified by mech, from the list of
1127 * mechanisms, if present in the list. Else, do nothing.
1128 *
1129 * Returns B_TRUE if mechanism is present in the list.
1130 */
1131 boolean_t
1132 filter_mechlist(mechlist_t **pmechlist, const char *mech)
1133 {
1134 int cnt = 0;
1135 mechlist_t *ptr, *pptr;
1136 boolean_t mech_present = B_FALSE;
1137
1138 ptr = pptr = *pmechlist;
1139
1140 while (ptr != NULL) {
1141 if (strncmp(ptr->name, mech, sizeof (mech_name_t)) == 0) {
1142 mech_present = B_TRUE;
1143 if (ptr == *pmechlist) {
1144 pptr = *pmechlist = ptr->next;
1145 free(ptr);
1146 ptr = pptr;
1147 } else {
1148 pptr->next = ptr->next;
1149 free(ptr);
1150 ptr = pptr->next;
1151 }
1152 } else {
1153 pptr = ptr;
1154 ptr = ptr->next;
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 }