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