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