xref: /onnv-gate/usr/src/cmd/cmd-crypto/kmfcfg/util.c (revision 5626:1f8878c75f54)
13089Swyllys /*
23089Swyllys  * CDDL HEADER START
33089Swyllys  *
43089Swyllys  * The contents of this file are subject to the terms of the
53089Swyllys  * Common Development and Distribution License (the "License").
63089Swyllys  * You may not use this file except in compliance with the License.
73089Swyllys  *
83089Swyllys  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93089Swyllys  * or http://www.opensolaris.org/os/licensing.
103089Swyllys  * See the License for the specific language governing permissions
113089Swyllys  * and limitations under the License.
123089Swyllys  *
133089Swyllys  * When distributing Covered Code, include this CDDL HEADER in each
143089Swyllys  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153089Swyllys  * If applicable, add the following below this CDDL HEADER, with the
163089Swyllys  * fields enclosed by brackets "[]" replaced with your own identifying
173089Swyllys  * information: Portions Copyright [yyyy] [name of copyright owner]
183089Swyllys  *
193089Swyllys  * CDDL HEADER END
203089Swyllys  *
215051Swyllys  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
223089Swyllys  * Use is subject to license terms.
233089Swyllys  */
243089Swyllys 
253089Swyllys #pragma ident	"%Z%%M%	%I%	%E% SMI"
263089Swyllys 
273089Swyllys #include <stdio.h>
283089Swyllys #include <strings.h>
293089Swyllys #include <ctype.h>
303089Swyllys #include <libgen.h>
313089Swyllys #include <libintl.h>
323089Swyllys 
333089Swyllys #include <libxml/tree.h>
343089Swyllys #include <libxml/parser.h>
353089Swyllys 
363089Swyllys #include <kmfapiP.h>
37*5626Shylee #include "util.h"
383089Swyllys 
393089Swyllys 
403089Swyllys /* Supporting structures and global variables for getopt_av(). */
413089Swyllys typedef struct	av_opts_s {
423089Swyllys 	int		shortnm;	/* short name character */
433089Swyllys 	char		*longnm;	/* long name string, NOT terminated */
443089Swyllys 	int		longnm_len;	/* length of long name string */
453089Swyllys 	boolean_t	has_arg;	/* takes optional argument */
463089Swyllys } av_opts;
473089Swyllys 
483089Swyllys static av_opts		*opts_av = NULL;
493089Swyllys static const char	*_save_optstr = NULL;
503089Swyllys static int		_save_numopts = 0;
513089Swyllys int			optind_av = 1;
523089Swyllys char			*optarg_av = NULL;
533089Swyllys 
543089Swyllys void
free_policy_list(POLICY_LIST * plist)553089Swyllys free_policy_list(POLICY_LIST *plist)
563089Swyllys {
573089Swyllys 	POLICY_LIST *n = plist, *old;
583089Swyllys 
593089Swyllys 	if (plist == NULL)
603089Swyllys 		return;
613089Swyllys 
623089Swyllys 	while (n != NULL) {
633089Swyllys 		old = n;
645051Swyllys 		kmf_free_policy_record(&n->plc);
653089Swyllys 		n = n->next;
663089Swyllys 		free(old);
673089Swyllys 	}
683089Swyllys 	plist = NULL;
693089Swyllys }
703089Swyllys 
713089Swyllys int
load_policies(char * file,POLICY_LIST ** policy_list)723089Swyllys load_policies(char *file, POLICY_LIST **policy_list)
733089Swyllys {
743089Swyllys 	int rv = KC_OK;
753089Swyllys 	KMF_RETURN kmfrv = KMF_OK;
763089Swyllys 	POLICY_LIST *newitem, *plist = NULL;
773089Swyllys 	xmlParserCtxtPtr ctxt;
783089Swyllys 	xmlDocPtr doc = NULL;
793089Swyllys 	xmlNodePtr cur, node;
803089Swyllys 
813089Swyllys 	/* Create a parser context */
823089Swyllys 	ctxt = xmlNewParserCtxt();
833089Swyllys 	if (ctxt == NULL)
843089Swyllys 		return (KMF_ERR_POLICY_DB_FORMAT);
853089Swyllys 
863089Swyllys 	/* Read the policy DB and verify it against the schema. */
873089Swyllys 	doc = xmlCtxtReadFile(ctxt, file, NULL,
883089Swyllys 	    XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
893089Swyllys 	if (doc == NULL || ctxt->valid == 0) {
903089Swyllys 		kmfrv = KMF_ERR_POLICY_DB_FORMAT;
913089Swyllys 		goto end;
923089Swyllys 	}
933089Swyllys 
943089Swyllys 	cur = xmlDocGetRootElement(doc);
953089Swyllys 	if (cur == NULL) {
963089Swyllys 		kmfrv = KMF_ERR_POLICY_DB_FORMAT;
973089Swyllys 		goto end;
983089Swyllys 	}
993089Swyllys 
1003089Swyllys 	node = cur->xmlChildrenNode;
1013089Swyllys 	while (node != NULL) {
1023089Swyllys 		char *c;
1033089Swyllys 		/*
1043089Swyllys 		 * Search for the policy that matches the given name.
1053089Swyllys 		 */
1063089Swyllys 		if (!xmlStrcmp((const xmlChar *)node->name,
1075051Swyllys 		    (const xmlChar *)KMF_POLICY_ELEMENT)) {
1083089Swyllys 			/* Check the name attribute */
1093089Swyllys 			c = (char *)xmlGetProp(node,
1105051Swyllys 			    (const xmlChar *)KMF_POLICY_NAME_ATTR);
1113089Swyllys 
1123089Swyllys 			/* If a match, parse the rest of the data */
1133089Swyllys 			if (c != NULL) {
1143089Swyllys 				xmlFree(c);
1153089Swyllys 				newitem = malloc(sizeof (POLICY_LIST));
1163089Swyllys 				if (newitem != NULL) {
1173089Swyllys 					(void) memset(newitem, 0,
1185051Swyllys 					    sizeof (POLICY_LIST));
1193089Swyllys 					kmfrv = parsePolicyElement(node,
1205051Swyllys 					    &newitem->plc);
1213089Swyllys 				} else {
1223089Swyllys 					kmfrv = KMF_ERR_MEMORY;
1233089Swyllys 					goto end;
1243089Swyllys 				}
1253089Swyllys 				/* add to linked list */
1263089Swyllys 				if (plist == NULL) {
1273089Swyllys 					plist = newitem;
1283089Swyllys 				} else {
1293089Swyllys 					POLICY_LIST *n = plist;
1303089Swyllys 					while (n->next != NULL)
1313089Swyllys 						n = n->next;
1323089Swyllys 
1333089Swyllys 					n->next = newitem;
1343089Swyllys 					newitem->next = NULL;
1353089Swyllys 				}
1363089Swyllys 			}
1373089Swyllys 		}
1383089Swyllys 		node = node->next;
1393089Swyllys 	}
1403089Swyllys 
1413089Swyllys end:
1423089Swyllys 	if (ctxt != NULL)
1433089Swyllys 		xmlFreeParserCtxt(ctxt);
1443089Swyllys 
1453089Swyllys 	if (doc != NULL)
1463089Swyllys 		xmlFreeDoc(doc);
1473089Swyllys 
1483089Swyllys 	if (kmfrv != KMF_OK) {
1493089Swyllys 		free_policy_list(plist);
1503089Swyllys 		rv = KC_ERR_LOADDB;
1513089Swyllys 	} else {
1523089Swyllys 		*policy_list = plist;
1533089Swyllys 	}
1543089Swyllys 
1553089Swyllys 	return (rv);
1563089Swyllys }
1573089Swyllys 
1583089Swyllys /*
1593089Swyllys  * Return 0 if there is any error in the input string.
1603089Swyllys  */
1613089Swyllys uint16_t
parseKUlist(char * kustring)1623089Swyllys parseKUlist(char *kustring)
1633089Swyllys {
1643089Swyllys 	uint16_t cur_bit;
1653089Swyllys 	uint16_t kubits = 0;
1663089Swyllys 	char *p;
1673089Swyllys 
1683089Swyllys 	p = strtok(kustring, ",");
1693089Swyllys 	while (p != NULL) {
1705051Swyllys 		cur_bit = kmf_string_to_ku(p);
1713089Swyllys 		if (cur_bit == 0) {
1723089Swyllys 			kubits = 0;
1733089Swyllys 			break;
1743089Swyllys 		}
1753089Swyllys 		kubits |= cur_bit;
1763089Swyllys 		p = strtok(NULL, ",");
1773089Swyllys 	}
1783089Swyllys 
1793089Swyllys 	return (kubits);
1803089Swyllys }
1813089Swyllys 
1823089Swyllys static void
addToEKUList(KMF_EKU_POLICY * ekus,KMF_OID * newoid)1833089Swyllys addToEKUList(KMF_EKU_POLICY *ekus, KMF_OID *newoid)
1843089Swyllys {
1853089Swyllys 	if (newoid != NULL && ekus != NULL) {
1863089Swyllys 		ekus->eku_count++;
1873089Swyllys 		ekus->ekulist = realloc(
1885051Swyllys 		    ekus->ekulist, ekus->eku_count * sizeof (KMF_OID));
1893089Swyllys 		if (ekus->ekulist != NULL) {
1903089Swyllys 			ekus->ekulist[ekus->eku_count-1] = *newoid;
1913089Swyllys 		}
1923089Swyllys 	}
1933089Swyllys }
1943089Swyllys 
1953089Swyllys int
parseEKUNames(char * ekulist,KMF_POLICY_RECORD * plc)1963089Swyllys parseEKUNames(char *ekulist, KMF_POLICY_RECORD *plc)
1973089Swyllys {
1983089Swyllys 	int rv = KC_OK;
1993089Swyllys 	char *p;
2003089Swyllys 	KMF_OID *newoid;
2013089Swyllys 	KMF_EKU_POLICY *ekus = &plc->eku_set;
2023089Swyllys 
2033089Swyllys 	if (ekulist == NULL || !strlen(ekulist))
2043089Swyllys 		return (0);
2053089Swyllys 
2063089Swyllys 	/*
2073089Swyllys 	 * The list should be comma separated list of EKU Names.
2083089Swyllys 	 */
2093089Swyllys 	p = strtok(ekulist, ",");
2103089Swyllys 
2113089Swyllys 	/* If no tokens found, then maybe its just a single EKU value */
2123089Swyllys 	if (p == NULL) {
2135051Swyllys 		newoid = kmf_ekuname_to_oid(ekulist);
2143089Swyllys 		if (newoid != NULL) {
2153089Swyllys 			addToEKUList(ekus, newoid);
2163089Swyllys 			free(newoid);
2173089Swyllys 		} else {
2183089Swyllys 			rv = KC_ERR_USAGE;
2193089Swyllys 		}
2203089Swyllys 	}
2213089Swyllys 
2223089Swyllys 	while (p != NULL) {
2235051Swyllys 		newoid = kmf_ekuname_to_oid(p);
2243089Swyllys 		if (newoid != NULL) {
2253089Swyllys 			addToEKUList(ekus, newoid);
2263089Swyllys 			free(newoid);
2273089Swyllys 		} else {
2283089Swyllys 			rv = KC_ERR_USAGE;
2293089Swyllys 			break;
2303089Swyllys 		}
2313089Swyllys 		p = strtok(NULL, ",");
2323089Swyllys 	}
2333089Swyllys 
2343089Swyllys 	if (rv != KC_OK)
2355051Swyllys 		kmf_free_eku_policy(ekus);
2363089Swyllys 
2373089Swyllys 	return (rv);
2383089Swyllys }
2393089Swyllys 
2403089Swyllys int
parseEKUOIDs(char * ekulist,KMF_POLICY_RECORD * plc)2413089Swyllys parseEKUOIDs(char *ekulist, KMF_POLICY_RECORD *plc)
2423089Swyllys {
2433089Swyllys 	int rv = KC_OK;
2443089Swyllys 	char *p;
2455051Swyllys 	KMF_OID newoid = {NULL, 0};
2463089Swyllys 	KMF_EKU_POLICY *ekus = &plc->eku_set;
2473089Swyllys 
2483089Swyllys 	if (ekulist == NULL || !strlen(ekulist))
2493089Swyllys 		return (0);
2503089Swyllys 
2513089Swyllys 	/*
2523089Swyllys 	 * The list should be comma separated list of EKU Names.
2533089Swyllys 	 */
2543089Swyllys 	p = strtok(ekulist, ",");
2553089Swyllys 	if (p == NULL) {
2565051Swyllys 		if (kmf_string_to_oid(ekulist, &newoid) == KMF_OK) {
2575051Swyllys 			addToEKUList(ekus, &newoid);
2583089Swyllys 		} else {
2593089Swyllys 			rv = KC_ERR_USAGE;
2603089Swyllys 		}
2613089Swyllys 	}
2623089Swyllys 
2633089Swyllys 	while (p != NULL && rv == 0) {
2645051Swyllys 		if (kmf_string_to_oid(p, &newoid) == KMF_OK) {
2655051Swyllys 			addToEKUList(ekus, &newoid);
2663089Swyllys 		} else {
2673089Swyllys 			rv = KC_ERR_USAGE;
2683089Swyllys 			break;
2693089Swyllys 		}
2703089Swyllys 		p = strtok(NULL, ",");
2713089Swyllys 	}
2723089Swyllys 
2733089Swyllys 	if (rv != KC_OK)
2745051Swyllys 		kmf_free_eku_policy(ekus);
2753089Swyllys 
2763089Swyllys 	return (rv);
2773089Swyllys }
2783089Swyllys 
2793089Swyllys int
get_boolean(char * arg)2803089Swyllys get_boolean(char *arg)
2813089Swyllys {
2823089Swyllys 	if (arg == NULL)
2833089Swyllys 		return (-1);
2843089Swyllys 	if (strcasecmp(arg, "true") == 0)
2853089Swyllys 		return (1);
2863089Swyllys 	if (strcasecmp(arg, "false") == 0)
2873089Swyllys 		return (0);
2883089Swyllys 	return (-1);
2893089Swyllys }
2903089Swyllys 
2913089Swyllys /*
2923089Swyllys  * This function processes the input string.  It removes the beginning
2933089Swyllys  * and ending blank's first, makes a copy of the resulting string and
2943089Swyllys  * return it.
2953089Swyllys  *
2963089Swyllys  * This function returns NULL, if there is an error in the
2973089Swyllys  * input string or when the system is out of memory.  The output
2983089Swyllys  * "err_flag" argument will record the error code, if it is not NULL.
2993089Swyllys  */
3003089Swyllys char *
get_string(char * str,int * err_flag)3013089Swyllys get_string(char *str, int *err_flag)
3023089Swyllys {
3033089Swyllys 	char *p;
3043089Swyllys 	int len, i;
3053089Swyllys 	char *retstr = NULL;
3063089Swyllys 
3073089Swyllys 	if (str == NULL) {
3083089Swyllys 		if (err_flag != NULL)
3093089Swyllys 			*err_flag = KC_ERR_USAGE;
3103089Swyllys 		return (NULL);
3113089Swyllys 	}
3123089Swyllys 
3133089Swyllys 	/* Remove beginning whitespace */
3143089Swyllys 	p = str;
3153089Swyllys 	while (p != NULL && isspace(*p))
3163089Swyllys 		p++;
3173089Swyllys 
3183089Swyllys 	if (p == NULL) {
3193089Swyllys 		if (err_flag != NULL)
3203089Swyllys 			*err_flag = KC_ERR_USAGE;
3213089Swyllys 		return (NULL);
3223089Swyllys 	}
3233089Swyllys 
3243089Swyllys 	/* Remove the trailing blanks */
3253089Swyllys 	len = strlen(p);
3263089Swyllys 	while (len > 0 && isspace(p[len-1]))
3273089Swyllys 		len--;
3283089Swyllys 
3293089Swyllys 	if (len == 0) {
3303089Swyllys 		if (err_flag != NULL)
3313089Swyllys 			*err_flag = KC_ERR_USAGE;
3323089Swyllys 		return (NULL);
3333089Swyllys 	}
3343089Swyllys 
3353089Swyllys 	/* Check if there is any non-printable character */
3363089Swyllys 	i = 0;
3373089Swyllys 	while (i < len) {
3383089Swyllys 		if (isprint(p[i]))
3393089Swyllys 			i++;
3403089Swyllys 		else {
3413089Swyllys 			if (err_flag != NULL)
3423089Swyllys 				*err_flag = KC_ERR_USAGE;
3433089Swyllys 			return (NULL);
3443089Swyllys 		}
3453089Swyllys 	}
3463089Swyllys 
3473089Swyllys 	/* Make a copy of the string and return it */
3483089Swyllys 	retstr = malloc(len + 1);
3493089Swyllys 	if (retstr == NULL) {
3503089Swyllys 		if (err_flag != NULL)
3513089Swyllys 			*err_flag = KC_ERR_MEMORY;
3523089Swyllys 		return (NULL);
3533089Swyllys 	}
3543089Swyllys 
3553089Swyllys 	if (err_flag != NULL)
3563089Swyllys 		*err_flag = KC_OK;
3573089Swyllys 
3583089Swyllys 	(void) strncpy(retstr, p, len);
3593089Swyllys 	retstr[len] = '\0';
3603089Swyllys 	return (retstr);
3613089Swyllys }
3623089Swyllys 
3633089Swyllys /*
3643089Swyllys  * Breaks out the getopt-style option string into a structure that can be
3653089Swyllys  * traversed later for calls to getopt_av().  Option string is NOT altered,
3663089Swyllys  * but the struct fields point to locations within option string.
3673089Swyllys  */
3683089Swyllys static int
populate_opts(char * optstring)3693089Swyllys populate_opts(char *optstring)
3703089Swyllys {
3713089Swyllys 	int		i;
3723089Swyllys 	av_opts		*temp;
3733089Swyllys 	char		*marker;
3743089Swyllys 
3753089Swyllys 	if (optstring == NULL || *optstring == '\0')
3763089Swyllys 		return (0);
3773089Swyllys 
3783089Swyllys 	/*
3793089Swyllys 	 * This tries to imitate getopt(3c) Each option must conform to:
3803089Swyllys 	 * <short name char> [ ':' ] [ '(' <long name string> ')' ]
3813089Swyllys 	 * If long name is missing, the short name is used for long name.
3823089Swyllys 	 */
3833089Swyllys 	for (i = 0; *optstring != '\0'; i++) {
3843089Swyllys 		if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) :
3853089Swyllys 		    realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) {
3863089Swyllys 			free(opts_av);
3873089Swyllys 			opts_av = NULL;
3883089Swyllys 			return (0);
3893089Swyllys 		} else
3903089Swyllys 			opts_av = (av_opts *)temp;
3913089Swyllys 
3923089Swyllys 		marker = optstring;		/* may need optstring later */
3933089Swyllys 
3943089Swyllys 		opts_av[i].shortnm = *marker++;	/* set short name */
3953089Swyllys 
3963089Swyllys 		if (*marker == ':') {		/* check for opt arg */
3973089Swyllys 			marker++;
3983089Swyllys 			opts_av[i].has_arg = B_TRUE;
3993089Swyllys 		}
4003089Swyllys 
4013089Swyllys 		if (*marker == '(') {		/* check and set long name */
4023089Swyllys 			marker++;
4033089Swyllys 			opts_av[i].longnm = marker;
4043089Swyllys 			opts_av[i].longnm_len = strcspn(marker, ")");
4053089Swyllys 			optstring = marker + opts_av[i].longnm_len + 1;
4063089Swyllys 		} else {
4073089Swyllys 			/* use short name option character */
4083089Swyllys 			opts_av[i].longnm = optstring;
4093089Swyllys 			opts_av[i].longnm_len = 1;
4103089Swyllys 			optstring = marker;
4113089Swyllys 		}
4123089Swyllys 	}
4133089Swyllys 
4143089Swyllys 	return (i);
4153089Swyllys }
4163089Swyllys 
4173089Swyllys /*
4183089Swyllys  * getopt_av() is very similar to getopt(3c) in that the takes an option
4193089Swyllys  * string, compares command line arguments for matches, and returns a single
4203089Swyllys  * letter option when a match is found.  However, getopt_av() differs from
4213089Swyllys  * getopt(3c) by allowing both longname options and values be found
4223089Swyllys  * on the command line.
4233089Swyllys  */
4243089Swyllys int
getopt_av(int argc,char * const * argv,const char * optstring)4253089Swyllys getopt_av(int argc, char * const *argv, const char *optstring)
4263089Swyllys {
4273089Swyllys 	int	i;
4283089Swyllys 	int	len;
4293089Swyllys 
4303089Swyllys 	if (optind_av >= argc)
4313089Swyllys 		return (EOF);
4323089Swyllys 
4333089Swyllys 	/* First time or when optstring changes from previous one */
4343089Swyllys 	if (_save_optstr != optstring) {
4353089Swyllys 		if (opts_av != NULL)
4365051Swyllys 			free(opts_av);
4373089Swyllys 		opts_av = NULL;
4383089Swyllys 		_save_optstr = optstring;
4393089Swyllys 		_save_numopts = populate_opts((char *)optstring);
4403089Swyllys 	}
4413089Swyllys 
4423089Swyllys 	for (i = 0; i < _save_numopts; i++) {
4433089Swyllys 		if (strcmp(argv[optind_av], "--") == 0) {
4443089Swyllys 			optind_av++;
4453089Swyllys 			break;
4463089Swyllys 		}
4473089Swyllys 
4483089Swyllys 		len = strcspn(argv[optind_av], "=");
4493089Swyllys 
4503089Swyllys 		if (len == opts_av[i].longnm_len && strncmp(argv[optind_av],
4513089Swyllys 		    opts_av[i].longnm, opts_av[i].longnm_len) == 0) {
4523089Swyllys 			/* matched */
4533089Swyllys 			if (!opts_av[i].has_arg) {
4543089Swyllys 				optind_av++;
4553089Swyllys 				return (opts_av[i].shortnm);
4563089Swyllys 			}
4573089Swyllys 
4583089Swyllys 			/* needs optarg */
4593089Swyllys 			if (argv[optind_av][len] == '=') {
4603089Swyllys 				optarg_av = &(argv[optind_av][len+1]);
4613089Swyllys 				optind_av++;
4623089Swyllys 				return (opts_av[i].shortnm);
4633089Swyllys 			}
4643089Swyllys 
4653089Swyllys 			optarg_av = NULL;
4663089Swyllys 			optind_av++;
4673089Swyllys 			return ((int)'?');
4683089Swyllys 		}
4693089Swyllys 	}
4703089Swyllys 
4713089Swyllys 	return (EOF);
4723089Swyllys }
4733089Swyllys 
4743089Swyllys void
print_sanity_error(KMF_RETURN ret)4753089Swyllys print_sanity_error(KMF_RETURN ret)
4763089Swyllys {
4773089Swyllys 	switch (ret) {
4783089Swyllys 	case KMF_ERR_POLICY_NAME:
4793089Swyllys 		(void) fprintf(stderr, gettext("Error in the policy name\n"));
4803089Swyllys 		break;
4813089Swyllys 	case KMF_ERR_TA_POLICY:
4823089Swyllys 		(void) fprintf(stderr,
4833089Swyllys 		    gettext("Error in trust anchor attributes\n"));
4843089Swyllys 		break;
4853089Swyllys 	case KMF_ERR_OCSP_POLICY:
4863089Swyllys 		(void) fprintf(stderr,
4873089Swyllys 		    gettext("Error in OCSP policy attributes\n"));
4883089Swyllys 		break;
4893089Swyllys 	default:
4903089Swyllys 		break;
4913089Swyllys 	}
4923089Swyllys }
493*5626Shylee 
494*5626Shylee 
495*5626Shylee conf_entry_t *
get_keystore_entry(char * kstore_name)496*5626Shylee get_keystore_entry(char *kstore_name)
497*5626Shylee {
498*5626Shylee 	conf_entrylist_t *phead = NULL;
499*5626Shylee 	conf_entrylist_t *ptr;
500*5626Shylee 	conf_entry_t	*rtn_entry = NULL;
501*5626Shylee 
502*5626Shylee 	if (kstore_name == NULL)
503*5626Shylee 		return (NULL);
504*5626Shylee 
505*5626Shylee 	if (get_entrylist(&phead) != KMF_OK)
506*5626Shylee 		return (NULL);
507*5626Shylee 
508*5626Shylee 	ptr = phead;
509*5626Shylee 	while (ptr != NULL) {
510*5626Shylee 		if (strcmp(ptr->entry->keystore, kstore_name) == 0)
511*5626Shylee 			break;
512*5626Shylee 		ptr = ptr->next;
513*5626Shylee 	}
514*5626Shylee 
515*5626Shylee 	if (ptr != NULL) /* found the entry */
516*5626Shylee 		rtn_entry = dup_entry(ptr->entry);
517*5626Shylee 
518*5626Shylee 	free_entrylist(phead);
519*5626Shylee 	return (rtn_entry);
520*5626Shylee }
521