10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57334SDaniel.Anderson@Sun.COM  * Common Development and Distribution License (the "License").
67334SDaniel.Anderson@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*10500SHai-May.Chao@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <errno.h>
270Sstevel@tonic-gate #include <fcntl.h>
280Sstevel@tonic-gate #include <stdio.h>
290Sstevel@tonic-gate #include <stdlib.h>
300Sstevel@tonic-gate #include <strings.h>
310Sstevel@tonic-gate #include <time.h>
320Sstevel@tonic-gate #include <unistd.h>
330Sstevel@tonic-gate #include <locale.h>
340Sstevel@tonic-gate #include <sys/types.h>
357968Sopensolaris@drydog.com #include <zone.h>
360Sstevel@tonic-gate #include <sys/stat.h>
370Sstevel@tonic-gate #include "cryptoadm.h"
38*10500SHai-May.Chao@Sun.COM #include <cryptoutil.h>
390Sstevel@tonic-gate 
400Sstevel@tonic-gate static int err; /* To store errno which may be overwritten by gettext() */
410Sstevel@tonic-gate static int build_entrylist(entry_t *, entrylist_t **);
420Sstevel@tonic-gate static entry_t *dup_entry(entry_t *);
430Sstevel@tonic-gate static mechlist_t *dup_mechlist(mechlist_t *);
440Sstevel@tonic-gate static entry_t *getent(char *, entrylist_t *);
450Sstevel@tonic-gate static int interpret(char *, entry_t **);
467968Sopensolaris@drydog.com static int parse_sup_dis_list(char *, entry_t *);
470Sstevel@tonic-gate 
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  * Duplicate the mechanism list.  A null pointer is returned if the storage
510Sstevel@tonic-gate  * space available is insufficient or the input argument is NULL.
520Sstevel@tonic-gate  */
530Sstevel@tonic-gate static mechlist_t *
540Sstevel@tonic-gate dup_mechlist(mechlist_t *plist)
550Sstevel@tonic-gate {
567968Sopensolaris@drydog.com 	mechlist_t	*pres = NULL;
577968Sopensolaris@drydog.com 	mechlist_t	*pcur;
587968Sopensolaris@drydog.com 	mechlist_t	*ptmp;
597968Sopensolaris@drydog.com 	int		rc = SUCCESS;
600Sstevel@tonic-gate 
610Sstevel@tonic-gate 	while (plist != NULL) {
620Sstevel@tonic-gate 		if (!(ptmp = create_mech(plist->name))) {
630Sstevel@tonic-gate 			rc = FAILURE;
640Sstevel@tonic-gate 			break;
650Sstevel@tonic-gate 		}
660Sstevel@tonic-gate 
670Sstevel@tonic-gate 		if (pres == NULL) {
680Sstevel@tonic-gate 			pres = pcur = ptmp;
690Sstevel@tonic-gate 		} else {
700Sstevel@tonic-gate 			pcur->next = ptmp;
710Sstevel@tonic-gate 			pcur = pcur->next;
720Sstevel@tonic-gate 		}
730Sstevel@tonic-gate 		plist = plist->next;
740Sstevel@tonic-gate 	}
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	if (rc != SUCCESS) {
770Sstevel@tonic-gate 		free_mechlist(pres);
780Sstevel@tonic-gate 		return (NULL);
790Sstevel@tonic-gate 	}
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 	return (pres);
820Sstevel@tonic-gate }
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 
850Sstevel@tonic-gate /*
860Sstevel@tonic-gate  * Get the number of mechanisms in the mechanism list.
870Sstevel@tonic-gate  */
880Sstevel@tonic-gate int
890Sstevel@tonic-gate get_mech_count(mechlist_t *plist)
900Sstevel@tonic-gate {
910Sstevel@tonic-gate 	int count = 0;
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 	while (plist != NULL) {
940Sstevel@tonic-gate 		count++;
950Sstevel@tonic-gate 		plist = plist->next;
960Sstevel@tonic-gate 	}
970Sstevel@tonic-gate 	return (count);
980Sstevel@tonic-gate }
990Sstevel@tonic-gate 
1007968Sopensolaris@drydog.com /*
1017968Sopensolaris@drydog.com  * Create one item of type entry_t with the provider name.
1027968Sopensolaris@drydog.com  * Return NULL if there's not enough memory or provname is NULL.
1037968Sopensolaris@drydog.com  */
1047968Sopensolaris@drydog.com entry_t *
1057968Sopensolaris@drydog.com create_entry(char *provname)
1067968Sopensolaris@drydog.com {
1077968Sopensolaris@drydog.com 	entry_t		*pent = NULL;
1087968Sopensolaris@drydog.com 
1097968Sopensolaris@drydog.com 	if (provname == NULL) {
1107968Sopensolaris@drydog.com 		return (NULL);
1117968Sopensolaris@drydog.com 	}
1127968Sopensolaris@drydog.com 
1137968Sopensolaris@drydog.com 	pent = calloc(1, sizeof (entry_t));
1147968Sopensolaris@drydog.com 	if (pent == NULL) {
1157968Sopensolaris@drydog.com 		cryptodebug("out of memory.");
1167968Sopensolaris@drydog.com 		return (NULL);
1177968Sopensolaris@drydog.com 	}
1187968Sopensolaris@drydog.com 
1197968Sopensolaris@drydog.com 	(void) strlcpy(pent->name, provname, MAXNAMELEN);
1207968Sopensolaris@drydog.com 	pent->suplist = NULL;
1217968Sopensolaris@drydog.com 	pent->sup_count = 0;
1227968Sopensolaris@drydog.com 	pent->dislist = NULL;
1237968Sopensolaris@drydog.com 	pent->dis_count = 0;
1247968Sopensolaris@drydog.com 	pent->load = B_TRUE;
1257968Sopensolaris@drydog.com 
1267968Sopensolaris@drydog.com 	return (pent);
1277968Sopensolaris@drydog.com }
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate /*
1307968Sopensolaris@drydog.com  * Duplicate an entry for a provider from kcf.conf.
1317968Sopensolaris@drydog.com  * Return NULL if memory is insufficient or the input argument is NULL.
1327968Sopensolaris@drydog.com  * Called by getent().
1330Sstevel@tonic-gate  */
1340Sstevel@tonic-gate static entry_t *
1350Sstevel@tonic-gate dup_entry(entry_t *pent1)
1360Sstevel@tonic-gate {
1370Sstevel@tonic-gate 	entry_t	*pent2 = NULL;
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	if (pent1 == NULL) {
1400Sstevel@tonic-gate 		return (NULL);
1410Sstevel@tonic-gate 	}
1420Sstevel@tonic-gate 
1437968Sopensolaris@drydog.com 	if ((pent2 = create_entry(pent1->name)) == NULL) {
1440Sstevel@tonic-gate 		cryptodebug("out of memory.");
1450Sstevel@tonic-gate 		return (NULL);
1460Sstevel@tonic-gate 	}
1470Sstevel@tonic-gate 
148*10500SHai-May.Chao@Sun.COM 	pent2->flag_fips_enabled = pent1->flag_fips_enabled;
1490Sstevel@tonic-gate 	pent2->sup_count = pent1->sup_count;
1500Sstevel@tonic-gate 	pent2->dis_count = pent1->dis_count;
1517968Sopensolaris@drydog.com 	pent2->load = pent1->load;
1520Sstevel@tonic-gate 	if (pent1->suplist != NULL) {
1530Sstevel@tonic-gate 		pent2->suplist = dup_mechlist(pent1->suplist);
1540Sstevel@tonic-gate 		if (pent2->suplist == NULL) {
1550Sstevel@tonic-gate 			free_entry(pent2);
1560Sstevel@tonic-gate 			return (NULL);
1570Sstevel@tonic-gate 		}
1580Sstevel@tonic-gate 	}
1590Sstevel@tonic-gate 	if (pent1->dislist != NULL) {
1600Sstevel@tonic-gate 		pent2->dislist = dup_mechlist(pent1->dislist);
1610Sstevel@tonic-gate 		if (pent2->dislist == NULL) {
1620Sstevel@tonic-gate 			free_entry(pent2);
1630Sstevel@tonic-gate 			return (NULL);
1640Sstevel@tonic-gate 		}
1650Sstevel@tonic-gate 	}
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	return (pent2);
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate /*
1720Sstevel@tonic-gate  * This routine parses the disabledlist or the supportedlist of an entry
1730Sstevel@tonic-gate  * in the kcf.conf configuration file.
1740Sstevel@tonic-gate  *
1750Sstevel@tonic-gate  * Arguments:
1767968Sopensolaris@drydog.com  *	buf: an input argument which is a char string with the format of
1770Sstevel@tonic-gate  *	     "disabledlist=m1,m2,..." or "supportedlist=m1,m2,..."
1780Sstevel@tonic-gate  *	pent: the entry for the disabledlist.  This is an IN/OUT argument.
1790Sstevel@tonic-gate  *
1800Sstevel@tonic-gate  * Return value: SUCCESS or FAILURE.
1810Sstevel@tonic-gate  */
1820Sstevel@tonic-gate static int
1837968Sopensolaris@drydog.com parse_sup_dis_list(char *buf, entry_t *pent)
1840Sstevel@tonic-gate {
1857968Sopensolaris@drydog.com 	mechlist_t	*pmech = NULL;
1867968Sopensolaris@drydog.com 	mechlist_t	*phead = NULL;
1877968Sopensolaris@drydog.com 	char		*next_token;
1887968Sopensolaris@drydog.com 	char		*value;
1897968Sopensolaris@drydog.com 	int		count;
1907968Sopensolaris@drydog.com 	int		supflag = B_FALSE;
1917968Sopensolaris@drydog.com 	int		disflag = B_FALSE;
1927968Sopensolaris@drydog.com 	int		rc = SUCCESS;
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	if (strncmp(buf, EF_SUPPORTED, strlen(EF_SUPPORTED)) == 0) {
1950Sstevel@tonic-gate 		supflag = B_TRUE;
1960Sstevel@tonic-gate 	} else if (strncmp(buf, EF_DISABLED, strlen(EF_DISABLED)) == 0) {
1970Sstevel@tonic-gate 		disflag = B_TRUE;
1980Sstevel@tonic-gate 	} else {
1990Sstevel@tonic-gate 		/* should not come here */
2000Sstevel@tonic-gate 		return (FAILURE);
2010Sstevel@tonic-gate 	}
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	if (value = strpbrk(buf, SEP_EQUAL)) {
2040Sstevel@tonic-gate 		value++; /* get rid of = */
2050Sstevel@tonic-gate 	} else {
2060Sstevel@tonic-gate 		cryptodebug("failed to parse the kcf.conf file.");
2070Sstevel@tonic-gate 		return (FAILURE);
2080Sstevel@tonic-gate 	}
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	if ((next_token = strtok(value, SEP_COMMA)) == NULL) {
2110Sstevel@tonic-gate 		cryptodebug("failed to parse the kcf.conf file.");
2120Sstevel@tonic-gate 		return (FAILURE);
2130Sstevel@tonic-gate 	}
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	if ((pmech = create_mech(next_token)) == NULL) {
2160Sstevel@tonic-gate 		return (FAILURE);
2170Sstevel@tonic-gate 	}
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	if (supflag) {
2200Sstevel@tonic-gate 		pent->suplist = phead = pmech;
2210Sstevel@tonic-gate 	} else if (disflag) {
2220Sstevel@tonic-gate 		pent->dislist = phead = pmech;
2230Sstevel@tonic-gate 	}
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	count = 1;
2260Sstevel@tonic-gate 	while (next_token) {
2270Sstevel@tonic-gate 		if (next_token = strtok(NULL, SEP_COMMA)) {
2280Sstevel@tonic-gate 			if ((pmech = create_mech(next_token)) == NULL) {
2290Sstevel@tonic-gate 				rc = FAILURE;
2300Sstevel@tonic-gate 				break;
2310Sstevel@tonic-gate 			}
2320Sstevel@tonic-gate 			count++;
2330Sstevel@tonic-gate 			phead->next = pmech;
2340Sstevel@tonic-gate 			phead = phead->next;
2350Sstevel@tonic-gate 		}
2360Sstevel@tonic-gate 	}
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	if (rc == SUCCESS) {
2390Sstevel@tonic-gate 		if (supflag) {
2400Sstevel@tonic-gate 			pent->sup_count = count;
2410Sstevel@tonic-gate 		} else if (disflag) {
2420Sstevel@tonic-gate 			pent->dis_count = count;
2430Sstevel@tonic-gate 		}
2440Sstevel@tonic-gate 	} else {
2450Sstevel@tonic-gate 		free_mechlist(phead);
2460Sstevel@tonic-gate 	}
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	return (rc);
2490Sstevel@tonic-gate }
2500Sstevel@tonic-gate 
251*10500SHai-May.Chao@Sun.COM static int
252*10500SHai-May.Chao@Sun.COM parse_fips(char *buf, entry_t *pent)
253*10500SHai-May.Chao@Sun.COM {
254*10500SHai-May.Chao@Sun.COM 	char *value;
255*10500SHai-May.Chao@Sun.COM 
256*10500SHai-May.Chao@Sun.COM 	if (strncmp(buf, EF_FIPS_STATUS, sizeof (EF_FIPS_STATUS) - 1) == 0) {
257*10500SHai-May.Chao@Sun.COM 		if (value = strpbrk(buf, SEP_EQUAL)) {
258*10500SHai-May.Chao@Sun.COM 			value++; /* get rid of = */
259*10500SHai-May.Chao@Sun.COM 			if (strcmp(value, DISABLED_KEYWORD) == 0) {
260*10500SHai-May.Chao@Sun.COM 				pent->flag_fips_enabled = B_FALSE;
261*10500SHai-May.Chao@Sun.COM 			} else if (strcmp(value, ENABLED_KEYWORD) == 0) {
262*10500SHai-May.Chao@Sun.COM 				pent->flag_fips_enabled = B_TRUE;
263*10500SHai-May.Chao@Sun.COM 			} else {
264*10500SHai-May.Chao@Sun.COM 				cryptoerror(LOG_ERR, gettext(
265*10500SHai-May.Chao@Sun.COM 				    "Failed to parse kcf.conf file.\n"));
266*10500SHai-May.Chao@Sun.COM 				return (FAILURE);
267*10500SHai-May.Chao@Sun.COM 			}
268*10500SHai-May.Chao@Sun.COM 			return (SUCCESS);
269*10500SHai-May.Chao@Sun.COM 		} else {
270*10500SHai-May.Chao@Sun.COM 			return (FAILURE);
271*10500SHai-May.Chao@Sun.COM 		}
272*10500SHai-May.Chao@Sun.COM 	} else {
273*10500SHai-May.Chao@Sun.COM 		/* should not come here */
274*10500SHai-May.Chao@Sun.COM 		cryptoerror(LOG_ERR, gettext(
275*10500SHai-May.Chao@Sun.COM 		    "Failed to parse kcf.conf file.\n"));
276*10500SHai-May.Chao@Sun.COM 		return (FAILURE);
277*10500SHai-May.Chao@Sun.COM 	}
278*10500SHai-May.Chao@Sun.COM 
279*10500SHai-May.Chao@Sun.COM }
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate /*
2827968Sopensolaris@drydog.com  * Convert a char string containing a line about a provider
2837968Sopensolaris@drydog.com  * from kcf.conf into an entry_t structure.
2847968Sopensolaris@drydog.com  *
2857968Sopensolaris@drydog.com  * See ent2str(), the reverse of this function, for the format of
2867968Sopensolaris@drydog.com  * kcf.conf lines.
2870Sstevel@tonic-gate  */
2880Sstevel@tonic-gate static int
2890Sstevel@tonic-gate interpret(char *buf, entry_t **ppent)
2900Sstevel@tonic-gate {
2917968Sopensolaris@drydog.com 	entry_t	*pent = NULL;
2927968Sopensolaris@drydog.com 	char	*token1;
2937968Sopensolaris@drydog.com 	char	*token2;
2947968Sopensolaris@drydog.com 	char	*token3;
2957968Sopensolaris@drydog.com 	int	rc;
2960Sstevel@tonic-gate 
2977968Sopensolaris@drydog.com 	/* Get provider name */
2980Sstevel@tonic-gate 	if ((token1 = strtok(buf, SEP_COLON)) == NULL) { /* buf is NULL */
2990Sstevel@tonic-gate 		return (FAILURE);
3000Sstevel@tonic-gate 	};
3010Sstevel@tonic-gate 
3027968Sopensolaris@drydog.com 	pent = create_entry(token1);
3030Sstevel@tonic-gate 	if (pent == NULL) {
3040Sstevel@tonic-gate 		cryptodebug("out of memory.");
3050Sstevel@tonic-gate 		return (FAILURE);
3060Sstevel@tonic-gate 	}
3070Sstevel@tonic-gate 
308*10500SHai-May.Chao@Sun.COM 	if (is_fips(token1)) {
309*10500SHai-May.Chao@Sun.COM 		if ((rc = parse_fips(buf + strlen(token1) + 1,
310*10500SHai-May.Chao@Sun.COM 		    pent)) != SUCCESS) {
311*10500SHai-May.Chao@Sun.COM 			free_entry(pent);
312*10500SHai-May.Chao@Sun.COM 		}
313*10500SHai-May.Chao@Sun.COM 		*ppent = pent;
314*10500SHai-May.Chao@Sun.COM 		return (rc);
315*10500SHai-May.Chao@Sun.COM 	}
316*10500SHai-May.Chao@Sun.COM 
3170Sstevel@tonic-gate 	if ((token2 = strtok(NULL, SEP_SEMICOLON)) == NULL) {
3180Sstevel@tonic-gate 		/* The entry contains a provider name only */
3190Sstevel@tonic-gate 		free_entry(pent);
3200Sstevel@tonic-gate 		return (FAILURE);
3210Sstevel@tonic-gate 	}
3220Sstevel@tonic-gate 
3237968Sopensolaris@drydog.com 	if (strncmp(token2, EF_UNLOAD, strlen(EF_UNLOAD)) == 0) {
3247968Sopensolaris@drydog.com 		pent->load = B_FALSE; /* cryptoadm unload */
3257968Sopensolaris@drydog.com 		if ((token2 = strtok(NULL, SEP_SEMICOLON)) == NULL) {
3267968Sopensolaris@drydog.com 			/* The entry contains a provider name:unload only */
3277968Sopensolaris@drydog.com 			free_entry(pent);
3287968Sopensolaris@drydog.com 			return (FAILURE);
3297968Sopensolaris@drydog.com 		}
3307968Sopensolaris@drydog.com 	}
3317968Sopensolaris@drydog.com 
3320Sstevel@tonic-gate 	/* need to get token3 first to satisfy nested strtok invocations */
3337968Sopensolaris@drydog.com 	token3 = strtok(NULL, SEP_SEMICOLON); /* optional */
3340Sstevel@tonic-gate 
3357968Sopensolaris@drydog.com 	/* parse supportedlist (or disabledlist if no supportedlist) */
3367968Sopensolaris@drydog.com 	if ((token2 != NULL) && ((rc = parse_sup_dis_list(token2, pent)) !=
3377968Sopensolaris@drydog.com 	    SUCCESS)) {
3380Sstevel@tonic-gate 		free_entry(pent);
3390Sstevel@tonic-gate 		return (rc);
3400Sstevel@tonic-gate 	}
3410Sstevel@tonic-gate 
3427968Sopensolaris@drydog.com 	/* parse disabledlist (if there's a supportedlist) */
3437968Sopensolaris@drydog.com 	if ((token3 != NULL) && ((rc = parse_sup_dis_list(token3, pent)) !=
3447968Sopensolaris@drydog.com 	    SUCCESS)) {
3450Sstevel@tonic-gate 		free_entry(pent);
3460Sstevel@tonic-gate 		return (rc);
3470Sstevel@tonic-gate 	}
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	*ppent = pent;
3500Sstevel@tonic-gate 	return (SUCCESS);
3510Sstevel@tonic-gate }
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate /*
3557968Sopensolaris@drydog.com  * Add an entry about a provider from kcf.conf to the end of an entry list.
3567968Sopensolaris@drydog.com  * If the entry list pplist is NULL, create the linked list with pent as the
3577968Sopensolaris@drydog.com  * first element.
3580Sstevel@tonic-gate  */
3590Sstevel@tonic-gate static int
3600Sstevel@tonic-gate build_entrylist(entry_t *pent, entrylist_t **pplist)
3610Sstevel@tonic-gate {
3627968Sopensolaris@drydog.com 	entrylist_t	*pentlist;
3637968Sopensolaris@drydog.com 	entrylist_t	*pcur = NULL;
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	pentlist = malloc(sizeof (entrylist_t));
3660Sstevel@tonic-gate 	if (pentlist == NULL) {
3670Sstevel@tonic-gate 		cryptodebug("out of memory.");
3680Sstevel@tonic-gate 		return (FAILURE);
3690Sstevel@tonic-gate 	}
3700Sstevel@tonic-gate 	pentlist->pent = pent;
3710Sstevel@tonic-gate 	pentlist->next = NULL;
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	if (*pplist) {
3740Sstevel@tonic-gate 		pcur = *pplist;
3750Sstevel@tonic-gate 		while (pcur->next != NULL)
3760Sstevel@tonic-gate 			pcur = pcur->next;
3770Sstevel@tonic-gate 		pcur->next = pentlist;
3780Sstevel@tonic-gate 	} else { /* empty list */
3790Sstevel@tonic-gate 		*pplist = pentlist;
3800Sstevel@tonic-gate 	}
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	return (SUCCESS);
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate /*
3880Sstevel@tonic-gate  * Find the entry with the "provname" name from the entry list and duplicate
3897968Sopensolaris@drydog.com  * it.  Called by getent_kef().
3900Sstevel@tonic-gate  */
3910Sstevel@tonic-gate static entry_t *
3920Sstevel@tonic-gate getent(char *provname, entrylist_t *entrylist)
3930Sstevel@tonic-gate {
3940Sstevel@tonic-gate 	boolean_t	found = B_FALSE;
3950Sstevel@tonic-gate 	entry_t		*pent1 = NULL;
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	if ((provname == NULL) || (entrylist == NULL)) {
3980Sstevel@tonic-gate 		return (NULL);
3990Sstevel@tonic-gate 	}
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	while (!found && entrylist) {
4020Sstevel@tonic-gate 		if (strcmp(entrylist->pent->name, provname) == 0) {
4030Sstevel@tonic-gate 			found = B_TRUE;
4040Sstevel@tonic-gate 			pent1 = entrylist->pent;
4050Sstevel@tonic-gate 		} else {
4060Sstevel@tonic-gate 			entrylist = entrylist->next;
4070Sstevel@tonic-gate 		}
4080Sstevel@tonic-gate 	}
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	if (!found) {
4110Sstevel@tonic-gate 		return (NULL);
4120Sstevel@tonic-gate 	}
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	/* duplicate the entry to be returned */
4150Sstevel@tonic-gate 	return (dup_entry(pent1));
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 
4197968Sopensolaris@drydog.com /*
4207968Sopensolaris@drydog.com  * Free memory in entry_t.
4217968Sopensolaris@drydog.com  * That is, the supported and disabled lists for a provider
4227968Sopensolaris@drydog.com  * from kcf.conf.
4237968Sopensolaris@drydog.com  */
4240Sstevel@tonic-gate void
4250Sstevel@tonic-gate free_entry(entry_t  *pent)
4260Sstevel@tonic-gate {
4270Sstevel@tonic-gate 	if (pent == NULL) {
4280Sstevel@tonic-gate 		return;
4290Sstevel@tonic-gate 	} else {
4300Sstevel@tonic-gate 		free_mechlist(pent->suplist);
4310Sstevel@tonic-gate 		free_mechlist(pent->dislist);
4320Sstevel@tonic-gate 		free(pent);
4330Sstevel@tonic-gate 	}
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 
4377968Sopensolaris@drydog.com /*
4387968Sopensolaris@drydog.com  * Free elements in a entrylist_t linked list,
4397968Sopensolaris@drydog.com  * which lists providers in kcf.conf.
4407968Sopensolaris@drydog.com  */
4410Sstevel@tonic-gate void
4420Sstevel@tonic-gate free_entrylist(entrylist_t *entrylist)
4430Sstevel@tonic-gate {
4440Sstevel@tonic-gate 	entrylist_t *pnext;
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	while (entrylist != NULL) {
4470Sstevel@tonic-gate 		pnext = entrylist->next;
4480Sstevel@tonic-gate 		free_entry(entrylist->pent);
4490Sstevel@tonic-gate 		entrylist = pnext;
4500Sstevel@tonic-gate 	}
4510Sstevel@tonic-gate }
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate /*
4550Sstevel@tonic-gate  * Convert an entry to a string.  This routine builds a string for the entry
4567968Sopensolaris@drydog.com  * to be inserted in the kcf.conf file.  Based on the content of each entry,
4577968Sopensolaris@drydog.com  * the result string can be one of these 6 forms:
4580Sstevel@tonic-gate  *  - name:supportedlist=m1,m2,...,mj
4590Sstevel@tonic-gate  *  - name:disabledlist=m1,m2,...,mj
4600Sstevel@tonic-gate  *  - name:supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk
4610Sstevel@tonic-gate  *
4627968Sopensolaris@drydog.com  *  - name:unload;supportedlist=m1,m2,...,mj
4637968Sopensolaris@drydog.com  *  - name:unload;disabledlist=m1,m2,...,mj
4647968Sopensolaris@drydog.com  *  - name:unload;supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk
4657968Sopensolaris@drydog.com  *
4667968Sopensolaris@drydog.com  * Note that the caller is responsible for freeing the returned string
4677968Sopensolaris@drydog.com  * (with free_entry()).
4687968Sopensolaris@drydog.com  * See interpret() for the reverse of this function: converting a string
4697968Sopensolaris@drydog.com  * to an entry_t.
4700Sstevel@tonic-gate  */
4710Sstevel@tonic-gate char *
4720Sstevel@tonic-gate ent2str(entry_t *pent)
4730Sstevel@tonic-gate {
4747968Sopensolaris@drydog.com 	char		*buf;
4757968Sopensolaris@drydog.com 	mechlist_t	*pcur = NULL;
4767968Sopensolaris@drydog.com 	boolean_t	semicolon_separator = B_FALSE;
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	if (pent == NULL) {
4800Sstevel@tonic-gate 		return (NULL);
4810Sstevel@tonic-gate 	}
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	if ((buf = malloc(BUFSIZ)) == NULL) {
4840Sstevel@tonic-gate 		return (NULL);
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	/* convert the provider name */
4880Sstevel@tonic-gate 	if (strlcpy(buf, pent->name, BUFSIZ) >= BUFSIZ) {
4890Sstevel@tonic-gate 		free(buf);
4900Sstevel@tonic-gate 		return (NULL);
4910Sstevel@tonic-gate 	}
4920Sstevel@tonic-gate 
4937968Sopensolaris@drydog.com 	if (!pent->load) { /* add "unload" keyword */
4947968Sopensolaris@drydog.com 		if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) {
4957968Sopensolaris@drydog.com 			free(buf);
4967968Sopensolaris@drydog.com 			return (NULL);
4977968Sopensolaris@drydog.com 		}
4987968Sopensolaris@drydog.com 
4997968Sopensolaris@drydog.com 		if (strlcat(buf, EF_UNLOAD, BUFSIZ) >= BUFSIZ) {
5007968Sopensolaris@drydog.com 			free(buf);
5017968Sopensolaris@drydog.com 			return (NULL);
5027968Sopensolaris@drydog.com 		}
5037968Sopensolaris@drydog.com 
5047968Sopensolaris@drydog.com 		semicolon_separator = B_TRUE;
5057968Sopensolaris@drydog.com 	}
5067968Sopensolaris@drydog.com 
5070Sstevel@tonic-gate 	/* convert the supported list if any */
5087968Sopensolaris@drydog.com 	pcur = pent->suplist;
5097968Sopensolaris@drydog.com 	if (pcur != NULL) {
5107968Sopensolaris@drydog.com 		if (strlcat(buf,
5117968Sopensolaris@drydog.com 		    semicolon_separator ? SEP_SEMICOLON : SEP_COLON,
5127968Sopensolaris@drydog.com 		    BUFSIZ) >= BUFSIZ) {
5130Sstevel@tonic-gate 			free(buf);
5140Sstevel@tonic-gate 			return (NULL);
5150Sstevel@tonic-gate 		}
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 		if (strlcat(buf, EF_SUPPORTED, BUFSIZ) >= BUFSIZ) {
5180Sstevel@tonic-gate 			free(buf);
5190Sstevel@tonic-gate 			return (NULL);
5200Sstevel@tonic-gate 		}
5210Sstevel@tonic-gate 
5227968Sopensolaris@drydog.com 		while (pcur != NULL) {
5237968Sopensolaris@drydog.com 			if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) {
5240Sstevel@tonic-gate 				free(buf);
5250Sstevel@tonic-gate 				return (NULL);
5260Sstevel@tonic-gate 			}
5270Sstevel@tonic-gate 
5287968Sopensolaris@drydog.com 			pcur = pcur->next;
5297968Sopensolaris@drydog.com 			if (pcur != NULL) {
5300Sstevel@tonic-gate 				if (strlcat(buf, SEP_COMMA, BUFSIZ)
5310Sstevel@tonic-gate 				    >= BUFSIZ) {
5320Sstevel@tonic-gate 					free(buf);
5330Sstevel@tonic-gate 					return (NULL);
5340Sstevel@tonic-gate 				}
5350Sstevel@tonic-gate 			}
5360Sstevel@tonic-gate 		}
5377968Sopensolaris@drydog.com 		semicolon_separator = B_TRUE;
5380Sstevel@tonic-gate 	}
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	/* convert the disabled list if any */
5417968Sopensolaris@drydog.com 	pcur = pent->dislist;
5427968Sopensolaris@drydog.com 	if (pcur != NULL) {
5437968Sopensolaris@drydog.com 		if (strlcat(buf,
5447968Sopensolaris@drydog.com 		    semicolon_separator ? SEP_SEMICOLON : SEP_COLON,
5457968Sopensolaris@drydog.com 		    BUFSIZ) >= BUFSIZ) {
5467968Sopensolaris@drydog.com 			free(buf);
5477968Sopensolaris@drydog.com 			return (NULL);
5480Sstevel@tonic-gate 		}
5490Sstevel@tonic-gate 
5507968Sopensolaris@drydog.com 		if (strlcat(buf, EF_DISABLED, BUFSIZ) >= BUFSIZ) {
5517968Sopensolaris@drydog.com 			free(buf);
5527968Sopensolaris@drydog.com 			return (NULL);
5537968Sopensolaris@drydog.com 		}
5547968Sopensolaris@drydog.com 
5557968Sopensolaris@drydog.com 		while (pcur != NULL) {
5567968Sopensolaris@drydog.com 			if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) {
5570Sstevel@tonic-gate 				free(buf);
5580Sstevel@tonic-gate 				return (NULL);
5590Sstevel@tonic-gate 			}
5600Sstevel@tonic-gate 
5617968Sopensolaris@drydog.com 			pcur = pcur->next;
5627968Sopensolaris@drydog.com 			if (pcur != NULL) {
5630Sstevel@tonic-gate 				if (strlcat(buf, SEP_COMMA, BUFSIZ)
5640Sstevel@tonic-gate 				    >= BUFSIZ) {
5650Sstevel@tonic-gate 					free(buf);
5660Sstevel@tonic-gate 					return (NULL);
5670Sstevel@tonic-gate 				}
5680Sstevel@tonic-gate 			}
5690Sstevel@tonic-gate 		}
5707968Sopensolaris@drydog.com 		semicolon_separator = B_TRUE;
5710Sstevel@tonic-gate 	}
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	if (strlcat(buf, "\n", BUFSIZ) >= BUFSIZ) {
5740Sstevel@tonic-gate 		free(buf);
5750Sstevel@tonic-gate 		return (NULL);
5760Sstevel@tonic-gate 	}
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	return (buf);
5790Sstevel@tonic-gate }
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate /*
5830Sstevel@tonic-gate  * Enable the mechanisms for the provider pointed by *ppent.  If allflag is
5840Sstevel@tonic-gate  * TRUE, enable all.  Otherwise, enable the mechanisms specified in the 3rd
5850Sstevel@tonic-gate  * argument "mlist".  The result will be stored in ppent also.
5860Sstevel@tonic-gate  */
5870Sstevel@tonic-gate int
5880Sstevel@tonic-gate enable_mechs(entry_t **ppent, boolean_t allflag, mechlist_t *mlist)
5890Sstevel@tonic-gate {
5907968Sopensolaris@drydog.com 	entry_t		*pent;
5917968Sopensolaris@drydog.com 	mechlist_t	*phead; /* the current and resulting disabled list */
5927968Sopensolaris@drydog.com 	mechlist_t	*ptr = NULL;
5937968Sopensolaris@drydog.com 	mechlist_t	*pcur = NULL;
5947968Sopensolaris@drydog.com 	boolean_t	found;
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	pent = *ppent;
5970Sstevel@tonic-gate 	if (pent == NULL) {
5980Sstevel@tonic-gate 		return (FAILURE);
5990Sstevel@tonic-gate 	}
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	if (allflag) {
6020Sstevel@tonic-gate 		free_mechlist(pent->dislist);
6030Sstevel@tonic-gate 		pent->dis_count = 0;
6040Sstevel@tonic-gate 		pent->dislist = NULL;
6050Sstevel@tonic-gate 		return (SUCCESS);
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	/*
6090Sstevel@tonic-gate 	 * for each mechanism in the to-be-enabled mechanism list,
6100Sstevel@tonic-gate 	 * -	check if it is in the current disabled list
6110Sstevel@tonic-gate 	 * -	if found, delete it from the disabled list
6127968Sopensolaris@drydog.com 	 *	otherwise, give a warning.
6130Sstevel@tonic-gate 	 */
6140Sstevel@tonic-gate 	ptr = mlist;
6150Sstevel@tonic-gate 	while (ptr != NULL) {
6160Sstevel@tonic-gate 		found = B_FALSE;
6170Sstevel@tonic-gate 		phead = pcur =  pent->dislist;
6180Sstevel@tonic-gate 		while (!found && pcur) {
6190Sstevel@tonic-gate 			if (strcmp(pcur->name, ptr->name) == 0) {
6200Sstevel@tonic-gate 				found = B_TRUE;
6210Sstevel@tonic-gate 			} else {
6220Sstevel@tonic-gate 				phead = pcur;
6230Sstevel@tonic-gate 				pcur = pcur->next;
6240Sstevel@tonic-gate 			}
6250Sstevel@tonic-gate 		}
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 		if (found) {
6280Sstevel@tonic-gate 			if (phead == pcur) {
6290Sstevel@tonic-gate 				pent->dislist = pent->dislist->next;
6300Sstevel@tonic-gate 				free(pcur);
6310Sstevel@tonic-gate 			} else {
6320Sstevel@tonic-gate 				phead->next = pcur->next;
6330Sstevel@tonic-gate 				free(pcur);
6340Sstevel@tonic-gate 			}
6350Sstevel@tonic-gate 			pent->dis_count--;
6360Sstevel@tonic-gate 		} else {
6370Sstevel@tonic-gate 			cryptoerror(LOG_STDERR, gettext(
6380Sstevel@tonic-gate 			    "(Warning) %1$s is either enabled already or not "
6390Sstevel@tonic-gate 			    "a valid mechanism for %2$s"), ptr->name,
6400Sstevel@tonic-gate 			    pent->name);
6410Sstevel@tonic-gate 		}
6420Sstevel@tonic-gate 		ptr = ptr->next;
6430Sstevel@tonic-gate 	}
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 	if (pent->dis_count == 0) {
6460Sstevel@tonic-gate 		pent->dislist = NULL;
6470Sstevel@tonic-gate 	}
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	return (SUCCESS);
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate }
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 
6547968Sopensolaris@drydog.com /*
6557968Sopensolaris@drydog.com  * Determine if the kernel provider name, path, is a device
6567968Sopensolaris@drydog.com  * (that is, it contains a slash character (e.g., "mca/0").
6577968Sopensolaris@drydog.com  * If so, it is a hardware provider; otherwise it is a software provider.
6587968Sopensolaris@drydog.com  */
6590Sstevel@tonic-gate boolean_t
6600Sstevel@tonic-gate is_device(char *path)
6610Sstevel@tonic-gate {
6620Sstevel@tonic-gate 	if (strchr(path, SEP_SLASH) != NULL) {
6630Sstevel@tonic-gate 		return (B_TRUE);
6640Sstevel@tonic-gate 	} else {
6650Sstevel@tonic-gate 		return (B_FALSE);
6660Sstevel@tonic-gate 	}
6670Sstevel@tonic-gate }
6680Sstevel@tonic-gate 
669*10500SHai-May.Chao@Sun.COM boolean_t
670*10500SHai-May.Chao@Sun.COM is_fips(char *name)
671*10500SHai-May.Chao@Sun.COM {
672*10500SHai-May.Chao@Sun.COM 	if (strcmp(name, FIPS_KEYWORD) == 0) {
673*10500SHai-May.Chao@Sun.COM 		return (B_TRUE);
674*10500SHai-May.Chao@Sun.COM 	} else {
675*10500SHai-May.Chao@Sun.COM 		return (B_FALSE);
676*10500SHai-May.Chao@Sun.COM 	}
677*10500SHai-May.Chao@Sun.COM }
678*10500SHai-May.Chao@Sun.COM 
6790Sstevel@tonic-gate /*
6800Sstevel@tonic-gate  * Split a hardware provider name with the "name/inst_num" format into
6817968Sopensolaris@drydog.com  * a name and a number (e.g., split "mca/0" into "mca" instance 0).
6820Sstevel@tonic-gate  */
6830Sstevel@tonic-gate int
6840Sstevel@tonic-gate split_hw_provname(char *provname, char *pname, int *inst_num)
6850Sstevel@tonic-gate {
6860Sstevel@tonic-gate 	char	name[MAXNAMELEN];
6870Sstevel@tonic-gate 	char	*inst_str;
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	if (provname == NULL) {
6900Sstevel@tonic-gate 		return (FAILURE);
6910Sstevel@tonic-gate 	}
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	(void) strlcpy(name, provname, MAXNAMELEN);
6940Sstevel@tonic-gate 	if (strtok(name, "/") == NULL) {
6950Sstevel@tonic-gate 		return (FAILURE);
6960Sstevel@tonic-gate 	}
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	if ((inst_str = strtok(NULL, "/")) == NULL) {
6990Sstevel@tonic-gate 		return (FAILURE);
7000Sstevel@tonic-gate 	}
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	(void) strlcpy(pname, name, MAXNAMELEN);
7030Sstevel@tonic-gate 	*inst_num = atoi(inst_str);
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	return (SUCCESS);
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate /*
7107968Sopensolaris@drydog.com  * Retrieve information from kcf.conf and build a hardware device entry list
7117968Sopensolaris@drydog.com  * and a software entry list of kernel crypto providers.
7127968Sopensolaris@drydog.com  *
7137968Sopensolaris@drydog.com  * This list is usually incomplete, as kernel crypto providers only have to
7147968Sopensolaris@drydog.com  * be listed in kcf.conf if a mechanism is disabled (by cryptoadm) or
7157968Sopensolaris@drydog.com  * if the kernel provider module is not one of the default kernel providers.
7167968Sopensolaris@drydog.com  *
7177968Sopensolaris@drydog.com  * The kcf.conf file is available only in the global zone.
7180Sstevel@tonic-gate  */
7190Sstevel@tonic-gate int
720*10500SHai-May.Chao@Sun.COM get_kcfconf_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist,
721*10500SHai-May.Chao@Sun.COM     entrylist_t **ppfipslist)
7220Sstevel@tonic-gate {
7237968Sopensolaris@drydog.com 	FILE	*pfile = NULL;
7247968Sopensolaris@drydog.com 	char	buffer[BUFSIZ];
7257968Sopensolaris@drydog.com 	int	len;
7267968Sopensolaris@drydog.com 	entry_t	*pent = NULL;
7277968Sopensolaris@drydog.com 	int	rc = SUCCESS;
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	if ((pfile = fopen(_PATH_KCF_CONF, "r")) == NULL) {
7300Sstevel@tonic-gate 		cryptodebug("failed to open the kcf.conf file for read only");
7310Sstevel@tonic-gate 		return (FAILURE);
7320Sstevel@tonic-gate 	}
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	*ppdevlist = NULL;
7350Sstevel@tonic-gate 	*ppsoftlist = NULL;
736*10500SHai-May.Chao@Sun.COM 	*ppfipslist = NULL;
737*10500SHai-May.Chao@Sun.COM 
7380Sstevel@tonic-gate 	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
7390Sstevel@tonic-gate 		if (buffer[0] == '#' || buffer[0] == ' ' ||
7400Sstevel@tonic-gate 		    buffer[0] == '\n'|| buffer[0] == '\t') {
7410Sstevel@tonic-gate 			continue;   /* ignore comment lines */
7420Sstevel@tonic-gate 		}
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 		len = strlen(buffer);
7457968Sopensolaris@drydog.com 		if (buffer[len - 1] == '\n') { /* get rid of trailing '\n' */
7460Sstevel@tonic-gate 			len--;
7470Sstevel@tonic-gate 		}
7480Sstevel@tonic-gate 		buffer[len] = '\0';
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 		if ((rc = interpret(buffer,  &pent)) == SUCCESS) {
751*10500SHai-May.Chao@Sun.COM 			if (is_fips(pent->name)) {
752*10500SHai-May.Chao@Sun.COM 				if (*ppfipslist != NULL) {
753*10500SHai-May.Chao@Sun.COM 					cryptoerror(LOG_STDERR, gettext(
754*10500SHai-May.Chao@Sun.COM 					"multiple fips entries."));
755*10500SHai-May.Chao@Sun.COM 					rc = FAILURE;
756*10500SHai-May.Chao@Sun.COM 				} else {
757*10500SHai-May.Chao@Sun.COM 					rc = build_entrylist(pent, ppfipslist);
758*10500SHai-May.Chao@Sun.COM 				}
759*10500SHai-May.Chao@Sun.COM 			} else if (is_device(pent->name)) {
7600Sstevel@tonic-gate 				rc = build_entrylist(pent, ppdevlist);
7610Sstevel@tonic-gate 			} else {
7620Sstevel@tonic-gate 				rc = build_entrylist(pent, ppsoftlist);
7630Sstevel@tonic-gate 			}
7640Sstevel@tonic-gate 		} else {
7650Sstevel@tonic-gate 			cryptoerror(LOG_STDERR, gettext(
7660Sstevel@tonic-gate 			    "failed to parse configuration."));
767*10500SHai-May.Chao@Sun.COM 			rc = FAILURE;
7680Sstevel@tonic-gate 		}
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 		if (rc != SUCCESS) {
7710Sstevel@tonic-gate 			free_entrylist(*ppdevlist);
7720Sstevel@tonic-gate 			free_entrylist(*ppsoftlist);
773*10500SHai-May.Chao@Sun.COM 			free_entrylist(*ppfipslist);
7740Sstevel@tonic-gate 			free_entry(pent);
7750Sstevel@tonic-gate 			break;
7760Sstevel@tonic-gate 		}
7770Sstevel@tonic-gate 	}
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 	(void) fclose(pfile);
7800Sstevel@tonic-gate 	return (rc);
7810Sstevel@tonic-gate }
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate /*
7840Sstevel@tonic-gate  * Retrieve information from admin device and build a device entry list and
7857968Sopensolaris@drydog.com  * a software entry list.  This is used where there is no kcf.conf, e.g., the
7860Sstevel@tonic-gate  * non-global zone.
7870Sstevel@tonic-gate  */
7880Sstevel@tonic-gate int
7890Sstevel@tonic-gate get_admindev_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist)
7900Sstevel@tonic-gate {
7917968Sopensolaris@drydog.com 	crypto_get_dev_list_t	*pdevlist_kernel = NULL;
7927968Sopensolaris@drydog.com 	crypto_get_soft_list_t	*psoftlist_kernel = NULL;
7937968Sopensolaris@drydog.com 	char			*devname;
7947968Sopensolaris@drydog.com 	int			inst_num;
7957968Sopensolaris@drydog.com 	int			mcount;
7967968Sopensolaris@drydog.com 	mechlist_t		*pmech = NULL;
7977968Sopensolaris@drydog.com 	entry_t			*pent_dev = NULL, *pent_soft = NULL;
7987968Sopensolaris@drydog.com 	int			i;
7997968Sopensolaris@drydog.com 	char			*psoftname;
8007968Sopensolaris@drydog.com 	entrylist_t		*tmp_pdev = NULL;
8017968Sopensolaris@drydog.com 	entrylist_t		*tmp_psoft = NULL;
8027968Sopensolaris@drydog.com 	entrylist_t		*phardlist = NULL, *psoftlist = NULL;
803*10500SHai-May.Chao@Sun.COM 	entrylist_t		*pfipslist = NULL;
8040Sstevel@tonic-gate 
8057968Sopensolaris@drydog.com 	/*
8067968Sopensolaris@drydog.com 	 * Get hardware providers
8077968Sopensolaris@drydog.com 	 */
8080Sstevel@tonic-gate 	if (get_dev_list(&pdevlist_kernel) != SUCCESS) {
8090Sstevel@tonic-gate 		cryptodebug("failed to get hardware provider list from kernel");
8100Sstevel@tonic-gate 		return (FAILURE);
8110Sstevel@tonic-gate 	}
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 	for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) {
8140Sstevel@tonic-gate 		devname = pdevlist_kernel->dl_devs[i].le_dev_name;
8150Sstevel@tonic-gate 		inst_num = pdevlist_kernel->dl_devs[i].le_dev_instance;
8160Sstevel@tonic-gate 		mcount = pdevlist_kernel->dl_devs[i].le_mechanism_count;
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 		pmech = NULL;
8190Sstevel@tonic-gate 		if (get_dev_info(devname, inst_num, mcount, &pmech) !=
8200Sstevel@tonic-gate 		    SUCCESS) {
8210Sstevel@tonic-gate 			cryptodebug(
8220Sstevel@tonic-gate 			    "failed to retrieve the mechanism list for %s/%d.",
8230Sstevel@tonic-gate 			    devname, inst_num);
8240Sstevel@tonic-gate 			goto fail_out;
8250Sstevel@tonic-gate 		}
8260Sstevel@tonic-gate 
8277968Sopensolaris@drydog.com 		if ((pent_dev = create_entry(devname)) == NULL) {
8280Sstevel@tonic-gate 			cryptodebug("out of memory.");
8290Sstevel@tonic-gate 			free_mechlist(pmech);
8300Sstevel@tonic-gate 			goto fail_out;
8310Sstevel@tonic-gate 		}
8327968Sopensolaris@drydog.com 		pent_dev->suplist = pmech;
8337968Sopensolaris@drydog.com 		pent_dev->sup_count = mcount;
8340Sstevel@tonic-gate 
8357968Sopensolaris@drydog.com 		if (build_entrylist(pent_dev, &tmp_pdev) != SUCCESS) {
8360Sstevel@tonic-gate 			goto fail_out;
8370Sstevel@tonic-gate 		}
8380Sstevel@tonic-gate 	}
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 	free(pdevlist_kernel);
8410Sstevel@tonic-gate 	pdevlist_kernel = NULL;
8420Sstevel@tonic-gate 
8437968Sopensolaris@drydog.com 	/*
8447968Sopensolaris@drydog.com 	 * Get software providers
8457968Sopensolaris@drydog.com 	 */
8467968Sopensolaris@drydog.com 	if (getzoneid() == GLOBAL_ZONEID) {
847*10500SHai-May.Chao@Sun.COM 		if (get_kcfconf_info(&phardlist, &psoftlist, &pfipslist) !=
848*10500SHai-May.Chao@Sun.COM 		    SUCCESS) {
8497968Sopensolaris@drydog.com 			goto fail_out;
8507968Sopensolaris@drydog.com 		}
8517968Sopensolaris@drydog.com 	}
8527968Sopensolaris@drydog.com 
8530Sstevel@tonic-gate 	if (get_soft_list(&psoftlist_kernel) != SUCCESS) {
8540Sstevel@tonic-gate 		cryptodebug("failed to get software provider list from kernel");
8550Sstevel@tonic-gate 		goto fail_out;
8560Sstevel@tonic-gate 	}
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	for (i = 0, psoftname = psoftlist_kernel->sl_soft_names;
8590Sstevel@tonic-gate 	    i < psoftlist_kernel->sl_soft_count;
8600Sstevel@tonic-gate 	    i++, psoftname = psoftname + strlen(psoftname) + 1) {
8610Sstevel@tonic-gate 		pmech = NULL;
862*10500SHai-May.Chao@Sun.COM 		if (get_soft_info(psoftname, &pmech, phardlist, psoftlist,
863*10500SHai-May.Chao@Sun.COM 		    pfipslist) != SUCCESS) {
8640Sstevel@tonic-gate 			cryptodebug(
8650Sstevel@tonic-gate 			    "failed to retrieve the mechanism list for %s.",
8660Sstevel@tonic-gate 			    psoftname);
8670Sstevel@tonic-gate 			goto fail_out;
8680Sstevel@tonic-gate 		}
8690Sstevel@tonic-gate 
8707968Sopensolaris@drydog.com 		if ((pent_soft = create_entry(psoftname)) == NULL) {
8710Sstevel@tonic-gate 			cryptodebug("out of memory.");
8720Sstevel@tonic-gate 			free_mechlist(pmech);
8730Sstevel@tonic-gate 			goto fail_out;
8740Sstevel@tonic-gate 		}
8757968Sopensolaris@drydog.com 		pent_soft->suplist = pmech;
8767968Sopensolaris@drydog.com 		pent_soft->sup_count = get_mech_count(pmech);
8770Sstevel@tonic-gate 
8787968Sopensolaris@drydog.com 		if (build_entrylist(pent_soft, &tmp_psoft) != SUCCESS) {
8790Sstevel@tonic-gate 			goto fail_out;
8800Sstevel@tonic-gate 		}
8810Sstevel@tonic-gate 	}
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 	free(psoftlist_kernel);
8840Sstevel@tonic-gate 	psoftlist_kernel = NULL;
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 	*ppdevlist = tmp_pdev;
8870Sstevel@tonic-gate 	*ppsoftlist = tmp_psoft;
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	return (SUCCESS);
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate fail_out:
8927968Sopensolaris@drydog.com 	if (pent_dev != NULL)
8937968Sopensolaris@drydog.com 		free_entry(pent_dev);
8947968Sopensolaris@drydog.com 	if (pent_soft != NULL)
8957968Sopensolaris@drydog.com 		free_entry(pent_soft);
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 	free_entrylist(tmp_pdev);
8980Sstevel@tonic-gate 	free_entrylist(tmp_psoft);
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	if (pdevlist_kernel != NULL)
9010Sstevel@tonic-gate 		free(pdevlist_kernel);
9020Sstevel@tonic-gate 	if (psoftlist_kernel != NULL)
9030Sstevel@tonic-gate 		free(psoftlist_kernel);
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 	return (FAILURE);
9060Sstevel@tonic-gate }
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate /*
9097968Sopensolaris@drydog.com  * Return configuration information for a kernel provider from kcf.conf.
9107968Sopensolaris@drydog.com  * For kernel software providers return a enabled list and disabled list.
9117968Sopensolaris@drydog.com  * For kernel hardware providers return just a disabled list.
9127968Sopensolaris@drydog.com  *
9137968Sopensolaris@drydog.com  * Parameters phardlist and psoftlist are supplied by get_kcfconf_info().
9147968Sopensolaris@drydog.com  * If NULL, this function calls get_kcfconf_info() internally.
9150Sstevel@tonic-gate  */
9160Sstevel@tonic-gate entry_t *
917*10500SHai-May.Chao@Sun.COM getent_kef(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist,
918*10500SHai-May.Chao@Sun.COM     entrylist_t *pfipslist)
9190Sstevel@tonic-gate {
9207968Sopensolaris@drydog.com 	entry_t		*pent = NULL;
9217968Sopensolaris@drydog.com 	boolean_t	memory_allocated = B_FALSE;
9220Sstevel@tonic-gate 
923*10500SHai-May.Chao@Sun.COM 	if ((phardlist == NULL) || (psoftlist == NULL) || (pfipslist == NULL)) {
924*10500SHai-May.Chao@Sun.COM 		if (get_kcfconf_info(&phardlist, &psoftlist, &pfipslist) !=
925*10500SHai-May.Chao@Sun.COM 		    SUCCESS) {
9267968Sopensolaris@drydog.com 			return (NULL);
9277968Sopensolaris@drydog.com 		}
9287968Sopensolaris@drydog.com 		memory_allocated = B_TRUE;
9290Sstevel@tonic-gate 	}
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	if (is_device(provname)) {
9327968Sopensolaris@drydog.com 		pent = getent(provname, phardlist);
933*10500SHai-May.Chao@Sun.COM 	} else if (is_fips(provname)) {
934*10500SHai-May.Chao@Sun.COM 		pent = getent(provname, pfipslist);
9350Sstevel@tonic-gate 	} else {
9360Sstevel@tonic-gate 		pent = getent(provname, psoftlist);
9370Sstevel@tonic-gate 	}
9380Sstevel@tonic-gate 
9397968Sopensolaris@drydog.com 	if (memory_allocated) {
9407968Sopensolaris@drydog.com 		free_entrylist(phardlist);
9417968Sopensolaris@drydog.com 		free_entrylist(psoftlist);
942*10500SHai-May.Chao@Sun.COM 		free_entrylist(pfipslist);
9437968Sopensolaris@drydog.com 	}
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 	return (pent);
9460Sstevel@tonic-gate }
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate /*
9490Sstevel@tonic-gate  * Print out the provider name and the mechanism list.
9500Sstevel@tonic-gate  */
9510Sstevel@tonic-gate void
9520Sstevel@tonic-gate print_mechlist(char *provname, mechlist_t *pmechlist)
9530Sstevel@tonic-gate {
9547968Sopensolaris@drydog.com 	mechlist_t *ptr = NULL;
9550Sstevel@tonic-gate 
9560Sstevel@tonic-gate 	if (provname == NULL) {
9570Sstevel@tonic-gate 		return;
9580Sstevel@tonic-gate 	}
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 	(void) printf("%s: ", provname);
9610Sstevel@tonic-gate 	if (pmechlist == NULL) {
9620Sstevel@tonic-gate 		(void) printf(gettext("No mechanisms presented.\n"));
9630Sstevel@tonic-gate 		return;
9640Sstevel@tonic-gate 	}
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	ptr = pmechlist;
9670Sstevel@tonic-gate 	while (ptr != NULL) {
9680Sstevel@tonic-gate 		(void) printf("%s", ptr->name);
9690Sstevel@tonic-gate 		ptr = ptr->next;
9700Sstevel@tonic-gate 		if (ptr == NULL) {
9710Sstevel@tonic-gate 			(void) printf("\n");
9720Sstevel@tonic-gate 		} else {
9730Sstevel@tonic-gate 			(void) printf(",");
9740Sstevel@tonic-gate 		}
9750Sstevel@tonic-gate 	}
9760Sstevel@tonic-gate }
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate /*
9807968Sopensolaris@drydog.com  * Update the kcf.conf file based on the update mode:
9817968Sopensolaris@drydog.com  * - If update_mode is MODIFY_MODE, modify the entry with the same name.
9827968Sopensolaris@drydog.com  *   If not found, append a new entry to the kcf.conf file.
9837968Sopensolaris@drydog.com  * - If update_mode is DELETE_MODE, delete the entry with the same name.
9847968Sopensolaris@drydog.com  * - If update_mode is ADD_MODE, append a new entry to the kcf.conf file.
9850Sstevel@tonic-gate  */
9860Sstevel@tonic-gate int
9870Sstevel@tonic-gate update_kcfconf(entry_t *pent, int update_mode)
9880Sstevel@tonic-gate {
9890Sstevel@tonic-gate 	boolean_t	add_it = B_FALSE;
9900Sstevel@tonic-gate 	boolean_t	delete_it = B_FALSE;
9918273Sopensolaris@drydog.com 	boolean_t	this_entry_matches = B_FALSE;
9920Sstevel@tonic-gate 	boolean_t	found_entry = B_FALSE;
9937968Sopensolaris@drydog.com 	FILE		*pfile = NULL;
9947968Sopensolaris@drydog.com 	FILE		*pfile_tmp = NULL;
9957968Sopensolaris@drydog.com 	char		buffer[BUFSIZ];
9967968Sopensolaris@drydog.com 	char		buffer2[BUFSIZ];
9977968Sopensolaris@drydog.com 	char		tmpfile_name[MAXPATHLEN];
9987968Sopensolaris@drydog.com 	char		*name;
9997968Sopensolaris@drydog.com 	char		*new_str = NULL;
10007968Sopensolaris@drydog.com 	int		rc = SUCCESS;
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 	if (pent == NULL) {
10030Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext("internal error."));
10040Sstevel@tonic-gate 		return (FAILURE);
10050Sstevel@tonic-gate 	}
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	/* Check the update_mode */
10087968Sopensolaris@drydog.com 	switch (update_mode) {
10097968Sopensolaris@drydog.com 	case ADD_MODE:
10100Sstevel@tonic-gate 		add_it = B_TRUE;
10117968Sopensolaris@drydog.com 		/* FALLTHROUGH */
10127968Sopensolaris@drydog.com 	case MODIFY_MODE:
10137968Sopensolaris@drydog.com 		/* Convert the entry a string to add to kcf.conf  */
10140Sstevel@tonic-gate 		if ((new_str = ent2str(pent)) == NULL) {
10150Sstevel@tonic-gate 			return (FAILURE);
10160Sstevel@tonic-gate 		}
10177968Sopensolaris@drydog.com 		break;
10187968Sopensolaris@drydog.com 	case DELETE_MODE:
10190Sstevel@tonic-gate 		delete_it = B_TRUE;
10207968Sopensolaris@drydog.com 		break;
10217968Sopensolaris@drydog.com 	default:
10220Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext("internal error."));
10230Sstevel@tonic-gate 		return (FAILURE);
10240Sstevel@tonic-gate 	}
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 	/* Open the kcf.conf file */
10270Sstevel@tonic-gate 	if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) {
10280Sstevel@tonic-gate 		err = errno;
10290Sstevel@tonic-gate 		cryptoerror(LOG_STDERR,
10300Sstevel@tonic-gate 		    gettext("failed to update the configuration - %s"),
10310Sstevel@tonic-gate 		    strerror(err));
10320Sstevel@tonic-gate 		cryptodebug("failed to open %s for write.", _PATH_KCF_CONF);
10330Sstevel@tonic-gate 		return (FAILURE);
10340Sstevel@tonic-gate 	}
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate 	/* Lock the kcf.conf file */
10370Sstevel@tonic-gate 	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
10380Sstevel@tonic-gate 		err = errno;
10390Sstevel@tonic-gate 		cryptoerror(LOG_STDERR,
10400Sstevel@tonic-gate 		    gettext("failed to update the configuration - %s"),
10417968Sopensolaris@drydog.com 		    strerror(err));
10420Sstevel@tonic-gate 		(void) fclose(pfile);
10430Sstevel@tonic-gate 		return (FAILURE);
10440Sstevel@tonic-gate 	}
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate 	/*
10470Sstevel@tonic-gate 	 * Create a temporary file in the /etc/crypto directory to save
10480Sstevel@tonic-gate 	 * updated configuration file first.
10490Sstevel@tonic-gate 	 */
10500Sstevel@tonic-gate 	(void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
10510Sstevel@tonic-gate 	if (mkstemp(tmpfile_name) == -1) {
10520Sstevel@tonic-gate 		err = errno;
10530Sstevel@tonic-gate 		cryptoerror(LOG_STDERR,
10540Sstevel@tonic-gate 		    gettext("failed to create a temporary file - %s"),
10550Sstevel@tonic-gate 		    strerror(err));
10560Sstevel@tonic-gate 		(void) fclose(pfile);
10570Sstevel@tonic-gate 		return (FAILURE);
10580Sstevel@tonic-gate 	}
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate 	if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
10610Sstevel@tonic-gate 		err = errno;
10620Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
10630Sstevel@tonic-gate 		    tmpfile_name, strerror(err));
10640Sstevel@tonic-gate 		(void) fclose(pfile);
10650Sstevel@tonic-gate 		return (FAILURE);
10660Sstevel@tonic-gate 	}
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	/*
10690Sstevel@tonic-gate 	 * Loop thru the entire kcf.conf file, insert, modify or delete
10700Sstevel@tonic-gate 	 * an entry.
10710Sstevel@tonic-gate 	 */
10720Sstevel@tonic-gate 	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
10730Sstevel@tonic-gate 		if (add_it) {
10740Sstevel@tonic-gate 			if (fputs(buffer, pfile_tmp) == EOF) {
10750Sstevel@tonic-gate 				err = errno;
10760Sstevel@tonic-gate 				cryptoerror(LOG_STDERR, gettext(
10770Sstevel@tonic-gate 				    "failed to write to a temp file: %s."),
10780Sstevel@tonic-gate 				    strerror(err));
10790Sstevel@tonic-gate 				rc = FAILURE;
10800Sstevel@tonic-gate 				break;
10810Sstevel@tonic-gate 			}
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 		} else { /* modify or delete */
10848273Sopensolaris@drydog.com 			this_entry_matches = B_FALSE;
10857968Sopensolaris@drydog.com 
10860Sstevel@tonic-gate 			if (!(buffer[0] == '#' || buffer[0] == ' ' ||
10870Sstevel@tonic-gate 			    buffer[0] == '\n'|| buffer[0] == '\t')) {
10880Sstevel@tonic-gate 				/*
10890Sstevel@tonic-gate 				 * Get the provider name from this line and
10900Sstevel@tonic-gate 				 * check if this is the entry to be updated
10910Sstevel@tonic-gate 				 * or deleted. Note: can not use "buffer"
10920Sstevel@tonic-gate 				 * directly because strtok will change its
10930Sstevel@tonic-gate 				 * value.
10940Sstevel@tonic-gate 				 */
10950Sstevel@tonic-gate 				(void) strlcpy(buffer2, buffer, BUFSIZ);
10960Sstevel@tonic-gate 				if ((name = strtok(buffer2, SEP_COLON)) ==
10970Sstevel@tonic-gate 				    NULL) {
10980Sstevel@tonic-gate 					rc = FAILURE;
10990Sstevel@tonic-gate 					break;
11000Sstevel@tonic-gate 				}
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 				if (strcmp(pent->name, name) == 0) {
11038273Sopensolaris@drydog.com 					this_entry_matches = B_TRUE;
11040Sstevel@tonic-gate 					found_entry = B_TRUE;
11050Sstevel@tonic-gate 				}
11060Sstevel@tonic-gate 			}
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate 
11098273Sopensolaris@drydog.com 			if (!this_entry_matches || !delete_it) {
11108273Sopensolaris@drydog.com 				/* write this entry */
11118273Sopensolaris@drydog.com 				if (this_entry_matches) {
11128273Sopensolaris@drydog.com 					/*
11138273Sopensolaris@drydog.com 					 * Modify this entry: get the
11148273Sopensolaris@drydog.com 					 * updated string and place into buffer.
11158273Sopensolaris@drydog.com 					 */
11168273Sopensolaris@drydog.com 					(void) strlcpy(buffer, new_str, BUFSIZ);
11178273Sopensolaris@drydog.com 					free(new_str);
11188273Sopensolaris@drydog.com 				}
11198273Sopensolaris@drydog.com 				/* write the (unchanged or modified) entry */
11200Sstevel@tonic-gate 				if (fputs(buffer, pfile_tmp) == EOF) {
11210Sstevel@tonic-gate 					err = errno;
11220Sstevel@tonic-gate 					cryptoerror(LOG_STDERR, gettext(
11230Sstevel@tonic-gate 					    "failed to write to a temp file: "
11240Sstevel@tonic-gate 					    "%s."), strerror(err));
11250Sstevel@tonic-gate 					rc = FAILURE;
11260Sstevel@tonic-gate 					break;
11270Sstevel@tonic-gate 				}
11280Sstevel@tonic-gate 			}
11290Sstevel@tonic-gate 		}
11300Sstevel@tonic-gate 	}
11310Sstevel@tonic-gate 
11327968Sopensolaris@drydog.com 	if ((!delete_it) && (rc != FAILURE)) {
11337968Sopensolaris@drydog.com 		if (add_it || !found_entry) {
11347968Sopensolaris@drydog.com 			/* append new entry to end of file */
11357968Sopensolaris@drydog.com 			if (fputs(new_str, pfile_tmp) == EOF) {
11367968Sopensolaris@drydog.com 				err = errno;
11377968Sopensolaris@drydog.com 				cryptoerror(LOG_STDERR, gettext(
11387968Sopensolaris@drydog.com 				    "failed to write to a temp file: %s."),
11397968Sopensolaris@drydog.com 				    strerror(err));
11407968Sopensolaris@drydog.com 				rc = FAILURE;
11417968Sopensolaris@drydog.com 			}
11427968Sopensolaris@drydog.com 			free(new_str);
11430Sstevel@tonic-gate 		}
11440Sstevel@tonic-gate 	}
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate 	(void) fclose(pfile);
11470Sstevel@tonic-gate 	if (fclose(pfile_tmp) != 0) {
11480Sstevel@tonic-gate 		err = errno;
11490Sstevel@tonic-gate 		cryptoerror(LOG_STDERR,
11500Sstevel@tonic-gate 		    gettext("failed to close %s: %s"), tmpfile_name,
11510Sstevel@tonic-gate 		    strerror(err));
11520Sstevel@tonic-gate 		return (FAILURE);
11530Sstevel@tonic-gate 	}
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 	/* Copy the temporary file to the kcf.conf file */
11560Sstevel@tonic-gate 	if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) {
11570Sstevel@tonic-gate 		err = errno;
11580Sstevel@tonic-gate 		cryptoerror(LOG_STDERR,
11590Sstevel@tonic-gate 		    gettext("failed to update the configuration - %s"),
11600Sstevel@tonic-gate 		    strerror(err));
11610Sstevel@tonic-gate 		cryptodebug("failed to rename %s to %s: %s", tmpfile,
11620Sstevel@tonic-gate 		    _PATH_KCF_CONF, strerror(err));
11630Sstevel@tonic-gate 		rc = FAILURE;
11640Sstevel@tonic-gate 	} else if (chmod(_PATH_KCF_CONF,
11650Sstevel@tonic-gate 	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
11660Sstevel@tonic-gate 		err = errno;
11670Sstevel@tonic-gate 		cryptoerror(LOG_STDERR,
11680Sstevel@tonic-gate 		    gettext("failed to update the configuration - %s"),
11690Sstevel@tonic-gate 		    strerror(err));
11700Sstevel@tonic-gate 		cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF,
11710Sstevel@tonic-gate 		    strerror(err));
11720Sstevel@tonic-gate 		rc = FAILURE;
11730Sstevel@tonic-gate 	} else {
11740Sstevel@tonic-gate 		rc = SUCCESS;
11750Sstevel@tonic-gate 	}
11760Sstevel@tonic-gate 
11770Sstevel@tonic-gate 	if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
11780Sstevel@tonic-gate 		err = errno;
11790Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext(
11800Sstevel@tonic-gate 		    "(Warning) failed to remove %s: %s"),
11810Sstevel@tonic-gate 		    tmpfile_name, strerror(err));
11820Sstevel@tonic-gate 	}
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate 	return (rc);
11850Sstevel@tonic-gate }
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate /*
11890Sstevel@tonic-gate  * Disable the mechanisms for the provider pointed by *ppent.  If allflag is
11900Sstevel@tonic-gate  * TRUE, disable all.  Otherwise, disable the mechanisms specified in the
11910Sstevel@tonic-gate  * dislist argument.  The "infolist" argument contains the mechanism list
11920Sstevel@tonic-gate  * supported by this provider.
11930Sstevel@tonic-gate  */
11940Sstevel@tonic-gate int
11950Sstevel@tonic-gate disable_mechs(entry_t **ppent, mechlist_t *infolist, boolean_t allflag,
11960Sstevel@tonic-gate mechlist_t *dislist)
11970Sstevel@tonic-gate {
11987968Sopensolaris@drydog.com 	entry_t		*pent;
11997968Sopensolaris@drydog.com 	mechlist_t	*plist = NULL;
12007968Sopensolaris@drydog.com 	mechlist_t	*phead = NULL;
12017968Sopensolaris@drydog.com 	mechlist_t	*pmech = NULL;
12027968Sopensolaris@drydog.com 	int		rc = SUCCESS;
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 	pent = *ppent;
12050Sstevel@tonic-gate 	if (pent == NULL) {
12060Sstevel@tonic-gate 		return (FAILURE);
12070Sstevel@tonic-gate 	}
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 	if (allflag) {
12100Sstevel@tonic-gate 		free_mechlist(pent->dislist);
12110Sstevel@tonic-gate 		pent->dis_count = get_mech_count(infolist);
12120Sstevel@tonic-gate 		if (!(pent->dislist = dup_mechlist(infolist))) {
12130Sstevel@tonic-gate 			return (FAILURE);
12140Sstevel@tonic-gate 		} else {
12150Sstevel@tonic-gate 			return (SUCCESS);
12160Sstevel@tonic-gate 		}
12170Sstevel@tonic-gate 	}
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 	/*
12200Sstevel@tonic-gate 	 * Not disable all. Now loop thru the mechanisms specified in the
12210Sstevel@tonic-gate 	 * dislist.  If the mechanism is not supported by the provider,
12220Sstevel@tonic-gate 	 * ignore it with a warning.  If the mechanism is disabled already,
12230Sstevel@tonic-gate 	 * do nothing. Otherwise, prepend it to the beginning of the disabled
12240Sstevel@tonic-gate 	 * list of the provider.
12250Sstevel@tonic-gate 	 */
12260Sstevel@tonic-gate 	plist = dislist;
12270Sstevel@tonic-gate 	while (plist != NULL) {
12280Sstevel@tonic-gate 		if (!is_in_list(plist->name, infolist)) {
12290Sstevel@tonic-gate 			cryptoerror(LOG_STDERR, gettext("(Warning) "
12300Sstevel@tonic-gate 			    "%1$s is not a valid mechanism for %2$s."),
12310Sstevel@tonic-gate 			    plist->name, pent->name);
12320Sstevel@tonic-gate 		} else if (!is_in_list(plist->name, pent->dislist)) {
12330Sstevel@tonic-gate 			/* Add this mechanism into the disabled list */
12340Sstevel@tonic-gate 			if ((pmech = create_mech(plist->name)) == NULL) {
12350Sstevel@tonic-gate 				rc = FAILURE;
12360Sstevel@tonic-gate 				break;
12370Sstevel@tonic-gate 			}
12380Sstevel@tonic-gate 
12390Sstevel@tonic-gate 			if (pent->dislist == NULL) {
12400Sstevel@tonic-gate 				pent->dislist = pmech;
12410Sstevel@tonic-gate 			} else {
12420Sstevel@tonic-gate 				phead = pent->dislist;
12430Sstevel@tonic-gate 				pent->dislist = pmech;
12440Sstevel@tonic-gate 				pmech->next = phead;
12450Sstevel@tonic-gate 			}
12460Sstevel@tonic-gate 			pent->dis_count++;
12470Sstevel@tonic-gate 		}
12480Sstevel@tonic-gate 		plist = plist->next;
12490Sstevel@tonic-gate 	}
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 	return (rc);
12520Sstevel@tonic-gate }
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate /*
12550Sstevel@tonic-gate  * Remove the mechanism passed, specified by mech, from the list of
12560Sstevel@tonic-gate  * mechanisms, if present in the list. Else, do nothing.
12570Sstevel@tonic-gate  *
12580Sstevel@tonic-gate  * Returns B_TRUE if mechanism is present in the list.
12590Sstevel@tonic-gate  */
12600Sstevel@tonic-gate boolean_t
12610Sstevel@tonic-gate filter_mechlist(mechlist_t **pmechlist, const char *mech)
12620Sstevel@tonic-gate {
12637968Sopensolaris@drydog.com 	int		cnt = 0;
12647968Sopensolaris@drydog.com 	mechlist_t	*ptr, *pptr;
12657968Sopensolaris@drydog.com 	boolean_t	mech_present = B_FALSE;
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate 	ptr = pptr = *pmechlist;
12680Sstevel@tonic-gate 
12690Sstevel@tonic-gate 	while (ptr != NULL) {
12700Sstevel@tonic-gate 		if (strncmp(ptr->name, mech, sizeof (mech_name_t)) == 0) {
12710Sstevel@tonic-gate 			mech_present = B_TRUE;
12720Sstevel@tonic-gate 			if (ptr == *pmechlist) {
12730Sstevel@tonic-gate 				pptr = *pmechlist = ptr->next;
12740Sstevel@tonic-gate 				free(ptr);
12750Sstevel@tonic-gate 				ptr = pptr;
12760Sstevel@tonic-gate 			} else {
12770Sstevel@tonic-gate 				pptr->next = ptr->next;
12780Sstevel@tonic-gate 				free(ptr);
12790Sstevel@tonic-gate 				ptr = pptr->next;
12800Sstevel@tonic-gate 			}
12810Sstevel@tonic-gate 		} else {
12820Sstevel@tonic-gate 			pptr = ptr;
12830Sstevel@tonic-gate 			ptr = ptr->next;
12840Sstevel@tonic-gate 			cnt++;
12850Sstevel@tonic-gate 		}
12860Sstevel@tonic-gate 	}
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 	/* Only one entry is present */
12890Sstevel@tonic-gate 	if (cnt == 0)
12900Sstevel@tonic-gate 		*pmechlist = NULL;
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 	return (mech_present);
12930Sstevel@tonic-gate }
12940Sstevel@tonic-gate 
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate 
12970Sstevel@tonic-gate /*
12980Sstevel@tonic-gate  * Print out the mechanism policy for a kernel provider that has an entry
12990Sstevel@tonic-gate  * in the kcf.conf file.
13000Sstevel@tonic-gate  *
13010Sstevel@tonic-gate  * The flag has_random is set to B_TRUE if the provider does random
13020Sstevel@tonic-gate  * numbers. The flag has_mechs is set by the caller to B_TRUE if the provider
13030Sstevel@tonic-gate  * has some mechanisms.
13047968Sopensolaris@drydog.com  *
13057968Sopensolaris@drydog.com  * If pent is NULL, the provider doesn't have a kcf.conf entry.
13060Sstevel@tonic-gate  */
13070Sstevel@tonic-gate void
13087968Sopensolaris@drydog.com print_kef_policy(char *provname, entry_t *pent, boolean_t has_random,
13097968Sopensolaris@drydog.com     boolean_t has_mechs)
13100Sstevel@tonic-gate {
13117968Sopensolaris@drydog.com 	mechlist_t	*ptr = NULL;
13127968Sopensolaris@drydog.com 	boolean_t	rnd_disabled = B_FALSE;
13130Sstevel@tonic-gate 
13147968Sopensolaris@drydog.com 	if (pent != NULL) {
13157968Sopensolaris@drydog.com 		rnd_disabled = filter_mechlist(&pent->dislist, RANDOM);
13167968Sopensolaris@drydog.com 		ptr = pent->dislist;
13170Sstevel@tonic-gate 	}
13180Sstevel@tonic-gate 
13197968Sopensolaris@drydog.com 	(void) printf("%s:", provname);
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate 	if (has_mechs == B_TRUE) {
13220Sstevel@tonic-gate 		/*
13237334SDaniel.Anderson@Sun.COM 		 * TRANSLATION_NOTE
13240Sstevel@tonic-gate 		 * This code block may need to be modified a bit to avoid
13250Sstevel@tonic-gate 		 * constructing the text message on the fly.
13260Sstevel@tonic-gate 		 */
13270Sstevel@tonic-gate 		(void) printf(gettext(" all mechanisms are enabled"));
13280Sstevel@tonic-gate 		if (ptr != NULL)
13290Sstevel@tonic-gate 			(void) printf(gettext(", except "));
13300Sstevel@tonic-gate 		while (ptr != NULL) {
13310Sstevel@tonic-gate 			(void) printf("%s", ptr->name);
13320Sstevel@tonic-gate 			ptr = ptr->next;
13330Sstevel@tonic-gate 			if (ptr != NULL)
13340Sstevel@tonic-gate 				(void) printf(",");
13350Sstevel@tonic-gate 		}
13360Sstevel@tonic-gate 		if (ptr == NULL)
13370Sstevel@tonic-gate 			(void) printf(".");
13380Sstevel@tonic-gate 	}
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 	/*
13417334SDaniel.Anderson@Sun.COM 	 * TRANSLATION_NOTE
13420Sstevel@tonic-gate 	 * "random" is a keyword and not to be translated.
13430Sstevel@tonic-gate 	 */
13440Sstevel@tonic-gate 	if (rnd_disabled)
13450Sstevel@tonic-gate 		(void) printf(gettext(" %s is disabled."), "random");
13460Sstevel@tonic-gate 	else if (has_random)
13470Sstevel@tonic-gate 		(void) printf(gettext(" %s is enabled."), "random");
13480Sstevel@tonic-gate 	(void) printf("\n");
13490Sstevel@tonic-gate }
13500Sstevel@tonic-gate 
13517968Sopensolaris@drydog.com 
13520Sstevel@tonic-gate /*
13530Sstevel@tonic-gate  * Check if a kernel software provider is in the kernel.
13547968Sopensolaris@drydog.com  *
13557968Sopensolaris@drydog.com  * Parameters:
13567968Sopensolaris@drydog.com  * provname		Provider name
13577968Sopensolaris@drydog.com  * psoftlist_kernel	Optional software provider list.  If NULL, it will be
13587968Sopensolaris@drydog.com  *			obtained from get_soft_list().
13597968Sopensolaris@drydog.com  * in_kernel		Set to B_TRUE if device is in the kernel, else B_FALSE
13600Sstevel@tonic-gate  */
13610Sstevel@tonic-gate int
13627968Sopensolaris@drydog.com check_kernel_for_soft(char *provname, crypto_get_soft_list_t *psoftlist_kernel,
13637968Sopensolaris@drydog.com     boolean_t *in_kernel)
13640Sstevel@tonic-gate {
13657968Sopensolaris@drydog.com 	char		*ptr;
13667968Sopensolaris@drydog.com 	int		i;
13677968Sopensolaris@drydog.com 	boolean_t	psoftlist_allocated = B_FALSE;
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 	if (provname == NULL) {
13700Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext("internal error."));
13710Sstevel@tonic-gate 		return (FAILURE);
13720Sstevel@tonic-gate 	}
13730Sstevel@tonic-gate 
13747968Sopensolaris@drydog.com 	if (psoftlist_kernel == NULL) {
13757968Sopensolaris@drydog.com 		if (get_soft_list(&psoftlist_kernel) == FAILURE) {
13767968Sopensolaris@drydog.com 			cryptodebug("failed to get the software provider list"
13777968Sopensolaris@drydog.com 			" from kernel.");
13787968Sopensolaris@drydog.com 			return (FAILURE);
13797968Sopensolaris@drydog.com 		}
13807968Sopensolaris@drydog.com 		psoftlist_allocated = B_TRUE;
13810Sstevel@tonic-gate 	}
13820Sstevel@tonic-gate 
13837968Sopensolaris@drydog.com 	*in_kernel = B_FALSE;
13840Sstevel@tonic-gate 	ptr = psoftlist_kernel->sl_soft_names;
13850Sstevel@tonic-gate 	for (i = 0; i < psoftlist_kernel->sl_soft_count; i++) {
13860Sstevel@tonic-gate 		if (strcmp(provname, ptr) == 0) {
13877968Sopensolaris@drydog.com 			*in_kernel = B_TRUE;
13880Sstevel@tonic-gate 			break;
13890Sstevel@tonic-gate 		}
13900Sstevel@tonic-gate 		ptr = ptr + strlen(ptr) + 1;
13910Sstevel@tonic-gate 	}
13927968Sopensolaris@drydog.com 
13937968Sopensolaris@drydog.com 	if (psoftlist_allocated)
13947968Sopensolaris@drydog.com 		free(psoftlist_kernel);
13950Sstevel@tonic-gate 
13960Sstevel@tonic-gate 	return (SUCCESS);
13970Sstevel@tonic-gate }
13980Sstevel@tonic-gate 
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate /*
14010Sstevel@tonic-gate  * Check if a kernel hardware provider is in the kernel.
14027968Sopensolaris@drydog.com  *
14037968Sopensolaris@drydog.com  * Parameters:
14047968Sopensolaris@drydog.com  * provname	Provider name
14057968Sopensolaris@drydog.com  * pdevlist	Optional Hardware Crypto Device List.  If NULL, it will be
14067968Sopensolaris@drydog.com  *		obtained from get_dev_list().
14077968Sopensolaris@drydog.com  * in_kernel	Set to B_TRUE if device is in the kernel, otherwise B_FALSE
14080Sstevel@tonic-gate  */
14090Sstevel@tonic-gate int
14107968Sopensolaris@drydog.com check_kernel_for_hard(char *provname,
14117968Sopensolaris@drydog.com     crypto_get_dev_list_t *pdevlist, boolean_t *in_kernel)
14120Sstevel@tonic-gate {
14137968Sopensolaris@drydog.com 	char		devname[MAXNAMELEN];
14147968Sopensolaris@drydog.com 	int		inst_num;
14157968Sopensolaris@drydog.com 	int		i;
14167968Sopensolaris@drydog.com 	boolean_t	dev_list_allocated = B_FALSE;
14170Sstevel@tonic-gate 
14180Sstevel@tonic-gate 	if (provname == NULL) {
14190Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext("internal error."));
14200Sstevel@tonic-gate 		return (FAILURE);
14210Sstevel@tonic-gate 	}
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 	if (split_hw_provname(provname, devname, &inst_num) == FAILURE) {
14240Sstevel@tonic-gate 		return (FAILURE);
14250Sstevel@tonic-gate 	}
14260Sstevel@tonic-gate 
14277968Sopensolaris@drydog.com 	if (pdevlist == NULL) {
14287968Sopensolaris@drydog.com 		if (get_dev_list(&pdevlist) == FAILURE) {
14297968Sopensolaris@drydog.com 			cryptoerror(LOG_STDERR, gettext("internal error."));
14307968Sopensolaris@drydog.com 			return (FAILURE);
14317968Sopensolaris@drydog.com 		}
14327968Sopensolaris@drydog.com 		dev_list_allocated = B_TRUE;
14330Sstevel@tonic-gate 	}
14340Sstevel@tonic-gate 
14357968Sopensolaris@drydog.com 	*in_kernel = B_FALSE;
14360Sstevel@tonic-gate 	for (i = 0; i < pdevlist->dl_dev_count; i++) {
14370Sstevel@tonic-gate 		if ((strcmp(pdevlist->dl_devs[i].le_dev_name, devname) == 0) &&
14380Sstevel@tonic-gate 		    (pdevlist->dl_devs[i].le_dev_instance == inst_num)) {
14397968Sopensolaris@drydog.com 			*in_kernel = B_TRUE;
14400Sstevel@tonic-gate 			break;
14410Sstevel@tonic-gate 		}
14420Sstevel@tonic-gate 	}
14437968Sopensolaris@drydog.com 
14447968Sopensolaris@drydog.com 	if (dev_list_allocated)
14457968Sopensolaris@drydog.com 		free(pdevlist);
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 	return (SUCCESS);
14480Sstevel@tonic-gate }
1449