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
51971Skrishna  * Common Development and Distribution License (the "License").
61971Skrishna  * 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 <fcntl.h>
270Sstevel@tonic-gate #include <stdio.h>
280Sstevel@tonic-gate #include <stdlib.h>
290Sstevel@tonic-gate #include <strings.h>
300Sstevel@tonic-gate #include <unistd.h>
310Sstevel@tonic-gate #include <locale.h>
320Sstevel@tonic-gate #include <libgen.h>
330Sstevel@tonic-gate #include <sys/types.h>
340Sstevel@tonic-gate #include <sys/stat.h>
350Sstevel@tonic-gate #include <sys/crypto/ioctladmin.h>
360Sstevel@tonic-gate #include <signal.h>
370Sstevel@tonic-gate #include <sys/crypto/elfsign.h>
380Sstevel@tonic-gate #include "cryptoadm.h"
390Sstevel@tonic-gate 
400Sstevel@tonic-gate static int check_hardware_provider(char *, char *, int *, int *);
410Sstevel@tonic-gate 
420Sstevel@tonic-gate /*
430Sstevel@tonic-gate  * Display the mechanism list for a kernel software provider.
447968Sopensolaris@drydog.com  * This implements part of the "cryptoadm list -m" command.
457968Sopensolaris@drydog.com  *
46*10500SHai-May.Chao@Sun.COM  * Parameters phardlist, psoftlist and pfipslist are supplied by
47*10500SHai-May.Chao@Sun.COM  * get_soft_info().
48*10500SHai-May.Chao@Sun.COM  * If NULL, this function obtains it by calling getent_kef() and
49*10500SHai-May.Chao@Sun.COM  * then get_kcfconf_info() via get_soft_info() internally.
500Sstevel@tonic-gate  */
510Sstevel@tonic-gate int
527968Sopensolaris@drydog.com list_mechlist_for_soft(char *provname,
53*10500SHai-May.Chao@Sun.COM     entrylist_t *phardlist, entrylist_t *psoftlist,
54*10500SHai-May.Chao@Sun.COM     entrylist_t *pfipslist)
550Sstevel@tonic-gate {
567968Sopensolaris@drydog.com 	mechlist_t	*pmechlist = NULL;
577968Sopensolaris@drydog.com 	int		rc;
580Sstevel@tonic-gate 
590Sstevel@tonic-gate 	if (provname == NULL) {
600Sstevel@tonic-gate 		return (FAILURE);
610Sstevel@tonic-gate 	}
620Sstevel@tonic-gate 
63*10500SHai-May.Chao@Sun.COM 	rc = get_soft_info(provname, &pmechlist, phardlist, psoftlist,
64*10500SHai-May.Chao@Sun.COM 	    pfipslist);
650Sstevel@tonic-gate 	if (rc == SUCCESS) {
660Sstevel@tonic-gate 		(void) filter_mechlist(&pmechlist, RANDOM);
670Sstevel@tonic-gate 		print_mechlist(provname, pmechlist);
680Sstevel@tonic-gate 		free_mechlist(pmechlist);
690Sstevel@tonic-gate 	} else {
700Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext(
710Sstevel@tonic-gate 		    "failed to retrieve the mechanism list for %s."),
720Sstevel@tonic-gate 		    provname);
730Sstevel@tonic-gate 	}
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	return (rc);
760Sstevel@tonic-gate }
770Sstevel@tonic-gate 
780Sstevel@tonic-gate /*
790Sstevel@tonic-gate  * Display the mechanism list for a kernel hardware provider.
807968Sopensolaris@drydog.com  * This implements part of the "cryptoadm list -m" command.
810Sstevel@tonic-gate  */
820Sstevel@tonic-gate int
830Sstevel@tonic-gate list_mechlist_for_hard(char *provname)
840Sstevel@tonic-gate {
857968Sopensolaris@drydog.com 	mechlist_t	*pmechlist = NULL;
867968Sopensolaris@drydog.com 	char		devname[MAXNAMELEN];
877968Sopensolaris@drydog.com 	int		inst_num;
887968Sopensolaris@drydog.com 	int		count;
897968Sopensolaris@drydog.com 	int		rc = SUCCESS;
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 	if (provname == NULL) {
920Sstevel@tonic-gate 		return (FAILURE);
930Sstevel@tonic-gate 	}
940Sstevel@tonic-gate 
950Sstevel@tonic-gate 	/*
960Sstevel@tonic-gate 	 * Check if the provider is valid. If it is valid, get the number of
970Sstevel@tonic-gate 	 * mechanisms also.
980Sstevel@tonic-gate 	 */
990Sstevel@tonic-gate 	if (check_hardware_provider(provname, devname, &inst_num, &count) ==
1000Sstevel@tonic-gate 	    FAILURE) {
1010Sstevel@tonic-gate 		return (FAILURE);
1020Sstevel@tonic-gate 	}
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 	/* Get the mechanism list for the kernel hardware provider */
1050Sstevel@tonic-gate 	if ((rc = get_dev_info(devname, inst_num, count, &pmechlist)) ==
1060Sstevel@tonic-gate 	    SUCCESS) {
1070Sstevel@tonic-gate 		(void) filter_mechlist(&pmechlist, RANDOM);
1080Sstevel@tonic-gate 		print_mechlist(provname, pmechlist);
1090Sstevel@tonic-gate 		free_mechlist(pmechlist);
1100Sstevel@tonic-gate 	}
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	return (rc);
1130Sstevel@tonic-gate }
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate /*
1170Sstevel@tonic-gate  * Display the policy information for a kernel software provider.
1187968Sopensolaris@drydog.com  * This implements part of the "cryptoadm list -p" command.
1197968Sopensolaris@drydog.com  *
120*10500SHai-May.Chao@Sun.COM  * Parameters phardlist, psoftlist and pfipslist are supplied by
121*10500SHai-May.Chao@Sun.COM  * getent_kef().
122*10500SHai-May.Chao@Sun.COM  * If NULL, this function obtains it by calling get_kcfconf_info()
123*10500SHai-May.Chao@Sun.COM  * via getent_kef() internally.
1240Sstevel@tonic-gate  */
1250Sstevel@tonic-gate int
1267968Sopensolaris@drydog.com list_policy_for_soft(char *provname,
127*10500SHai-May.Chao@Sun.COM     entrylist_t *phardlist, entrylist_t *psoftlist,
128*10500SHai-May.Chao@Sun.COM     entrylist_t *pfipslist)
1290Sstevel@tonic-gate {
1307968Sopensolaris@drydog.com 	int		rc;
1317968Sopensolaris@drydog.com 	entry_t		*pent = NULL;
1327968Sopensolaris@drydog.com 	mechlist_t	*pmechlist = NULL;
1337968Sopensolaris@drydog.com 	boolean_t	has_random = B_FALSE;
1347968Sopensolaris@drydog.com 	boolean_t	has_mechs = B_FALSE;
1357968Sopensolaris@drydog.com 	boolean_t	in_kernel = B_FALSE;
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 	if (provname == NULL) {
1380Sstevel@tonic-gate 		return (FAILURE);
1390Sstevel@tonic-gate 	}
1400Sstevel@tonic-gate 
1417968Sopensolaris@drydog.com 	if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) {
1427968Sopensolaris@drydog.com 		return (FAILURE);
1437968Sopensolaris@drydog.com 	} else if (in_kernel == B_FALSE) {
1440Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext("%s does not exist."),
1450Sstevel@tonic-gate 		    provname);
1460Sstevel@tonic-gate 		return (FAILURE);
1470Sstevel@tonic-gate 	}
148*10500SHai-May.Chao@Sun.COM 	pent = getent_kef(provname, phardlist, psoftlist,
149*10500SHai-May.Chao@Sun.COM 	    pfipslist);
1500Sstevel@tonic-gate 
151*10500SHai-May.Chao@Sun.COM 	rc = get_soft_info(provname, &pmechlist, phardlist, psoftlist,
152*10500SHai-May.Chao@Sun.COM 	    pfipslist);
1530Sstevel@tonic-gate 	if (rc == SUCCESS) {
1540Sstevel@tonic-gate 		has_random = filter_mechlist(&pmechlist, RANDOM);
1550Sstevel@tonic-gate 		if (pmechlist != NULL) {
1560Sstevel@tonic-gate 			has_mechs = B_TRUE;
1570Sstevel@tonic-gate 			free_mechlist(pmechlist);
1580Sstevel@tonic-gate 		}
1590Sstevel@tonic-gate 	} else {
1600Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext(
1610Sstevel@tonic-gate 		    "failed to retrieve the mechanism list for %s."),
1620Sstevel@tonic-gate 		    provname);
1630Sstevel@tonic-gate 		return (rc);
1640Sstevel@tonic-gate 	}
1650Sstevel@tonic-gate 
1667968Sopensolaris@drydog.com 	print_kef_policy(provname, pent, has_random, has_mechs);
1670Sstevel@tonic-gate 	free_entry(pent);
1680Sstevel@tonic-gate 	return (SUCCESS);
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate /*
1740Sstevel@tonic-gate  * Display the policy information for a kernel hardware provider.
1757968Sopensolaris@drydog.com  * This implements part of the "cryptoadm list -p" command.
1767968Sopensolaris@drydog.com  *
177*10500SHai-May.Chao@Sun.COM  * Parameters phardlist, psoftlist and pfipslist are supplied by getent_kef().
178*10500SHai-May.Chao@Sun.COM  * If NULL, this function obtains it by calling get_kcfconf_info() via
179*10500SHai-May.Chao@Sun.COM  * getent_kef() internally.
180*10500SHai-May.Chao@Sun.COM  * Parameter pdevlist is supplied by check_kernel_for_hard().
181*10500SHai-May.Chao@Sun.COM  * If NULL, this function obtains it by calling get_dev_list() via
182*10500SHai-May.Chao@Sun.COM  * check_kernel_for_hard() internally.
1830Sstevel@tonic-gate  */
1840Sstevel@tonic-gate int
1857968Sopensolaris@drydog.com list_policy_for_hard(char *provname,
1867968Sopensolaris@drydog.com 	entrylist_t *phardlist, entrylist_t *psoftlist,
187*10500SHai-May.Chao@Sun.COM 	entrylist_t *pfipslist, crypto_get_dev_list_t *pdevlist)
1880Sstevel@tonic-gate {
1897968Sopensolaris@drydog.com 	entry_t		*pent = NULL;
1907968Sopensolaris@drydog.com 	boolean_t	in_kernel;
1917968Sopensolaris@drydog.com 	mechlist_t	*pmechlist = NULL;
1927968Sopensolaris@drydog.com 	char		devname[MAXNAMELEN];
1937968Sopensolaris@drydog.com 	int		inst_num;
1947968Sopensolaris@drydog.com 	int		count;
1957968Sopensolaris@drydog.com 	int		rc = SUCCESS;
1967968Sopensolaris@drydog.com 	boolean_t	has_random = B_FALSE;
1977968Sopensolaris@drydog.com 	boolean_t 	has_mechs = B_FALSE;
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	if (provname == NULL) {
2000Sstevel@tonic-gate 		return (FAILURE);
2010Sstevel@tonic-gate 	}
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	/*
2040Sstevel@tonic-gate 	 * Check if the provider is valid. If it is valid, get the number of
2050Sstevel@tonic-gate 	 * mechanisms also.
2060Sstevel@tonic-gate 	 */
2070Sstevel@tonic-gate 	if (check_hardware_provider(provname, devname, &inst_num, &count) ==
2080Sstevel@tonic-gate 	    FAILURE) {
2090Sstevel@tonic-gate 		return (FAILURE);
2100Sstevel@tonic-gate 	}
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	/* Get the mechanism list for the kernel hardware provider */
2130Sstevel@tonic-gate 	if ((rc = get_dev_info(devname, inst_num, count, &pmechlist)) ==
2140Sstevel@tonic-gate 	    SUCCESS) {
2150Sstevel@tonic-gate 		has_random = filter_mechlist(&pmechlist, RANDOM);
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 		if (pmechlist != NULL) {
2180Sstevel@tonic-gate 			has_mechs = B_TRUE;
2190Sstevel@tonic-gate 			free_mechlist(pmechlist);
2200Sstevel@tonic-gate 		}
2210Sstevel@tonic-gate 	} else {
2220Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext(
2230Sstevel@tonic-gate 		    "failed to retrieve the mechanism list for %s."),
2240Sstevel@tonic-gate 		    devname);
2250Sstevel@tonic-gate 		return (rc);
2260Sstevel@tonic-gate 	}
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	/*
2290Sstevel@tonic-gate 	 * If the hardware provider has an entry in the kcf.conf file,
2300Sstevel@tonic-gate 	 * some of its mechanisms must have been disabled.  Print out
2310Sstevel@tonic-gate 	 * the disabled list from the config file entry.  Otherwise,
2320Sstevel@tonic-gate 	 * if it is active, then all the mechanisms for it are enabled.
2330Sstevel@tonic-gate 	 */
234*10500SHai-May.Chao@Sun.COM 	if ((pent = getent_kef(provname, phardlist, psoftlist,
235*10500SHai-May.Chao@Sun.COM 	    pfipslist)) != NULL) {
2367968Sopensolaris@drydog.com 		print_kef_policy(provname, pent, has_random, has_mechs);
2370Sstevel@tonic-gate 		free_entry(pent);
2380Sstevel@tonic-gate 		return (SUCCESS);
2390Sstevel@tonic-gate 	} else {
2407968Sopensolaris@drydog.com 		if (check_kernel_for_hard(provname, pdevlist,
2417968Sopensolaris@drydog.com 		    &in_kernel) == FAILURE) {
2420Sstevel@tonic-gate 			return (FAILURE);
2437968Sopensolaris@drydog.com 		} else if (in_kernel == B_TRUE) {
2440Sstevel@tonic-gate 			(void) printf(gettext(
2450Sstevel@tonic-gate 			    "%s: all mechanisms are enabled."), provname);
2460Sstevel@tonic-gate 			if (has_random)
2470Sstevel@tonic-gate 				/*
2487334SDaniel.Anderson@Sun.COM 				 * TRANSLATION_NOTE
2490Sstevel@tonic-gate 				 * "random" is a keyword and not to be
2500Sstevel@tonic-gate 				 * translated.
2510Sstevel@tonic-gate 				 */
2520Sstevel@tonic-gate 				(void) printf(gettext(" %s is enabled.\n"),
2530Sstevel@tonic-gate 				    "random");
2540Sstevel@tonic-gate 			else
2550Sstevel@tonic-gate 				(void) printf("\n");
2560Sstevel@tonic-gate 			return (SUCCESS);
2570Sstevel@tonic-gate 		} else {
2580Sstevel@tonic-gate 			cryptoerror(LOG_STDERR,
2590Sstevel@tonic-gate 			    gettext("%s does not exist."), provname);
2600Sstevel@tonic-gate 			return (FAILURE);
2610Sstevel@tonic-gate 		}
2620Sstevel@tonic-gate 	}
2630Sstevel@tonic-gate }
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 
2667968Sopensolaris@drydog.com /*
2677968Sopensolaris@drydog.com  * Disable a kernel hardware provider.
2687968Sopensolaris@drydog.com  * This implements the "cryptoadm disable" command for
2697968Sopensolaris@drydog.com  * kernel hardware providers.
2707968Sopensolaris@drydog.com  */
2710Sstevel@tonic-gate int
2720Sstevel@tonic-gate disable_kef_hardware(char *provname, boolean_t rndflag, boolean_t allflag,
2730Sstevel@tonic-gate     mechlist_t *dislist)
2740Sstevel@tonic-gate {
2757968Sopensolaris@drydog.com 	crypto_load_dev_disabled_t	*pload_dev_dis = NULL;
2767968Sopensolaris@drydog.com 	mechlist_t			*infolist = NULL;
2777968Sopensolaris@drydog.com 	entry_t				*pent = NULL;
2787968Sopensolaris@drydog.com 	boolean_t			new_dev_entry = B_FALSE;
2797968Sopensolaris@drydog.com 	char				devname[MAXNAMELEN];
2807968Sopensolaris@drydog.com 	int				inst_num;
2817968Sopensolaris@drydog.com 	int				count;
2827968Sopensolaris@drydog.com 	int				fd = -1;
2837968Sopensolaris@drydog.com 	int				rc = SUCCESS;
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	if (provname == NULL) {
2860Sstevel@tonic-gate 		return (FAILURE);
2870Sstevel@tonic-gate 	}
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	/*
2900Sstevel@tonic-gate 	 * Check if the provider is valid. If it is valid, get the number of
2910Sstevel@tonic-gate 	 * mechanisms also.
2920Sstevel@tonic-gate 	 */
2930Sstevel@tonic-gate 	if (check_hardware_provider(provname, devname, &inst_num, &count)
2940Sstevel@tonic-gate 	    == FAILURE) {
2950Sstevel@tonic-gate 		return (FAILURE);
2960Sstevel@tonic-gate 	}
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	/* Get the mechanism list for the kernel hardware provider */
2990Sstevel@tonic-gate 	if (get_dev_info(devname, inst_num, count, &infolist) == FAILURE) {
3000Sstevel@tonic-gate 		return (FAILURE);
3010Sstevel@tonic-gate 	}
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	/*
3040Sstevel@tonic-gate 	 * Get the entry of this hardware provider from the config file.
3050Sstevel@tonic-gate 	 * If there is no entry yet, create one for it.
3060Sstevel@tonic-gate 	 */
307*10500SHai-May.Chao@Sun.COM 	if ((pent = getent_kef(provname, NULL, NULL, NULL)) == NULL) {
3087968Sopensolaris@drydog.com 		if ((pent = create_entry(provname)) == NULL) {
3090Sstevel@tonic-gate 			cryptoerror(LOG_STDERR, gettext("out of memory."));
3100Sstevel@tonic-gate 			free_mechlist(infolist);
3110Sstevel@tonic-gate 			return (FAILURE);
3120Sstevel@tonic-gate 		}
3130Sstevel@tonic-gate 		new_dev_entry = B_TRUE;
3140Sstevel@tonic-gate 	}
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	/*
3170Sstevel@tonic-gate 	 * kCF treats random as an internal mechanism. So, we need to
3180Sstevel@tonic-gate 	 * filter it from the mechanism list here, if we are NOT disabling
3190Sstevel@tonic-gate 	 * or enabling the random feature. Note that we map random feature at
3200Sstevel@tonic-gate 	 * cryptoadm(1M) level to the "random" mechanism in kCF.
3210Sstevel@tonic-gate 	 */
3220Sstevel@tonic-gate 	if (!rndflag) {
3232860Smcpowers 		(void) filter_mechlist(&dislist, RANDOM);
3240Sstevel@tonic-gate 	}
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	/* Calculate the new disabled list */
3270Sstevel@tonic-gate 	if (disable_mechs(&pent, infolist, allflag, dislist) == FAILURE) {
3282860Smcpowers 		free_mechlist(infolist);
3290Sstevel@tonic-gate 		free_entry(pent);
3300Sstevel@tonic-gate 		return (FAILURE);
3310Sstevel@tonic-gate 	}
3322860Smcpowers 	free_mechlist(infolist);
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	/* If no mechanisms are to be disabled, return */
3350Sstevel@tonic-gate 	if (pent->dis_count == 0) {
3360Sstevel@tonic-gate 		free_entry(pent);
3370Sstevel@tonic-gate 		return (SUCCESS);
3380Sstevel@tonic-gate 	}
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	/* Update the config file with the new entry or the updated entry */
3410Sstevel@tonic-gate 	if (new_dev_entry) {
3420Sstevel@tonic-gate 		rc = update_kcfconf(pent, ADD_MODE);
3430Sstevel@tonic-gate 	} else {
3440Sstevel@tonic-gate 		rc = update_kcfconf(pent, MODIFY_MODE);
3450Sstevel@tonic-gate 	}
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	if (rc == FAILURE) {
3480Sstevel@tonic-gate 		free_entry(pent);
3490Sstevel@tonic-gate 		return (FAILURE);
3500Sstevel@tonic-gate 	}
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	/* Inform kernel about the new disabled mechanism list */
3530Sstevel@tonic-gate 	if ((pload_dev_dis = setup_dev_dis(pent)) == NULL) {
3540Sstevel@tonic-gate 		free_entry(pent);
3550Sstevel@tonic-gate 		return (FAILURE);
3560Sstevel@tonic-gate 	}
3570Sstevel@tonic-gate 	free_entry(pent);
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
3600Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
3610Sstevel@tonic-gate 		    ADMIN_IOCTL_DEVICE, strerror(errno));
3620Sstevel@tonic-gate 		free(pload_dev_dis);
3630Sstevel@tonic-gate 		return (FAILURE);
3640Sstevel@tonic-gate 	}
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis) == -1) {
3670Sstevel@tonic-gate 		cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl failed: %s",
3680Sstevel@tonic-gate 		    strerror(errno));
3690Sstevel@tonic-gate 		free(pload_dev_dis);
3700Sstevel@tonic-gate 		(void) close(fd);
3710Sstevel@tonic-gate 		return (FAILURE);
3720Sstevel@tonic-gate 	}
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) {
3750Sstevel@tonic-gate 		cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl return_value = "
3760Sstevel@tonic-gate 		    "%d", pload_dev_dis->dd_return_value);
3770Sstevel@tonic-gate 		free(pload_dev_dis);
3780Sstevel@tonic-gate 		(void) close(fd);
3790Sstevel@tonic-gate 		return (FAILURE);
3800Sstevel@tonic-gate 	}
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	free(pload_dev_dis);
3830Sstevel@tonic-gate 	(void) close(fd);
3840Sstevel@tonic-gate 	return (SUCCESS);
3850Sstevel@tonic-gate }
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 
3887968Sopensolaris@drydog.com /*
3897968Sopensolaris@drydog.com  * Disable a kernel software provider.
3907968Sopensolaris@drydog.com  * This implements the "cryptoadm disable" command for
3917968Sopensolaris@drydog.com  * kernel software providers.
3927968Sopensolaris@drydog.com  */
3930Sstevel@tonic-gate int
3940Sstevel@tonic-gate disable_kef_software(char *provname, boolean_t rndflag, boolean_t allflag,
3950Sstevel@tonic-gate     mechlist_t *dislist)
3960Sstevel@tonic-gate {
3970Sstevel@tonic-gate 	crypto_load_soft_disabled_t	*pload_soft_dis = NULL;
3987968Sopensolaris@drydog.com 	mechlist_t			*infolist = NULL;
3997968Sopensolaris@drydog.com 	entry_t				*pent = NULL;
4007968Sopensolaris@drydog.com 	entrylist_t			*phardlist = NULL;
4017968Sopensolaris@drydog.com 	entrylist_t			*psoftlist = NULL;
402*10500SHai-May.Chao@Sun.COM 	entrylist_t			*pfipslist = NULL;
4037968Sopensolaris@drydog.com 	boolean_t			in_kernel = B_FALSE;
4047968Sopensolaris@drydog.com 	int				fd = -1;
4057968Sopensolaris@drydog.com 	int				rc = SUCCESS;
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	if (provname == NULL) {
4080Sstevel@tonic-gate 		return (FAILURE);
4090Sstevel@tonic-gate 	}
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	/*
4120Sstevel@tonic-gate 	 * Check if the kernel software provider is currently unloaded.
4130Sstevel@tonic-gate 	 * If it is unloaded, return FAILURE, because the disable subcommand
4140Sstevel@tonic-gate 	 * can not perform on inactive (unloaded) providers.
4150Sstevel@tonic-gate 	 */
416*10500SHai-May.Chao@Sun.COM 	if (check_kernel_for_soft(provname, NULL, &in_kernel) ==
417*10500SHai-May.Chao@Sun.COM 	    FAILURE) {
4187968Sopensolaris@drydog.com 		return (FAILURE);
4197968Sopensolaris@drydog.com 	} else if (in_kernel == B_FALSE) {
4207968Sopensolaris@drydog.com 		cryptoerror(LOG_STDERR,
4217968Sopensolaris@drydog.com 		    gettext("%s is not loaded or does not exist."),
4227968Sopensolaris@drydog.com 		    provname);
4230Sstevel@tonic-gate 		return (FAILURE);
4247968Sopensolaris@drydog.com 	}
4257968Sopensolaris@drydog.com 
426*10500SHai-May.Chao@Sun.COM 	if (get_kcfconf_info(&phardlist, &psoftlist, &pfipslist) ==
427*10500SHai-May.Chao@Sun.COM 	    FAILURE) {
4287968Sopensolaris@drydog.com 		cryptoerror(LOG_ERR,
4297968Sopensolaris@drydog.com 		    "failed to retrieve the providers' "
4307968Sopensolaris@drydog.com 		    "information from the configuration file - %s.",
4317968Sopensolaris@drydog.com 		    _PATH_KCF_CONF);
4320Sstevel@tonic-gate 		return (FAILURE);
4330Sstevel@tonic-gate 	}
4340Sstevel@tonic-gate 
4357968Sopensolaris@drydog.com 	/*
4367968Sopensolaris@drydog.com 	 * Get the entry of this provider from the kcf.conf file, if any.
4377968Sopensolaris@drydog.com 	 * Otherwise, create a new kcf.conf entry for writing back to the file.
4387968Sopensolaris@drydog.com 	 */
439*10500SHai-May.Chao@Sun.COM 	pent = getent_kef(provname, phardlist, psoftlist, pfipslist);
4407968Sopensolaris@drydog.com 	if (pent == NULL) { /* create a new entry */
4417968Sopensolaris@drydog.com 		pent = create_entry(provname);
4427968Sopensolaris@drydog.com 		if (pent == NULL) {
4437968Sopensolaris@drydog.com 			cryptodebug("out of memory.");
4447968Sopensolaris@drydog.com 			rc = FAILURE;
4457968Sopensolaris@drydog.com 			goto out;
4467968Sopensolaris@drydog.com 		}
4470Sstevel@tonic-gate 	}
4480Sstevel@tonic-gate 
4497968Sopensolaris@drydog.com 	/* Get the mechanism list for the software provider from the kernel */
450*10500SHai-May.Chao@Sun.COM 	if (get_soft_info(provname, &infolist, phardlist, psoftlist,
451*10500SHai-May.Chao@Sun.COM 	    pfipslist) == FAILURE) {
4527968Sopensolaris@drydog.com 		rc = FAILURE;
4537968Sopensolaris@drydog.com 		goto out;
4547968Sopensolaris@drydog.com 	}
4557968Sopensolaris@drydog.com 
4567968Sopensolaris@drydog.com 	if ((infolist != NULL) && (infolist->name[0] != '\0')) {
4577968Sopensolaris@drydog.com 		/*
4587968Sopensolaris@drydog.com 		 * Replace the supportedlist from kcf.conf with possibly
4597968Sopensolaris@drydog.com 		 * more-up-to-date list from the kernel.  This is the case
4607968Sopensolaris@drydog.com 		 * for default software providers that had more mechanisms
4617968Sopensolaris@drydog.com 		 * added in the current version of the kernel.
4627968Sopensolaris@drydog.com 		 */
4637968Sopensolaris@drydog.com 		free_mechlist(pent->suplist);
4647968Sopensolaris@drydog.com 		pent->suplist = infolist;
4657968Sopensolaris@drydog.com 	}
4667968Sopensolaris@drydog.com 
4677968Sopensolaris@drydog.com 	/*
4687968Sopensolaris@drydog.com 	 * kCF treats random as an internal mechanism. So, we need to
4697968Sopensolaris@drydog.com 	 * filter it from the mechanism list here, if we are NOT disabling
4707968Sopensolaris@drydog.com 	 * or enabling the random feature. Note that we map random feature at
4717968Sopensolaris@drydog.com 	 * cryptoadm(1M) level to the "random" mechanism in kCF.
4727968Sopensolaris@drydog.com 	 */
4730Sstevel@tonic-gate 	if (!rndflag) {
4740Sstevel@tonic-gate 		(void) filter_mechlist(&infolist, RANDOM);
4750Sstevel@tonic-gate 	}
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	/* Calculate the new disabled list */
4780Sstevel@tonic-gate 	if (disable_mechs(&pent, infolist, allflag, dislist) == FAILURE) {
4797968Sopensolaris@drydog.com 		rc = FAILURE;
4807968Sopensolaris@drydog.com 		goto out;
4810Sstevel@tonic-gate 	}
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	/* Update the kcf.conf file with the updated entry */
4840Sstevel@tonic-gate 	if (update_kcfconf(pent, MODIFY_MODE) == FAILURE) {
4857968Sopensolaris@drydog.com 		rc = FAILURE;
4867968Sopensolaris@drydog.com 		goto out;
4870Sstevel@tonic-gate 	}
4880Sstevel@tonic-gate 
4897968Sopensolaris@drydog.com 	/* Setup argument to inform kernel about the new disabled list. */
4900Sstevel@tonic-gate 	if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) {
4917968Sopensolaris@drydog.com 		rc = FAILURE;
4927968Sopensolaris@drydog.com 		goto out;
4930Sstevel@tonic-gate 	}
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
4960Sstevel@tonic-gate 		cryptoerror(LOG_STDERR,
4970Sstevel@tonic-gate 		    gettext("failed to open %s for RW: %s"),
4980Sstevel@tonic-gate 		    ADMIN_IOCTL_DEVICE, strerror(errno));
4997968Sopensolaris@drydog.com 		rc = FAILURE;
5007968Sopensolaris@drydog.com 		goto out;
5010Sstevel@tonic-gate 	}
5020Sstevel@tonic-gate 
5037968Sopensolaris@drydog.com 	/* Inform kernel about the new disabled list. */
5040Sstevel@tonic-gate 	if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis) == -1) {
5050Sstevel@tonic-gate 		cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: %s",
5060Sstevel@tonic-gate 		    strerror(errno));
5077968Sopensolaris@drydog.com 		rc = FAILURE;
5087968Sopensolaris@drydog.com 		goto out;
5090Sstevel@tonic-gate 	}
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) {
5120Sstevel@tonic-gate 		cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl return_value = "
5130Sstevel@tonic-gate 		    "%d", pload_soft_dis->sd_return_value);
5147968Sopensolaris@drydog.com 		rc = FAILURE;
5157968Sopensolaris@drydog.com 		goto out;
5160Sstevel@tonic-gate 	}
5170Sstevel@tonic-gate 
5187968Sopensolaris@drydog.com out:
5197968Sopensolaris@drydog.com 	free_entrylist(phardlist);
5207968Sopensolaris@drydog.com 	free_entrylist(psoftlist);
5217968Sopensolaris@drydog.com 	free_mechlist(infolist);
5227968Sopensolaris@drydog.com 	free_entry(pent);
5230Sstevel@tonic-gate 	free(pload_soft_dis);
5247968Sopensolaris@drydog.com 	if (fd != -1)
5257968Sopensolaris@drydog.com 		(void) close(fd);
5267968Sopensolaris@drydog.com 	return (rc);
5270Sstevel@tonic-gate }
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 
5307968Sopensolaris@drydog.com /*
5317968Sopensolaris@drydog.com  * Enable a kernel software or hardware provider.
5327968Sopensolaris@drydog.com  * This implements the "cryptoadm enable" command for kernel providers.
5337968Sopensolaris@drydog.com  */
5340Sstevel@tonic-gate int
5350Sstevel@tonic-gate enable_kef(char *provname, boolean_t rndflag, boolean_t allflag,
5360Sstevel@tonic-gate     mechlist_t *mlist)
5370Sstevel@tonic-gate {
5380Sstevel@tonic-gate 	crypto_load_soft_disabled_t	*pload_soft_dis = NULL;
5390Sstevel@tonic-gate 	crypto_load_dev_disabled_t	*pload_dev_dis = NULL;
5407968Sopensolaris@drydog.com 	entry_t				*pent = NULL;
5417968Sopensolaris@drydog.com 	boolean_t			redo_flag = B_FALSE;
5427968Sopensolaris@drydog.com 	boolean_t			in_kernel = B_FALSE;
5437968Sopensolaris@drydog.com 	int				fd = -1;
5447968Sopensolaris@drydog.com 	int				rc = SUCCESS;
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 
5477968Sopensolaris@drydog.com 	/* Get the entry of this provider from the kcf.conf file, if any. */
548*10500SHai-May.Chao@Sun.COM 	pent = getent_kef(provname, NULL, NULL, NULL);
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 	if (is_device(provname)) {
5510Sstevel@tonic-gate 		if (pent == NULL) {
5520Sstevel@tonic-gate 			/*
5530Sstevel@tonic-gate 			 * This device doesn't have an entry in the config
5540Sstevel@tonic-gate 			 * file, therefore nothing is disabled.
5550Sstevel@tonic-gate 			 */
5560Sstevel@tonic-gate 			cryptoerror(LOG_STDERR, gettext(
5570Sstevel@tonic-gate 			    "all mechanisms are enabled already for %s."),
5580Sstevel@tonic-gate 			    provname);
5597968Sopensolaris@drydog.com 			free_entry(pent);
5600Sstevel@tonic-gate 			return (SUCCESS);
5610Sstevel@tonic-gate 		}
5620Sstevel@tonic-gate 	} else { /* a software module */
5637968Sopensolaris@drydog.com 		if (check_kernel_for_soft(provname, NULL, &in_kernel) ==
5647968Sopensolaris@drydog.com 		    FAILURE) {
5657968Sopensolaris@drydog.com 			free_entry(pent);
5660Sstevel@tonic-gate 			return (FAILURE);
5677968Sopensolaris@drydog.com 		} else if (in_kernel == B_FALSE) {
5687968Sopensolaris@drydog.com 			cryptoerror(LOG_STDERR, gettext("%s does not exist."),
5697968Sopensolaris@drydog.com 			    provname);
5707968Sopensolaris@drydog.com 			free_entry(pent);
5717968Sopensolaris@drydog.com 			return (FAILURE);
5727968Sopensolaris@drydog.com 		} else if ((pent == NULL) || (pent->dis_count == 0)) {
5730Sstevel@tonic-gate 			/* nothing to be enabled. */
5740Sstevel@tonic-gate 			cryptoerror(LOG_STDERR, gettext(
5750Sstevel@tonic-gate 			    "all mechanisms are enabled already for %s."),
5760Sstevel@tonic-gate 			    provname);
5770Sstevel@tonic-gate 			free_entry(pent);
5780Sstevel@tonic-gate 			return (SUCCESS);
5790Sstevel@tonic-gate 		}
5800Sstevel@tonic-gate 	}
5810Sstevel@tonic-gate 
5827968Sopensolaris@drydog.com 	/*
5837968Sopensolaris@drydog.com 	 * kCF treats random as an internal mechanism. So, we need to
5847968Sopensolaris@drydog.com 	 * filter it from the mechanism list here, if we are NOT disabling
5857968Sopensolaris@drydog.com 	 * or enabling the random feature. Note that we map random feature at
5867968Sopensolaris@drydog.com 	 * cryptoadm(1M) level to the "random" mechanism in kCF.
5877968Sopensolaris@drydog.com 	 */
5880Sstevel@tonic-gate 	if (!rndflag) {
5890Sstevel@tonic-gate 		redo_flag = filter_mechlist(&pent->dislist, RANDOM);
5900Sstevel@tonic-gate 		if (redo_flag)
5910Sstevel@tonic-gate 			pent->dis_count--;
5920Sstevel@tonic-gate 	}
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	/* Update the entry by enabling mechanisms for this provider */
5950Sstevel@tonic-gate 	if ((rc = enable_mechs(&pent, allflag, mlist)) != SUCCESS) {
5960Sstevel@tonic-gate 		free_entry(pent);
5970Sstevel@tonic-gate 		return (rc);
5980Sstevel@tonic-gate 	}
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	if (redo_flag) {
6010Sstevel@tonic-gate 		mechlist_t *tmp;
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 		if ((tmp = create_mech(RANDOM)) == NULL) {
6040Sstevel@tonic-gate 			free_entry(pent);
6050Sstevel@tonic-gate 			return (FAILURE);
6060Sstevel@tonic-gate 		}
6070Sstevel@tonic-gate 		tmp->next = pent->dislist;
6080Sstevel@tonic-gate 		pent->dislist = tmp;
6090Sstevel@tonic-gate 		pent->dis_count++;
6100Sstevel@tonic-gate 	}
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 	/*
6137968Sopensolaris@drydog.com 	 * Update the kcf.conf file with the updated entry.
6140Sstevel@tonic-gate 	 * For a hardware provider, if there is no more disabled mechanism,
6157968Sopensolaris@drydog.com 	 * remove the entire kcf.conf entry.
6160Sstevel@tonic-gate 	 */
6170Sstevel@tonic-gate 	if (is_device(pent->name) && (pent->dis_count == 0)) {
6180Sstevel@tonic-gate 		rc = update_kcfconf(pent, DELETE_MODE);
6190Sstevel@tonic-gate 	} else {
6200Sstevel@tonic-gate 		rc = update_kcfconf(pent, MODIFY_MODE);
6210Sstevel@tonic-gate 	}
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	if (rc == FAILURE) {
6240Sstevel@tonic-gate 		free_entry(pent);
6250Sstevel@tonic-gate 		return (FAILURE);
6260Sstevel@tonic-gate 	}
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	/* Inform Kernel about the policy change */
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
6320Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
6330Sstevel@tonic-gate 		    ADMIN_IOCTL_DEVICE, strerror(errno));
6347968Sopensolaris@drydog.com 		free_entry(pent);
6350Sstevel@tonic-gate 		return (FAILURE);
6360Sstevel@tonic-gate 	}
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	if (is_device(provname)) {
6390Sstevel@tonic-gate 		/*  LOAD_DEV_DISABLED */
6400Sstevel@tonic-gate 		if ((pload_dev_dis = setup_dev_dis(pent)) == NULL) {
6417968Sopensolaris@drydog.com 			free_entry(pent);
6420Sstevel@tonic-gate 			return (FAILURE);
6430Sstevel@tonic-gate 		}
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 		if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis) == -1) {
6460Sstevel@tonic-gate 			cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl failed: "
6470Sstevel@tonic-gate 			    "%s", strerror(errno));
6487968Sopensolaris@drydog.com 			free_entry(pent);
6490Sstevel@tonic-gate 			free(pload_dev_dis);
6500Sstevel@tonic-gate 			(void) close(fd);
6510Sstevel@tonic-gate 			return (FAILURE);
6520Sstevel@tonic-gate 		}
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 		if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) {
6550Sstevel@tonic-gate 			cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl "
6560Sstevel@tonic-gate 			    "return_value = %d",
6570Sstevel@tonic-gate 			    pload_dev_dis->dd_return_value);
6587968Sopensolaris@drydog.com 			free_entry(pent);
6590Sstevel@tonic-gate 			free(pload_dev_dis);
6600Sstevel@tonic-gate 			(void) close(fd);
6610Sstevel@tonic-gate 			return (FAILURE);
6620Sstevel@tonic-gate 		}
6630Sstevel@tonic-gate 
6647968Sopensolaris@drydog.com 	} else { /* a software module */
6650Sstevel@tonic-gate 		/* LOAD_SOFT_DISABLED */
6660Sstevel@tonic-gate 		if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) {
6677968Sopensolaris@drydog.com 			free_entry(pent);
6680Sstevel@tonic-gate 			return (FAILURE);
6690Sstevel@tonic-gate 		}
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 		if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis)
6720Sstevel@tonic-gate 		    == -1) {
6730Sstevel@tonic-gate 			cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: "
6740Sstevel@tonic-gate 			    "%s", strerror(errno));
6757968Sopensolaris@drydog.com 			free_entry(pent);
6760Sstevel@tonic-gate 			free(pload_soft_dis);
6770Sstevel@tonic-gate 			(void) close(fd);
6780Sstevel@tonic-gate 			return (FAILURE);
6790Sstevel@tonic-gate 		}
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 		if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) {
6820Sstevel@tonic-gate 			cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl "
6830Sstevel@tonic-gate 			    "return_value = %d",
6840Sstevel@tonic-gate 			    pload_soft_dis->sd_return_value);
6857968Sopensolaris@drydog.com 			free_entry(pent);
6860Sstevel@tonic-gate 			free(pload_soft_dis);
6870Sstevel@tonic-gate 			(void) close(fd);
6880Sstevel@tonic-gate 			return (FAILURE);
6890Sstevel@tonic-gate 		}
6900Sstevel@tonic-gate 	}
6910Sstevel@tonic-gate 
6927968Sopensolaris@drydog.com 	free_entry(pent);
6937968Sopensolaris@drydog.com 	free(pload_soft_dis);
6940Sstevel@tonic-gate 	(void) close(fd);
6950Sstevel@tonic-gate 	return (SUCCESS);
6960Sstevel@tonic-gate }
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate /*
7000Sstevel@tonic-gate  * Install a software module with the specified mechanism list into the system.
7010Sstevel@tonic-gate  * This routine adds an entry into the config file for this software module
7020Sstevel@tonic-gate  * first, then makes a CRYPTO_LOAD_SOFT_CONFIG ioctl call to inform kernel
7030Sstevel@tonic-gate  * about the new addition.
7040Sstevel@tonic-gate  */
7050Sstevel@tonic-gate int
7060Sstevel@tonic-gate install_kef(char *provname, mechlist_t *mlist)
7070Sstevel@tonic-gate {
7080Sstevel@tonic-gate 	crypto_load_soft_config_t	*pload_soft_conf = NULL;
7097968Sopensolaris@drydog.com 	boolean_t			found;
7107968Sopensolaris@drydog.com 	entry_t				*pent = NULL;
7117968Sopensolaris@drydog.com 	FILE				*pfile = NULL;
7127968Sopensolaris@drydog.com 	FILE				*pfile_tmp = NULL;
7137968Sopensolaris@drydog.com 	char				tmpfile_name[MAXPATHLEN];
7147968Sopensolaris@drydog.com 	char				*ptr;
7157968Sopensolaris@drydog.com 	char				*str;
7167968Sopensolaris@drydog.com 	char				*name;
7177968Sopensolaris@drydog.com 	char				buffer[BUFSIZ];
7187968Sopensolaris@drydog.com 	char				buffer2[BUFSIZ];
7197968Sopensolaris@drydog.com 	int				found_count;
7207968Sopensolaris@drydog.com 	int				fd = -1;
7217968Sopensolaris@drydog.com 	int				rc = SUCCESS;
7227968Sopensolaris@drydog.com 	int				err;
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	if ((provname == NULL) || (mlist == NULL)) {
7250Sstevel@tonic-gate 		return (FAILURE);
7260Sstevel@tonic-gate 	}
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	/* Check if the provider already exists */
729*10500SHai-May.Chao@Sun.COM 	if ((pent = getent_kef(provname, NULL, NULL, NULL)) != NULL) {
7300Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext("%s exists already."),
7310Sstevel@tonic-gate 		    provname);
7320Sstevel@tonic-gate 		free_entry(pent);
7330Sstevel@tonic-gate 		return (FAILURE);
7340Sstevel@tonic-gate 	}
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	/* Create an entry with provname and mlist. */
7377968Sopensolaris@drydog.com 	if ((pent = create_entry(provname)) == NULL) {
7380Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext("out of memory."));
7390Sstevel@tonic-gate 		return (FAILURE);
7400Sstevel@tonic-gate 	}
7410Sstevel@tonic-gate 	pent->sup_count = get_mech_count(mlist);
7420Sstevel@tonic-gate 	pent->suplist = mlist;
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	/* Append an entry for this software module to the kcf.conf file. */
7450Sstevel@tonic-gate 	if ((str = ent2str(pent)) == NULL) {
7460Sstevel@tonic-gate 		free_entry(pent);
7470Sstevel@tonic-gate 		return (FAILURE);
7480Sstevel@tonic-gate 	}
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) {
7510Sstevel@tonic-gate 		err = errno;
7520Sstevel@tonic-gate 		cryptoerror(LOG_STDERR,
7530Sstevel@tonic-gate 		    gettext("failed to update the configuration - %s"),
7540Sstevel@tonic-gate 		    strerror(err));
7550Sstevel@tonic-gate 		cryptodebug("failed to open %s for write.", _PATH_KCF_CONF);
7560Sstevel@tonic-gate 		free_entry(pent);
7570Sstevel@tonic-gate 		return (FAILURE);
7580Sstevel@tonic-gate 	}
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
7610Sstevel@tonic-gate 		err = errno;
7620Sstevel@tonic-gate 		cryptoerror(LOG_STDERR,
7630Sstevel@tonic-gate 		    gettext("failed to lock the configuration - %s"),
7640Sstevel@tonic-gate 		    strerror(err));
7650Sstevel@tonic-gate 		free_entry(pent);
7660Sstevel@tonic-gate 		(void) fclose(pfile);
7670Sstevel@tonic-gate 		return (FAILURE);
7680Sstevel@tonic-gate 	}
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	/*
7710Sstevel@tonic-gate 	 * Create a temporary file in the /etc/crypto directory.
7720Sstevel@tonic-gate 	 */
7730Sstevel@tonic-gate 	(void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
7740Sstevel@tonic-gate 	if (mkstemp(tmpfile_name) == -1) {
7750Sstevel@tonic-gate 		err = errno;
7760Sstevel@tonic-gate 		cryptoerror(LOG_STDERR,
7770Sstevel@tonic-gate 		    gettext("failed to create a temporary file - %s"),
7780Sstevel@tonic-gate 		    strerror(err));
7790Sstevel@tonic-gate 		free_entry(pent);
7800Sstevel@tonic-gate 		(void) fclose(pfile);
7810Sstevel@tonic-gate 		return (FAILURE);
7820Sstevel@tonic-gate 	}
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 	if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
7850Sstevel@tonic-gate 		err = errno;
7860Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
7870Sstevel@tonic-gate 		    tmpfile_name, strerror(err));
7880Sstevel@tonic-gate 		free_entry(pent);
7890Sstevel@tonic-gate 		(void) fclose(pfile);
7900Sstevel@tonic-gate 		return (FAILURE);
7910Sstevel@tonic-gate 	}
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 	/*
7950Sstevel@tonic-gate 	 * Loop thru the config file. If the provider was reserved within a
7960Sstevel@tonic-gate 	 * package bracket, just uncomment it.  Otherwise, append it at
7970Sstevel@tonic-gate 	 * the end.  The resulting file will be saved in the temp file first.
7980Sstevel@tonic-gate 	 */
7990Sstevel@tonic-gate 	found_count = 0;
8000Sstevel@tonic-gate 	rc = SUCCESS;
8010Sstevel@tonic-gate 	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
8020Sstevel@tonic-gate 		found = B_FALSE;
8030Sstevel@tonic-gate 		if (buffer[0] == '#') {
8040Sstevel@tonic-gate 			(void) strlcpy(buffer2, buffer, BUFSIZ);
8050Sstevel@tonic-gate 			ptr = buffer2;
8060Sstevel@tonic-gate 			ptr++;
8070Sstevel@tonic-gate 			if ((name = strtok(ptr, SEP_COLON)) == NULL) {
8080Sstevel@tonic-gate 				rc = FAILURE;
8090Sstevel@tonic-gate 				break;
8100Sstevel@tonic-gate 			} else if (strcmp(provname, name) == 0) {
8110Sstevel@tonic-gate 				found = B_TRUE;
8120Sstevel@tonic-gate 				found_count++;
8130Sstevel@tonic-gate 			}
8140Sstevel@tonic-gate 		}
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 		if (found == B_FALSE) {
8170Sstevel@tonic-gate 			if (fputs(buffer, pfile_tmp) == EOF) {
8180Sstevel@tonic-gate 				rc = FAILURE;
8190Sstevel@tonic-gate 			}
8200Sstevel@tonic-gate 		} else {
8210Sstevel@tonic-gate 			if (found_count == 1) {
8220Sstevel@tonic-gate 				if (fputs(str, pfile_tmp) == EOF) {
8230Sstevel@tonic-gate 					rc = FAILURE;
8240Sstevel@tonic-gate 				}
8250Sstevel@tonic-gate 			} else {
8260Sstevel@tonic-gate 				/*
8270Sstevel@tonic-gate 				 * Found a second entry with #libname.
8287968Sopensolaris@drydog.com 				 * Should not happen. The kcf.conf file
8290Sstevel@tonic-gate 				 * is corrupted. Give a warning and skip
8300Sstevel@tonic-gate 				 * this entry.
8310Sstevel@tonic-gate 				 */
8320Sstevel@tonic-gate 				cryptoerror(LOG_STDERR, gettext(
8330Sstevel@tonic-gate 				    "(Warning) Found an additional reserved "
8340Sstevel@tonic-gate 				    "entry for %s."), provname);
8350Sstevel@tonic-gate 			}
8360Sstevel@tonic-gate 		}
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 		if (rc == FAILURE) {
8390Sstevel@tonic-gate 			break;
8400Sstevel@tonic-gate 		}
8410Sstevel@tonic-gate 	}
8420Sstevel@tonic-gate 	(void) fclose(pfile);
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 	if (rc == FAILURE) {
8450Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext("write error."));
8460Sstevel@tonic-gate 		(void) fclose(pfile_tmp);
8470Sstevel@tonic-gate 		if (unlink(tmpfile_name) != 0) {
8480Sstevel@tonic-gate 			err = errno;
8490Sstevel@tonic-gate 			cryptoerror(LOG_STDERR, gettext(
8500Sstevel@tonic-gate 			    "(Warning) failed to remove %s: %s"), tmpfile_name,
8510Sstevel@tonic-gate 			    strerror(err));
8520Sstevel@tonic-gate 		}
8530Sstevel@tonic-gate 		free_entry(pent);
8540Sstevel@tonic-gate 		return (FAILURE);
8550Sstevel@tonic-gate 	}
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	if (found_count == 0) {
8580Sstevel@tonic-gate 		/*
8590Sstevel@tonic-gate 		 * This libname was not in package before, append it to the
8600Sstevel@tonic-gate 		 * end of the temp file.
8610Sstevel@tonic-gate 		 */
8620Sstevel@tonic-gate 		if (fputs(str, pfile_tmp) == EOF) {
8630Sstevel@tonic-gate 			cryptoerror(LOG_STDERR, gettext(
8640Sstevel@tonic-gate 			    "failed to write to %s: %s"), tmpfile_name,
8650Sstevel@tonic-gate 			    strerror(errno));
8660Sstevel@tonic-gate 			(void) fclose(pfile_tmp);
8670Sstevel@tonic-gate 			if (unlink(tmpfile_name) != 0) {
8680Sstevel@tonic-gate 				err = errno;
8690Sstevel@tonic-gate 				cryptoerror(LOG_STDERR, gettext(
8700Sstevel@tonic-gate 				    "(Warning) failed to remove %s: %s"),
8710Sstevel@tonic-gate 				    tmpfile_name, strerror(err));
8720Sstevel@tonic-gate 			}
8730Sstevel@tonic-gate 			free_entry(pent);
8740Sstevel@tonic-gate 			return (FAILURE);
8750Sstevel@tonic-gate 		}
8760Sstevel@tonic-gate 	}
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	if (fclose(pfile_tmp) != 0) {
8790Sstevel@tonic-gate 		err = errno;
8800Sstevel@tonic-gate 		cryptoerror(LOG_STDERR,
8810Sstevel@tonic-gate 		    gettext("failed to close %s: %s"), tmpfile_name,
8820Sstevel@tonic-gate 		    strerror(err));
8837968Sopensolaris@drydog.com 		free_entry(pent);
8840Sstevel@tonic-gate 		return (FAILURE);
8850Sstevel@tonic-gate 	}
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) {
8880Sstevel@tonic-gate 		err = errno;
8890Sstevel@tonic-gate 		cryptoerror(LOG_STDERR,
8900Sstevel@tonic-gate 		    gettext("failed to update the configuration - %s"),
8917968Sopensolaris@drydog.com 		    strerror(err));
8920Sstevel@tonic-gate 		cryptodebug("failed to rename %s to %s: %s", tmpfile_name,
8930Sstevel@tonic-gate 		    _PATH_KCF_CONF, strerror(err));
8940Sstevel@tonic-gate 		rc = FAILURE;
8950Sstevel@tonic-gate 	} else if (chmod(_PATH_KCF_CONF,
8960Sstevel@tonic-gate 	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
8970Sstevel@tonic-gate 		err = errno;
8980Sstevel@tonic-gate 		cryptoerror(LOG_STDERR,
8990Sstevel@tonic-gate 		    gettext("failed to update the configuration - %s"),
9000Sstevel@tonic-gate 		    strerror(err));
9010Sstevel@tonic-gate 		cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF,
9020Sstevel@tonic-gate 		    strerror(err));
9030Sstevel@tonic-gate 		rc = FAILURE;
9040Sstevel@tonic-gate 	} else {
9050Sstevel@tonic-gate 		rc = SUCCESS;
9060Sstevel@tonic-gate 	}
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate 	if (rc == FAILURE) {
9090Sstevel@tonic-gate 		if (unlink(tmpfile_name) != 0) {
9100Sstevel@tonic-gate 			err = errno;
9110Sstevel@tonic-gate 			cryptoerror(LOG_STDERR, gettext(
9120Sstevel@tonic-gate 			    "(Warning) failed to remove %s: %s"),
9130Sstevel@tonic-gate 			    tmpfile_name, strerror(err));
9140Sstevel@tonic-gate 		}
9157968Sopensolaris@drydog.com 		free_entry(pent);
9160Sstevel@tonic-gate 		return (FAILURE);
9170Sstevel@tonic-gate 	}
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	/* Inform kernel of this new software module. */
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 	if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) {
9230Sstevel@tonic-gate 		free_entry(pent);
9240Sstevel@tonic-gate 		return (FAILURE);
9250Sstevel@tonic-gate 	}
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
9280Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
9290Sstevel@tonic-gate 		    ADMIN_IOCTL_DEVICE, strerror(errno));
9300Sstevel@tonic-gate 		free_entry(pent);
9310Sstevel@tonic-gate 		free(pload_soft_conf);
9320Sstevel@tonic-gate 		return (FAILURE);
9330Sstevel@tonic-gate 	}
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG, pload_soft_conf) == -1) {
9360Sstevel@tonic-gate 		cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s",
9370Sstevel@tonic-gate 		    strerror(errno));
9380Sstevel@tonic-gate 		free_entry(pent);
9390Sstevel@tonic-gate 		free(pload_soft_conf);
9400Sstevel@tonic-gate 		(void) close(fd);
9410Sstevel@tonic-gate 		return (FAILURE);
9420Sstevel@tonic-gate 	}
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 	if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) {
9450Sstevel@tonic-gate 		cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed, "
9460Sstevel@tonic-gate 		    "return_value = %d", pload_soft_conf->sc_return_value);
9470Sstevel@tonic-gate 		free_entry(pent);
9480Sstevel@tonic-gate 		free(pload_soft_conf);
9490Sstevel@tonic-gate 		(void) close(fd);
9500Sstevel@tonic-gate 		return (FAILURE);
9510Sstevel@tonic-gate 	}
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 	free_entry(pent);
9540Sstevel@tonic-gate 	free(pload_soft_conf);
9550Sstevel@tonic-gate 	(void) close(fd);
9560Sstevel@tonic-gate 	return (SUCCESS);
9570Sstevel@tonic-gate }
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate /*
9600Sstevel@tonic-gate  * Uninstall the software module. This routine first unloads the software
9610Sstevel@tonic-gate  * module with 3 ioctl calls, then deletes its entry from the config file.
9620Sstevel@tonic-gate  * Removing an entry from the config file needs to be done last to ensure
9630Sstevel@tonic-gate  * that there is still an entry if the earlier unload failed for any reason.
9640Sstevel@tonic-gate  */
9650Sstevel@tonic-gate int
9660Sstevel@tonic-gate uninstall_kef(char *provname)
9670Sstevel@tonic-gate {
9687968Sopensolaris@drydog.com 	entry_t		*pent = NULL;
9697968Sopensolaris@drydog.com 	int		rc = SUCCESS;
9707968Sopensolaris@drydog.com 	boolean_t	in_kernel = B_FALSE;
9717968Sopensolaris@drydog.com 	boolean_t	in_kcfconf = B_FALSE;
9727968Sopensolaris@drydog.com 	int		fd = -1;
9737968Sopensolaris@drydog.com 	crypto_load_soft_config_t *pload_soft_conf = NULL;
9740Sstevel@tonic-gate 
9757968Sopensolaris@drydog.com 	/* Check to see if the provider exists first. */
9767968Sopensolaris@drydog.com 	if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) {
9770Sstevel@tonic-gate 		return (FAILURE);
9787968Sopensolaris@drydog.com 	} else if (in_kernel == B_FALSE) {
9797968Sopensolaris@drydog.com 		cryptoerror(LOG_STDERR, gettext("%s does not exist."),
9807968Sopensolaris@drydog.com 		    provname);
9810Sstevel@tonic-gate 		return (FAILURE);
9820Sstevel@tonic-gate 	}
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 	/*
9857968Sopensolaris@drydog.com 	 * If it is loaded, unload it first.  This does 2 ioctl calls:
9867968Sopensolaris@drydog.com 	 * CRYPTO_UNLOAD_SOFT_MODULE and CRYPTO_LOAD_SOFT_DISABLED.
9870Sstevel@tonic-gate 	 */
9887968Sopensolaris@drydog.com 	if (unload_kef_soft(provname) == FAILURE) {
9890Sstevel@tonic-gate 		cryptoerror(LOG_STDERR,
9907968Sopensolaris@drydog.com 		    gettext("failed to unload %s during uninstall.\n"),
9917968Sopensolaris@drydog.com 		    provname);
9920Sstevel@tonic-gate 		return (FAILURE);
9930Sstevel@tonic-gate 	}
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate 	/*
9967968Sopensolaris@drydog.com 	 * Inform kernel to remove the configuration of this software module.
9970Sstevel@tonic-gate 	 */
9980Sstevel@tonic-gate 
9997968Sopensolaris@drydog.com 	/* Setup ioctl() parameter */
1000*10500SHai-May.Chao@Sun.COM 	pent = getent_kef(provname, NULL, NULL, NULL);
10017968Sopensolaris@drydog.com 	if (pent != NULL) { /* in kcf.conf */
10027968Sopensolaris@drydog.com 		in_kcfconf = B_TRUE;
10037968Sopensolaris@drydog.com 		free_mechlist(pent->suplist);
10047968Sopensolaris@drydog.com 		pent->suplist = NULL;
10057968Sopensolaris@drydog.com 		pent->sup_count = 0;
10067968Sopensolaris@drydog.com 	} else if ((pent = create_entry(provname)) == NULL) {
10077968Sopensolaris@drydog.com 		cryptoerror(LOG_STDERR, gettext("out of memory."));
10087968Sopensolaris@drydog.com 		return (FAILURE);
10097968Sopensolaris@drydog.com 	}
10107968Sopensolaris@drydog.com 	if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) {
10117968Sopensolaris@drydog.com 		free_entry(pent);
10127968Sopensolaris@drydog.com 		return (FAILURE);
10130Sstevel@tonic-gate 	}
10140Sstevel@tonic-gate 
10157968Sopensolaris@drydog.com 	/* Open the /dev/cryptoadm device */
10167968Sopensolaris@drydog.com 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
10177968Sopensolaris@drydog.com 		int	err = errno;
10187968Sopensolaris@drydog.com 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
10197968Sopensolaris@drydog.com 		    ADMIN_IOCTL_DEVICE, strerror(err));
10207968Sopensolaris@drydog.com 		free_entry(pent);
10217968Sopensolaris@drydog.com 		free(pload_soft_conf);
10227968Sopensolaris@drydog.com 		return (FAILURE);
10237968Sopensolaris@drydog.com 	}
10247968Sopensolaris@drydog.com 
10257968Sopensolaris@drydog.com 	if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG,
10267968Sopensolaris@drydog.com 	    pload_soft_conf) == -1) {
10277968Sopensolaris@drydog.com 		cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s",
10287968Sopensolaris@drydog.com 		    strerror(errno));
10297968Sopensolaris@drydog.com 		free_entry(pent);
10307968Sopensolaris@drydog.com 		free(pload_soft_conf);
10317968Sopensolaris@drydog.com 		(void) close(fd);
10320Sstevel@tonic-gate 		return (FAILURE);
10330Sstevel@tonic-gate 	}
10340Sstevel@tonic-gate 
10357968Sopensolaris@drydog.com 	if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) {
10367968Sopensolaris@drydog.com 		cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl = return_value = %d",
10377968Sopensolaris@drydog.com 		    pload_soft_conf->sc_return_value);
10387968Sopensolaris@drydog.com 		free_entry(pent);
10397968Sopensolaris@drydog.com 		free(pload_soft_conf);
10407968Sopensolaris@drydog.com 		(void) close(fd);
10410Sstevel@tonic-gate 		return (FAILURE);
10420Sstevel@tonic-gate 	}
10430Sstevel@tonic-gate 
10447968Sopensolaris@drydog.com 	/* ioctl cleanup */
10457968Sopensolaris@drydog.com 	free(pload_soft_conf);
10467968Sopensolaris@drydog.com 	(void) close(fd);
10477968Sopensolaris@drydog.com 
10487968Sopensolaris@drydog.com 
10497968Sopensolaris@drydog.com 	/* Finally, remove entry from kcf.conf, if present */
10507968Sopensolaris@drydog.com 	if (in_kcfconf && (pent != NULL)) {
10517968Sopensolaris@drydog.com 		rc = update_kcfconf(pent, DELETE_MODE);
10520Sstevel@tonic-gate 	}
10530Sstevel@tonic-gate 
10547968Sopensolaris@drydog.com 	free_entry(pent);
10550Sstevel@tonic-gate 	return (rc);
10560Sstevel@tonic-gate }
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 
10597968Sopensolaris@drydog.com /*
10607968Sopensolaris@drydog.com  * Implement the "cryptoadm refresh" command for global zones.
10617968Sopensolaris@drydog.com  * That is, send the current contents of kcf.conf to the kernel via ioctl().
10627968Sopensolaris@drydog.com  */
10630Sstevel@tonic-gate int
10640Sstevel@tonic-gate refresh(void)
10650Sstevel@tonic-gate {
10660Sstevel@tonic-gate 	crypto_load_soft_config_t	*pload_soft_conf = NULL;
10670Sstevel@tonic-gate 	crypto_load_soft_disabled_t	*pload_soft_dis = NULL;
10680Sstevel@tonic-gate 	crypto_load_dev_disabled_t	*pload_dev_dis = NULL;
10697968Sopensolaris@drydog.com 	entrylist_t			*pdevlist = NULL;
10707968Sopensolaris@drydog.com 	entrylist_t			*psoftlist = NULL;
1071*10500SHai-May.Chao@Sun.COM 	entrylist_t			*pfipslist = NULL;
10727968Sopensolaris@drydog.com 	entrylist_t			*ptr;
10737968Sopensolaris@drydog.com 	int				fd = -1;
10747968Sopensolaris@drydog.com 	int				rc = SUCCESS;
10757968Sopensolaris@drydog.com 	int				err;
10760Sstevel@tonic-gate 
1077*10500SHai-May.Chao@Sun.COM 	if (get_kcfconf_info(&pdevlist, &psoftlist, &pfipslist) ==
1078*10500SHai-May.Chao@Sun.COM 	    FAILURE) {
10790Sstevel@tonic-gate 		cryptoerror(LOG_ERR, "failed to retrieve the providers' "
10800Sstevel@tonic-gate 		    "information from the configuration file - %s.",
10810Sstevel@tonic-gate 		    _PATH_KCF_CONF);
10820Sstevel@tonic-gate 		return (FAILURE);
10830Sstevel@tonic-gate 	}
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
10860Sstevel@tonic-gate 		err = errno;
10870Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
10880Sstevel@tonic-gate 		    ADMIN_IOCTL_DEVICE, strerror(err));
10890Sstevel@tonic-gate 		free(psoftlist);
10900Sstevel@tonic-gate 		free(pdevlist);
10910Sstevel@tonic-gate 		return (FAILURE);
10920Sstevel@tonic-gate 	}
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 	/*
10957968Sopensolaris@drydog.com 	 * For each software provider module, pass two sets of information to
10967968Sopensolaris@drydog.com 	 * the kernel: the supported list and the disabled list.
10970Sstevel@tonic-gate 	 */
10987968Sopensolaris@drydog.com 	for (ptr = psoftlist; ptr != NULL; ptr = ptr->next) {
10997968Sopensolaris@drydog.com 		entry_t		*pent = ptr->pent;
11007968Sopensolaris@drydog.com 
11010Sstevel@tonic-gate 		/* load the supported list */
11027968Sopensolaris@drydog.com 		if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) {
11037968Sopensolaris@drydog.com 			cryptodebug("setup_soft_conf() failed");
11040Sstevel@tonic-gate 			rc = FAILURE;
11050Sstevel@tonic-gate 			break;
11060Sstevel@tonic-gate 		}
11070Sstevel@tonic-gate 
11087968Sopensolaris@drydog.com 		if (!pent->load) { /* unloaded--mark as loaded */
11097968Sopensolaris@drydog.com 			pent->load = B_TRUE;
11107968Sopensolaris@drydog.com 			rc = update_kcfconf(pent, MODIFY_MODE);
11117968Sopensolaris@drydog.com 			if (rc != SUCCESS) {
11127968Sopensolaris@drydog.com 				free(pload_soft_conf);
11137968Sopensolaris@drydog.com 				break;
11147968Sopensolaris@drydog.com 			}
11157968Sopensolaris@drydog.com 		}
11167968Sopensolaris@drydog.com 
11170Sstevel@tonic-gate 		if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG, pload_soft_conf)
11180Sstevel@tonic-gate 		    == -1) {
11190Sstevel@tonic-gate 			cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s",
11200Sstevel@tonic-gate 			    strerror(errno));
11210Sstevel@tonic-gate 			free(pload_soft_conf);
11220Sstevel@tonic-gate 			rc = FAILURE;
11230Sstevel@tonic-gate 			break;
11240Sstevel@tonic-gate 		}
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 		if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) {
11270Sstevel@tonic-gate 			cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl "
11280Sstevel@tonic-gate 			    "return_value = %d",
11290Sstevel@tonic-gate 			    pload_soft_conf->sc_return_value);
11300Sstevel@tonic-gate 			free(pload_soft_conf);
11310Sstevel@tonic-gate 			rc = FAILURE;
11320Sstevel@tonic-gate 			break;
11330Sstevel@tonic-gate 		}
11340Sstevel@tonic-gate 
11357968Sopensolaris@drydog.com 		free(pload_soft_conf);
11367968Sopensolaris@drydog.com 
11370Sstevel@tonic-gate 		/* load the disabled list */
11380Sstevel@tonic-gate 		if (ptr->pent->dis_count != 0) {
11390Sstevel@tonic-gate 			pload_soft_dis = setup_soft_dis(ptr->pent);
11400Sstevel@tonic-gate 			if (pload_soft_dis == NULL) {
11417968Sopensolaris@drydog.com 				cryptodebug("setup_soft_dis() failed");
11427968Sopensolaris@drydog.com 				free(pload_soft_dis);
11430Sstevel@tonic-gate 				rc = FAILURE;
11440Sstevel@tonic-gate 				break;
11450Sstevel@tonic-gate 			}
11460Sstevel@tonic-gate 
11470Sstevel@tonic-gate 			if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED,
11480Sstevel@tonic-gate 			    pload_soft_dis) == -1) {
11490Sstevel@tonic-gate 				cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl "
11500Sstevel@tonic-gate 				    "failed: %s", strerror(errno));
11510Sstevel@tonic-gate 				free(pload_soft_dis);
11520Sstevel@tonic-gate 				rc = FAILURE;
11530Sstevel@tonic-gate 				break;
11540Sstevel@tonic-gate 			}
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 			if (pload_soft_dis->sd_return_value !=
11570Sstevel@tonic-gate 			    CRYPTO_SUCCESS) {
11580Sstevel@tonic-gate 				cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl "
11590Sstevel@tonic-gate 				    "return_value = %d",
11600Sstevel@tonic-gate 				    pload_soft_dis->sd_return_value);
11610Sstevel@tonic-gate 				free(pload_soft_dis);
11620Sstevel@tonic-gate 				rc = FAILURE;
11630Sstevel@tonic-gate 				break;
11640Sstevel@tonic-gate 			}
11650Sstevel@tonic-gate 			free(pload_soft_dis);
11660Sstevel@tonic-gate 		}
11670Sstevel@tonic-gate 	}
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 	if (rc != SUCCESS) {
11700Sstevel@tonic-gate 		(void) close(fd);
11710Sstevel@tonic-gate 		return (rc);
11720Sstevel@tonic-gate 	}
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 
11757968Sopensolaris@drydog.com 	/*
11767968Sopensolaris@drydog.com 	 * For each hardware provider module, pass the disabled list
11777968Sopensolaris@drydog.com 	 * information to the kernel.
11787968Sopensolaris@drydog.com 	 */
11797968Sopensolaris@drydog.com 	for (ptr = pdevlist; ptr != NULL; ptr = ptr->next) {
11800Sstevel@tonic-gate 		/* load the disabled list */
11810Sstevel@tonic-gate 		if (ptr->pent->dis_count != 0) {
11820Sstevel@tonic-gate 			pload_dev_dis = setup_dev_dis(ptr->pent);
11830Sstevel@tonic-gate 			if (pload_dev_dis == NULL) {
11840Sstevel@tonic-gate 				rc = FAILURE;
11850Sstevel@tonic-gate 				break;
11860Sstevel@tonic-gate 			}
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate 			if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis)
11890Sstevel@tonic-gate 			    == -1) {
11900Sstevel@tonic-gate 				cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl "
11910Sstevel@tonic-gate 				    "failed: %s", strerror(errno));
11920Sstevel@tonic-gate 				free(pload_dev_dis);
11930Sstevel@tonic-gate 				rc = FAILURE;
11940Sstevel@tonic-gate 				break;
11950Sstevel@tonic-gate 			}
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate 			if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) {
11980Sstevel@tonic-gate 				cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl "
11990Sstevel@tonic-gate 				    "return_value = %d",
12000Sstevel@tonic-gate 				    pload_dev_dis->dd_return_value);
12010Sstevel@tonic-gate 				free(pload_dev_dis);
12020Sstevel@tonic-gate 				rc = FAILURE;
12030Sstevel@tonic-gate 				break;
12040Sstevel@tonic-gate 			}
12050Sstevel@tonic-gate 			free(pload_dev_dis);
12060Sstevel@tonic-gate 		}
12070Sstevel@tonic-gate 	}
12080Sstevel@tonic-gate 
1209*10500SHai-May.Chao@Sun.COM 	/*
1210*10500SHai-May.Chao@Sun.COM 	 * handle fips_status=enabled|disabled
1211*10500SHai-May.Chao@Sun.COM 	 */
1212*10500SHai-May.Chao@Sun.COM 	ptr = pfipslist;
1213*10500SHai-May.Chao@Sun.COM 	if (ptr != NULL) {
1214*10500SHai-May.Chao@Sun.COM 		if (ptr->pent->flag_fips_enabled) {
1215*10500SHai-May.Chao@Sun.COM 			rc = do_fips_actions(FIPS140_ENABLE, REFRESH);
1216*10500SHai-May.Chao@Sun.COM 		} else {
1217*10500SHai-May.Chao@Sun.COM 			rc = do_fips_actions(FIPS140_DISABLE, REFRESH);
1218*10500SHai-May.Chao@Sun.COM 		}
1219*10500SHai-May.Chao@Sun.COM 	}
1220*10500SHai-May.Chao@Sun.COM 
12210Sstevel@tonic-gate 	(void) close(fd);
12220Sstevel@tonic-gate 	return (rc);
12230Sstevel@tonic-gate }
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate /*
12260Sstevel@tonic-gate  * Unload the kernel software provider. Before calling this function, the
12277968Sopensolaris@drydog.com  * caller should check to see if the provider is in the kernel.
12287968Sopensolaris@drydog.com  *
12297968Sopensolaris@drydog.com  * This routine makes 2 ioctl calls to remove it completely from the kernel:
12307968Sopensolaris@drydog.com  *	CRYPTO_UNLOAD_SOFT_MODULE - does a modunload of the KCF module
12317968Sopensolaris@drydog.com  *	CRYPTO_LOAD_SOFT_DISABLED - updates kernel disabled mechanism list
12327968Sopensolaris@drydog.com  *
12337968Sopensolaris@drydog.com  * This implements part of "cryptoadm unload" and "cryptoadm uninstall".
12340Sstevel@tonic-gate  */
12350Sstevel@tonic-gate int
12367968Sopensolaris@drydog.com unload_kef_soft(char *provname)
12370Sstevel@tonic-gate {
12387968Sopensolaris@drydog.com 	crypto_unload_soft_module_t	*punload_soft = NULL;
12390Sstevel@tonic-gate 	crypto_load_soft_disabled_t	*pload_soft_dis = NULL;
12407968Sopensolaris@drydog.com 	entry_t				*pent = NULL;
12417968Sopensolaris@drydog.com 	int				fd = -1;
12427968Sopensolaris@drydog.com 	int				err;
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate 	if (provname == NULL) {
12450Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext("internal error."));
12460Sstevel@tonic-gate 		return (FAILURE);
12470Sstevel@tonic-gate 	}
12480Sstevel@tonic-gate 
1249*10500SHai-May.Chao@Sun.COM 	pent = getent_kef(provname, NULL, NULL, NULL);
12507968Sopensolaris@drydog.com 	if (pent == NULL) { /* not in kcf.conf */
12511971Skrishna 		/* Construct an entry using the provname */
12527968Sopensolaris@drydog.com 		pent = create_entry(provname);
12531971Skrishna 		if (pent == NULL) {
12541971Skrishna 			cryptoerror(LOG_STDERR, gettext("out of memory."));
12551971Skrishna 			return (FAILURE);
12561971Skrishna 		}
12570Sstevel@tonic-gate 	}
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 	/* Open the admin_ioctl_device */
12600Sstevel@tonic-gate 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
12610Sstevel@tonic-gate 		err = errno;
12620Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
12630Sstevel@tonic-gate 		    ADMIN_IOCTL_DEVICE, strerror(err));
12647968Sopensolaris@drydog.com 		free_entry(pent);
12650Sstevel@tonic-gate 		return (FAILURE);
12660Sstevel@tonic-gate 	}
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	/* Inform kernel to unload this software module */
12690Sstevel@tonic-gate 	if ((punload_soft = setup_unload_soft(pent)) == NULL) {
12707968Sopensolaris@drydog.com 		free_entry(pent);
12710Sstevel@tonic-gate 		(void) close(fd);
12720Sstevel@tonic-gate 		return (FAILURE);
12730Sstevel@tonic-gate 	}
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 	if (ioctl(fd, CRYPTO_UNLOAD_SOFT_MODULE, punload_soft) == -1) {
12760Sstevel@tonic-gate 		cryptodebug("CRYPTO_UNLOAD_SOFT_MODULE ioctl failed: %s",
12770Sstevel@tonic-gate 		    strerror(errno));
12780Sstevel@tonic-gate 		free_entry(pent);
12790Sstevel@tonic-gate 		free(punload_soft);
12800Sstevel@tonic-gate 		(void) close(fd);
12810Sstevel@tonic-gate 		return (FAILURE);
12820Sstevel@tonic-gate 	}
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate 	if (punload_soft->sm_return_value != CRYPTO_SUCCESS) {
12850Sstevel@tonic-gate 		cryptodebug("CRYPTO_UNLOAD_SOFT_MODULE ioctl return_value = "
12860Sstevel@tonic-gate 		    "%d", punload_soft->sm_return_value);
12870Sstevel@tonic-gate 		/*
12887334SDaniel.Anderson@Sun.COM 		 * If the return value is CRYPTO_UNKNOWN_PROVIDER, it means
12890Sstevel@tonic-gate 		 * that the provider is not registered yet.  Should just
12900Sstevel@tonic-gate 		 * continue.
12910Sstevel@tonic-gate 		 */
12920Sstevel@tonic-gate 		if (punload_soft->sm_return_value != CRYPTO_UNKNOWN_PROVIDER) {
12930Sstevel@tonic-gate 			free_entry(pent);
12940Sstevel@tonic-gate 			free(punload_soft);
12950Sstevel@tonic-gate 			(void) close(fd);
12960Sstevel@tonic-gate 			return (FAILURE);
12970Sstevel@tonic-gate 		}
12980Sstevel@tonic-gate 	}
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate 	free(punload_soft);
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 	/* Inform kernel to remove the disabled entries if any */
13030Sstevel@tonic-gate 	if (pent->dis_count == 0) {
13040Sstevel@tonic-gate 		free_entry(pent);
13050Sstevel@tonic-gate 		(void) close(fd);
13060Sstevel@tonic-gate 		return (SUCCESS);
13070Sstevel@tonic-gate 	} else {
13080Sstevel@tonic-gate 		free_mechlist(pent->dislist);
13090Sstevel@tonic-gate 		pent->dislist = NULL;
13100Sstevel@tonic-gate 		pent->dis_count = 0;
13110Sstevel@tonic-gate 	}
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 	if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) {
13140Sstevel@tonic-gate 		free_entry(pent);
13150Sstevel@tonic-gate 		(void) close(fd);
13160Sstevel@tonic-gate 		return (FAILURE);
13170Sstevel@tonic-gate 	}
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate 	/* pent is no longer needed; free it */
13200Sstevel@tonic-gate 	free_entry(pent);
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate 	if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis) == -1) {
13230Sstevel@tonic-gate 		cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: %s",
13240Sstevel@tonic-gate 		    strerror(errno));
13250Sstevel@tonic-gate 		free(pload_soft_dis);
13260Sstevel@tonic-gate 		(void) close(fd);
13270Sstevel@tonic-gate 		return (FAILURE);
13280Sstevel@tonic-gate 	}
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) {
13310Sstevel@tonic-gate 		cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl return_value = "
13320Sstevel@tonic-gate 		    "%d", pload_soft_dis->sd_return_value);
13330Sstevel@tonic-gate 		free(pload_soft_dis);
13340Sstevel@tonic-gate 		(void) close(fd);
13350Sstevel@tonic-gate 		return (FAILURE);
13360Sstevel@tonic-gate 	}
13370Sstevel@tonic-gate 
13380Sstevel@tonic-gate 	free(pload_soft_dis);
13390Sstevel@tonic-gate 	(void) close(fd);
13400Sstevel@tonic-gate 	return (SUCCESS);
13410Sstevel@tonic-gate }
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate /*
13450Sstevel@tonic-gate  * Check if a hardware provider is valid.  If it is valid, returns its device
13460Sstevel@tonic-gate  * name,  instance number and the number of mechanisms it supports.
13470Sstevel@tonic-gate  */
13480Sstevel@tonic-gate static int
13490Sstevel@tonic-gate check_hardware_provider(char *provname, char *pname, int *pnum, int *pcount)
13500Sstevel@tonic-gate {
13510Sstevel@tonic-gate 	crypto_get_dev_list_t *dev_list = NULL;
13520Sstevel@tonic-gate 	int	i;
13530Sstevel@tonic-gate 
13540Sstevel@tonic-gate 	if (provname == NULL) {
13550Sstevel@tonic-gate 		return (FAILURE);
13560Sstevel@tonic-gate 	}
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	/* First, get the device name and the instance number from provname */
13590Sstevel@tonic-gate 	if (split_hw_provname(provname, pname, pnum) == FAILURE) {
13600Sstevel@tonic-gate 		return (FAILURE);
13610Sstevel@tonic-gate 	}
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate 	/*
13640Sstevel@tonic-gate 	 * Get the complete device list from kernel and check if this provider
13650Sstevel@tonic-gate 	 * is in the list.
13660Sstevel@tonic-gate 	 */
13670Sstevel@tonic-gate 	if (get_dev_list(&dev_list) == FAILURE) {
13680Sstevel@tonic-gate 		return (FAILURE);
13690Sstevel@tonic-gate 	}
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 	for (i = 0; i < dev_list->dl_dev_count; i++) {
13720Sstevel@tonic-gate 		if ((strcmp(dev_list->dl_devs[i].le_dev_name, pname) == 0) &&
13730Sstevel@tonic-gate 		    (dev_list->dl_devs[i].le_dev_instance == *pnum)) {
13740Sstevel@tonic-gate 			break;
13750Sstevel@tonic-gate 		}
13760Sstevel@tonic-gate 	}
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate 	if (i == dev_list->dl_dev_count) {
13790Sstevel@tonic-gate 		/* didn't find this provider in the kernel device list */
13800Sstevel@tonic-gate 		cryptoerror(LOG_STDERR, gettext("%s does not exist."),
13810Sstevel@tonic-gate 		    provname);
13820Sstevel@tonic-gate 		free(dev_list);
13830Sstevel@tonic-gate 		return (FAILURE);
13840Sstevel@tonic-gate 	}
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 	/* This provider is valid.  Get its mechanism count */
13870Sstevel@tonic-gate 	*pcount = dev_list->dl_devs[i].le_mechanism_count;
13880Sstevel@tonic-gate 
13890Sstevel@tonic-gate 	free(dev_list);
13900Sstevel@tonic-gate 	return (SUCCESS);
13910Sstevel@tonic-gate }
1392*10500SHai-May.Chao@Sun.COM 
1393*10500SHai-May.Chao@Sun.COM int
1394*10500SHai-May.Chao@Sun.COM fips_update_kcfconf(int action)
1395*10500SHai-May.Chao@Sun.COM {
1396*10500SHai-May.Chao@Sun.COM 
1397*10500SHai-May.Chao@Sun.COM 	char	*str;
1398*10500SHai-May.Chao@Sun.COM 
1399*10500SHai-May.Chao@Sun.COM 	if (action == FIPS140_ENABLE)
1400*10500SHai-May.Chao@Sun.COM 		str = "fips-140:fips_status=enabled\n";
1401*10500SHai-May.Chao@Sun.COM 	else
1402*10500SHai-May.Chao@Sun.COM 		str = "fips-140:fips_status=disabled\n";
1403*10500SHai-May.Chao@Sun.COM 
1404*10500SHai-May.Chao@Sun.COM 	if (update_conf(_PATH_KCF_CONF, str) != SUCCESS)
1405*10500SHai-May.Chao@Sun.COM 		return (FAILURE);
1406*10500SHai-May.Chao@Sun.COM 
1407*10500SHai-May.Chao@Sun.COM 	return (SUCCESS);
1408*10500SHai-May.Chao@Sun.COM }
1409*10500SHai-May.Chao@Sun.COM 
1410*10500SHai-May.Chao@Sun.COM void
1411*10500SHai-May.Chao@Sun.COM fips_status_kcfconf(int *status)
1412*10500SHai-May.Chao@Sun.COM {
1413*10500SHai-May.Chao@Sun.COM 
1414*10500SHai-May.Chao@Sun.COM 	entry_t *pent = NULL;
1415*10500SHai-May.Chao@Sun.COM 
1416*10500SHai-May.Chao@Sun.COM 	if ((pent = getent_kef(FIPS_KEYWORD, NULL, NULL, NULL)) == NULL) {
1417*10500SHai-May.Chao@Sun.COM 		/*
1418*10500SHai-May.Chao@Sun.COM 		 * By default (no FIPS entry), we assume FIPS is disabled.
1419*10500SHai-May.Chao@Sun.COM 		 */
1420*10500SHai-May.Chao@Sun.COM 		*status = CRYPTO_FIPS_MODE_DISABLED;
1421*10500SHai-May.Chao@Sun.COM 		return;
1422*10500SHai-May.Chao@Sun.COM 	}
1423*10500SHai-May.Chao@Sun.COM 
1424*10500SHai-May.Chao@Sun.COM 	if (pent->flag_fips_enabled)
1425*10500SHai-May.Chao@Sun.COM 		*status = CRYPTO_FIPS_MODE_ENABLED;
1426*10500SHai-May.Chao@Sun.COM 	else
1427*10500SHai-May.Chao@Sun.COM 		*status = CRYPTO_FIPS_MODE_DISABLED;
1428*10500SHai-May.Chao@Sun.COM 
1429*10500SHai-May.Chao@Sun.COM 	return;
1430*10500SHai-May.Chao@Sun.COM 
1431*10500SHai-May.Chao@Sun.COM }
1432