xref: /titanic_50/usr/src/cmd/cmd-crypto/cryptoadm/adm_kef_util.c (revision fbd1eea75de85d354a131a825206994dfdece931)
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	this_entry_matches = B_FALSE;
922 	boolean_t	found_entry = B_FALSE;
923 	FILE		*pfile = NULL;
924 	FILE		*pfile_tmp = NULL;
925 	char		buffer[BUFSIZ];
926 	char		buffer2[BUFSIZ];
927 	char		tmpfile_name[MAXPATHLEN];
928 	char		*name;
929 	char		*new_str = NULL;
930 	int		rc = SUCCESS;
931 
932 	if (pent == NULL) {
933 		cryptoerror(LOG_STDERR, gettext("internal error."));
934 		return (FAILURE);
935 	}
936 
937 	/* Check the update_mode */
938 	switch (update_mode) {
939 	case ADD_MODE:
940 		add_it = B_TRUE;
941 		/* FALLTHROUGH */
942 	case MODIFY_MODE:
943 		/* Convert the entry a string to add to kcf.conf  */
944 		if ((new_str = ent2str(pent)) == NULL) {
945 			return (FAILURE);
946 		}
947 		break;
948 	case DELETE_MODE:
949 		delete_it = B_TRUE;
950 		break;
951 	default:
952 		cryptoerror(LOG_STDERR, gettext("internal error."));
953 		return (FAILURE);
954 	}
955 
956 	/* Open the kcf.conf file */
957 	if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) {
958 		err = errno;
959 		cryptoerror(LOG_STDERR,
960 		    gettext("failed to update the configuration - %s"),
961 		    strerror(err));
962 		cryptodebug("failed to open %s for write.", _PATH_KCF_CONF);
963 		return (FAILURE);
964 	}
965 
966 	/* Lock the kcf.conf file */
967 	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
968 		err = errno;
969 		cryptoerror(LOG_STDERR,
970 		    gettext("failed to update the configuration - %s"),
971 		    strerror(err));
972 		(void) fclose(pfile);
973 		return (FAILURE);
974 	}
975 
976 	/*
977 	 * Create a temporary file in the /etc/crypto directory to save
978 	 * updated configuration file first.
979 	 */
980 	(void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
981 	if (mkstemp(tmpfile_name) == -1) {
982 		err = errno;
983 		cryptoerror(LOG_STDERR,
984 		    gettext("failed to create a temporary file - %s"),
985 		    strerror(err));
986 		(void) fclose(pfile);
987 		return (FAILURE);
988 	}
989 
990 	if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
991 		err = errno;
992 		cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
993 		    tmpfile_name, strerror(err));
994 		(void) fclose(pfile);
995 		return (FAILURE);
996 	}
997 
998 	/*
999 	 * Loop thru the entire kcf.conf file, insert, modify or delete
1000 	 * an entry.
1001 	 */
1002 	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
1003 		if (add_it) {
1004 			if (fputs(buffer, pfile_tmp) == EOF) {
1005 				err = errno;
1006 				cryptoerror(LOG_STDERR, gettext(
1007 				    "failed to write to a temp file: %s."),
1008 				    strerror(err));
1009 				rc = FAILURE;
1010 				break;
1011 			}
1012 
1013 		} else { /* modify or delete */
1014 			this_entry_matches = B_FALSE;
1015 
1016 			if (!(buffer[0] == '#' || buffer[0] == ' ' ||
1017 			    buffer[0] == '\n'|| buffer[0] == '\t')) {
1018 				/*
1019 				 * Get the provider name from this line and
1020 				 * check if this is the entry to be updated
1021 				 * or deleted. Note: can not use "buffer"
1022 				 * directly because strtok will change its
1023 				 * value.
1024 				 */
1025 				(void) strlcpy(buffer2, buffer, BUFSIZ);
1026 				if ((name = strtok(buffer2, SEP_COLON)) ==
1027 				    NULL) {
1028 					rc = FAILURE;
1029 					break;
1030 				}
1031 
1032 				if (strcmp(pent->name, name) == 0) {
1033 					this_entry_matches = B_TRUE;
1034 					found_entry = B_TRUE;
1035 				}
1036 			}
1037 
1038 
1039 			if (!this_entry_matches || !delete_it) {
1040 				/* write this entry */
1041 				if (this_entry_matches) {
1042 					/*
1043 					 * Modify this entry: get the
1044 					 * updated string and place into buffer.
1045 					 */
1046 					(void) strlcpy(buffer, new_str, BUFSIZ);
1047 					free(new_str);
1048 				}
1049 				/* write the (unchanged or modified) entry */
1050 				if (fputs(buffer, pfile_tmp) == EOF) {
1051 					err = errno;
1052 					cryptoerror(LOG_STDERR, gettext(
1053 					    "failed to write to a temp file: "
1054 					    "%s."), strerror(err));
1055 					rc = FAILURE;
1056 					break;
1057 				}
1058 			}
1059 		}
1060 	}
1061 
1062 	if ((!delete_it) && (rc != FAILURE)) {
1063 		if (add_it || !found_entry) {
1064 			/* append new entry to end of file */
1065 			if (fputs(new_str, pfile_tmp) == EOF) {
1066 				err = errno;
1067 				cryptoerror(LOG_STDERR, gettext(
1068 				    "failed to write to a temp file: %s."),
1069 				    strerror(err));
1070 				rc = FAILURE;
1071 			}
1072 			free(new_str);
1073 		}
1074 	}
1075 
1076 	(void) fclose(pfile);
1077 	if (fclose(pfile_tmp) != 0) {
1078 		err = errno;
1079 		cryptoerror(LOG_STDERR,
1080 		    gettext("failed to close %s: %s"), tmpfile_name,
1081 		    strerror(err));
1082 		return (FAILURE);
1083 	}
1084 
1085 	/* Copy the temporary file to the kcf.conf file */
1086 	if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) {
1087 		err = errno;
1088 		cryptoerror(LOG_STDERR,
1089 		    gettext("failed to update the configuration - %s"),
1090 		    strerror(err));
1091 		cryptodebug("failed to rename %s to %s: %s", tmpfile,
1092 		    _PATH_KCF_CONF, strerror(err));
1093 		rc = FAILURE;
1094 	} else if (chmod(_PATH_KCF_CONF,
1095 	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
1096 		err = errno;
1097 		cryptoerror(LOG_STDERR,
1098 		    gettext("failed to update the configuration - %s"),
1099 		    strerror(err));
1100 		cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF,
1101 		    strerror(err));
1102 		rc = FAILURE;
1103 	} else {
1104 		rc = SUCCESS;
1105 	}
1106 
1107 	if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
1108 		err = errno;
1109 		cryptoerror(LOG_STDERR, gettext(
1110 		    "(Warning) failed to remove %s: %s"),
1111 		    tmpfile_name, strerror(err));
1112 	}
1113 
1114 	return (rc);
1115 }
1116 
1117 
1118 /*
1119  * Disable the mechanisms for the provider pointed by *ppent.  If allflag is
1120  * TRUE, disable all.  Otherwise, disable the mechanisms specified in the
1121  * dislist argument.  The "infolist" argument contains the mechanism list
1122  * supported by this provider.
1123  */
1124 int
1125 disable_mechs(entry_t **ppent, mechlist_t *infolist, boolean_t allflag,
1126 mechlist_t *dislist)
1127 {
1128 	entry_t		*pent;
1129 	mechlist_t	*plist = NULL;
1130 	mechlist_t	*phead = NULL;
1131 	mechlist_t	*pmech = NULL;
1132 	int		rc = SUCCESS;
1133 
1134 	pent = *ppent;
1135 	if (pent == NULL) {
1136 		return (FAILURE);
1137 	}
1138 
1139 	if (allflag) {
1140 		free_mechlist(pent->dislist);
1141 		pent->dis_count = get_mech_count(infolist);
1142 		if (!(pent->dislist = dup_mechlist(infolist))) {
1143 			return (FAILURE);
1144 		} else {
1145 			return (SUCCESS);
1146 		}
1147 	}
1148 
1149 	/*
1150 	 * Not disable all. Now loop thru the mechanisms specified in the
1151 	 * dislist.  If the mechanism is not supported by the provider,
1152 	 * ignore it with a warning.  If the mechanism is disabled already,
1153 	 * do nothing. Otherwise, prepend it to the beginning of the disabled
1154 	 * list of the provider.
1155 	 */
1156 	plist = dislist;
1157 	while (plist != NULL) {
1158 		if (!is_in_list(plist->name, infolist)) {
1159 			cryptoerror(LOG_STDERR, gettext("(Warning) "
1160 			    "%1$s is not a valid mechanism for %2$s."),
1161 			    plist->name, pent->name);
1162 		} else if (!is_in_list(plist->name, pent->dislist)) {
1163 			/* Add this mechanism into the disabled list */
1164 			if ((pmech = create_mech(plist->name)) == NULL) {
1165 				rc = FAILURE;
1166 				break;
1167 			}
1168 
1169 			if (pent->dislist == NULL) {
1170 				pent->dislist = pmech;
1171 			} else {
1172 				phead = pent->dislist;
1173 				pent->dislist = pmech;
1174 				pmech->next = phead;
1175 			}
1176 			pent->dis_count++;
1177 		}
1178 		plist = plist->next;
1179 	}
1180 
1181 	return (rc);
1182 }
1183 
1184 /*
1185  * Remove the mechanism passed, specified by mech, from the list of
1186  * mechanisms, if present in the list. Else, do nothing.
1187  *
1188  * Returns B_TRUE if mechanism is present in the list.
1189  */
1190 boolean_t
1191 filter_mechlist(mechlist_t **pmechlist, const char *mech)
1192 {
1193 	int		cnt = 0;
1194 	mechlist_t	*ptr, *pptr;
1195 	boolean_t	mech_present = B_FALSE;
1196 
1197 	ptr = pptr = *pmechlist;
1198 
1199 	while (ptr != NULL) {
1200 		if (strncmp(ptr->name, mech, sizeof (mech_name_t)) == 0) {
1201 			mech_present = B_TRUE;
1202 			if (ptr == *pmechlist) {
1203 				pptr = *pmechlist = ptr->next;
1204 				free(ptr);
1205 				ptr = pptr;
1206 			} else {
1207 				pptr->next = ptr->next;
1208 				free(ptr);
1209 				ptr = pptr->next;
1210 			}
1211 		} else {
1212 			pptr = ptr;
1213 			ptr = ptr->next;
1214 			cnt++;
1215 		}
1216 	}
1217 
1218 	/* Only one entry is present */
1219 	if (cnt == 0)
1220 		*pmechlist = NULL;
1221 
1222 	return (mech_present);
1223 }
1224 
1225 
1226 
1227 /*
1228  * Print out the mechanism policy for a kernel provider that has an entry
1229  * in the kcf.conf file.
1230  *
1231  * The flag has_random is set to B_TRUE if the provider does random
1232  * numbers. The flag has_mechs is set by the caller to B_TRUE if the provider
1233  * has some mechanisms.
1234  *
1235  * If pent is NULL, the provider doesn't have a kcf.conf entry.
1236  */
1237 void
1238 print_kef_policy(char *provname, entry_t *pent, boolean_t has_random,
1239     boolean_t has_mechs)
1240 {
1241 	mechlist_t	*ptr = NULL;
1242 	boolean_t	rnd_disabled = B_FALSE;
1243 
1244 	if (pent != NULL) {
1245 		rnd_disabled = filter_mechlist(&pent->dislist, RANDOM);
1246 		ptr = pent->dislist;
1247 	}
1248 
1249 	(void) printf("%s:", provname);
1250 
1251 	if (has_mechs == B_TRUE) {
1252 		/*
1253 		 * TRANSLATION_NOTE
1254 		 * This code block may need to be modified a bit to avoid
1255 		 * constructing the text message on the fly.
1256 		 */
1257 		(void) printf(gettext(" all mechanisms are enabled"));
1258 		if (ptr != NULL)
1259 			(void) printf(gettext(", except "));
1260 		while (ptr != NULL) {
1261 			(void) printf("%s", ptr->name);
1262 			ptr = ptr->next;
1263 			if (ptr != NULL)
1264 				(void) printf(",");
1265 		}
1266 		if (ptr == NULL)
1267 			(void) printf(".");
1268 	}
1269 
1270 	/*
1271 	 * TRANSLATION_NOTE
1272 	 * "random" is a keyword and not to be translated.
1273 	 */
1274 	if (rnd_disabled)
1275 		(void) printf(gettext(" %s is disabled."), "random");
1276 	else if (has_random)
1277 		(void) printf(gettext(" %s is enabled."), "random");
1278 	(void) printf("\n");
1279 }
1280 
1281 
1282 /*
1283  * Check if a kernel software provider is in the kernel.
1284  *
1285  * Parameters:
1286  * provname		Provider name
1287  * psoftlist_kernel	Optional software provider list.  If NULL, it will be
1288  *			obtained from get_soft_list().
1289  * in_kernel		Set to B_TRUE if device is in the kernel, else B_FALSE
1290  */
1291 int
1292 check_kernel_for_soft(char *provname, crypto_get_soft_list_t *psoftlist_kernel,
1293     boolean_t *in_kernel)
1294 {
1295 	char		*ptr;
1296 	int		i;
1297 	boolean_t	psoftlist_allocated = B_FALSE;
1298 
1299 	if (provname == NULL) {
1300 		cryptoerror(LOG_STDERR, gettext("internal error."));
1301 		return (FAILURE);
1302 	}
1303 
1304 	if (psoftlist_kernel == NULL) {
1305 		if (get_soft_list(&psoftlist_kernel) == FAILURE) {
1306 			cryptodebug("failed to get the software provider list"
1307 			" from kernel.");
1308 			return (FAILURE);
1309 		}
1310 		psoftlist_allocated = B_TRUE;
1311 	}
1312 
1313 	*in_kernel = B_FALSE;
1314 	ptr = psoftlist_kernel->sl_soft_names;
1315 	for (i = 0; i < psoftlist_kernel->sl_soft_count; i++) {
1316 		if (strcmp(provname, ptr) == 0) {
1317 			*in_kernel = B_TRUE;
1318 			break;
1319 		}
1320 		ptr = ptr + strlen(ptr) + 1;
1321 	}
1322 
1323 	if (psoftlist_allocated)
1324 		free(psoftlist_kernel);
1325 
1326 	return (SUCCESS);
1327 }
1328 
1329 
1330 /*
1331  * Check if a kernel hardware provider is in the kernel.
1332  *
1333  * Parameters:
1334  * provname	Provider name
1335  * pdevlist	Optional Hardware Crypto Device List.  If NULL, it will be
1336  *		obtained from get_dev_list().
1337  * in_kernel	Set to B_TRUE if device is in the kernel, otherwise B_FALSE
1338  */
1339 int
1340 check_kernel_for_hard(char *provname,
1341     crypto_get_dev_list_t *pdevlist, boolean_t *in_kernel)
1342 {
1343 	char		devname[MAXNAMELEN];
1344 	int		inst_num;
1345 	int		i;
1346 	boolean_t	dev_list_allocated = B_FALSE;
1347 
1348 	if (provname == NULL) {
1349 		cryptoerror(LOG_STDERR, gettext("internal error."));
1350 		return (FAILURE);
1351 	}
1352 
1353 	if (split_hw_provname(provname, devname, &inst_num) == FAILURE) {
1354 		return (FAILURE);
1355 	}
1356 
1357 	if (pdevlist == NULL) {
1358 		if (get_dev_list(&pdevlist) == FAILURE) {
1359 			cryptoerror(LOG_STDERR, gettext("internal error."));
1360 			return (FAILURE);
1361 		}
1362 		dev_list_allocated = B_TRUE;
1363 	}
1364 
1365 	*in_kernel = B_FALSE;
1366 	for (i = 0; i < pdevlist->dl_dev_count; i++) {
1367 		if ((strcmp(pdevlist->dl_devs[i].le_dev_name, devname) == 0) &&
1368 		    (pdevlist->dl_devs[i].le_dev_instance == inst_num)) {
1369 			*in_kernel = B_TRUE;
1370 			break;
1371 		}
1372 	}
1373 
1374 	if (dev_list_allocated)
1375 		free(pdevlist);
1376 
1377 	return (SUCCESS);
1378 }
1379