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