8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / cmd-crypto / cryptoadm / adm_kef_util.c
blobf2df86b8e36f7430258ff13933840db3f68e0e8a
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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"
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);
49 * Duplicate the mechanism list. A null pointer is returned if the storage
50 * space available is insufficient or the input argument is NULL.
52 static mechlist_t *
53 dup_mechlist(mechlist_t *plist)
55 mechlist_t *pres = NULL;
56 mechlist_t *pcur;
57 mechlist_t *ptmp;
58 int rc = SUCCESS;
60 while (plist != NULL) {
61 if (!(ptmp = create_mech(plist->name))) {
62 rc = FAILURE;
63 break;
66 if (pres == NULL) {
67 pres = pcur = ptmp;
68 } else {
69 pcur->next = ptmp;
70 pcur = pcur->next;
72 plist = plist->next;
75 if (rc != SUCCESS) {
76 free_mechlist(pres);
77 return (NULL);
80 return (pres);
85 * Get the number of mechanisms in the mechanism list.
87 int
88 get_mech_count(mechlist_t *plist)
90 int count = 0;
92 while (plist != NULL) {
93 count++;
94 plist = plist->next;
96 return (count);
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.
103 entry_t *
104 create_entry(char *provname)
106 entry_t *pent = NULL;
108 if (provname == NULL) {
109 return (NULL);
112 pent = calloc(1, sizeof (entry_t));
113 if (pent == NULL) {
114 cryptodebug("out of memory.");
115 return (NULL);
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;
125 return (pent);
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().
133 static entry_t *
134 dup_entry(entry_t *pent1)
136 entry_t *pent2 = NULL;
138 if (pent1 == NULL) {
139 return (NULL);
142 if ((pent2 = create_entry(pent1->name)) == NULL) {
143 cryptodebug("out of memory.");
144 return (NULL);
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);
157 if (pent1->dislist != NULL) {
158 pent2->dislist = dup_mechlist(pent1->dislist);
159 if (pent2->dislist == NULL) {
160 free_entry(pent2);
161 return (NULL);
165 return (pent2);
170 * This routine parses the disabledlist or the supportedlist of an entry
171 * in the kcf.conf configuration file.
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.
178 * Return value: SUCCESS or FAILURE.
180 static int
181 parse_sup_dis_list(const char *buf, entry_t *pent)
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;
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);
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);
208 if ((next_token = strtok(value, SEP_COMMA)) == NULL) {
209 cryptodebug("failed to parse the kcf.conf file.");
210 return (FAILURE);
213 if ((pmech = create_mech(next_token)) == NULL) {
214 return (FAILURE);
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;
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;
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;
242 count++;
243 phead->next = pmech;
244 phead = phead->next;
248 if (rc == SUCCESS) {
249 if (supflag) {
250 pent->sup_count = count;
251 } else if (disflag) {
252 pent->dis_count = count;
254 } else {
255 free_mechlist(phead);
258 return (rc);
263 * Convert a char string containing a line about a provider
264 * from kcf.conf into an entry_t structure.
266 * Note: the input string, buf, may be modified by this function.
268 * See ent2str(), the reverse of this function, for the format of
269 * kcf.conf lines.
271 static int
272 interpret(char *buf, entry_t **ppent)
274 entry_t *pent = NULL;
275 char *token1;
276 char *token2;
277 char *token3;
278 int rc;
280 /* Get provider name */
281 if ((token1 = strtok(buf, SEP_COLON)) == NULL) { /* buf is NULL */
282 return (FAILURE);
285 pent = create_entry(token1);
286 if (pent == NULL) {
287 cryptodebug("out of memory.");
288 return (FAILURE);
291 if ((token2 = strtok(NULL, SEP_SEMICOLON)) == NULL) {
292 /* The entry contains a provider name only */
293 free_entry(pent);
294 return (FAILURE);
297 if (strncmp(token2, EF_UNLOAD, strlen(EF_UNLOAD)) == 0) {
298 pent->load = B_FALSE; /* cryptoadm unload */
299 token2 = strtok(NULL, SEP_SEMICOLON);
301 * If token2 is NULL, the entry contains a
302 * provider name:unload only
306 if (token2 != NULL) {
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.
313 token3 = strtok(NULL, SEP_SEMICOLON); /* optional */
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);
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);
329 *ppent = pent;
330 return (SUCCESS);
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.
339 static int
340 build_entrylist(entry_t *pent, entrylist_t **pplist)
342 entrylist_t *pentlist;
343 entrylist_t *pcur = NULL;
345 pentlist = malloc(sizeof (entrylist_t));
346 if (pentlist == NULL) {
347 cryptodebug("out of memory.");
348 return (FAILURE);
350 pentlist->pent = pent;
351 pentlist->next = NULL;
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;
362 return (SUCCESS);
368 * Find the entry with the "provname" name from the entry list and duplicate
369 * it. Called by getent_kef().
371 static entry_t *
372 getent(char *provname, entrylist_t *entrylist)
374 boolean_t found = B_FALSE;
375 entry_t *pent1 = NULL;
377 if ((provname == NULL) || (entrylist == NULL)) {
378 return (NULL);
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;
390 if (!found) {
391 return (NULL);
394 /* duplicate the entry to be returned */
395 return (dup_entry(pent1));
400 * Free memory in entry_t.
401 * That is, the supported and disabled lists for a provider
402 * from kcf.conf.
404 void
405 free_entry(entry_t *pent)
407 if (pent == NULL) {
408 return;
409 } else {
410 free_mechlist(pent->suplist);
411 free_mechlist(pent->dislist);
412 free(pent);
418 * Free elements in a entrylist_t linked list,
419 * which lists providers in kcf.conf.
421 void
422 free_entrylist(entrylist_t *entrylist)
424 entrylist_t *pnext;
426 while (entrylist != NULL) {
427 pnext = entrylist->next;
428 free_entry(entrylist->pent);
429 entrylist = pnext;
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
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
447 * - (NUL character or 0-length string)
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.
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.
458 char *
459 ent2str(entry_t *pent)
461 char *buf;
462 mechlist_t *pcur = NULL;
463 boolean_t keyword_already_present = B_FALSE;
465 if (pent == NULL) {
466 return (NULL);
469 if ((buf = malloc(BUFSIZ)) == NULL) {
470 return (NULL);
473 /* convert the provider name */
474 if (strlcpy(buf, pent->name, BUFSIZ) >= BUFSIZ) {
475 free(buf);
476 return (NULL);
479 if (!pent->load) { /* add "unload" keyword */
480 if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) {
481 free(buf);
482 return (NULL);
485 if (strlcat(buf, EF_UNLOAD, BUFSIZ) >= BUFSIZ) {
486 free(buf);
487 return (NULL);
490 keyword_already_present = B_TRUE;
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);
503 if (strlcat(buf, EF_SUPPORTED, BUFSIZ) >= BUFSIZ) {
504 free(buf);
505 return (NULL);
508 while (pcur != NULL) {
509 if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) {
510 free(buf);
511 return (NULL);
514 pcur = pcur->next;
515 if (pcur != NULL) {
516 if (strlcat(buf, SEP_COMMA, BUFSIZ)
517 >= BUFSIZ) {
518 free(buf);
519 return (NULL);
523 keyword_already_present = B_TRUE;
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);
536 if (strlcat(buf, EF_DISABLED, BUFSIZ) >= BUFSIZ) {
537 free(buf);
538 return (NULL);
541 while (pcur != NULL) {
542 if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) {
543 free(buf);
544 return (NULL);
547 pcur = pcur->next;
548 if (pcur != NULL) {
549 if (strlcat(buf, SEP_COMMA, BUFSIZ)
550 >= BUFSIZ) {
551 free(buf);
552 return (NULL);
556 keyword_already_present = B_TRUE;
559 if (strlcat(buf, "\n", BUFSIZ) >= BUFSIZ) {
560 free(buf);
561 return (NULL);
564 if (!keyword_already_present) {
565 /* Only the provider name, without a keyword, is on the line */
566 buf[0] = '\0';
568 return (buf);
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.
578 enable_mechs(entry_t **ppent, boolean_t allflag, mechlist_t *mlist)
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;
586 pent = *ppent;
587 if (pent == NULL) {
588 return (FAILURE);
591 if (allflag) {
592 free_mechlist(pent->dislist);
593 pent->dis_count = 0;
594 pent->dislist = NULL;
595 return (SUCCESS);
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.
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;
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);
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);
632 ptr = ptr->next;
635 if (pent->dis_count == 0) {
636 pent->dislist = NULL;
639 return (SUCCESS);
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.
649 boolean_t
650 is_device(char *path)
652 if (strchr(path, SEP_SLASH) != NULL) {
653 return (B_TRUE);
654 } else {
655 return (B_FALSE);
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).
664 split_hw_provname(char *provname, char *pname, int *inst_num)
666 char name[MAXNAMELEN];
667 char *inst_str;
669 if (provname == NULL) {
670 return (FAILURE);
673 (void) strlcpy(name, provname, MAXNAMELEN);
674 if (strtok(name, "/") == NULL) {
675 return (FAILURE);
678 if ((inst_str = strtok(NULL, "/")) == NULL) {
679 return (FAILURE);
682 (void) strlcpy(pname, name, MAXNAMELEN);
683 *inst_num = atoi(inst_str);
685 return (SUCCESS);
690 * Retrieve information from kcf.conf and build a hardware device entry list
691 * and a software entry list of kernel crypto providers.
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.
697 * The kcf.conf file is available only in the global zone.
700 get_kcfconf_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist)
702 FILE *pfile = NULL;
703 char buffer[BUFSIZ];
704 int len;
705 entry_t *pent = NULL;
706 int rc = SUCCESS;
708 if ((pfile = fopen(_PATH_KCF_CONF, "r")) == NULL) {
709 cryptodebug("failed to open the kcf.conf file for read only");
710 return (FAILURE);
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 */
721 len = strlen(buffer);
722 if (buffer[len - 1] == '\n') { /* get rid of trailing '\n' */
723 len--;
725 buffer[len] = '\0';
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);
733 } else {
734 cryptoerror(LOG_STDERR, gettext(
735 "failed to parse configuration."));
738 if (rc != SUCCESS) {
739 free_entrylist(*ppdevlist);
740 free_entrylist(*ppsoftlist);
741 free_entry(pent);
742 break;
746 (void) fclose(pfile);
747 return (rc);
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.
756 get_admindev_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist)
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;
772 * Get hardware providers
774 if (get_dev_list(&pdevlist_kernel) != SUCCESS) {
775 cryptodebug("failed to get hardware provider list from kernel");
776 return (FAILURE);
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;
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;
793 if ((pent_dev = create_entry(devname)) == NULL) {
794 cryptodebug("out of memory.");
795 free_mechlist(pmech);
796 goto fail_out;
798 pent_dev->suplist = pmech;
799 pent_dev->sup_count = mcount;
801 if (build_entrylist(pent_dev, &tmp_pdev) != SUCCESS) {
802 goto fail_out;
806 free(pdevlist_kernel);
807 pdevlist_kernel = NULL;
810 * Get software providers
812 if (getzoneid() == GLOBAL_ZONEID) {
813 if (get_kcfconf_info(&phardlist, &psoftlist) != SUCCESS) {
814 goto fail_out;
818 if (get_soft_list(&psoftlist_kernel) != SUCCESS) {
819 cryptodebug("failed to get software provider list from kernel");
820 goto fail_out;
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;
835 if ((pent_soft = create_entry(psoftname)) == NULL) {
836 cryptodebug("out of memory.");
837 free_mechlist(pmech);
838 goto fail_out;
840 pent_soft->suplist = pmech;
841 pent_soft->sup_count = get_mech_count(pmech);
843 if (build_entrylist(pent_soft, &tmp_psoft) != SUCCESS) {
844 goto fail_out;
848 free(psoftlist_kernel);
849 psoftlist_kernel = NULL;
851 *ppdevlist = tmp_pdev;
852 *ppsoftlist = tmp_psoft;
854 return (SUCCESS);
856 fail_out:
857 if (pent_dev != NULL)
858 free_entry(pent_dev);
859 if (pent_soft != NULL)
860 free_entry(pent_soft);
862 free_entrylist(tmp_pdev);
863 free_entrylist(tmp_psoft);
865 if (pdevlist_kernel != NULL)
866 free(pdevlist_kernel);
867 if (psoftlist_kernel != NULL)
868 free(psoftlist_kernel);
870 return (FAILURE);
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.
878 * Parameters phardlist and psoftlist are supplied by get_kcfconf_info().
879 * If NULL, this function calls get_kcfconf_info() internally.
881 entry_t *
882 getent_kef(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist)
884 entry_t *pent = NULL;
885 boolean_t memory_allocated = B_FALSE;
887 if ((phardlist == NULL) || (psoftlist == NULL)) {
888 if (get_kcfconf_info(&phardlist, &psoftlist) != SUCCESS) {
889 return (NULL);
891 memory_allocated = B_TRUE;
894 if (is_device(provname)) {
895 pent = getent(provname, phardlist);
896 } else {
897 pent = getent(provname, psoftlist);
900 if (memory_allocated) {
901 free_entrylist(phardlist);
902 free_entrylist(psoftlist);
905 return (pent);
909 * Print out the provider name and the mechanism list.
911 void
912 print_mechlist(char *provname, mechlist_t *pmechlist)
914 mechlist_t *ptr = NULL;
916 if (provname == NULL) {
917 return;
920 (void) printf("%s: ", provname);
921 if (pmechlist == NULL) {
922 (void) printf(gettext("No mechanisms presented.\n"));
923 return;
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(",");
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.
947 update_kcfconf(entry_t *pent, int update_mode)
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;
962 if (pent == NULL) {
963 cryptoerror(LOG_STDERR, gettext("internal error."));
964 return (FAILURE);
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);
977 if (strlen(new_str) == 0) {
978 free(new_str);
979 delete_it = B_TRUE;
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);
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);
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);
1011 * Create a temporary file in the /etc/crypto directory to save
1012 * updated configuration file first.
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);
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);
1033 * Loop thru the entire kcf.conf file, insert, modify or delete
1034 * an entry.
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;
1047 } else { /* modify or delete */
1048 this_entry_matches = B_FALSE;
1050 if (!(buffer[0] == '#' || buffer[0] == ' ' ||
1051 buffer[0] == '\n'|| buffer[0] == '\t')) {
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.
1059 (void) strlcpy(buffer2, buffer, BUFSIZ);
1060 if ((name = strtok(buffer2, SEP_COLON)) ==
1061 NULL) {
1062 rc = FAILURE;
1063 break;
1066 if (strcmp(pent->name, name) == 0) {
1067 this_entry_matches = B_TRUE;
1068 found_entry = B_TRUE;
1073 if (!this_entry_matches || !delete_it) {
1074 /* write this entry */
1075 if (this_entry_matches) {
1077 * Modify this entry: get the
1078 * updated string and place into buffer.
1080 (void) strlcpy(buffer, new_str, BUFSIZ);
1081 free(new_str);
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;
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;
1106 free(new_str);
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);
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;
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));
1148 return (rc);
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.
1159 disable_mechs(entry_t **ppent, mechlist_t *infolist, boolean_t allflag,
1160 mechlist_t *dislist)
1162 entry_t *pent;
1163 mechlist_t *plist = NULL;
1164 mechlist_t *phead = NULL;
1165 mechlist_t *pmech = NULL;
1166 int rc = SUCCESS;
1168 pent = *ppent;
1169 if (pent == NULL) {
1170 return (FAILURE);
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);
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.
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;
1203 if (pent->dislist == NULL) {
1204 pent->dislist = pmech;
1205 } else {
1206 phead = pent->dislist;
1207 pent->dislist = pmech;
1208 pmech->next = phead;
1210 pent->dis_count++;
1212 plist = plist->next;
1215 return (rc);
1219 * Remove the mechanism passed, specified by mech, from the list of
1220 * mechanisms, if present in the list. Else, do nothing.
1222 * Returns B_TRUE if mechanism is present in the list.
1224 boolean_t
1225 filter_mechlist(mechlist_t **pmechlist, const char *mech)
1227 int cnt = 0;
1228 mechlist_t *ptr, *pptr;
1229 boolean_t mech_present = B_FALSE;
1231 ptr = pptr = *pmechlist;
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;
1245 } else {
1246 pptr = ptr;
1247 ptr = ptr->next;
1248 cnt++;
1252 /* Only one entry is present */
1253 if (cnt == 0)
1254 *pmechlist = NULL;
1256 return (mech_present);
1262 * Print out the mechanism policy for a kernel provider that has an entry
1263 * in the kcf.conf file.
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.
1269 * If pent is NULL, the provider doesn't have a kcf.conf entry.
1271 void
1272 print_kef_policy(char *provname, entry_t *pent, boolean_t has_random,
1273 boolean_t has_mechs)
1275 mechlist_t *ptr = NULL;
1276 boolean_t rnd_disabled = B_FALSE;
1278 if (pent != NULL) {
1279 rnd_disabled = filter_mechlist(&pent->dislist, RANDOM);
1280 ptr = pent->dislist;
1283 (void) printf("%s:", provname);
1285 if (has_mechs == B_TRUE) {
1287 * TRANSLATION_NOTE
1288 * This code block may need to be modified a bit to avoid
1289 * constructing the text message on the fly.
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(",");
1300 if (ptr == NULL)
1301 (void) printf(".");
1305 * TRANSLATION_NOTE
1306 * "random" is a keyword and not to be translated.
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");
1317 * Check if a kernel software provider is in the kernel.
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
1326 check_kernel_for_soft(char *provname, crypto_get_soft_list_t *psoftlist_kernel,
1327 boolean_t *in_kernel)
1329 char *ptr;
1330 int i;
1331 boolean_t psoftlist_allocated = B_FALSE;
1333 if (provname == NULL) {
1334 cryptoerror(LOG_STDERR, gettext("internal error."));
1335 return (FAILURE);
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);
1344 psoftlist_allocated = B_TRUE;
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;
1354 ptr = ptr + strlen(ptr) + 1;
1357 if (psoftlist_allocated)
1358 free(psoftlist_kernel);
1360 return (SUCCESS);
1365 * Check if a kernel hardware provider is in the kernel.
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
1374 check_kernel_for_hard(char *provname,
1375 crypto_get_dev_list_t *pdevlist, boolean_t *in_kernel)
1377 char devname[MAXNAMELEN];
1378 int inst_num;
1379 int i;
1380 boolean_t dev_list_allocated = B_FALSE;
1382 if (provname == NULL) {
1383 cryptoerror(LOG_STDERR, gettext("internal error."));
1384 return (FAILURE);
1387 if (split_hw_provname(provname, devname, &inst_num) == FAILURE) {
1388 return (FAILURE);
1391 if (pdevlist == NULL) {
1392 if (get_dev_list(&pdevlist) == FAILURE) {
1393 cryptoerror(LOG_STDERR, gettext("internal error."));
1394 return (FAILURE);
1396 dev_list_allocated = B_TRUE;
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;
1408 if (dev_list_allocated)
1409 free(pdevlist);
1411 return (SUCCESS);