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 <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
66 if (pres == NULL) {
67 pres = pcur = ptmp;
68 } else {
69 pcur->next = ptmp;
70 pcur = pcur->next;
71 }
72 plist = plist->next;
73 }
74
75 if (rc != SUCCESS) {
76 free_mechlist(pres);
77 return (NULL);
78 }
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.");
205 return (FAILURE);
206 }
207
208 if ((next_token = strtok(value, SEP_COMMA)) == NULL) {
209 cryptodebug("failed to parse the kcf.conf file.");
210 return (FAILURE);
211 }
212
213 if ((pmech = create_mech(next_token)) == NULL) {
214 return (FAILURE);
215 }
216
217 if (supflag) {
218 pent->suplist = phead = pmech;
219 } else if (disflag) {
220 pent->dislist = phead = pmech;
221 }
222
223 count = 1;
224 while (next_token) {
225 if (next_token = strtok(NULL, SEP_COMMA)) {
226 if ((pmech = create_mech(next_token)) == NULL) {
227 rc = FAILURE;
228 break;
229 }
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 */
574 ptr = mlist;
575 while (ptr != NULL) {
576 found = B_FALSE;
577 phead = pcur = pent->dislist;
578 while (!found && pcur) {
579 if (strcmp(pcur->name, ptr->name) == 0) {
580 found = B_TRUE;
581 } else {
582 phead = pcur;
583 pcur = pcur->next;
584 }
585 }
586
587 if (found) {
588 if (phead == pcur) {
589 pent->dislist = pent->dislist->next;
590 free(pcur);
591 } else {
592 phead->next = pcur->next;
593 free(pcur);
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
975 /*
976 * Create a temporary file in the /etc/crypto directory to save
977 * updated configuration file first.
978 */
979 (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
980 if (mkstemp(tmpfile_name) == -1) {
981 err = errno;
982 cryptoerror(LOG_STDERR,
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,
1092 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
1093 err = errno;
1094 cryptoerror(LOG_STDERR,
1095 gettext("failed to update the configuration - %s"),
1096 strerror(err));
1097 cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF,
1098 strerror(err));
1099 rc = FAILURE;
1100 } else {
1101 rc = SUCCESS;
1102 }
1103
1104 if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
1105 err = errno;
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,
1149 * ignore it with a warning. If the mechanism is disabled already,
1150 * do nothing. Otherwise, prepend it to the beginning of the disabled
1151 * list of the provider.
1152 */
1153 plist = dislist;
1154 while (plist != NULL) {
1155 if (!is_in_list(plist->name, infolist)) {
1156 cryptoerror(LOG_STDERR, gettext("(Warning) "
1157 "%1$s is not a valid mechanism for %2$s."),
1158 plist->name, pent->name);
1159 } else if (!is_in_list(plist->name, pent->dislist)) {
1160 /* Add this mechanism into the disabled list */
1161 if ((pmech = create_mech(plist->name)) == NULL) {
1162 rc = FAILURE;
1163 break;
1164 }
1165
1166 if (pent->dislist == NULL) {
1167 pent->dislist = pmech;
1168 } else {
1169 phead = pent->dislist;
1170 pent->dislist = pmech;
1171 pmech->next = phead;
1172 }
1173 pent->dis_count++;
1174 }
1175 plist = plist->next;
1176 }
1177
1178 return (rc);
1179 }
1180
1181 /*
1182 * Remove the mechanism passed, specified by mech, from the list of
1183 * mechanisms, if present in the list. Else, do nothing.
1184 *
1185 * Returns B_TRUE if mechanism is present in the list.
1186 */
1187 boolean_t
1188 filter_mechlist(mechlist_t **pmechlist, const char *mech)
1189 {
1190 int cnt = 0;
1191 mechlist_t *ptr, *pptr;
1192 boolean_t mech_present = B_FALSE;
1193
1194 ptr = pptr = *pmechlist;
1195
1196 while (ptr != NULL) {
1197 if (strncmp(ptr->name, mech, sizeof (mech_name_t)) == 0) {
1198 mech_present = B_TRUE;
1199 if (ptr == *pmechlist) {
1200 pptr = *pmechlist = ptr->next;
1201 free(ptr);
1202 ptr = pptr;
1203 } else {
1204 pptr->next = ptr->next;
1205 free(ptr);
1206 ptr = pptr->next;
1207 }
1208 } else {
1209 pptr = ptr;
1210 ptr = ptr->next;
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 }