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