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