--- old/usr/src/cmd/cmd-crypto/cryptoadm/adm_kef.c	Tue Oct 28 16:45:22 2008
+++ new/usr/src/cmd/cmd-crypto/cryptoadm/adm_kef.c	Tue Oct 28 16:45:20 2008
@@ -37,23 +37,27 @@
 #include <sys/crypto/elfsign.h>
 #include "cryptoadm.h"
 
-static int err; /* to store the value of errno in case being overwritten */
 static int check_hardware_provider(char *, char *, int *, int *);
 
 /*
  * Display the mechanism list for a kernel software provider.
+ * This implements part of the "cryptoadm list -m" command.
+ *
+ * Parameters phardlist and psoftlist are supplied by get_kcfconf_info().
+ * If NULL, this function obtains it by calling get_kcfconf_info() internally.
  */
 int
-list_mechlist_for_soft(char *provname)
+list_mechlist_for_soft(char *provname,
+    entrylist_t *phardlist, entrylist_t *psoftlist)
 {
-	mechlist_t *pmechlist;
-	int rc;
+	mechlist_t	*pmechlist = NULL;
+	int		rc;
 
 	if (provname == NULL) {
 		return (FAILURE);
 	}
 
-	rc = get_soft_info(provname, &pmechlist);
+	rc = get_soft_info(provname, &pmechlist, phardlist, psoftlist);
 	if (rc == SUCCESS) {
 		(void) filter_mechlist(&pmechlist, RANDOM);
 		print_mechlist(provname, pmechlist);
@@ -65,20 +69,20 @@
 	}
 
 	return (rc);
-
 }
 
 /*
  * Display the mechanism list for a kernel hardware provider.
+ * This implements part of the "cryptoadm list -m" command.
  */
 int
 list_mechlist_for_hard(char *provname)
 {
-	mechlist_t *pmechlist;
-	char	devname[MAXNAMELEN];
-	int	inst_num;
-	int	count;
-	int rc = SUCCESS;
+	mechlist_t	*pmechlist = NULL;
+	char		devname[MAXNAMELEN];
+	int		inst_num;
+	int		count;
+	int		rc = SUCCESS;
 
 	if (provname == NULL) {
 		return (FAILURE);
@@ -107,27 +111,36 @@
 
 /*
  * Display the policy information for a kernel software provider.
+ * This implements part of the "cryptoadm list -p" command.
+ *
+ * Parameters phardlist and psoftlist are supplied by get_kcfconf_info().
+ * If NULL, this function obtains it by calling get_kcfconf_info() internally.
  */
 int
-list_policy_for_soft(char *provname)
+list_policy_for_soft(char *provname,
+    entrylist_t *phardlist, entrylist_t *psoftlist)
 {
-	int rc;
-	entry_t *pent = NULL;
-	mechlist_t *pmechlist;
-	boolean_t has_random = B_FALSE;
-	boolean_t has_mechs = B_FALSE;
+	int		rc;
+	entry_t		*pent = NULL;
+	mechlist_t	*pmechlist = NULL;
+	boolean_t	has_random = B_FALSE;
+	boolean_t	has_mechs = B_FALSE;
+	boolean_t	in_kernel = B_FALSE;
 
 	if (provname == NULL) {
 		return (FAILURE);
 	}
 
-	if ((pent = getent_kef(provname)) == NULL) {
+	if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) {
+		return (FAILURE);
+	} else if (in_kernel == B_FALSE) {
 		cryptoerror(LOG_STDERR, gettext("%s does not exist."),
 		    provname);
 		return (FAILURE);
 	}
+	pent = getent_kef(provname, phardlist, psoftlist);
 
-	rc = get_soft_info(provname, &pmechlist);
+	rc = get_soft_info(provname, &pmechlist, phardlist, psoftlist);
 	if (rc == SUCCESS) {
 		has_random = filter_mechlist(&pmechlist, RANDOM);
 		if (pmechlist != NULL) {
@@ -141,7 +154,7 @@
 		return (rc);
 	}
 
-	print_kef_policy(pent, has_random, has_mechs);
+	print_kef_policy(provname, pent, has_random, has_mechs);
 	free_entry(pent);
 	return (SUCCESS);
 }
@@ -150,19 +163,27 @@
 
 /*
  * Display the policy information for a kernel hardware provider.
+ * This implements part of the "cryptoadm list -p" command.
+ *
+ * Parameters phardlist and psoftlist are supplied by get_kcfconf_info().
+ * If NULL, this function obtains it by calling get_kcfconf_info() internally.
+ * Parameter pdevlist is supplied by get_dev_list().
+ * If NULL, this function obtains it by calling get_dev_list() internally.
  */
 int
-list_policy_for_hard(char *provname)
+list_policy_for_hard(char *provname,
+	entrylist_t *phardlist, entrylist_t *psoftlist,
+	crypto_get_dev_list_t *pdevlist)
 {
-	entry_t *pent;
-	boolean_t is_active;
-	mechlist_t *pmechlist;
-	char	devname[MAXNAMELEN];
-	int	inst_num;
-	int	count;
-	int rc = SUCCESS;
-	boolean_t has_random = B_FALSE;
-	boolean_t has_mechs = B_FALSE;
+	entry_t		*pent = NULL;
+	boolean_t	in_kernel;
+	mechlist_t	*pmechlist = NULL;
+	char		devname[MAXNAMELEN];
+	int		inst_num;
+	int		count;
+	int		rc = SUCCESS;
+	boolean_t	has_random = B_FALSE;
+	boolean_t 	has_mechs = B_FALSE;
 
 	if (provname == NULL) {
 		return (FAILURE);
@@ -199,15 +220,15 @@
 	 * the disabled list from the config file entry.  Otherwise,
 	 * if it is active, then all the mechanisms for it are enabled.
 	 */
-	if ((pent = getent_kef(provname)) != NULL) {
-		print_kef_policy(pent, has_random, has_mechs);
+	if ((pent = getent_kef(provname, phardlist, psoftlist)) != NULL) {
+		print_kef_policy(provname, pent, has_random, has_mechs);
 		free_entry(pent);
 		return (SUCCESS);
 	} else {
-		if (check_active_for_hard(provname, &is_active) ==
-		    FAILURE) {
+		if (check_kernel_for_hard(provname, pdevlist,
+		    &in_kernel) == FAILURE) {
 			return (FAILURE);
-		} else if (is_active == B_TRUE) {
+		} else if (in_kernel == B_TRUE) {
 			(void) printf(gettext(
 			    "%s: all mechanisms are enabled."), provname);
 			if (has_random)
@@ -230,20 +251,24 @@
 }
 
 
-
+/*
+ * Disable a kernel hardware provider.
+ * This implements the "cryptoadm disable" command for
+ * kernel hardware providers.
+ */
 int
 disable_kef_hardware(char *provname, boolean_t rndflag, boolean_t allflag,
     mechlist_t *dislist)
 {
-	crypto_load_dev_disabled_t	*pload_dev_dis;
-	mechlist_t 	*infolist;
-	entry_t		*pent;
-	boolean_t	new_dev_entry = B_FALSE;
-	char	devname[MAXNAMELEN];
-	int	inst_num;
-	int	count;
-	int	fd;
-	int	rc = SUCCESS;
+	crypto_load_dev_disabled_t	*pload_dev_dis = NULL;
+	mechlist_t			*infolist = NULL;
+	entry_t				*pent = NULL;
+	boolean_t			new_dev_entry = B_FALSE;
+	char				devname[MAXNAMELEN];
+	int				inst_num;
+	int				count;
+	int				fd = -1;
+	int				rc = SUCCESS;
 
 	if (provname == NULL) {
 		return (FAILURE);
@@ -267,18 +292,13 @@
 	 * Get the entry of this hardware provider from the config file.
 	 * If there is no entry yet, create one for it.
 	 */
-	if ((pent = getent_kef(provname)) == NULL) {
-		if ((pent = malloc(sizeof (entry_t))) == NULL) {
+	if ((pent = getent_kef(provname, NULL, NULL)) == NULL) {
+		if ((pent = create_entry(provname)) == NULL) {
 			cryptoerror(LOG_STDERR, gettext("out of memory."));
 			free_mechlist(infolist);
 			return (FAILURE);
 		}
 		new_dev_entry = B_TRUE;
-		(void) strlcpy(pent->name, provname, MAXNAMELEN);
-		pent->suplist = NULL;
-		pent->sup_count = 0;
-		pent->dislist = NULL;
-		pent->dis_count = 0;
 	}
 
 	/*
@@ -353,55 +373,88 @@
 }
 
 
-
+/*
+ * Disable a kernel software provider.
+ * This implements the "cryptoadm disable" command for
+ * kernel software providers.
+ */
 int
 disable_kef_software(char *provname, boolean_t rndflag, boolean_t allflag,
     mechlist_t *dislist)
 {
 	crypto_load_soft_disabled_t	*pload_soft_dis = NULL;
-	mechlist_t 	*infolist;
-	entry_t		*pent;
-	boolean_t	is_active;
-	int	fd;
+	mechlist_t			*infolist = NULL;
+	entry_t				*pent = NULL;
+	entrylist_t			*phardlist = NULL;
+	entrylist_t			*psoftlist = NULL;
+	boolean_t			in_kernel = B_FALSE;
+	int				fd = -1;
+	int				rc = SUCCESS;
 
 	if (provname == NULL) {
 		return (FAILURE);
 	}
 
-	/* Get the entry of this provider from the config file. */
-	if ((pent = getent_kef(provname)) == NULL) {
-		cryptoerror(LOG_STDERR,
-		    gettext("%s does not exist."), provname);
-		return (FAILURE);
-	}
-
 	/*
 	 * Check if the kernel software provider is currently unloaded.
 	 * If it is unloaded, return FAILURE, because the disable subcommand
 	 * can not perform on inactive (unloaded) providers.
 	 */
-	if (check_active_for_soft(provname, &is_active) == FAILURE) {
-		free_entry(pent);
+	if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) {
 		return (FAILURE);
-	} else if (is_active == B_FALSE) {
-		/*
-		 * TRANSLATION_NOTE
-		 * "disable" is a keyword and not to be translated.
-		 */
+	} else if (in_kernel == B_FALSE) {
 		cryptoerror(LOG_STDERR,
-		    gettext("can not do %1$s on an unloaded "
-		    "kernel software provider -- %2$s."), "disable", provname);
-		free_entry(pent);
+		    gettext("%s is not loaded or does not exist."),
+		    provname);
 		return (FAILURE);
 	}
 
-	/* Get the mechanism list for the software provider */
-	if (get_soft_info(provname, &infolist) == FAILURE) {
-		free(pent);
+	if (get_kcfconf_info(&phardlist, &psoftlist) == FAILURE) {
+		cryptoerror(LOG_ERR,
+		    "failed to retrieve the providers' "
+		    "information from the configuration file - %s.",
+		    _PATH_KCF_CONF);
 		return (FAILURE);
 	}
 
-	/* See comments in disable_kef_hardware() */
+	/*
+	 * Get the entry of this provider from the kcf.conf file, if any.
+	 * Otherwise, create a new kcf.conf entry for writing back to the file.
+	 */
+	pent = getent_kef(provname, phardlist, psoftlist);
+	if (pent == NULL) { /* create a new entry */
+		pent = create_entry(provname);
+		if (pent == NULL) {
+			cryptodebug("out of memory.");
+			rc = FAILURE;
+			goto out;
+		}
+	}
+
+	/* Get the mechanism list for the software provider from the kernel */
+	if (get_soft_info(provname, &infolist, phardlist, psoftlist) ==
+	    FAILURE) {
+		rc = FAILURE;
+		goto out;
+	}
+
+	if ((infolist != NULL) && (infolist->name[0] != '\0')) {
+		/*
+		 * Replace the supportedlist from kcf.conf with possibly
+		 * more-up-to-date list from the kernel.  This is the case
+		 * for default software providers that had more mechanisms
+		 * added in the current version of the kernel.
+		 */
+		free_mechlist(pent->suplist);
+		pent->suplist = infolist;
+	}
+
+	/*
+	 * kCF treats random as an internal mechanism. So, we need to
+	 * filter it from the mechanism list here, if we are NOT disabling
+	 * or enabling the random feature. Note that we map random feature at
+	 * cryptoadm(1M) level to the "random" mechanism in kCF.
+	 */
 	if (!rndflag) {
 		(void) filter_mechlist(&infolist, RANDOM);
 	}
@@ -408,59 +461,61 @@
 
 	/* Calculate the new disabled list */
 	if (disable_mechs(&pent, infolist, allflag, dislist) == FAILURE) {
-		free_entry(pent);
-		free_mechlist(infolist);
-		return (FAILURE);
+		rc = FAILURE;
+		goto out;
 	}
 
-	/* infolist is no longer needed; free it */
-	free_mechlist(infolist);
-
 	/* Update the kcf.conf file with the updated entry */
 	if (update_kcfconf(pent, MODIFY_MODE) == FAILURE) {
-		free_entry(pent);
-		return (FAILURE);
+		rc = FAILURE;
+		goto out;
 	}
 
-	/* Inform kernel about the new disabled list. */
+	/* Setup argument to inform kernel about the new disabled list. */
 	if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) {
-		free_entry(pent);
-		return (FAILURE);
+		rc = FAILURE;
+		goto out;
 	}
 
-	/* pent is no longer needed; free it. */
-	free_entry(pent);
-
 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
 		cryptoerror(LOG_STDERR,
 		    gettext("failed to open %s for RW: %s"),
 		    ADMIN_IOCTL_DEVICE, strerror(errno));
-		free(pload_soft_dis);
-		return (FAILURE);
+		rc = FAILURE;
+		goto out;
 	}
 
+	/* Inform kernel about the new disabled list. */
 	if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis) == -1) {
 		cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: %s",
 		    strerror(errno));
-		free(pload_soft_dis);
-		(void) close(fd);
-		return (FAILURE);
+		rc = FAILURE;
+		goto out;
 	}
 
 	if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) {
 		cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl return_value = "
 		    "%d", pload_soft_dis->sd_return_value);
-		free(pload_soft_dis);
-		(void) close(fd);
-		return (FAILURE);
+		rc = FAILURE;
+		goto out;
 	}
 
+out:
+	free_entrylist(phardlist);
+	free_entrylist(psoftlist);
+	free_mechlist(infolist);
+	free_entry(pent);
 	free(pload_soft_dis);
-	(void) close(fd);
-	return (SUCCESS);
+	if (fd != -1)
+		(void) close(fd);
+	return (rc);
 }
 
 
+/*
+ * Enable a kernel software or hardware provider.
+ * This implements the "cryptoadm enable" command for kernel providers.
+ */
 int
 enable_kef(char *provname, boolean_t rndflag, boolean_t allflag,
     mechlist_t *mlist)
@@ -467,14 +522,15 @@
 {
 	crypto_load_soft_disabled_t	*pload_soft_dis = NULL;
 	crypto_load_dev_disabled_t	*pload_dev_dis = NULL;
-	entry_t		*pent;
-	boolean_t redo_flag = B_FALSE;
-	int	fd;
-	int	rc = SUCCESS;
+	entry_t				*pent = NULL;
+	boolean_t			redo_flag = B_FALSE;
+	boolean_t			in_kernel = B_FALSE;
+	int				fd = -1;
+	int				rc = SUCCESS;
 
 
-	/* Get the entry with the provider name from the kcf.conf file */
-	pent = getent_kef(provname);
+	/* Get the entry of this provider from the kcf.conf file, if any. */
+	pent = getent_kef(provname, NULL, NULL);
 
 	if (is_device(provname)) {
 		if (pent == NULL) {
@@ -485,14 +541,20 @@
 			cryptoerror(LOG_STDERR, gettext(
 			    "all mechanisms are enabled already for %s."),
 			    provname);
+			free_entry(pent);
 			return (SUCCESS);
 		}
 	} else { /* a software module */
-		if (pent == NULL) {
-			cryptoerror(LOG_STDERR,
-			    gettext("%s does not exist."), provname);
+		if (check_kernel_for_soft(provname, NULL, &in_kernel) ==
+		    FAILURE) {
+			free_entry(pent);
 			return (FAILURE);
-		} else if (pent->dis_count == 0) {
+		} else if (in_kernel == B_FALSE) {
+			cryptoerror(LOG_STDERR, gettext("%s does not exist."),
+			    provname);
+			free_entry(pent);
+			return (FAILURE);
+		} else if ((pent == NULL) || (pent->dis_count == 0)) {
 			/* nothing to be enabled. */
 			cryptoerror(LOG_STDERR, gettext(
 			    "all mechanisms are enabled already for %s."),
@@ -502,8 +564,13 @@
 		}
 	}
 
+	/*
+	 * kCF treats random as an internal mechanism. So, we need to
+	 * filter it from the mechanism list here, if we are NOT disabling
+	 * or enabling the random feature. Note that we map random feature at
+	 * cryptoadm(1M) level to the "random" mechanism in kCF.
+	 */
 	if (!rndflag) {
-		/* See comments in disable_kef_hardware() */
 		redo_flag = filter_mechlist(&pent->dislist, RANDOM);
 		if (redo_flag)
 			pent->dis_count--;
@@ -528,9 +595,9 @@
 	}
 
 	/*
-	 * Update the kcf.conf file  with the updated entry.
+	 * Update the kcf.conf file with the updated entry.
 	 * For a hardware provider, if there is no more disabled mechanism,
-	 * the entire entry in the config file should be removed.
+	 * remove the entire kcf.conf entry.
 	 */
 	if (is_device(pent->name) && (pent->dis_count == 0)) {
 		rc = update_kcfconf(pent, DELETE_MODE);
@@ -549,6 +616,7 @@
 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
 		    ADMIN_IOCTL_DEVICE, strerror(errno));
+		free_entry(pent);
 		return (FAILURE);
 	}
 
@@ -555,6 +623,7 @@
 	if (is_device(provname)) {
 		/*  LOAD_DEV_DISABLED */
 		if ((pload_dev_dis = setup_dev_dis(pent)) == NULL) {
+			free_entry(pent);
 			return (FAILURE);
 		}
 
@@ -561,6 +630,7 @@
 		if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis) == -1) {
 			cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl failed: "
 			    "%s", strerror(errno));
+			free_entry(pent);
 			free(pload_dev_dis);
 			(void) close(fd);
 			return (FAILURE);
@@ -570,14 +640,16 @@
 			cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl "
 			    "return_value = %d",
 			    pload_dev_dis->dd_return_value);
+			free_entry(pent);
 			free(pload_dev_dis);
 			(void) close(fd);
 			return (FAILURE);
 		}
 
-	} else {
+	} else { /* a software module */
 		/* LOAD_SOFT_DISABLED */
 		if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) {
+			free_entry(pent);
 			return (FAILURE);
 		}
 
@@ -585,6 +657,7 @@
 		    == -1) {
 			cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: "
 			    "%s", strerror(errno));
+			free_entry(pent);
 			free(pload_soft_dis);
 			(void) close(fd);
 			return (FAILURE);
@@ -594,6 +667,7 @@
 			cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl "
 			    "return_value = %d",
 			    pload_soft_dis->sd_return_value);
+			free_entry(pent);
 			free(pload_soft_dis);
 			(void) close(fd);
 			return (FAILURE);
@@ -600,6 +674,8 @@
 		}
 	}
 
+	free_entry(pent);
+	free(pload_soft_dis);
 	(void) close(fd);
 	return (SUCCESS);
 }
@@ -615,19 +691,20 @@
 install_kef(char *provname, mechlist_t *mlist)
 {
 	crypto_load_soft_config_t	*pload_soft_conf = NULL;
-	boolean_t	found;
-	entry_t	*pent;
-	FILE	*pfile;
-	FILE	*pfile_tmp;
-	char	tmpfile_name[MAXPATHLEN];
-	char	*ptr;
-	char	*str;
-	char	*name;
-	char	buffer[BUFSIZ];
-	char	buffer2[BUFSIZ];
-	int	found_count;
-	int	fd;
-	int	rc = SUCCESS;
+	boolean_t			found;
+	entry_t				*pent = NULL;
+	FILE				*pfile = NULL;
+	FILE				*pfile_tmp = NULL;
+	char				tmpfile_name[MAXPATHLEN];
+	char				*ptr;
+	char				*str;
+	char				*name;
+	char				buffer[BUFSIZ];
+	char				buffer2[BUFSIZ];
+	int				found_count;
+	int				fd = -1;
+	int				rc = SUCCESS;
+	int				err;
 
 	if ((provname == NULL) || (mlist == NULL)) {
 		return (FAILURE);
@@ -634,7 +711,7 @@
 	}
 
 	/* Check if the provider already exists */
-	if ((pent = getent_kef(provname)) != NULL) {
+	if ((pent = getent_kef(provname, NULL, NULL)) != NULL) {
 		cryptoerror(LOG_STDERR, gettext("%s exists already."),
 		    provname);
 		free_entry(pent);
@@ -642,16 +719,12 @@
 	}
 
 	/* Create an entry with provname and mlist. */
-	if ((pent = malloc(sizeof (entry_t))) == NULL) {
+	if ((pent = create_entry(provname)) == NULL) {
 		cryptoerror(LOG_STDERR, gettext("out of memory."));
 		return (FAILURE);
 	}
-
-	(void) strlcpy(pent->name, provname, MAXNAMELEN);
 	pent->sup_count = get_mech_count(mlist);
 	pent->suplist = mlist;
-	pent->dis_count = 0;
-	pent->dislist = NULL;
 
 	/* Append an entry for this software module to the kcf.conf file. */
 	if ((str = ent2str(pent)) == NULL) {
@@ -737,7 +810,7 @@
 			} else {
 				/*
 				 * Found a second entry with #libname.
-				 * Should not happen. The kcf.conf ffile
+				 * Should not happen. The kcf.conf file
 				 * is corrupted. Give a warning and skip
 				 * this entry.
 				 */
@@ -792,6 +865,7 @@
 		cryptoerror(LOG_STDERR,
 		    gettext("failed to close %s: %s"), tmpfile_name,
 		    strerror(err));
+		free_entry(pent);
 		return (FAILURE);
 	}
 
@@ -799,7 +873,7 @@
 		err = errno;
 		cryptoerror(LOG_STDERR,
 		    gettext("failed to update the configuration - %s"),
-			strerror(err));
+		    strerror(err));
 		cryptodebug("failed to rename %s to %s: %s", tmpfile_name,
 		    _PATH_KCF_CONF, strerror(err));
 		rc = FAILURE;
@@ -823,6 +897,7 @@
 			    "(Warning) failed to remove %s: %s"),
 			    tmpfile_name, strerror(err));
 		}
+		free_entry(pent);
 		return (FAILURE);
 	}
 
@@ -875,235 +950,114 @@
 int
 uninstall_kef(char *provname)
 {
-	entry_t		*pent;
-	boolean_t	is_active;
-	boolean_t	in_package;
-	boolean_t	found;
-	FILE	*pfile;
-	FILE	*pfile_tmp;
-	char	tmpfile_name[MAXPATHLEN];
-	char	*name;
-	char	strbuf[BUFSIZ];
-	char	buffer[BUFSIZ];
-	char	buffer2[BUFSIZ];
-	char	*str;
-	int	len;
-	int	rc = SUCCESS;
+	entry_t		*pent = NULL;
+	int		rc = SUCCESS;
+	boolean_t	in_kernel = B_FALSE;
+	boolean_t	in_kcfconf = B_FALSE;
+	int		fd = -1;
+	crypto_load_soft_config_t *pload_soft_conf = NULL;
 
-
-	/* Check if it is in the kcf.conf file first. */
-	if ((pent = getent_kef(provname)) == NULL) {
-		cryptoerror(LOG_STDERR,
-		    gettext("%s does not exist."), provname);
+	/* Check to see if the provider exists first. */
+	if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) {
 		return (FAILURE);
+	} else if (in_kernel == B_FALSE) {
+		cryptoerror(LOG_STDERR, gettext("%s does not exist."),
+		    provname);
+		return (FAILURE);
 	}
 
-
 	/*
-	 * Get rid of the disabled list for the provider and get the converted
-	 * string for the entry.  This is to prepare the string for a provider
-	 * that is in a package.
+	 * If it is loaded, unload it first.  This does 2 ioctl calls:
+	 * CRYPTO_UNLOAD_SOFT_MODULE and CRYPTO_LOAD_SOFT_DISABLED.
 	 */
-	free_mechlist(pent->dislist);
-	pent->dis_count = 0;
-	pent->dislist = NULL;
-	str = ent2str(pent);
-	free_entry(pent);
-	if (str == NULL) {
-		cryptoerror(LOG_STDERR, gettext("internal error."));
-		return (FAILURE);
-	}
-	(void) snprintf(strbuf, sizeof (strbuf), "%s%s", "#", str);
-	free(str);
-
-	/* If it is not loaded, unload it first  */
-	if (check_active_for_soft(provname, &is_active) == FAILURE) {
-		return (FAILURE);
-	} else if ((is_active == B_TRUE) &&
-	    (unload_kef_soft(provname, B_TRUE) == FAILURE)) {
+	if (unload_kef_soft(provname) == FAILURE) {
 		cryptoerror(LOG_STDERR,
-		    gettext("failed to uninstall %s.\n"), provname);
+		    gettext("failed to unload %s during uninstall.\n"),
+		    provname);
 		return (FAILURE);
 	}
 
 	/*
-	 * Remove the entry from the config file.  If the provider to be
-	 * uninstalled is in a package, just comment it off.
+	 * Inform kernel to remove the configuration of this software module.
 	 */
-	if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) {
-		err = errno;
-		cryptoerror(LOG_STDERR,
-		    gettext("failed to update the configuration - %s"),
-		    strerror(err));
-		cryptodebug("failed to open %s for write.", _PATH_KCF_CONF);
-		return (FAILURE);
-	}
 
-	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
-		err = errno;
-		cryptoerror(LOG_STDERR,
-		    gettext("failed to lock the configuration - %s"),
-		    strerror(err));
-		(void) fclose(pfile);
+	/* Setup ioctl() parameter */
+	pent = getent_kef(provname, NULL, NULL);
+	if (pent != NULL) { /* in kcf.conf */
+		in_kcfconf = B_TRUE;
+		free_mechlist(pent->suplist);
+		pent->suplist = NULL;
+		pent->sup_count = 0;
+	} else if ((pent = create_entry(provname)) == NULL) {
+		cryptoerror(LOG_STDERR, gettext("out of memory."));
 		return (FAILURE);
 	}
-
-	/*
-	 * Create a temporary file in the /etc/crypto directory to save
-	 * the new configuration file first.
-	 */
-	(void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
-	if (mkstemp(tmpfile_name) == -1) {
-		err = errno;
-		cryptoerror(LOG_STDERR,
-		    gettext("failed to create a temporary file - %s"),
-		    strerror(err));
-		(void) fclose(pfile);
+	if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) {
+		free_entry(pent);
 		return (FAILURE);
 	}
 
-	if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
-		err = errno;
-		cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
-		    tmpfile_name, strerror(err));
-		if (unlink(tmpfile_name) != 0) {
-			err = errno;
-			cryptoerror(LOG_STDERR, gettext(
-			    "(Warning) failed to remove %s: %s"), tmpfile_name,
-			    strerror(err));
-		}
-		(void) fclose(pfile);
+	/* Open the /dev/cryptoadm device */
+	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
+		int	err = errno;
+		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
+		    ADMIN_IOCTL_DEVICE, strerror(err));
+		free_entry(pent);
+		free(pload_soft_conf);
 		return (FAILURE);
 	}
 
-	/*
-	 * Loop thru the config file.  If the kernel software provider
-	 * to be uninstalled is in a package, just comment it off.
-	 */
-	in_package = B_FALSE;
-	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
-		found = B_FALSE;
-		if (!(buffer[0] == ' ' || buffer[0] == '\n' ||
-		    buffer[0] == '\t')) {
-			if (strstr(buffer, " Start ") != NULL) {
-				in_package = B_TRUE;
-			} else if (strstr(buffer, " End ") != NULL) {
-				in_package = B_FALSE;
-			} else if (buffer[0] != '#') {
-				(void) strlcpy(buffer2, buffer, BUFSIZ);
-
-				/* get rid of trailing '\n' */
-				len = strlen(buffer2);
-				if (buffer2[len-1] == '\n') {
-					len--;
-				}
-				buffer2[len] = '\0';
-
-				if ((name = strtok(buffer2, SEP_COLON))
-				    == NULL) {
-					rc = FAILURE;
-					break;
-				} else if (strcmp(provname, name) == 0) {
-					found = B_TRUE;
-				}
-			}
-		}
-
-		if (found) {
-			if (in_package) {
-				if (fputs(strbuf, pfile_tmp) == EOF) {
-					rc = FAILURE;
-				}
-			}
-		} else {
-			if (fputs(buffer, pfile_tmp) == EOF) {
-				rc = FAILURE;
-			}
-		}
-
-		if (rc == FAILURE) {
-			break;
-		}
-	}
-
-	if (rc == FAILURE) {
-		cryptoerror(LOG_STDERR, gettext("write error."));
-		(void) fclose(pfile);
-		(void) fclose(pfile_tmp);
-		if (unlink(tmpfile_name) != 0) {
-			err = errno;
-			cryptoerror(LOG_STDERR, gettext(
-			    "(Warning) failed to remove %s: %s"), tmpfile_name,
-			    strerror(err));
-		}
+	if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG,
+	    pload_soft_conf) == -1) {
+		cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s",
+		    strerror(errno));
+		free_entry(pent);
+		free(pload_soft_conf);
+		(void) close(fd);
 		return (FAILURE);
 	}
 
-	(void) fclose(pfile);
-	if (fclose(pfile_tmp) != 0) {
-		err = errno;
-		cryptoerror(LOG_STDERR,
-		    gettext("failed to close %s: %s"), tmpfile_name,
-		    strerror(err));
+	if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) {
+		cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl = return_value = %d",
+		    pload_soft_conf->sc_return_value);
+		free_entry(pent);
+		free(pload_soft_conf);
+		(void) close(fd);
 		return (FAILURE);
 	}
 
-	/* Now update the real config file */
-	if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) {
-		err = errno;
-		cryptoerror(LOG_STDERR,
-		    gettext("failed to update the configuration - %s"),
-		    strerror(err));
-		cryptodebug("failed to rename %1$s to %2$s: %3$s", tmpfile,
-		    _PATH_KCF_CONF, strerror(err));
-		rc = FAILURE;
-	} else if (chmod(_PATH_KCF_CONF,
-	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
-		err = errno;
-		cryptoerror(LOG_STDERR,
-		    gettext("failed to update the configuration - %s"),
-		    strerror(err));
-		cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF,
-		    strerror(err));
-		rc = FAILURE;
-	} else {
-		rc = SUCCESS;
-	}
+	/* ioctl cleanup */
+	free(pload_soft_conf);
+	(void) close(fd);
 
-	if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
-		err = errno;
-		cryptoerror(LOG_STDERR, gettext(
-		    "(Warning) failed to remove %s: %s"), tmpfile_name,
-		    strerror(err));
+
+	/* Finally, remove entry from kcf.conf, if present */
+	if (in_kcfconf && (pent != NULL)) {
+		rc = update_kcfconf(pent, DELETE_MODE);
 	}
 
+	free_entry(pent);
 	return (rc);
-
 }
 
 
+/*
+ * Implement the "cryptoadm refresh" command for global zones.
+ * That is, send the current contents of kcf.conf to the kernel via ioctl().
+ */
 int
 refresh(void)
 {
-	crypto_get_soft_list_t		*psoftlist_kernel = NULL;
 	crypto_load_soft_config_t	*pload_soft_conf = NULL;
 	crypto_load_soft_disabled_t	*pload_soft_dis = NULL;
 	crypto_load_dev_disabled_t	*pload_dev_dis = NULL;
-	entrylist_t	*pdevlist = NULL;
-	entrylist_t	*psoftlist = NULL;
-	entrylist_t	*ptr;
-	boolean_t	found;
-	char 	*psoftname;
-	int	fd;
-	int	rc = SUCCESS;
-	int	i;
+	entrylist_t			*pdevlist = NULL;
+	entrylist_t			*psoftlist = NULL;
+	entrylist_t			*ptr;
+	int				fd = -1;
+	int				rc = SUCCESS;
+	int				err;
 
-	if (get_soft_list(&psoftlist_kernel) == FAILURE) {
-		cryptoerror(LOG_ERR, gettext("Failed to retrieve the "
-		    "software provider list from kernel."));
-		return (FAILURE);
-	}
-
 	if (get_kcfconf_info(&pdevlist, &psoftlist) == FAILURE) {
 		cryptoerror(LOG_ERR, "failed to retrieve the providers' "
 		    "information from the configuration file - %s.",
@@ -1111,37 +1065,6 @@
 		return (FAILURE);
 	}
 
-	/*
-	 * If a kernel software provider is in kernel, but it is not in the
-	 * kcf.conf file, it must have been pkgrm'ed and needs to be unloaded
-	 * now.
-	 */
-	if (psoftlist_kernel->sl_soft_count > 0) {
-		psoftname = psoftlist_kernel->sl_soft_names;
-		for (i = 0; i < psoftlist_kernel->sl_soft_count; i++) {
-			ptr = psoftlist;
-			found = B_FALSE;
-			while (ptr != NULL) {
-				if (strcmp(psoftname, ptr->pent->name) == 0) {
-					found = B_TRUE;
-					break;
-				}
-				ptr = ptr->next;
-			}
-
-			if (!found) {
-				rc = unload_kef_soft(psoftname, B_FALSE);
-				if (rc == FAILURE) {
-					cryptoerror(LOG_ERR, gettext(
-					    "WARNING - the provider %s is "
-					    "still in kernel."), psoftname);
-				}
-			}
-			psoftname = psoftname + strlen(psoftname) + 1;
-		}
-	}
-	free(psoftlist_kernel);
-
 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
 		err = errno;
 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
@@ -1152,17 +1075,28 @@
 	}
 
 	/*
-	 * For each software module, pass two sets of information to kernel
-	 * - the supported list and the disabled list
+	 * For each software provider module, pass two sets of information to
+	 * the kernel: the supported list and the disabled list.
 	 */
-	ptr = psoftlist;
-	while (ptr != NULL) {
+	for (ptr = psoftlist; ptr != NULL; ptr = ptr->next) {
+		entry_t		*pent = ptr->pent;
+
 		/* load the supported list */
-		if ((pload_soft_conf = setup_soft_conf(ptr->pent)) == NULL) {
+		if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) {
+			cryptodebug("setup_soft_conf() failed");
 			rc = FAILURE;
 			break;
 		}
 
+		if (!pent->load) { /* unloaded--mark as loaded */
+			pent->load = B_TRUE;
+			rc = update_kcfconf(pent, MODIFY_MODE);
+			if (rc != SUCCESS) {
+				free(pload_soft_conf);
+				break;
+			}
+		}
+
 		if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG, pload_soft_conf)
 		    == -1) {
 			cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s",
@@ -1181,10 +1115,14 @@
 			break;
 		}
 
+		free(pload_soft_conf);
+
 		/* load the disabled list */
 		if (ptr->pent->dis_count != 0) {
 			pload_soft_dis = setup_soft_dis(ptr->pent);
 			if (pload_soft_dis == NULL) {
+				cryptodebug("setup_soft_dis() failed");
+				free(pload_soft_dis);
 				rc = FAILURE;
 				break;
 			}
@@ -1209,9 +1147,6 @@
 			}
 			free(pload_soft_dis);
 		}
-
-		free(pload_soft_conf);
-		ptr = ptr->next;
 	}
 
 	if (rc != SUCCESS) {
@@ -1220,9 +1155,11 @@
 	}
 
 
-	/* Pass the disabledlist information for Device to kernel */
-	ptr = pdevlist;
-	while (ptr != NULL) {
+	/*
+	 * For each hardware provider module, pass the disabled list
+	 * information to the kernel.
+	 */
+	for (ptr = pdevlist; ptr != NULL; ptr = ptr->next) {
 		/* load the disabled list */
 		if (ptr->pent->dis_count != 0) {
 			pload_dev_dis = setup_dev_dis(ptr->pent);
@@ -1250,8 +1187,6 @@
 			}
 			free(pload_dev_dis);
 		}
-
-		ptr = ptr->next;
 	}
 
 	(void) close(fd);
@@ -1260,20 +1195,22 @@
 
 /*
  * Unload the kernel software provider. Before calling this function, the
- * caller should check if the provider is in the config file and if it
- * is kernel. This routine makes 3 ioctl calls to remove it from kernel
- * completely. The argument do_check set to B_FALSE means that the
- * caller knows the provider is not the config file and hence the check
- * is skipped.
+ * caller should check to see if the provider is in the kernel.
+ *
+ * This routine makes 2 ioctl calls to remove it completely from the kernel:
+ *	CRYPTO_UNLOAD_SOFT_MODULE - does a modunload of the KCF module
+ *	CRYPTO_LOAD_SOFT_DISABLED - updates kernel disabled mechanism list
+ *
+ * This implements part of "cryptoadm unload" and "cryptoadm uninstall".
  */
 int
-unload_kef_soft(char *provname, boolean_t do_check)
+unload_kef_soft(char *provname)
 {
-	crypto_unload_soft_module_t 	*punload_soft = NULL;
-	crypto_load_soft_config_t	*pload_soft_conf = NULL;
+	crypto_unload_soft_module_t	*punload_soft = NULL;
 	crypto_load_soft_disabled_t	*pload_soft_dis = NULL;
-	entry_t	*pent = NULL;
-	int	fd;
+	entry_t				*pent = NULL;
+	int				fd = -1;
+	int				err;
 
 	if (provname == NULL) {
 		cryptoerror(LOG_STDERR, gettext("internal error."));
@@ -1280,18 +1217,14 @@
 		return (FAILURE);
 	}
 
-	if (!do_check) {
+	pent = getent_kef(provname, NULL, NULL);
+	if (pent == NULL) { /* not in kcf.conf */
 		/* Construct an entry using the provname */
-		pent = calloc(1, sizeof (entry_t));
+		pent = create_entry(provname);
 		if (pent == NULL) {
 			cryptoerror(LOG_STDERR, gettext("out of memory."));
 			return (FAILURE);
 		}
-		(void) strlcpy(pent->name, provname, MAXNAMELEN);
-	} else if ((pent = getent_kef(provname)) == NULL) {
-		cryptoerror(LOG_STDERR, gettext("%s does not exist."),
-		    provname);
-		return (FAILURE);
 	}
 
 	/* Open the admin_ioctl_device */
@@ -1299,11 +1232,13 @@
 		err = errno;
 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
 		    ADMIN_IOCTL_DEVICE, strerror(err));
+		free_entry(pent);
 		return (FAILURE);
 	}
 
 	/* Inform kernel to unload this software module */
 	if ((punload_soft = setup_unload_soft(pent)) == NULL) {
+		free_entry(pent);
 		(void) close(fd);
 		return (FAILURE);
 	}
@@ -1335,39 +1270,6 @@
 
 	free(punload_soft);
 
-	/*
-	 * Inform kernel to remove the configuration of this software
-	 * module.
-	 */
-	free_mechlist(pent->suplist);
-	pent->suplist = NULL;
-	pent->sup_count = 0;
-	if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) {
-		free_entry(pent);
-		(void) close(fd);
-		return (FAILURE);
-	}
-
-	if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG, pload_soft_conf) == -1) {
-		cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s",
-		    strerror(errno));
-		free_entry(pent);
-		free(pload_soft_conf);
-		(void) close(fd);
-		return (FAILURE);
-	}
-
-	if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) {
-		cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl return_value = "
-		    "%d", pload_soft_conf->sc_return_value);
-		free_entry(pent);
-		free(pload_soft_conf);
-		(void) close(fd);
-		return (FAILURE);
-	}
-
-	free(pload_soft_conf);
-
 	/* Inform kernel to remove the disabled entries if any */
 	if (pent->dis_count == 0) {
 		free_entry(pent);
--- old/usr/src/cmd/cmd-crypto/cryptoadm/adm_kef_ioctl.c	Tue Oct 28 16:45:24 2008
+++ new/usr/src/cmd/cmd-crypto/cryptoadm/adm_kef_ioctl.c	Tue Oct 28 16:45:23 2008
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -52,9 +49,9 @@
 {
 	crypto_load_soft_config_t	*pload_soft_conf;
 	mechlist_t	*plist;
-	uint_t	sup_count;
-	size_t	extra_mech_size = 0;
-	int	i;
+	uint_t		sup_count;
+	size_t		extra_mech_size = 0;
+	int		i;
 
 	if (pent == NULL) {
 		return (NULL);
@@ -95,11 +92,11 @@
 crypto_load_soft_disabled_t *
 setup_soft_dis(entry_t *pent)
 {
-	crypto_load_soft_disabled_t	*pload_soft_dis;
-	mechlist_t	*plist;
-	size_t	extra_mech_size = 0;
-	uint_t	dis_count;
-	int	i;
+	crypto_load_soft_disabled_t	*pload_soft_dis = NULL;
+	mechlist_t	*plist = NULL;
+	size_t		extra_mech_size = 0;
+	uint_t		dis_count;
+	int		i;
 
 	if (pent == NULL) {
 		return (NULL);
@@ -140,13 +137,13 @@
 crypto_load_dev_disabled_t *
 setup_dev_dis(entry_t *pent)
 {
-	crypto_load_dev_disabled_t	*pload_dev_dis;
-	mechlist_t	*plist;
-	size_t	extra_mech_size = 0;
-	uint_t	dis_count;
-	int	i;
-	char 	pname[MAXNAMELEN];
-	int	inst_num;
+	crypto_load_dev_disabled_t	*pload_dev_dis = NULL;
+	mechlist_t	*plist = NULL;
+	size_t		extra_mech_size = 0;
+	uint_t		dis_count;
+	int		i;
+	char		pname[MAXNAMELEN];
+	int		inst_num;
 
 	if (pent == NULL) {
 		return (NULL);
@@ -216,12 +213,14 @@
 /*
  * Prepare the calling argument for the GET_SOFT_INFO call for the provider
  * with the number of mechanisms specified in the second argument.
+ *
+ * Called by get_soft_info().
  */
 static crypto_get_soft_info_t *
 setup_get_soft_info(char *provname, int count)
 {
-	crypto_get_soft_info_t *psoft_info;
-	size_t extra_mech_size = 0;
+	crypto_get_soft_info_t	*psoft_info;
+	size_t			extra_mech_size = 0;
 
 	if (provname == NULL) {
 		return (NULL);
@@ -250,9 +249,9 @@
 int
 get_dev_list(crypto_get_dev_list_t **ppdevlist)
 {
-	crypto_get_dev_list_t *pdevlist;
-	int fd;
-	int count = DEFAULT_DEV_NUM;
+	crypto_get_dev_list_t	*pdevlist;
+	int			fd = -1;
+	int			count = DEFAULT_DEV_NUM;
 
 	pdevlist = malloc(sizeof (crypto_get_dev_list_t) +
 	    sizeof (crypto_dev_list_entry_t) * (count - 1));
@@ -318,13 +317,13 @@
 int
 get_dev_info(char *devname, int inst_num, int count, mechlist_t **ppmechlist)
 {
-	crypto_get_dev_info_t *dev_info;
-	mechlist_t *phead;
-	mechlist_t *pcur;
-	mechlist_t *pmech;
-	int fd;
-	int i;
-	int rc;
+	crypto_get_dev_info_t	*dev_info;
+	mechlist_t	*phead;
+	mechlist_t	*pcur;
+	mechlist_t	*pmech;
+	int		fd = -1;
+	int		i;
+	int		rc;
 
 	if (devname == NULL || count < 1) {
 		cryptodebug("get_dev_info(): devname is NULL or bogus count");
@@ -395,22 +394,26 @@
 }
 
 
-
 /*
  * Get the supported mechanism list of the software provider from kernel.
+ *
+ * Parameters phardlist and psoftlist are supplied by get_kcfconf_info().
+ * If NULL, this function calls get_kcfconf_info() internally.
  */
 int
-get_soft_info(char *provname, mechlist_t **ppmechlist)
+get_soft_info(char *provname, mechlist_t **ppmechlist,
+	entrylist_t *phardlist, entrylist_t *psoftlist)
 {
+	boolean_t		in_kernel = B_FALSE;
 	crypto_get_soft_info_t	*psoft_info;
-	mechlist_t	*phead;
-	mechlist_t	*pmech;
-	mechlist_t	*pcur;
-	entry_t	*pent;
-	int	count;
-	int	fd;
-	int	rc;
-	int	i;
+	mechlist_t		*phead;
+	mechlist_t		*pmech;
+	mechlist_t		*pcur;
+	entry_t			*pent = NULL;
+	int			count;
+	int			fd = -1;
+	int			rc;
+	int			i;
 
 	if (provname == NULL) {
 		return (FAILURE);
@@ -418,18 +421,33 @@
 
 	if (getzoneid() == GLOBAL_ZONEID) {
 		/* use kcf.conf for kernel software providers in global zone */
-		if ((pent = getent_kef(provname)) == NULL) {
-			cryptoerror(LOG_STDERR, gettext("%s does not exist."),
-			    provname);
-			return (FAILURE);
+		if ((pent = getent_kef(provname, phardlist, psoftlist)) ==
+		    NULL) {
+
+			/* No kcf.conf entry for this provider */
+			if (check_kernel_for_soft(provname, NULL, &in_kernel)
+			    == FAILURE) {
+				return (FAILURE);
+			} else if (in_kernel == B_FALSE) {
+				cryptoerror(LOG_STDERR,
+				    gettext("%s does not exist."), provname);
+				return (FAILURE);
+			}
+
+			/*
+			 * Set mech count to 1.  It will be reset to the
+			 * correct value later if the setup buffer is too small.
+			 */
+			count = 1;
+		} else {
+			count = pent->sup_count;
+			free_entry(pent);
 		}
-		count = pent->sup_count;
-		free_entry(pent);
 	} else {
 		/*
-		 * kcf.conf not there in non-global zone, set mech count to 1;
-		 * it will be reset to the correct value later if the setup
-		 * buffer is too small
+		 * kcf.conf not there in non-global zone: set mech count to 1.
+		 * It will be reset to the correct value later if the setup
+		 * buffer is too small.
 		 */
 		count = 1;
 	}
@@ -483,7 +501,7 @@
 	}
 
 
-	/* Get the mechanism list and return it */
+	/* Build the mechanism linked list and return it */
 	rc = SUCCESS;
 	phead = pcur = NULL;
 	for (i = 0; i < psoft_info->si_count; i++) {
@@ -519,9 +537,9 @@
 get_soft_list(crypto_get_soft_list_t **ppsoftlist)
 {
 	crypto_get_soft_list_t *psoftlist = NULL;
-	int count = DEFAULT_SOFT_NUM;
-	int len;
-	int fd;
+	int	count = DEFAULT_SOFT_NUM;
+	int	len;
+	int	fd = -1;
 
 	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) {
 		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
--- old/usr/src/cmd/cmd-crypto/cryptoadm/adm_kef_util.c	Tue Oct 28 16:45:31 2008
+++ new/usr/src/cmd/cmd-crypto/cryptoadm/adm_kef_util.c	Tue Oct 28 16:45:29 2008
@@ -32,6 +32,7 @@
 #include <unistd.h>
 #include <locale.h>
 #include <sys/types.h>
+#include <zone.h>
 #include <sys/stat.h>
 #include "cryptoadm.h"
 
@@ -41,7 +42,7 @@
 static mechlist_t *dup_mechlist(mechlist_t *);
 static entry_t *getent(char *, entrylist_t *);
 static int interpret(char *, entry_t **);
-static int parse_dislist(char *, entry_t *);
+static int parse_sup_dis_list(char *, entry_t *);
 
 
 /*
@@ -51,10 +52,10 @@
 static mechlist_t *
 dup_mechlist(mechlist_t *plist)
 {
-	mechlist_t *pres = NULL;
-	mechlist_t *pcur;
-	mechlist_t *ptmp;
-	int rc = SUCCESS;
+	mechlist_t	*pres = NULL;
+	mechlist_t	*pcur;
+	mechlist_t	*ptmp;
+	int		rc = SUCCESS;
 
 	while (plist != NULL) {
 		if (!(ptmp = create_mech(plist->name))) {
@@ -95,10 +96,39 @@
 	return (count);
 }
 
+/*
+ * Create one item of type entry_t with the provider name.
+ * Return NULL if there's not enough memory or provname is NULL.
+ */
+entry_t *
+create_entry(char *provname)
+{
+	entry_t		*pent = NULL;
 
+	if (provname == NULL) {
+		return (NULL);
+	}
+
+	pent = calloc(1, sizeof (entry_t));
+	if (pent == NULL) {
+		cryptodebug("out of memory.");
+		return (NULL);
+	}
+
+	(void) strlcpy(pent->name, provname, MAXNAMELEN);
+	pent->suplist = NULL;
+	pent->sup_count = 0;
+	pent->dislist = NULL;
+	pent->dis_count = 0;
+	pent->load = B_TRUE;
+
+	return (pent);
+}
+
 /*
- * Duplicate an entry.  A null pointer is returned if the storage space
- * available is insufficient or the input argument is NULL.
+ * Duplicate an entry for a provider from kcf.conf.
+ * Return NULL if memory is insufficient or the input argument is NULL.
+ * Called by getent().
  */
 static entry_t *
 dup_entry(entry_t *pent1)
@@ -109,16 +139,14 @@
 		return (NULL);
 	}
 
-	if ((pent2 = malloc(sizeof (entry_t))) == NULL) {
+	if ((pent2 = create_entry(pent1->name)) == NULL) {
 		cryptodebug("out of memory.");
 		return (NULL);
 	}
 
-	(void) strlcpy(pent2->name, pent1->name, sizeof (pent2->name));
 	pent2->sup_count = pent1->sup_count;
 	pent2->dis_count = pent1->dis_count;
-	pent2->suplist = NULL;
-	pent2->dislist = NULL;
+	pent2->load = pent1->load;
 	if (pent1->suplist != NULL) {
 		pent2->suplist = dup_mechlist(pent1->suplist);
 		if (pent2->suplist == NULL) {
@@ -143,7 +171,7 @@
  * in the kcf.conf configuration file.
  *
  * Arguments:
- * 	buf: an input argument which is a char string with the format of
+ *	buf: an input argument which is a char string with the format of
  *	     "disabledlist=m1,m2,..." or "supportedlist=m1,m2,..."
  *	pent: the entry for the disabledlist.  This is an IN/OUT argument.
  *
@@ -150,16 +178,16 @@
  * Return value: SUCCESS or FAILURE.
  */
 static int
-parse_dislist(char *buf, entry_t *pent)
+parse_sup_dis_list(char *buf, entry_t *pent)
 {
-	mechlist_t *pmech;
-	mechlist_t *phead;
-	char *next_token;
-	char *value;
-	int count;
-	int supflag = B_FALSE;
-	int disflag = B_FALSE;
-	int rc = SUCCESS;
+	mechlist_t	*pmech = NULL;
+	mechlist_t	*phead = NULL;
+	char		*next_token;
+	char		*value;
+	int		count;
+	int		supflag = B_FALSE;
+	int		disflag = B_FALSE;
+	int		rc = SUCCESS;
 
 	if (strncmp(buf, EF_SUPPORTED, strlen(EF_SUPPORTED)) == 0) {
 		supflag = B_TRUE;
@@ -219,33 +247,32 @@
 }
 
 
-
 /*
- * This routine converts a char string into an entry_t structure
+ * Convert a char string containing a line about a provider
+ * from kcf.conf into an entry_t structure.
+ *
+ * See ent2str(), the reverse of this function, for the format of
+ * kcf.conf lines.
  */
 static int
 interpret(char *buf, entry_t **ppent)
 {
-	entry_t *pent;
-	char *token1;
-	char *token2;
-	char *token3;
-	int rc;
+	entry_t	*pent = NULL;
+	char	*token1;
+	char	*token2;
+	char	*token3;
+	int	rc;
 
+	/* Get provider name */
 	if ((token1 = strtok(buf, SEP_COLON)) == NULL) { /* buf is NULL */
 		return (FAILURE);
 	};
 
-	pent = malloc(sizeof (entry_t));
+	pent = create_entry(token1);
 	if (pent == NULL) {
 		cryptodebug("out of memory.");
 		return (FAILURE);
 	}
-	(void) strlcpy(pent->name, token1, sizeof (pent->name));
-	pent->suplist = NULL;
-	pent->dislist = NULL;
-	pent->sup_count = 0;
-	pent->dis_count = 0;
 
 	if ((token2 = strtok(NULL, SEP_SEMICOLON)) == NULL) {
 		/* The entry contains a provider name only */
@@ -253,15 +280,28 @@
 		return (FAILURE);
 	}
 
+	if (strncmp(token2, EF_UNLOAD, strlen(EF_UNLOAD)) == 0) {
+		pent->load = B_FALSE; /* cryptoadm unload */
+		if ((token2 = strtok(NULL, SEP_SEMICOLON)) == NULL) {
+			/* The entry contains a provider name:unload only */
+			free_entry(pent);
+			return (FAILURE);
+		}
+	}
+
 	/* need to get token3 first to satisfy nested strtok invocations */
-	token3 = strtok(NULL, SEP_SEMICOLON);
+	token3 = strtok(NULL, SEP_SEMICOLON); /* optional */
 
-	if (token2 && ((rc = parse_dislist(token2, pent)) != SUCCESS)) {
+	/* parse supportedlist (or disabledlist if no supportedlist) */
+	if ((token2 != NULL) && ((rc = parse_sup_dis_list(token2, pent)) !=
+	    SUCCESS)) {
 		free_entry(pent);
 		return (rc);
 	}
 
-	if (token3 && ((rc = parse_dislist(token3, pent)) != SUCCESS)) {
+	/* parse disabledlist (if there's a supportedlist) */
+	if ((token3 != NULL) && ((rc = parse_sup_dis_list(token3, pent)) !=
+	    SUCCESS)) {
 		free_entry(pent);
 		return (rc);
 	}
@@ -272,14 +312,15 @@
 
 
 /*
- * Add an entry to the end of an entry list. If the entry list is NULL, will
- * create an entry list with the pent.
+ * Add an entry about a provider from kcf.conf to the end of an entry list.
+ * If the entry list pplist is NULL, create the linked list with pent as the
+ * first element.
  */
 static int
 build_entrylist(entry_t *pent, entrylist_t **pplist)
 {
-	entrylist_t *pentlist;
-	entrylist_t *pcur;
+	entrylist_t	*pentlist;
+	entrylist_t	*pcur = NULL;
 
 	pentlist = malloc(sizeof (entrylist_t));
 	if (pentlist == NULL) {
@@ -305,7 +346,7 @@
 
 /*
  * Find the entry with the "provname" name from the entry list and duplicate
- * it.
+ * it.  Called by getent_kef().
  */
 static entry_t *
 getent(char *provname, entrylist_t *entrylist)
@@ -335,7 +376,11 @@
 }
 
 
-
+/*
+ * Free memory in entry_t.
+ * That is, the supported and disabled lists for a provider
+ * from kcf.conf.
+ */
 void
 free_entry(entry_t  *pent)
 {
@@ -349,6 +394,10 @@
 }
 
 
+/*
+ * Free elements in a entrylist_t linked list,
+ * which lists providers in kcf.conf.
+ */
 void
 free_entrylist(entrylist_t *entrylist)
 {
@@ -364,21 +413,27 @@
 
 /*
  * Convert an entry to a string.  This routine builds a string for the entry
- * to be inserted in the config file.  Based on the content of each entry,
- * the result string can be one of the 4 forms:
- *  - name
+ * to be inserted in the kcf.conf file.  Based on the content of each entry,
+ * the result string can be one of these 6 forms:
  *  - name:supportedlist=m1,m2,...,mj
  *  - name:disabledlist=m1,m2,...,mj
  *  - name:supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk
  *
- * Note that the caller is responsible for freeing the returned string.
+ *  - name:unload;supportedlist=m1,m2,...,mj
+ *  - name:unload;disabledlist=m1,m2,...,mj
+ *  - name:unload;supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk
+ *
+ * Note that the caller is responsible for freeing the returned string
+ * (with free_entry()).
+ * See interpret() for the reverse of this function: converting a string
+ * to an entry_t.
  */
 char *
 ent2str(entry_t *pent)
 {
-	char	*buf;
-	mechlist_t  *phead;
-	boolean_t supflag = B_FALSE;
+	char		*buf;
+	mechlist_t	*pcur = NULL;
+	boolean_t	semicolon_separator = B_FALSE;
 
 
 	if (pent == NULL) {
@@ -395,29 +450,43 @@
 		return (NULL);
 	}
 
-	/* convert the supported list if any */
-	phead = pent->suplist;
-	if (phead != NULL) {
-		supflag = B_TRUE;
-
+	if (!pent->load) { /* add "unload" keyword */
 		if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) {
 			free(buf);
 			return (NULL);
 		}
 
+		if (strlcat(buf, EF_UNLOAD, BUFSIZ) >= BUFSIZ) {
+			free(buf);
+			return (NULL);
+		}
+
+		semicolon_separator = B_TRUE;
+	}
+
+	/* convert the supported list if any */
+	pcur = pent->suplist;
+	if (pcur != NULL) {
+		if (strlcat(buf,
+		    semicolon_separator ? SEP_SEMICOLON : SEP_COLON,
+		    BUFSIZ) >= BUFSIZ) {
+			free(buf);
+			return (NULL);
+		}
+
 		if (strlcat(buf, EF_SUPPORTED, BUFSIZ) >= BUFSIZ) {
 			free(buf);
 			return (NULL);
 		}
 
-		while (phead != NULL) {
-			if (strlcat(buf, phead->name, BUFSIZ) >= BUFSIZ) {
+		while (pcur != NULL) {
+			if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) {
 				free(buf);
 				return (NULL);
 			}
 
-			phead = phead->next;
-			if (phead != NULL) {
+			pcur = pcur->next;
+			if (pcur != NULL) {
 				if (strlcat(buf, SEP_COMMA, BUFSIZ)
 				    >= BUFSIZ) {
 					free(buf);
@@ -425,31 +494,32 @@
 				}
 			}
 		}
+		semicolon_separator = B_TRUE;
 	}
 
 	/* convert the disabled list if any */
-	phead = pent->dislist;
-	if (phead != NULL) {
-		if (supflag) {
-			if (strlcat(buf, ";disabledlist=", BUFSIZ) >= BUFSIZ) {
-				free(buf);
-				return (NULL);
-			}
-		} else {
-			if (strlcat(buf, ":disabledlist=", BUFSIZ) >= BUFSIZ) {
-				free(buf);
-				return (NULL);
-			}
+	pcur = pent->dislist;
+	if (pcur != NULL) {
+		if (strlcat(buf,
+		    semicolon_separator ? SEP_SEMICOLON : SEP_COLON,
+		    BUFSIZ) >= BUFSIZ) {
+			free(buf);
+			return (NULL);
 		}
 
-		while (phead != NULL) {
-			if (strlcat(buf, phead->name, BUFSIZ) >= BUFSIZ) {
+		if (strlcat(buf, EF_DISABLED, BUFSIZ) >= BUFSIZ) {
+			free(buf);
+			return (NULL);
+		}
+
+		while (pcur != NULL) {
+			if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) {
 				free(buf);
 				return (NULL);
 			}
 
-			phead = phead->next;
-			if (phead != NULL) {
+			pcur = pcur->next;
+			if (pcur != NULL) {
 				if (strlcat(buf, SEP_COMMA, BUFSIZ)
 				    >= BUFSIZ) {
 					free(buf);
@@ -457,6 +527,7 @@
 				}
 			}
 		}
+		semicolon_separator = B_TRUE;
 	}
 
 	if (strlcat(buf, "\n", BUFSIZ) >= BUFSIZ) {
@@ -476,11 +547,11 @@
 int
 enable_mechs(entry_t **ppent, boolean_t allflag, mechlist_t *mlist)
 {
-	entry_t *pent;
-	mechlist_t *phead; /* the current and resulting disabled list */
-	mechlist_t *ptr;
-	mechlist_t *pcur;
-	boolean_t found;
+	entry_t		*pent;
+	mechlist_t	*phead; /* the current and resulting disabled list */
+	mechlist_t	*ptr = NULL;
+	mechlist_t	*pcur = NULL;
+	boolean_t	found;
 
 	pent = *ppent;
 	if (pent == NULL) {
@@ -498,7 +569,7 @@
 	 * for each mechanism in the to-be-enabled mechanism list,
 	 * -	check if it is in the current disabled list
 	 * -	if found, delete it from the disabled list
-	 * 	otherwise, give a warning.
+	 *	otherwise, give a warning.
 	 */
 	ptr = mlist;
 	while (ptr != NULL) {
@@ -540,6 +611,11 @@
 }
 
 
+/*
+ * Determine if the kernel provider name, path, is a device
+ * (that is, it contains a slash character (e.g., "mca/0").
+ * If so, it is a hardware provider; otherwise it is a software provider.
+ */
 boolean_t
 is_device(char *path)
 {
@@ -552,7 +628,7 @@
 
 /*
  * Split a hardware provider name with the "name/inst_num" format into
- * a name and a number.
+ * a name and a number (e.g., split "mca/0" into "mca" instance 0).
  */
 int
 split_hw_provname(char *provname, char *pname, int *inst_num)
@@ -581,17 +657,23 @@
 
 
 /*
- * Retrieve information from kcf.conf and build a device entry list and
- * a software entry list
+ * Retrieve information from kcf.conf and build a hardware device entry list
+ * and a software entry list of kernel crypto providers.
+ *
+ * This list is usually incomplete, as kernel crypto providers only have to
+ * be listed in kcf.conf if a mechanism is disabled (by cryptoadm) or
+ * if the kernel provider module is not one of the default kernel providers.
+ *
+ * The kcf.conf file is available only in the global zone.
  */
 int
 get_kcfconf_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist)
 {
-	FILE *pfile;
-	char buffer[BUFSIZ];
-	int len;
-	entry_t *pent = NULL;
-	int rc = SUCCESS;
+	FILE	*pfile = NULL;
+	char	buffer[BUFSIZ];
+	int	len;
+	entry_t	*pent = NULL;
+	int	rc = SUCCESS;
 
 	if ((pfile = fopen(_PATH_KCF_CONF, "r")) == NULL) {
 		cryptodebug("failed to open the kcf.conf file for read only");
@@ -607,7 +689,7 @@
 		}
 
 		len = strlen(buffer);
-		if (buffer[len-1] == '\n') { /* get rid of trailing '\n' */
+		if (buffer[len - 1] == '\n') { /* get rid of trailing '\n' */
 			len--;
 		}
 		buffer[len] = '\0';
@@ -637,24 +719,28 @@
 
 /*
  * Retrieve information from admin device and build a device entry list and
- * a software entry list.  This is used where there is no kcf.conf, e.g.
+ * a software entry list.  This is used where there is no kcf.conf, e.g., the
  * non-global zone.
  */
 int
 get_admindev_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist)
 {
-	crypto_get_dev_list_t *pdevlist_kernel = NULL;
-	crypto_get_soft_list_t *psoftlist_kernel = NULL;
-	char *devname;
-	int inst_num;
-	int mcount;
-	mechlist_t *pmech;
-	entry_t *pent = NULL;
-	int i;
-	char *psoftname;
-	entrylist_t *tmp_pdev = NULL;
-	entrylist_t *tmp_psoft = NULL;
+	crypto_get_dev_list_t	*pdevlist_kernel = NULL;
+	crypto_get_soft_list_t	*psoftlist_kernel = NULL;
+	char			*devname;
+	int			inst_num;
+	int			mcount;
+	mechlist_t		*pmech = NULL;
+	entry_t			*pent_dev = NULL, *pent_soft = NULL;
+	int			i;
+	char			*psoftname;
+	entrylist_t		*tmp_pdev = NULL;
+	entrylist_t		*tmp_psoft = NULL;
+	entrylist_t		*phardlist = NULL, *psoftlist = NULL;
 
+	/*
+	 * Get hardware providers
+	 */
 	if (get_dev_list(&pdevlist_kernel) != SUCCESS) {
 		cryptodebug("failed to get hardware provider list from kernel");
 		return (FAILURE);
@@ -674,29 +760,31 @@
 			goto fail_out;
 		}
 
-		if ((pent = malloc(sizeof (entry_t))) == NULL) {
+		if ((pent_dev = create_entry(devname)) == NULL) {
 			cryptodebug("out of memory.");
 			free_mechlist(pmech);
 			goto fail_out;
 		}
+		pent_dev->suplist = pmech;
+		pent_dev->sup_count = mcount;
 
-		(void) strlcpy(pent->name, devname, MAXNAMELEN);
-		pent->suplist = pmech;
-		pent->sup_count = mcount;
-		pent->dislist = NULL;
-		pent->dis_count = 0;
-
-		if (build_entrylist(pent, &tmp_pdev) != SUCCESS) {
+		if (build_entrylist(pent_dev, &tmp_pdev) != SUCCESS) {
 			goto fail_out;
 		}
-
-		/* because incorporated in tmp_pdev */
-		pent = NULL;
 	}
 
 	free(pdevlist_kernel);
 	pdevlist_kernel = NULL;
 
+	/*
+	 * Get software providers
+	 */
+	if (getzoneid() == GLOBAL_ZONEID) {
+		if (get_kcfconf_info(&phardlist, &psoftlist) != SUCCESS) {
+			goto fail_out;
+		}
+	}
+
 	if (get_soft_list(&psoftlist_kernel) != SUCCESS) {
 		cryptodebug("failed to get software provider list from kernel");
 		goto fail_out;
@@ -706,7 +794,8 @@
 	    i < psoftlist_kernel->sl_soft_count;
 	    i++, psoftname = psoftname + strlen(psoftname) + 1) {
 		pmech = NULL;
-		if (get_soft_info(psoftname, &pmech) != SUCCESS) {
+		if (get_soft_info(psoftname, &pmech, phardlist, psoftlist) !=
+		    SUCCESS) {
 			cryptodebug(
 			    "failed to retrieve the mechanism list for %s.",
 			    psoftname);
@@ -713,19 +802,15 @@
 			goto fail_out;
 		}
 
-		if ((pent = malloc(sizeof (entry_t))) == NULL) {
+		if ((pent_soft = create_entry(psoftname)) == NULL) {
 			cryptodebug("out of memory.");
 			free_mechlist(pmech);
 			goto fail_out;
 		}
+		pent_soft->suplist = pmech;
+		pent_soft->sup_count = get_mech_count(pmech);
 
-		(void) strlcpy(pent->name, psoftname, MAXNAMELEN);
-		pent->suplist = pmech;
-		pent->sup_count = get_mech_count(pmech);
-		pent->dislist = NULL;
-		pent->dis_count = 0;
-
-		if (build_entrylist(pent, &tmp_psoft) != SUCCESS) {
+		if (build_entrylist(pent_soft, &tmp_psoft) != SUCCESS) {
 			goto fail_out;
 		}
 	}
@@ -739,8 +824,10 @@
 	return (SUCCESS);
 
 fail_out:
-	if (pent != NULL)
-		free_entry(pent);
+	if (pent_dev != NULL)
+		free_entry(pent_dev);
+	if (pent_soft != NULL)
+		free_entry(pent_soft);
 
 	free_entrylist(tmp_pdev);
 	free_entrylist(tmp_psoft);
@@ -754,28 +841,36 @@
 }
 
 /*
- * Find the entry in the "kcf.conf" file with "provname" as the provider name.
- * Return the entry if found, otherwise return NULL.
+ * Return configuration information for a kernel provider from kcf.conf.
+ * For kernel software providers return a enabled list and disabled list.
+ * For kernel hardware providers return just a disabled list.
+ *
+ * Parameters phardlist and psoftlist are supplied by get_kcfconf_info().
+ * If NULL, this function calls get_kcfconf_info() internally.
  */
 entry_t *
-getent_kef(char *provname)
+getent_kef(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist)
 {
-	entrylist_t *pdevlist = NULL;
-	entrylist_t *psoftlist = NULL;
-	entry_t *pent = NULL;
+	entry_t		*pent = NULL;
+	boolean_t	memory_allocated = B_FALSE;
 
-	if (get_kcfconf_info(&pdevlist, &psoftlist) != SUCCESS) {
-		return (NULL);
+	if ((phardlist == NULL) || (psoftlist == NULL)) {
+		if (get_kcfconf_info(&phardlist, &psoftlist) != SUCCESS) {
+			return (NULL);
+		}
+		memory_allocated = B_TRUE;
 	}
 
 	if (is_device(provname)) {
-		pent = getent(provname, pdevlist);
+		pent = getent(provname, phardlist);
 	} else {
 		pent = getent(provname, psoftlist);
 	}
 
-	free_entrylist(pdevlist);
-	free_entrylist(psoftlist);
+	if (memory_allocated) {
+		free_entrylist(phardlist);
+		free_entrylist(psoftlist);
+	}
 
 	return (pent);
 }
@@ -786,7 +881,7 @@
 void
 print_mechlist(char *provname, mechlist_t *pmechlist)
 {
-	mechlist_t *ptr;
+	mechlist_t *ptr = NULL;
 
 	if (provname == NULL) {
 		return;
@@ -812,12 +907,11 @@
 
 
 /*
- * Update the kcf.conf file based on the specified entry and the update mode.
- * - If update_mode is MODIFY_MODE or DELETE_MODE, the entry with the same
- *   provider name will be modified or deleted.
- * - If update_mode is ADD_MODE, this must be a hardware provider without
- *   an entry in the kcf.conf file yet.  Need to locate its driver package
- *   bracket and insert an entry into the bracket.
+ * Update the kcf.conf file based on the update mode:
+ * - If update_mode is MODIFY_MODE, modify the entry with the same name.
+ *   If not found, append a new entry to the kcf.conf file.
+ * - If update_mode is DELETE_MODE, delete the entry with the same name.
+ * - If update_mode is ADD_MODE, append a new entry to the kcf.conf file.
  */
 int
 update_kcfconf(entry_t *pent, int update_mode)
@@ -824,21 +918,16 @@
 {
 	boolean_t	add_it = B_FALSE;
 	boolean_t	delete_it = B_FALSE;
-	boolean_t	found_package = B_FALSE;
 	boolean_t	found_entry = B_FALSE;
-	FILE	*pfile;
-	FILE	*pfile_tmp;
-	char	buffer[BUFSIZ];
-	char	buffer2[BUFSIZ];
-	char	devname[MAXNAMELEN];
-	char	tmpfile_name[MAXPATHLEN];
-	char	*name;
-	char	*str;
-	char	*new_str = NULL;
-	int	inst_num;
-	int rc = SUCCESS;
+	FILE		*pfile = NULL;
+	FILE		*pfile_tmp = NULL;
+	char		buffer[BUFSIZ];
+	char		buffer2[BUFSIZ];
+	char		tmpfile_name[MAXPATHLEN];
+	char		*name;
+	char		*new_str = NULL;
+	int		rc = SUCCESS;
 
-
 	if (pent == NULL) {
 		cryptoerror(LOG_STDERR, gettext("internal error."));
 		return (FAILURE);
@@ -845,26 +934,24 @@
 	}
 
 	/* Check the update_mode */
-	if (update_mode == ADD_MODE) {
+	switch (update_mode) {
+	case ADD_MODE:
 		add_it = B_TRUE;
-		/* Get the hardware provider name first */
-		if (split_hw_provname(pent->name, devname, &inst_num) ==
-		    FAILURE) {
-			return (FAILURE);
-		}
-
-		/* Convert the entry to be a string  */
+		/* FALLTHROUGH */
+	case MODIFY_MODE:
+		/* Convert the entry a string to add to kcf.conf  */
 		if ((new_str = ent2str(pent)) == NULL) {
 			return (FAILURE);
 		}
-	} else if (update_mode == DELETE_MODE) {
+		break;
+	case DELETE_MODE:
 		delete_it = B_TRUE;
-	} else if (update_mode != MODIFY_MODE) {
+		break;
+	default:
 		cryptoerror(LOG_STDERR, gettext("internal error."));
 		return (FAILURE);
 	}
 
-
 	/* Open the kcf.conf file */
 	if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) {
 		err = errno;
@@ -880,7 +967,7 @@
 		err = errno;
 		cryptoerror(LOG_STDERR,
 		    gettext("failed to update the configuration - %s"),
-			strerror(err));
+		    strerror(err));
 		(void) fclose(pfile);
 		return (FAILURE);
 	}
@@ -913,7 +1000,6 @@
 	 */
 	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
 		if (add_it) {
-			/* always keep the current line */
 			if (fputs(buffer, pfile_tmp) == EOF) {
 				err = errno;
 				cryptoerror(LOG_STDERR, gettext(
@@ -923,26 +1009,9 @@
 				break;
 			}
 
-			/*
-			 * If the current position is the beginning of a driver
-			 * package and if the driver name matches the hardware
-			 * provider name, then we want to insert the entry
-			 * here.
-			 */
-			if ((strstr(buffer, HW_DRIVER_STRING) != NULL) &&
-			    (strstr(buffer, devname) != NULL)) {
-				found_package = B_TRUE;
-				if (fputs(new_str, pfile_tmp) == EOF) {
-					err = errno;
-					cryptoerror(LOG_STDERR, gettext(
-					    "failed to write to a temp file: "
-					    "%s."), strerror(err));
-					rc = FAILURE;
-					break;
-				}
-			}
 		} else { /* modify or delete */
 			found_entry = B_FALSE;
+
 			if (!(buffer[0] == '#' || buffer[0] == ' ' ||
 			    buffer[0] == '\n'|| buffer[0] == '\t')) {
 				/*
@@ -969,13 +1038,8 @@
 				 * This is the entry to be updated; get the
 				 * updated string and place into buffer.
 				 */
-				if ((str = ent2str(pent)) == NULL) {
-					rc = FAILURE;
-					break;
-				} else {
-					(void) strlcpy(buffer, str, BUFSIZ);
-					free(str);
-				}
+				(void) strlcpy(buffer, new_str, BUFSIZ);
+				free(new_str);
 			}
 
 			if (!(found_entry && delete_it)) {
@@ -992,26 +1056,18 @@
 		}
 	}
 
-	if (add_it) {
-		free(new_str);
-	}
-
-	if ((add_it && !found_package) || (rc == FAILURE)) {
-		if (add_it && !found_package) {
-			cryptoerror(LOG_STDERR,
-			    gettext("failed to update configuration - no "
-			    "driver package information."));
+	if ((!delete_it) && (rc != FAILURE)) {
+		if (add_it || !found_entry) {
+			/* append new entry to end of file */
+			if (fputs(new_str, pfile_tmp) == EOF) {
+				err = errno;
+				cryptoerror(LOG_STDERR, gettext(
+				    "failed to write to a temp file: %s."),
+				    strerror(err));
+				rc = FAILURE;
+			}
+			free(new_str);
 		}
-
-		(void) fclose(pfile);
-		(void) fclose(pfile_tmp);
-		if (unlink(tmpfile_name) != 0) {
-			err = errno;
-			cryptoerror(LOG_STDERR, gettext(
-			    "(Warning) failed to remove %s: %s"),
-			    tmpfile_name, strerror(err));
-		}
-		return (FAILURE);
 	}
 
 	(void) fclose(pfile);
@@ -1066,11 +1122,11 @@
 disable_mechs(entry_t **ppent, mechlist_t *infolist, boolean_t allflag,
 mechlist_t *dislist)
 {
-	entry_t *pent;
-	mechlist_t *plist;
-	mechlist_t *phead;
-	mechlist_t *pmech;
-	int rc = SUCCESS;
+	entry_t		*pent;
+	mechlist_t	*plist = NULL;
+	mechlist_t	*phead = NULL;
+	mechlist_t	*pmech = NULL;
+	int		rc = SUCCESS;
 
 	pent = *ppent;
 	if (pent == NULL) {
@@ -1131,9 +1187,9 @@
 boolean_t
 filter_mechlist(mechlist_t **pmechlist, const char *mech)
 {
-	int cnt = 0;
-	mechlist_t *ptr, *pptr;
-	boolean_t mech_present = B_FALSE;
+	int		cnt = 0;
+	mechlist_t	*ptr, *pptr;
+	boolean_t	mech_present = B_FALSE;
 
 	ptr = pptr = *pmechlist;
 
@@ -1172,22 +1228,23 @@
  * The flag has_random is set to B_TRUE if the provider does random
  * numbers. The flag has_mechs is set by the caller to B_TRUE if the provider
  * has some mechanisms.
+ *
+ * If pent is NULL, the provider doesn't have a kcf.conf entry.
  */
 void
-print_kef_policy(entry_t *pent, boolean_t has_random, boolean_t has_mechs)
+print_kef_policy(char *provname, entry_t *pent, boolean_t has_random,
+    boolean_t has_mechs)
 {
-	mechlist_t *ptr;
-	boolean_t rnd_disabled = B_FALSE;
+	mechlist_t	*ptr = NULL;
+	boolean_t	rnd_disabled = B_FALSE;
 
-	if (pent == NULL) {
-		return;
+	if (pent != NULL) {
+		rnd_disabled = filter_mechlist(&pent->dislist, RANDOM);
+		ptr = pent->dislist;
 	}
 
-	rnd_disabled = filter_mechlist(&pent->dislist, RANDOM);
-	ptr = pent->dislist;
+	(void) printf("%s:", provname);
 
-	(void) printf("%s:", pent->name);
-
 	if (has_mechs == B_TRUE) {
 		/*
 		 * TRANSLATION_NOTE
@@ -1218,15 +1275,23 @@
 	(void) printf("\n");
 }
 
+
 /*
  * Check if a kernel software provider is in the kernel.
+ *
+ * Parameters:
+ * provname		Provider name
+ * psoftlist_kernel	Optional software provider list.  If NULL, it will be
+ *			obtained from get_soft_list().
+ * in_kernel		Set to B_TRUE if device is in the kernel, else B_FALSE
  */
 int
-check_active_for_soft(char *provname, boolean_t *is_active)
+check_kernel_for_soft(char *provname, crypto_get_soft_list_t *psoftlist_kernel,
+    boolean_t *in_kernel)
 {
-	crypto_get_soft_list_t	*psoftlist_kernel = NULL;
-	char	*ptr;
-	int	i;
+	char		*ptr;
+	int		i;
+	boolean_t	psoftlist_allocated = B_FALSE;
 
 	if (provname == NULL) {
 		cryptoerror(LOG_STDERR, gettext("internal error."));
@@ -1233,23 +1298,28 @@
 		return (FAILURE);
 	}
 
-	if (get_soft_list(&psoftlist_kernel) == FAILURE) {
-		cryptodebug("failed to get the software provider list from"
-		    "kernel.");
-		return (FAILURE);
+	if (psoftlist_kernel == NULL) {
+		if (get_soft_list(&psoftlist_kernel) == FAILURE) {
+			cryptodebug("failed to get the software provider list"
+			" from kernel.");
+			return (FAILURE);
+		}
+		psoftlist_allocated = B_TRUE;
 	}
 
-	*is_active = B_FALSE;
+	*in_kernel = B_FALSE;
 	ptr = psoftlist_kernel->sl_soft_names;
 	for (i = 0; i < psoftlist_kernel->sl_soft_count; i++) {
 		if (strcmp(provname, ptr) == 0) {
-			*is_active = B_TRUE;
+			*in_kernel = B_TRUE;
 			break;
 		}
 		ptr = ptr + strlen(ptr) + 1;
 	}
-	free(psoftlist_kernel);
 
+	if (psoftlist_allocated)
+		free(psoftlist_kernel);
+
 	return (SUCCESS);
 }
 
@@ -1256,14 +1326,21 @@
 
 /*
  * Check if a kernel hardware provider is in the kernel.
+ *
+ * Parameters:
+ * provname	Provider name
+ * pdevlist	Optional Hardware Crypto Device List.  If NULL, it will be
+ *		obtained from get_dev_list().
+ * in_kernel	Set to B_TRUE if device is in the kernel, otherwise B_FALSE
  */
 int
-check_active_for_hard(char *provname, boolean_t *is_active)
+check_kernel_for_hard(char *provname,
+    crypto_get_dev_list_t *pdevlist, boolean_t *in_kernel)
 {
-	crypto_get_dev_list_t	*pdevlist = NULL;
-	char 	devname[MAXNAMELEN];
-	int	inst_num;
-	int	i;
+	char		devname[MAXNAMELEN];
+	int		inst_num;
+	int		i;
+	boolean_t	dev_list_allocated = B_FALSE;
 
 	if (provname == NULL) {
 		cryptoerror(LOG_STDERR, gettext("internal error."));
@@ -1274,20 +1351,25 @@
 		return (FAILURE);
 	}
 
-	if (get_dev_list(&pdevlist) == FAILURE) {
-		cryptoerror(LOG_STDERR, gettext("internal error."));
-		return (FAILURE);
+	if (pdevlist == NULL) {
+		if (get_dev_list(&pdevlist) == FAILURE) {
+			cryptoerror(LOG_STDERR, gettext("internal error."));
+			return (FAILURE);
+		}
+		dev_list_allocated = B_TRUE;
 	}
 
-	*is_active = B_FALSE;
+	*in_kernel = B_FALSE;
 	for (i = 0; i < pdevlist->dl_dev_count; i++) {
 		if ((strcmp(pdevlist->dl_devs[i].le_dev_name, devname) == 0) &&
 		    (pdevlist->dl_devs[i].le_dev_instance == inst_num)) {
-			*is_active = B_TRUE;
+			*in_kernel = B_TRUE;
 			break;
 		}
 	}
-	free(pdevlist);
 
+	if (dev_list_allocated)
+		free(pdevlist);
+
 	return (SUCCESS);
 }
--- old/usr/src/cmd/cmd-crypto/cryptoadm/cryptoadm.c	Tue Oct 28 16:45:34 2008
+++ new/usr/src/cmd/cmd-crypto/cryptoadm/cryptoadm.c	Tue Oct 28 16:45:32 2008
@@ -248,9 +248,9 @@
 /*
  * Get the provider type.  This function returns
  * - PROV_UEF_LIB if provname contains an absolute path name
- * - PROV_KEF_SOFT if provname is a base name only
+ * - PROV_KEF_SOFT if provname is a base name only (e.g., "aes").
  * - PROV_KEF_HARD if provname contains one slash only and the slash is not
- *	the 1st character.
+ *	the 1st character (e.g., "mca/0").
  * - PROV_BADNAME otherwise.
  */
 static int
@@ -287,11 +287,11 @@
 static cryptoadm_provider_t *
 get_provider(int argc, char **argv)
 {
-	int c = 0;
-	boolean_t found = B_FALSE;
-	cryptoadm_provider_t *provider = NULL;
-	char *provstr = NULL, *savstr;
-	boolean_t is_metaslot = B_FALSE;
+	int			c = 0;
+	boolean_t		found = B_FALSE;
+	cryptoadm_provider_t	*provider = NULL;
+	char			*provstr = NULL, *savstr;
+	boolean_t		is_metaslot = B_FALSE;
 
 	while (!found && ++c < argc) {
 		if (strncmp(argv[c], METASLOT_KEYWORD,
@@ -457,21 +457,21 @@
  * mechanism operands and save it in the static variable mecharglist.
  *
  * This function returns
- * 	ERROR_USAGE: mechanism operand is missing.
- * 	FAILURE: out of memory.
- * 	SUCCESS: otherwise.
+ *	ERROR_USAGE: mechanism operand is missing.
+ *	FAILURE: out of memory.
+ *	SUCCESS: otherwise.
  */
 static int
 process_mech_operands(int argc, char **argv, boolean_t quiet)
 {
-	mechlist_t *pmech;
-	mechlist_t *pcur = NULL;
-	mechlist_t *phead = NULL;
-	boolean_t found = B_FALSE;
-	char *mechliststr = NULL;
-	char *curmech = NULL;
-	int c = -1;
-	int rc = SUCCESS;
+	mechlist_t	*pmech;
+	mechlist_t	*pcur = NULL;
+	mechlist_t	*phead = NULL;
+	boolean_t	found = B_FALSE;
+	char		*mechliststr = NULL;
+	char		*curmech = NULL;
+	int		c = -1;
+	int		rc = SUCCESS;
 
 	while (!found && ++c < argc) {
 		if ((strncmp(argv[c], KN_MECH, strlen(KN_MECH)) == 0) &&
@@ -489,8 +489,8 @@
 			 * view it as a literal keyword.
 			 */
 			cryptoerror(LOG_STDERR,
-				gettext("the %s operand is missing.\n"),
-				"mechanism");
+			    gettext("the %s operand is missing.\n"),
+			    "mechanism");
 		return (ERROR_USAGE);
 	}
 	(void) strtok(argv[c], "=");
@@ -530,17 +530,17 @@
 
 
 /*
- * The top level function for the list subcommand and options.
+ * The top level function for the "cryptoadm list" subcommand and options.
  */
 static int
 do_list(int argc, char **argv)
 {
-	boolean_t	mflag = B_FALSE;
-	boolean_t	pflag = B_FALSE;
-	boolean_t	vflag = B_FALSE;
-	char	ch;
-	cryptoadm_provider_t 	*prov = NULL;
-	int	rc = SUCCESS;
+	boolean_t		mflag = B_FALSE;
+	boolean_t		pflag = B_FALSE;
+	boolean_t		vflag = B_FALSE;
+	char			ch;
+	cryptoadm_provider_t	*prov = NULL;
+	int			rc = SUCCESS;
 
 	argc -= 1;
 	argv += 1;
@@ -551,7 +551,7 @@
 	}
 
 	/*
-	 * [-v] [-m] [-p] [provider=<>] [mechanism=<>]
+	 * cryptoadm list [-v] [-m] [-p] [provider=<>] [mechanism=<>]
 	 */
 	if (argc > 5) {
 		usage();
@@ -631,21 +631,23 @@
 		rc = ERROR_USAGE;
 		goto out;
 	} else { /* do the listing for a provider only */
+		char	*provname = prov->cp_name;
+
 		if (mflag || vflag) {
 			if (vflag)
 				(void) printf(gettext("Provider: %s\n"),
-					prov->cp_name);
+				    provname);
 			switch (prov->cp_type) {
 			case PROV_UEF_LIB:
-				rc = list_mechlist_for_lib(prov->cp_name,
-					mecharglist, NULL, B_FALSE,
-					vflag, mflag);
+				rc = list_mechlist_for_lib(provname,
+				    mecharglist, NULL, B_FALSE, vflag, mflag);
 				break;
 			case PROV_KEF_SOFT:
-				rc = list_mechlist_for_soft(prov->cp_name);
+				rc = list_mechlist_for_soft(provname,
+				    NULL, NULL);
 				break;
 			case PROV_KEF_HARD:
-				rc = list_mechlist_for_hard(prov->cp_name);
+				rc = list_mechlist_for_hard(provname);
 				break;
 			default: /* should not come here */
 				rc = FAILURE;
@@ -654,12 +656,12 @@
 		} else if (pflag) {
 			switch (prov->cp_type) {
 			case PROV_UEF_LIB:
-				rc = list_policy_for_lib(prov->cp_name);
+				rc = list_policy_for_lib(provname);
 				break;
 			case PROV_KEF_SOFT:
 				if (getzoneid() == GLOBAL_ZONEID) {
-					rc = list_policy_for_soft(
-					    prov->cp_name);
+					rc = list_policy_for_soft(provname,
+					    NULL, NULL);
 				} else {
 					/*
 					 * TRANSLATION_NOTE
@@ -676,7 +678,7 @@
 			case PROV_KEF_HARD:
 				if (getzoneid() == GLOBAL_ZONEID) {
 					rc = list_policy_for_hard(
-					    prov->cp_name);
+					    provname, NULL, NULL, NULL);
 				} else {
 					/*
 					 * TRANSLATION_NOTE
@@ -713,14 +715,14 @@
 
 
 /*
- * The top level function for the disable subcommand.
+ * The top level function for the "cryptoadm disable" subcommand.
  */
 static int
 do_disable(int argc, char **argv)
 {
 	cryptoadm_provider_t	*prov = NULL;
-	int	rc = SUCCESS;
-	boolean_t auto_key_migrate_flag = B_FALSE;
+	int			rc = SUCCESS;
+	boolean_t		auto_key_migrate_flag = B_FALSE;
 
 	if ((argc < 3) || (argc > 5)) {
 		usage();
@@ -752,7 +754,7 @@
 			return (rc);
 		}
 	} else if (!allflag && !rndflag &&
-		(rc = process_mech_operands(argc, argv, B_FALSE)) != SUCCESS) {
+	    (rc = process_mech_operands(argc, argv, B_FALSE)) != SUCCESS) {
 			return (rc);
 	}
 
@@ -830,15 +832,16 @@
 
 
 /*
- * The top level function fo the enable subcommand.
+ * The top level function for the "cryptoadm enable" subcommand.
  */
 static int
 do_enable(int argc, char **argv)
 {
-	cryptoadm_provider_t 	*prov = NULL;
-	int	rc = SUCCESS;
-	char *alt_token = NULL, *alt_slot = NULL;
-	boolean_t use_default = B_FALSE, auto_key_migrate_flag = B_FALSE;
+	cryptoadm_provider_t	*prov = NULL;
+	int			rc = SUCCESS;
+	char 			*alt_token = NULL, *alt_slot = NULL;
+	boolean_t		use_default = B_FALSE;
+	boolean_t		auto_key_migrate_flag = B_FALSE;
 
 	if ((argc < 3) || (argc > 6)) {
 		usage();
@@ -944,12 +947,12 @@
 
 
 /*
- * The top level function fo the install subcommand.
+ * The top level function for the "cryptoadm install" subcommand.
  */
 static int
 do_install(int argc, char **argv)
 {
-	cryptoadm_provider_t 	*prov = NULL;
+	cryptoadm_provider_t	*prov = NULL;
 	int	rc;
 
 	if (argc < 3) {
@@ -1034,12 +1037,12 @@
 
 
 /*
- * The top level function for the uninstall subcommand.
+ * The top level function for the "cryptoadm uninstall" subcommand.
  */
 static int
 do_uninstall(int argc, char **argv)
 {
-	cryptoadm_provider_t 	*prov = NULL;
+	cryptoadm_provider_t	*prov = NULL;
 	int	rc = SUCCESS;
 
 	if (argc != 3) {
@@ -1064,8 +1067,10 @@
 
 	if (prov->cp_type == PROV_UEF_LIB) {
 		rc = uninstall_uef_lib(prov->cp_name);
+
 	} else if (prov->cp_type == PROV_KEF_SOFT) {
 		if (getzoneid() == GLOBAL_ZONEID) {
+			/* unload and remove from kcf.conf */
 			rc = uninstall_kef(prov->cp_name);
 		} else {
 			/*
@@ -1089,15 +1094,16 @@
 
 
 /*
- * The top level function for the unload subcommand.
+ * The top level function for the "cryptoadm unload" subcommand.
  */
 static int
 do_unload(int argc, char **argv)
 {
-	cryptoadm_provider_t 	*prov = NULL;
-	entry_t	*pent;
-	boolean_t	is_active;
-	int rc = SUCCESS;
+	cryptoadm_provider_t	*prov = NULL;
+	entry_t			*pent = NULL;
+	boolean_t		in_kernel = B_FALSE;
+	int			rc = SUCCESS;
+	char			*provname = NULL;
 
 	if (argc != 3) {
 		usage();
@@ -1111,10 +1117,11 @@
 		    gettext("unable to determine provider name."));
 		goto out;
 	}
+	provname = prov->cp_name;
 	if (prov->cp_type != PROV_KEF_SOFT) {
 		cryptoerror(LOG_STDERR,
 		    gettext("%s is not a valid kernel software provider."),
-		    prov->cp_name);
+		    provname);
 		rc = FAILURE;
 		goto out;
 	}
@@ -1133,36 +1140,45 @@
 		goto out;
 	}
 
-	/* Check if it is in the kcf.conf file first */
-	if ((pent = getent_kef(prov->cp_name)) == NULL) {
+	if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) {
+		cryptodebug("internal error");
+		rc = FAILURE;
+		goto out;
+	} else if (in_kernel == B_FALSE) {
 		cryptoerror(LOG_STDERR,
-		    gettext("provider %s does not exist."), prov->cp_name);
+		    gettext("provider %s is not loaded or does not exist."),
+		    provname);
 		rc = FAILURE;
 		goto out;
 	}
-	free_entry(pent);
 
+	/* Get kcf.conf entry.  If none, build a new entry */
+	if ((pent = getent_kef(provname, NULL, NULL)) == NULL) {
+		if ((pent = create_entry(provname)) == NULL) {
+			cryptoerror(LOG_STDERR, gettext("out of memory."));
+			rc = FAILURE;
+			goto out;
+		}
+	}
+
 	/* If it is unloaded already, return  */
-	if (check_active_for_soft(prov->cp_name, &is_active) == FAILURE) {
-		cryptodebug("internal error");
+	if (!pent->load) { /* unloaded already */
 		cryptoerror(LOG_STDERR,
-		    gettext("failed to unload %s."), prov->cp_name);
+		    gettext("failed to unload %s."), provname);
 		rc = FAILURE;
 		goto out;
-	}
-
-	if (is_active == B_FALSE) { /* unloaded already */
-		rc = SUCCESS;
-		goto out;
-	} else if (unload_kef_soft(prov->cp_name, B_TRUE) == FAILURE) {
+	} else if (unload_kef_soft(provname) != FAILURE) {
+		/* Mark as unloaded in kcf.conf */
+		pent->load = B_FALSE;
+		rc = update_kcfconf(pent, MODIFY_MODE);
+	} else {
 		cryptoerror(LOG_STDERR,
-		    gettext("failed to unload %s."), prov->cp_name);
+		    gettext("failed to unload %s."), provname);
 		rc = FAILURE;
-	} else {
-		rc = SUCCESS;
 	}
 out:
 	free(prov);
+	free_entry(pent);
 	return (rc);
 }
 
@@ -1169,7 +1185,7 @@
 
 
 /*
- * The top level function for the refresh subcommand.
+ * The top level function for the "cryptoadm refresh" subcommand.
  */
 static int
 do_refresh(int argc)
@@ -1179,19 +1195,20 @@
 		return (ERROR_USAGE);
 	}
 
-	/*
-	 * Note:  in non-global zone, this must silently return SUCCESS
-	 * due to integration with SMF, for "svcadm refresh cryptosvc"
-	 */
-	if (getzoneid() != GLOBAL_ZONEID)
+	if (getzoneid() == GLOBAL_ZONEID) {
+		return (refresh());
+	} else { /* non-global zone */
+		/*
+		 * Note:  in non-global zone, this must silently return SUCCESS
+		 * due to integration with SMF, for "svcadm refresh cryptosvc"
+		 */
 		return (SUCCESS);
-
-	return (refresh());
+	}
 }
 
 
 /*
- * The top level function for the start subcommand.
+ * The top level function for the "cryptoadm start" subcommand.
  */
 static int
 do_start(int argc)
@@ -1211,7 +1228,7 @@
 }
 
 /*
- * The top level function for the stop subcommand.
+ * The top level function for the "cryptoadm stop" subcommand.
  */
 static int
 do_stop(int argc)
@@ -1227,24 +1244,18 @@
 
 
 /*
- * List all the providers.
+ * Print a list all the the providers.
+ * Called for "cryptoadm list" or "cryptoadm list -v" (no -m or -p).
  */
 static int
 list_simple_for_all(boolean_t verbose)
 {
-	uentrylist_t	*pliblist;
-	uentrylist_t	*plibptr;
-	entrylist_t	*pdevlist_conf;
-	entrylist_t	*psoftlist_conf;
-	entrylist_t	*pdevlist_zone;
-	entrylist_t	*psoftlist_zone;
-	entrylist_t	*ptr;
+	uentrylist_t		*pliblist = NULL;
+	uentrylist_t		*plibptr = NULL;
+	entry_t			*pent = NULL;
 	crypto_get_dev_list_t	*pdevlist_kernel = NULL;
-	boolean_t	is_active;
-	int	ru = SUCCESS;
-	int	rs = SUCCESS;
-	int	rd = SUCCESS;
-	int	i;
+	int			rc = SUCCESS;
+	int			i;
 
 	/* get user-level providers */
 	(void) printf(gettext("\nUser-level providers:\n"));
@@ -1251,10 +1262,10 @@
 	if (get_pkcs11conf_info(&pliblist) != SUCCESS) {
 		cryptoerror(LOG_STDERR, gettext(
 		    "failed to retrieve the list of user-level providers."));
-		ru = FAILURE;
+		rc = FAILURE;
 	}
-	plibptr = pliblist;
-	while (plibptr != NULL) {
+
+	for (plibptr = pliblist; plibptr != NULL; plibptr = plibptr->next) {
 		if (strcmp(plibptr->puent->name, METASLOT_KEYWORD) != 0) {
 			(void) printf(gettext("Provider: %s\n"),
 			    plibptr->puent->name);
@@ -1265,7 +1276,6 @@
 				(void) printf("\n");
 			}
 		}
-		plibptr = plibptr->next;
 	}
 	free_uentrylist(pliblist);
 
@@ -1273,44 +1283,51 @@
 	(void) printf(gettext("\nKernel software providers:\n"));
 
 	if (getzoneid() == GLOBAL_ZONEID) {
-		/* use kcf.conf for kernel software providers in global zone */
-		pdevlist_conf = NULL;
-		psoftlist_conf = NULL;
+		/* get kernel software providers from kernel ioctl */
+		crypto_get_soft_list_t		*psoftlist_kernel = NULL;
+		uint_t				sl_soft_count;
+		char				*psoftname;
+		entrylist_t			*pdevlist_conf = NULL;
+		entrylist_t			*psoftlist_conf = NULL;
 
-		if (get_kcfconf_info(&pdevlist_conf, &psoftlist_conf) !=
-		    SUCCESS) {
-			cryptoerror(LOG_STDERR,
-			    gettext("failed to retrieve the "
-			    "list of kernel software providers.\n"));
-			rs = FAILURE;
-		}
+		if (get_soft_list(&psoftlist_kernel) == FAILURE) {
+			cryptoerror(LOG_ERR, gettext("Failed to retrieve the "
+			    "software provider list from kernel."));
+			rc = FAILURE;
+		} else {
+			sl_soft_count = psoftlist_kernel->sl_soft_count;
 
-		ptr = psoftlist_conf;
-		while (ptr != NULL) {
-			if (check_active_for_soft(ptr->pent->name, &is_active)
+			if (get_kcfconf_info(&pdevlist_conf, &psoftlist_conf)
 			    == FAILURE) {
-				rs = FAILURE;
-				cryptoerror(LOG_STDERR, gettext("failed to "
-				    "get the state of a kernel software "
-				    "providers.\n"));
-				break;
-			}
-
-			(void) printf("\t%s", ptr->pent->name);
-			if (is_active == B_FALSE) {
-				(void) printf(gettext(" (inactive)\n"));
+				cryptoerror(LOG_ERR,
+				    "failed to retrieve the providers' "
+				    "information from file kcf.conf - %s.",
+				    _PATH_KCF_CONF);
+				free(psoftlist_kernel);
+				rc = FAILURE;
 			} else {
-				(void) printf("\n");
+
+				for (i = 0,
+				    psoftname = psoftlist_kernel->sl_soft_names;
+				    i < sl_soft_count;
+				    ++i, psoftname += strlen(psoftname) + 1) {
+					pent = getent_kef(psoftname,
+					    pdevlist_conf, psoftlist_conf);
+					(void) printf("\t%s%s\n", psoftname,
+					    (pent == NULL) || (pent->load) ?
+					    "" : gettext(" (inactive)"));
+				}
+				free_entrylist(pdevlist_conf);
+				free_entrylist(psoftlist_conf);
 			}
-			ptr = ptr->next;
+			free(psoftlist_kernel);
 		}
 
-		free_entrylist(pdevlist_conf);
-		free_entrylist(psoftlist_conf);
 	} else {
 		/* kcf.conf not there in non-global zone, use /dev/cryptoadm */
-		pdevlist_zone = NULL;
-		psoftlist_zone = NULL;
+		entrylist_t	*pdevlist_zone = NULL;
+		entrylist_t	*psoftlist_zone = NULL;
+		entrylist_t	*ptr;
 
 		if (get_admindev_info(&pdevlist_zone, &psoftlist_zone) !=
 		    SUCCESS) {
@@ -1317,7 +1334,7 @@
 			cryptoerror(LOG_STDERR,
 			    gettext("failed to retrieve the "
 			    "list of kernel software providers.\n"));
-			rs = FAILURE;
+			rc = FAILURE;
 		}
 
 		ptr = psoftlist_zone;
@@ -1335,7 +1352,7 @@
 	if (get_dev_list(&pdevlist_kernel) == FAILURE) {
 		cryptoerror(LOG_STDERR, gettext("failed to retrieve "
 		    "the list of kernel hardware providers.\n"));
-		rd = FAILURE;
+		rc = FAILURE;
 	} else {
 		for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) {
 			(void) printf("\t%s/%d\n",
@@ -1345,11 +1362,7 @@
 	}
 	free(pdevlist_kernel);
 
-	if (ru == FAILURE || rs == FAILURE || rd == FAILURE) {
-		return (FAILURE);
-	} else {
-		return (SUCCESS);
-	}
+	return (rc);
 }
 
 
@@ -1356,27 +1369,23 @@
 
 /*
  * List all the providers. And for each provider, list the mechanism list.
+ * Called for "cryptoadm list -m" or "cryptoadm list -mv" .
  */
 static int
 list_mechlist_for_all(boolean_t verbose)
 {
-	crypto_get_dev_list_t	*pdevlist_kernel;
-	uentrylist_t	*pliblist;
-	uentrylist_t	*plibptr;
-	entrylist_t	*pdevlist_conf;
-	entrylist_t	*psoftlist_conf;
-	entrylist_t	*pdevlist_zone;
-	entrylist_t	*psoftlist_zone;
-	entrylist_t	*ptr;
-	mechlist_t	*pmechlist;
-	boolean_t	is_active;
-	char	provname[MAXNAMELEN];
-	char	devname[MAXNAMELEN];
-	int 	inst_num;
-	int	count;
-	int	i;
-	int	rv;
-	int	rc = SUCCESS;
+	crypto_get_dev_list_t	*pdevlist_kernel = NULL;
+	uentrylist_t		*pliblist = NULL;
+	uentrylist_t		*plibptr = NULL;
+	entry_t			*pent = NULL;
+	mechlist_t		*pmechlist = NULL;
+	char			provname[MAXNAMELEN];
+	char			devname[MAXNAMELEN];
+	int			inst_num;
+	int			count;
+	int			i;
+	int			rv;
+	int			rc = SUCCESS;
 
 	/* get user-level providers */
 	(void) printf(gettext("\nUser-level providers:\n"));
@@ -1410,6 +1419,7 @@
 
 	/* get kernel software providers */
 	(void) printf(gettext("\nKernel software providers:\n"));
+
 	/*
 	 * TRANSLATION_NOTE
 	 * Strictly for appearance's sake, this line should be as long as
@@ -1417,48 +1427,57 @@
 	 */
 	(void) printf(gettext("==========================\n"));
 	if (getzoneid() == GLOBAL_ZONEID) {
-		/* use kcf.conf for kernel software providers in global zone */
-		pdevlist_conf = NULL;
-		psoftlist_conf = NULL;
+		/* get kernel software providers from kernel ioctl */
+		crypto_get_soft_list_t		*psoftlist_kernel = NULL;
+		uint_t				sl_soft_count;
+		char				*psoftname;
+		int				i;
+		entrylist_t			*pdevlist_conf = NULL;
+		entrylist_t			*psoftlist_conf = NULL;
 
-		if (get_kcfconf_info(&pdevlist_conf, &psoftlist_conf) !=
-		    SUCCESS) {
-			cryptoerror(LOG_STDERR, gettext("failed to retrieve "
-			    "the list of kernel software providers.\n"));
-			rc = FAILURE;
+		if (get_soft_list(&psoftlist_kernel) == FAILURE) {
+			cryptoerror(LOG_ERR, gettext("Failed to retrieve the "
+			    "software provider list from kernel."));
+			return (FAILURE);
 		}
+		sl_soft_count = psoftlist_kernel->sl_soft_count;
 
-		ptr = psoftlist_conf;
-		while (ptr != NULL) {
-			if (check_active_for_soft(ptr->pent->name, &is_active)
-			    == SUCCESS) {
-				if (is_active) {
-					rv = list_mechlist_for_soft(
-					    ptr->pent->name);
-					if (rv == FAILURE) {
-						rc = FAILURE;
-					}
-				} else {
-					(void) printf(gettext(
-					    "%s: (inactive)\n"),
-					    ptr->pent->name);
+		if (get_kcfconf_info(&pdevlist_conf, &psoftlist_conf)
+		    == FAILURE) {
+			cryptoerror(LOG_ERR,
+			    "failed to retrieve the providers' "
+			    "information from file kcf.conf - %s.",
+			    _PATH_KCF_CONF);
+			free(psoftlist_kernel);
+			return (FAILURE);
+		}
+
+		for (i = 0, psoftname = psoftlist_kernel->sl_soft_names;
+		    i < sl_soft_count;
+		    ++i, psoftname += strlen(psoftname) + 1) {
+			pent = getent_kef(psoftname, pdevlist_conf,
+			    psoftlist_conf);
+			if ((pent == NULL) || (pent->load)) {
+				rv = list_mechlist_for_soft(psoftname,
+				    NULL, NULL);
+				if (rv == FAILURE) {
+					rc = FAILURE;
 				}
 			} else {
-				/* should not happen */
-				(void) printf(gettext(
-				    "%s: failed to get the mechanism list.\n"),
-				    ptr->pent->name);
-				rc = FAILURE;
+				(void) printf(gettext("%s: (inactive)\n"),
+				    psoftname);
 			}
-			ptr = ptr->next;
 		}
 
+		free(psoftlist_kernel);
 		free_entrylist(pdevlist_conf);
 		free_entrylist(psoftlist_conf);
+
 	} else {
 		/* kcf.conf not there in non-global zone, use /dev/cryptoadm */
-		pdevlist_zone = NULL;
-		psoftlist_zone = NULL;
+		entrylist_t	*pdevlist_zone = NULL;
+		entrylist_t	*psoftlist_zone = NULL;
+		entrylist_t	*ptr;
 
 		if (get_admindev_info(&pdevlist_zone, &psoftlist_zone) !=
 		    SUCCESS) {
@@ -1467,9 +1486,9 @@
 			rc = FAILURE;
 		}
 
-		ptr = psoftlist_zone;
-		while (ptr != NULL) {
-			rv = list_mechlist_for_soft(ptr->pent->name);
+		for (ptr = psoftlist_zone; ptr != NULL; ptr = ptr->next) {
+			rv = list_mechlist_for_soft(ptr->pent->name,
+			    pdevlist_zone, psoftlist_zone);
 			if (rv == FAILURE) {
 				(void) printf(gettext(
 				    "%s: failed to get the mechanism list.\n"),
@@ -1476,7 +1495,6 @@
 				    ptr->pent->name);
 				rc = FAILURE;
 			}
-			ptr = ptr->next;
 		}
 
 		free_entrylist(pdevlist_zone);
@@ -1522,21 +1540,21 @@
 
 /*
  * List all the providers. And for each provider, list the policy information.
+ * Called for "cryptoadm list -p".
  */
 static int
 list_policy_for_all(void)
 {
-	crypto_get_dev_list_t	*pdevlist_kernel;
-	uentrylist_t	*pliblist;
-	uentrylist_t	*plibptr;
-	entrylist_t	*pdevlist_conf;
-	entrylist_t	*psoftlist_conf;
-	entrylist_t	*ptr;
-	entrylist_t	*phead;
-	boolean_t	found;
-	char	provname[MAXNAMELEN];
-	int	i;
-	int	rc = SUCCESS;
+	crypto_get_dev_list_t	*pdevlist_kernel = NULL;
+	uentrylist_t		*pliblist = NULL;
+	entrylist_t		*pdevlist_conf = NULL;
+	entrylist_t		*psoftlist_conf = NULL;
+	entrylist_t		*ptr = NULL;
+	entrylist_t		*phead = NULL;
+	boolean_t		found = B_FALSE;
+	char			provname[MAXNAMELEN];
+	int			i;
+	int			rc = SUCCESS;
 
 	/* Get user-level providers */
 	(void) printf(gettext("\nUser-level providers:\n"));
@@ -1549,8 +1567,10 @@
 	if (get_pkcs11conf_info(&pliblist) == FAILURE) {
 		cryptoerror(LOG_STDERR, gettext("failed to retrieve "
 		    "the list of user-level providers.\n"));
+		rc = FAILURE;
 	} else {
-		plibptr = pliblist;
+		uentrylist_t	*plibptr = pliblist;
+
 		while (plibptr != NULL) {
 			/* skip metaslot entry */
 			if (strcmp(plibptr->puent->name,
@@ -1574,27 +1594,30 @@
 	 */
 	(void) printf(gettext("==========================\n"));
 
-	/* Get all entries from the kcf.conf file */
-	pdevlist_conf = NULL;
+	/* Get all entries from the kernel */
 	if (getzoneid() == GLOBAL_ZONEID) {
-		/* use kcf.conf for kernel software providers in global zone */
-		psoftlist_conf = NULL;
+		/* get kernel software providers from kernel ioctl */
+		crypto_get_soft_list_t		*psoftlist_kernel = NULL;
+		uint_t				sl_soft_count;
+		char				*psoftname;
+		int				i;
 
-		if (get_kcfconf_info(&pdevlist_conf, &psoftlist_conf) ==
-		    FAILURE) {
-			cryptoerror(LOG_STDERR, gettext(
-			    "failed to retrieve the list of kernel "
-			    "providers.\n"));
-			return (FAILURE);
-		}
+		if (get_soft_list(&psoftlist_kernel) == FAILURE) {
+			cryptoerror(LOG_ERR, gettext("Failed to retrieve the "
+			    "software provider list from kernel."));
+			rc = FAILURE;
+		} else {
+			sl_soft_count = psoftlist_kernel->sl_soft_count;
 
-		ptr = psoftlist_conf;
-		while (ptr != NULL) {
-			(void) list_policy_for_soft(ptr->pent->name);
-			ptr = ptr->next;
+			for (i = 0, psoftname = psoftlist_kernel->sl_soft_names;
+			    i < sl_soft_count;
+			    ++i, psoftname += strlen(psoftname) + 1) {
+				(void) list_policy_for_soft(psoftname,
+				    pdevlist_conf, psoftlist_conf);
+			}
+			free(psoftlist_kernel);
 		}
 
-		free_entrylist(psoftlist_conf);
 	} else {
 		/* kcf.conf not there in non-global zone, no policy info */
 
@@ -1631,10 +1654,17 @@
 	if (get_dev_list(&pdevlist_kernel) != SUCCESS) {
 		cryptoerror(LOG_STDERR, gettext(
 		    "failed to retrieve the list of hardware providers.\n"));
-		free_entrylist(pdevlist_conf);
 		return (FAILURE);
 	}
 
+	if (get_kcfconf_info(&pdevlist_conf, &psoftlist_conf) == FAILURE) {
+		cryptoerror(LOG_ERR, "failed to retrieve the providers' "
+		    "information from file kcf.conf - %s.",
+		    _PATH_KCF_CONF);
+		return (FAILURE);
+	}
+
+
 	/*
 	 * For each hardware provider from kernel, check if it has an entry
 	 * in the config file.  If it has an entry, print out the policy from
@@ -1647,6 +1677,7 @@
 		(void) snprintf(provname, sizeof (provname), "%s/%d",
 		    pdevlist_kernel->dl_devs[i].le_dev_name,
 		    pdevlist_kernel->dl_devs[i].le_dev_instance);
+
 		found = B_FALSE;
 		phead = ptr = pdevlist_conf;
 		while (!found && ptr) {
@@ -1659,7 +1690,8 @@
 		}
 
 		if (found) {
-			(void) list_policy_for_hard(ptr->pent->name);
+			(void) list_policy_for_hard(ptr->pent->name,
+			    pdevlist_conf, psoftlist_conf, pdevlist_kernel);
 			if (phead == ptr) {
 				pdevlist_conf = pdevlist_conf->next;
 			} else {
@@ -1668,7 +1700,8 @@
 			free_entry(ptr->pent);
 			free(ptr);
 		} else {
-			(void) list_policy_for_hard(provname);
+			(void) list_policy_for_hard(provname, pdevlist_conf,
+			    psoftlist_conf, pdevlist_kernel);
 		}
 	}
 
@@ -1677,13 +1710,12 @@
 	 * the config file, these providers must have been detached.
 	 * Should print out their policy information also.
 	 */
-	ptr = pdevlist_conf;
-	while (ptr != NULL) {
-		print_kef_policy(ptr->pent, B_FALSE, B_TRUE);
-		ptr = ptr->next;
+	for (ptr = pdevlist_conf; ptr != NULL; ptr = ptr->next) {
+		print_kef_policy(ptr->pent->name, ptr->pent, B_FALSE, B_TRUE);
 	}
 
 	free_entrylist(pdevlist_conf);
+	free_entrylist(psoftlist_conf);
 	free(pdevlist_kernel);
 
 	return (rc);
--- old/usr/src/cmd/cmd-crypto/cryptoadm/cryptoadm.h	Tue Oct 28 16:45:38 2008
+++ new/usr/src/cmd/cmd-crypto/cryptoadm/cryptoadm.h	Tue Oct 28 16:45:36 2008
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -26,8 +26,7 @@
 #ifndef	_CRYPTOADM_H
 #define	_CRYPTOADM_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
+#include <sys/types.h>
 #include <sys/crypto/ioctladmin.h>
 #include <cryptoutil.h>
 #include <security/cryptoki.h>
@@ -49,7 +48,7 @@
  */
 #define	SEP_SLASH		'/'
 #define	EF_SUPPORTED		"supportedlist="
-#define	HW_DRIVER_STRING	"driver_names"
+#define	EF_UNLOAD		"unload"
 #define	RANDOM			"random"
 #define	UEF_FRAME_LIB		"/usr/lib/libpkcs11.so"
 
@@ -69,9 +68,10 @@
 typedef struct entry {
 	prov_name_t	name;
 	mechlist_t	*suplist; /* supported list */
-	uint_t 		sup_count;
+	uint_t		sup_count;
 	mechlist_t	*dislist; /* disabled list */
-	uint_t 		dis_count;
+	uint_t		dis_count;
+	boolean_t	load; /* B_FALSE after cryptoadm unload */
 } entry_t;
 
 
@@ -95,14 +95,18 @@
 /* adm_kef_util */
 extern boolean_t is_device(char *);
 extern char *ent2str(entry_t *);
-extern entry_t *getent_kef(char *);
-extern int check_active_for_soft(char *, boolean_t *);
-extern int check_active_for_hard(char *, boolean_t *);
+extern entry_t *getent_kef(char *provname,
+		entrylist_t *pdevlist, entrylist_t *psoftlist);
+extern int check_kernel_for_soft(char *provname,
+		crypto_get_soft_list_t *psoftlist, boolean_t *in_kernel);
+extern int check_kernel_for_hard(char *provname,
+		crypto_get_dev_list_t *pdevlist, boolean_t *in_kernel);
 extern int disable_mechs(entry_t **, mechlist_t *, boolean_t, mechlist_t *);
 extern int enable_mechs(entry_t **, boolean_t, mechlist_t *);
 extern int get_kcfconf_info(entrylist_t **, entrylist_t **);
 extern int get_admindev_info(entrylist_t **, entrylist_t **);
 extern int get_mech_count(mechlist_t *);
+extern entry_t *create_entry(char *provname);
 extern int insert_kcfconf(entry_t *);
 extern int split_hw_provname(char *, char *, int *);
 extern int update_kcfconf(entry_t *, int);
@@ -109,7 +113,8 @@
 extern void free_entry(entry_t *);
 extern void free_entrylist(entrylist_t *);
 extern void print_mechlist(char *, mechlist_t *);
-extern void print_kef_policy(entry_t *, boolean_t, boolean_t);
+extern void print_kef_policy(char *provname, entry_t *pent,
+		boolean_t has_random, boolean_t has_mechs);
 extern boolean_t filter_mechlist(mechlist_t **, const char *);
 extern uentry_t *getent_uef(char *);
 
@@ -132,16 +137,20 @@
 extern int update_policylist(uentry_t *, mechlist_t *, int);
 
 /* adm_kef */
-extern int list_mechlist_for_soft(char *);
+extern int list_mechlist_for_soft(char *provname,
+		entrylist_t *phardlist, entrylist_t *psoftlist);
 extern int list_mechlist_for_hard(char *);
-extern int list_policy_for_soft(char *);
-extern int list_policy_for_hard(char *);
+extern int list_policy_for_soft(char *provname,
+		entrylist_t *phardlist, entrylist_t *psoftlist);
+extern int list_policy_for_hard(char *provname,
+		entrylist_t *phardlist, entrylist_t *psoftlist,
+		crypto_get_dev_list_t *pdevlist);
 extern int disable_kef_software(char *, boolean_t, boolean_t, mechlist_t *);
 extern int disable_kef_hardware(char *, boolean_t, boolean_t, mechlist_t *);
 extern int enable_kef(char *, boolean_t, boolean_t, mechlist_t *);
 extern int install_kef(char *, mechlist_t *);
 extern int uninstall_kef(char *);
-extern int unload_kef_soft(char *, boolean_t);
+extern int unload_kef_soft(char *provname);
 extern int refresh(void);
 extern int start_daemon(void);
 extern int stop_daemon(void);
@@ -153,7 +162,8 @@
 extern crypto_unload_soft_module_t *setup_unload_soft(entry_t *);
 extern int get_dev_info(char *, int, int, mechlist_t **);
 extern int get_dev_list(crypto_get_dev_list_t **);
-extern int get_soft_info(char *, mechlist_t **);
+extern int get_soft_info(char *provname, mechlist_t **ppmechlist,
+		entrylist_t *phardlist, entrylist_t *psoftlist);
 extern int get_soft_list(crypto_get_soft_list_t **);
 
 /* adm_metaslot */
--- old/usr/src/cmd/cmd-crypto/etc/kcf.conf	Tue Oct 28 16:45:42 2008
+++ new/usr/src/cmd/cmd-crypto/etc/kcf.conf	Tue Oct 28 16:45:40 2008
@@ -18,37 +18,16 @@
 #
 # CDDL HEADER END
 #
-#
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 # /etc/crypto/kcf.conf
 #
 # Do NOT edit this file by hand.   An administrator should use cryptoadm(1m)
-# to administer the cryptographic framework.  A developer for a kernel software
-# provider package or a cryptographic provider device driver(s) package should
-# provide an input file and use the {i,r}.kcfconf class action scripts to
-# update this file during the installation and removal of the package.
+# to administer the cryptographic framework.
 #
 # This document does not constitute an API.  The /etc/crypto/kcf.conf file may
-# not exist or may have a different content or interpretation in a future 
-# release.  The existence of this notice does not imply that any other 
+# not exist or may have a different content or interpretation in a future
+# release.  The existence of this notice does not imply that any other
 # documentation that lacks this notice constitutes an API.
 #
-#  
-#	
-# Start SUNWcsr
-des:supportedlist=CKM_DES_CBC,CKM_DES_ECB,CKM_DES3_CBC,CKM_DES3_ECB
-aes:supportedlist=CKM_AES_ECB,CKM_AES_CBC,CKM_AES_CTR
-arcfour:supportedlist=CKM_RC4
-blowfish:supportedlist=CKM_BLOWFISH_ECB,CKM_BLOWFISH_CBC
-ecc:supportedlist=CKM_EC_KEY_PAIR_GEN,CKM_ECDH1_DERIVE,CKM_ECDSA,CKM_ECDSA_SHA1
-sha1:supportedlist=CKM_SHA_1,CKM_SHA_1_HMAC_GENERAL,CKM_SHA_1_HMAC
-sha2:supportedlist=CKM_SHA256,CKM_SHA256_HMAC,CKM_SHA256_HMAC_GENERAL,CKM_SHA384,CKM_SHA384_HMAC,CKM_SHA384_HMAC_GENERAL,CKM_SHA512,CKM_SHA512_HMAC,CKM_SHA512_HMAC_GENERAL
-md4:supportedlist=CKM_MD4
-md5:supportedlist=CKM_MD5,CKM_MD5_HMAC_GENERAL,CKM_MD5_HMAC
-rsa:supportedlist=CKM_RSA_PKCS,CKM_RSA_X_509,CKM_MD5_RSA_PKCS,CKM_SHA1_RSA_PKCS,CKM_SHA256_RSA_PKCS,CKM_SHA384_RSA_PKCS,CKM_SHA512_RSA_PKCS
-swrand:supportedlist=random
-# End SUNWcsr
--- old/usr/src/pkgdefs/SUNWcryptoint/postinstall	Tue Oct 28 16:45:44 2008
+++ /dev/null	Tue Oct 28 16:45:44 2008
@@ -1,94 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
-# Postinstall script for SUNWcryptoint.
-#
-# This script appends a hardware provider section for the dprov
-# test driver to /etc/crypto/kcf.conf
-#
-
-pkg_start="# Start $PKGINST"
-pkg_end="# End $PKGINST"
-kcfconf=${BASEDIR}/etc/crypto/kcf.conf
-tmpfile=/tmp/$$kcfconf
-error=no
-
-#
-# If /etc/crypto/kcf.conf doesn't exist, bail immediately
-#
-if [ ! -f "$kcfconf" ]
-then
-	echo "$0: ERROR - $kcfconf doesn't exist"
-	exit 2
-fi
-
-#
-# If the package has been already installed, remove old entries
-#
-start=0
-end=0
-egrep -s "$pkg_start" $kcfconf && start=1
-egrep -s "$pkg_end" $kcfconf && end=1
-
-if [ $start -ne $end ] ; then
-	echo "$0: missing Start or End delimiters for $PKGINST in $kcfconf."
-	echo "$0: $kcfconf may be corrupted and was not updated."
-	error=yes
-	exit 2
-fi
-
-if [ $start -eq 1 ]
-then
-	cp -p $kcfconf $tmpfile || error=yes
-	sed -e "/$pkg_start/,/$pkg_end/d" $kcfconf > $tmpfile || error=yes
-else
-	cp -p $kcfconf $tmpfile || error=yes
-fi
-
-#
-# Append the delimiters for this package
-#
-echo "$pkg_start driver_names=dprov" >> $tmpfile || error=yes
-echo "$pkg_end" >> $tmpfile || error=yes
-
-#
-# Install the updated config file and clean up the tmp file
-#
-if [ "$error" = no ]
-then 
-	mv $tmpfile $kcfconf || error=yes
-fi
-rm -f $tmpfile
-
-#
-# All done, if any of the steps above fail, report the error
-#
-if [ "$error" = yes ]
-then
-	echo "$0: ERROR - failed to update $kcfconf."
-	exit 2
-fi
-exit 0
--- old/usr/src/pkgdefs/SUNWcryptoint/preremove	Tue Oct 28 16:45:46 2008
+++ /dev/null	Tue Oct 28 16:45:46 2008
@@ -1,82 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
-# Preremove script for SUNWcryptoint.
-#
-# This script removes the hardware provider section for the dprov
-# test driver from /etc/crypto/kcf.conf
-#
-
-pkg_start="# Start $PKGINST"
-pkg_end="# End $PKGINST"
-kcfconf=${BASEDIR}/etc/crypto/kcf.conf
-tmpfile=/tmp/$$kcfconf
-error=no
-
-#
-# If /etc/crypto/kcf.conf doesn't exist, bail immediately
-#
-if [ ! -f "$kcfconf" ]
-then
-	echo "$0: ERROR - $kcfconf doesn't exist"
-	exit 2
-fi
-
-#
-# Strip all entries belonging to this package
-#
-start=0
-end=0
-egrep -s "$pkg_start" $kcfconf && start=1
-egrep -s "$pkg_end" $kcfconf && end=1
-
-if [ $start -ne $end ] ; then
-	echo "$0: missing Start or End delimiters for $PKGINST in $kcfconf."
-	echo "$0: $kcfconf may be corrupted and was not updated."
-	error=yes
-	exit 2
-fi
-
-if [ $start -eq 1 ]
-then
-	cp -p $kcfconf $tmpfile || error=yes
-	sed -e "/$pkg_start/,/$pkg_end/d" $kcfconf > $tmpfile || error=yes
-	if [ "$error" = no ]
-	then 
-		mv $tmpfile $kcfconf || error=yes
-	fi
-	rm -f $tmpfile
-else
-	echo "$0: WARNING - no entries to be removed from $kcfconf" 
-	exit 0
-fi
-
-if [ "$error" = yes ]
-then
-	echo "$0: ERROR - failed to update $kcfconf."
-	exit 2
-fi
-exit 0
--- old/usr/src/pkgdefs/SUNWcryptoint/prototype_com	Tue Oct 28 16:45:48 2008
+++ new/usr/src/pkgdefs/SUNWcryptoint/prototype_com	Tue Oct 28 16:45:46 2008
@@ -36,8 +36,6 @@
 i pkginfo
 i copyright
 i depend
-i postinstall
-i preremove
 #
 # source locations relative to the prototype file
 #
--- old/usr/src/pkgdefs/SUNWdcar/postinstall	Tue Oct 28 16:45:55 2008
+++ new/usr/src/pkgdefs/SUNWdcar/postinstall	Tue Oct 28 16:45:53 2008
@@ -21,11 +21,9 @@
 #
 
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 #
 # install the Sun Crypto Accelerator 1000 device drivers.
@@ -33,71 +31,6 @@
 
 PATH="/usr/bin:/usr/sbin:${PATH}"
 export PATH
-
-# Add hardware provider section for the dca driver
-# to /etc/crypto/kcf.conf
-
-pkg_start="# Start $PKGINST"
-pkg_end="# End $PKGINST"
-kcfconf=${BASEDIR}/etc/crypto/kcf.conf
-tmpfile=/tmp/$$kcfconf
-error=no
-
-#
-# If /etc/crypto/kcf.conf doesn't exist, bail immediately
-#
-if [ ! -f "$kcfconf" ]
-then
-	echo "$0: ERROR - $kcfconf doesn't exist"
-        exit 2
-fi
-
-#
-# If the package has been already installed, remove old entries
-#
-start=0
-end=0
-egrep -s "$pkg_start" $kcfconf && start=1
-egrep -s "$pkg_end" $kcfconf && end=1
-
-if [ $start -ne $end ] ; then
-	echo "$0: missing Start or End delimiters for $PKGINST in $kcfconf."
-	echo "$0: $kcfconf may be corrupted and was not updated."
-	error=yes
-	exit 2
-fi
-
-# to preserve the gid
-cp -p $kcfconf $tmpfile || error=yes
-if [ $start -eq 1 ]
-then
-	sed -e "/$pkg_start/,/$pkg_end/d" $kcfconf > $tmpfile || error=yes
-fi
-
-#
-# Append the delimiters for this package
-#
-echo "$pkg_start driver_names=dca" >> $tmpfile || error=yes
-echo "$pkg_end" >> $tmpfile || error=yes
-
-#
-# Install the updated config file and clean up the tmp file
-#
-if [ "$error" = no ]
-then
-	mv $tmpfile $kcfconf || error=yes
-fi
-rm -f $tmpfile
-
-#
-# All done, if any of the steps above fail, report the error
-#
-if [ "$error" = yes ]
-then
-	echo "$0: ERROR - failed to update $kcfconf."
-        exit 2
-fi
-
 NAMEMAJOR="${BASEDIR}/etc/name_to_major"
 
 #
--- old/usr/src/pkgdefs/SUNWdcar/preremove	Tue Oct 28 16:45:59 2008
+++ new/usr/src/pkgdefs/SUNWdcar/preremove	Tue Oct 28 16:45:58 2008
@@ -21,19 +21,16 @@
 #
 
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
 #
-#
 # Preremove script for SUNWdcar.
 #
-# This script removes the hardware provider section for the dca
-# driver from /etc/crypto/kcf.conf
+# This script removes the driver with rem_drv(1M) if necessary.
 #
 DRV=dca
-
 NAMEMAJOR="${BASEDIR}/etc/name_to_major"
 
 #
@@ -54,54 +51,4 @@
     ${REM_DRV} ${DRV} || exit 1
 fi
 
-pkg_start="# Start $PKGINST"
-pkg_end="# End $PKGINST"
-kcfconf=${BASEDIR}/etc/crypto/kcf.conf
-tmpfile=/tmp/$$kcfconf
-error=no
-
-#
-# If /etc/crypto/kcf.conf doesn't exist, bail immediately
-#
-if [ ! -f "$kcfconf" ]
-then
-	echo "$0: ERROR - $kcfconf doesn't exist"
-	exit 2
-fi
-
-#
-# Strip all entries belonging to this package
-#
-start=0
-end=0
-egrep -s "$pkg_start" $kcfconf && start=1
-egrep -s "$pkg_end" $kcfconf && end=1
-
-if [ $start -ne $end ] ; then
-	echo "$0: missing Start or End delimiters for $PKGINST in $kcfconf."
-	echo "$0: $kcfconf may be corrupted and was not updated."
-	error=yes
-	exit 2
-fi
-
-if [ $start -eq 1 ]
-then
-	# To preserve the gid
-	cp -p $kcfconf $tmpfile
-	sed -e "/$pkg_start/,/$pkg_end/d" $kcfconf > $tmpfile || error=yes
-	if [ "$error" = no ]
-	then 
-		mv $tmpfile $kcfconf || error=yes
-	fi
-	rm -f $tmpfile
-else
-	echo "$0: WARNING - no entries to be removed from $kcfconf" 
-	exit 0
-fi
-
-if [ "$error" = yes ]
-then
-	echo "$0: ERROR - failed to update $kcfconf."
-	exit 2
-fi
 exit 0
--- old/usr/src/pkgdefs/SUNWn2cp.v/postinstall	Tue Oct 28 16:46:03 2008
+++ new/usr/src/pkgdefs/SUNWn2cp.v/postinstall	Tue Oct 28 16:46:02 2008
@@ -21,11 +21,9 @@
 #
 
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 #
 # install the UltraSPARC-T2 Crypto Provider device driver
@@ -33,72 +31,6 @@
 
 PATH="/usr/bin:/usr/sbin:${PATH}"
 export PATH
-
-# Add hardware provider section for the n2cp driver
-# to /etc/crypto/kcf.conf
-
-pkg_start="# Start $PKGINST"
-pkg_end="# End $PKGINST"
-kcfconf=${BASEDIR}/etc/crypto/kcf.conf
-tmpfile=/tmp/$$kcfconf
-error=no
-
-#
-# If /etc/crypto/kcf.conf doesn't exist, bail immediately
-#
-if [ ! -f "$kcfconf" ]
-then
-	echo "$0: ERROR - $kcfconf doesn't exist"
-        exit 2
-fi
-
-#
-# If the package has been already installed, remove old entries
-#
-start=0
-end=0
-egrep -s "$pkg_start" $kcfconf && start=1
-egrep -s "$pkg_end" $kcfconf && end=1
-
-if [ $start -ne $end ] ; then
-	echo "$0: missing Start or End delimiters for $PKGINST in $kcfconf."
-	echo "$0: $kcfconf may be corrupted and was not updated."
-	error=yes
-	exit 2
-fi
-
-if [ $start -eq 1 ]
-then
-	cp -p $kcfconf $tmpfile || error=yes
-	sed -e "/$pkg_start/,/$pkg_end/d" $kcfconf > $tmpfile || error=yes
-else
-	cp -p $kcfconf $tmpfile || error=yes
-fi
-
-#
-# Append the delimiters for this package
-#
-echo "$pkg_start driver_names=n2cp" >> $tmpfile || error=yes
-echo "$pkg_end" >> $tmpfile || error=yes
-
-#
-# Install the updated config file and clean up the tmp file
-#
-if [ "$error" = no ]
-then
-	mv $tmpfile $kcfconf || error=yes
-fi
-rm -f $tmpfile
-
-#
-# All done, if any of the steps above fail, report the error
-#
-if [ "$error" = yes ]
-then
-	echo "$0: ERROR - failed to update $kcfconf."
-        exit 2
-fi
-
 NAMEMAJOR="${BASEDIR}/etc/name_to_major"
 
 if [ "${BASEDIR:=/}" = "/" ]
--- old/usr/src/pkgdefs/SUNWn2cp.v/preremove	Tue Oct 28 16:46:11 2008
+++ new/usr/src/pkgdefs/SUNWn2cp.v/preremove	Tue Oct 28 16:46:07 2008
@@ -21,19 +21,16 @@
 #
 
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
+
 #
-#
 # Preremove script for SUNWn2cp.v.
 #
-# This script removes the hardware provider section for the n2cp
-# driver from /etc/crypto/kcf.conf
+# This script removes driver with rem_drv(1M) if necessary.
 #
 DRV=n2cp
-
 NAMEMAJOR="${BASEDIR}/etc/name_to_major"
 
 #
@@ -54,52 +51,4 @@
     ${REM_DRV} ${DRV} || exit 1
 fi
 
-pkg_start="# Start $PKGINST"
-pkg_end="# End $PKGINST"
-kcfconf=${BASEDIR}/etc/crypto/kcf.conf
-tmpfile=/tmp/$$kcfconf
-error=no
-
-#
-# If /etc/crypto/kcf.conf doesn't exist, bail immediately
-#
-if [ ! -f "$kcfconf" ]
-then
-	echo "$0: ERROR - $kcfconf doesn't exist"
-	exit 2
-fi
-
-#
-# Strip all entries belonging to this package
-#
-start=0
-end=0
-egrep -s "$pkg_start" $kcfconf && start=1
-egrep -s "$pkg_end" $kcfconf && end=1
-
-if [ $start -ne $end ] ; then
-	echo "$0: missing Start or End delimiters for $PKGINST in $kcfconf."
-	echo "$0: $kcfconf may be corrupted and was not updated."
-	error=yes
-	exit 2
-fi
-
-if [ $start -eq 1 ]
-then
-	cp -p $kcfconf $tmpfile || error=yes
-	sed -e "/$pkg_start/,/$pkg_end/d" $kcfconf > $tmpfile || error=yes
-	if [ "$error" = no ]
-	then 
-		mv $tmpfile $kcfconf || error=yes
-	fi
-	rm -f $tmpfile
-else
-	exit 0
-fi
-
-if [ "$error" = yes ]
-then
-	echo "$0: ERROR - failed to update $kcfconf."
-	exit 2
-fi
 exit 0
--- old/usr/src/uts/common/crypto/core/kcf_cryptoadm.c	Tue Oct 28 16:46:19 2008
+++ new/usr/src/uts/common/crypto/core/kcf_cryptoadm.c	Tue Oct 28 16:46:18 2008
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Core KCF (Kernel Cryptographic Framework). This file implements
  * the cryptoadm entry points.
@@ -48,9 +46,13 @@
 kmutex_t soft_config_mutex;
 
 /*
- * This linked list contains software configuration entries that
- * are loaded into the kernel by the CRYPTO_LOAD_SOFT_CONFIG ioctl.
- * It is protected by the soft_config_mutex.
+ * This linked list contains software configuration entries.
+ * The initial list is just software providers loaded by kcf_soft_config_init().
+ * Additional entries may appear for both hardware and software providers
+ * from kcf.conf.  These come from "cryptoadm start", which reads file kcf.conf
+ * and updates this table using the CRYPTO_LOAD_SOFT_CONFIG ioctl.
+ * Further cryptoadm commands modify this file and update this table with ioctl.
+ * This list is protected by the soft_config_mutex.
  */
 kcf_soft_conf_entry_t *soft_config_list;
 
@@ -61,17 +63,190 @@
 
 #define	KCF_MAX_CONFIG_ENTRIES 512 /* maximum entries in soft_config_list */
 
+#if DEBUG
+extern int kcf_frmwrk_debug;
+static void kcf_soft_config_dump(char *message);
+#endif /* DEBUG */
+
+/*
+ * Count and return the number of mechanisms in an array of crypto_mech_name_t
+ * (excluding final NUL-character string element).
+ */
+static int
+count_mechanisms(crypto_mech_name_t mechs[]) {
+	int	count;
+	for (count = 0; mechs[count][0] != '\0'; ++count);
+	return (count);
+}
+
+/*
+ * Initialize a mutex and populate soft_config_list with default entries
+ * of kernel software providers.
+ * Called from kcf module _init().
+ */
 void
 kcf_soft_config_init(void)
 {
+	typedef struct {
+		char			*name;
+		crypto_mech_name_t	*mechs;
+	} initial_soft_config_entry_t;
+
+	/*
+	 * This provides initial default values to soft_config_list.
+	 * It is equivalent to these lines in /etc/crypto/kcf.conf
+	 * (without line breaks and indenting):
+	 *
+	 * # /etc/crypto/kcf.conf
+	 * des:supportedlist=CKM_DES_CBC,CKM_DES_ECB,CKM_DES3_CBC,CKM_DES3_ECB
+	 * aes:supportedlist=CKM_AES_ECB,CKM_AES_CBC,CKM_AES_CTR,CKM_AES_CCM
+	 * arcfour:supportedlist=CKM_RC4
+	 * blowfish:supportedlist=CKM_BLOWFISH_ECB,CKM_BLOWFISH_CBC
+	 * ecc:supportedlist=CKM_EC_KEY_PAIR_GEN,CKM_ECDH1_DERIVE,CKM_ECDSA,\
+	 * CKM_ECDSA_SHA1
+	 * sha1:supportedlist=CKM_SHA_1,CKM_SHA_1_HMAC_GENERAL,CKM_SHA_1_HMAC
+	 * sha2:supportedlist=CKM_SHA256,CKM_SHA256_HMAC,
+	 * CKM_SHA256_HMAC_GENERAL,CKM_SHA384,CKM_SHA384_HMAC,\
+	 * CKM_SHA384_HMAC_GENERAL,CKM_SHA512,CKM_SHA512_HMAC,\
+	 * CKM_SHA512_HMAC_GENERAL
+	 * md4:supportedlist=CKM_MD4
+	 * md5:supportedlist=CKM_MD5,CKM_MD5_HMAC_GENERAL,CKM_MD5_HMAC
+	 * rsa:supportedlist=CKM_RSA_PKCS,CKM_RSA_X_509,CKM_MD5_RSA_PKCS,\
+	 * CKM_SHA1_RSA_PKCS,CKM_SHA256_RSA_PKCS,CKM_SHA384_RSA_PKCS,\
+	 * CKM_SHA512_RSA_PKCS
+	 * swrand:supportedlist=random
+	 *
+	 * WARNING: If you add a new kernel crypto provider or mechanism,
+	 * you must update these constants.
+	 *
+	 * 1. To add a new mechanism to a provider add the string to the
+	 * appropriate array below.
+	 *
+	 * 2. To add a new provider, create a new *_mechs array listing the
+	 * provider's mechanism(s).  For example:
+	 *	sha3_mechs[SHA3_MECH_COUNT] = {"CKM_SHA_3"};
+	 * Add the new *_mechs array to initial_soft_config_entry[].
+	 */
+	static crypto_mech_name_t	des_mechs[] = {
+	    "CKM_DES_CBC", "CKM_DES_ECB", "CKM_DES3_CBC", "CKM_DES3_ECB", ""};
+	static crypto_mech_name_t	aes_mechs[] = {
+	    "CKM_AES_ECB", "CKM_AES_CBC", "CKM_AES_CTR", "CKM_AES_CCM", ""};
+	static crypto_mech_name_t 	arcfour_mechs[] = {
+	    "CKM_RC4", ""};
+	static crypto_mech_name_t	blowfish_mechs[] = {
+	    "CKM_BLOWFISH_ECB", "CKM_BLOWFISH_CBC", ""};
+	static crypto_mech_name_t	ecc_mechs[] = {
+	    "CKM_EC_KEY_PAIR_GEN", "CKM_ECDH1_DERIVE", "CKM_ECDSA",
+	    "CKM_ECDSA_SHA1", ""};
+	static crypto_mech_name_t	sha1_mechs[] = {
+	    "CKM_SHA_1", "CKM_SHA_1_HMAC_GENERAL", "CKM_SHA_1_HMAC", ""};
+	static crypto_mech_name_t	sha2_mechs[] = {
+	    "CKM_SHA256", "CKM_SHA256_HMAC", "CKM_SHA256_HMAC_GENERAL",
+	    "CKM_SHA384", "CKM_SHA384_HMAC", "CKM_SHA384_HMAC_GENERAL",
+	    "CKM_SHA512", "CKM_SHA512_HMAC", "CKM_SHA512_HMAC_GENERAL", ""};
+	static crypto_mech_name_t	md4_mechs[] = {
+	    "CKM_MD4", ""};
+	static crypto_mech_name_t	md5_mechs[] = {
+	    "CKM_MD5", "CKM_MD5_HMAC_GENERAL", "CKM_MD5_HMAC", ""};
+	static crypto_mech_name_t	rsa_mechs[] = {
+	    "CKM_RSA_PKCS", "CKM_RSA_X_509", "CKM_MD5_RSA_PKCS",
+	    "CKM_SHA1_RSA_PKCS", "CKM_SHA256_RSA_PKCS", "CKM_SHA384_RSA_PKCS",
+	    "CKM_SHA512_RSA_PKCS", ""};
+	static crypto_mech_name_t	swrand_mechs[] = {
+	    "random", NULL};
+	static initial_soft_config_entry_t
+	    initial_soft_config_entry[] = {
+		"des", des_mechs,
+		"aes", aes_mechs,
+		"arcfour", arcfour_mechs,
+		"blowfish", blowfish_mechs,
+		"ecc", ecc_mechs,
+		"sha1", sha1_mechs,
+		"sha2", sha2_mechs,
+		"md4", md4_mechs,
+		"md5", md5_mechs,
+		"rsa", rsa_mechs,
+		"swrand", swrand_mechs
+	};
+	const int	initial_soft_config_entries =
+	    sizeof (initial_soft_config_entry)
+	    / sizeof (initial_soft_config_entry_t);
+	int		i;
+
 	mutex_init(&soft_config_mutex, NULL, MUTEX_DRIVER, NULL);
+
+	/*
+	 * Initialize soft_config_list with default providers.
+	 * Populate the linked list backwards so the first entry appears first.
+	 */
+	for (i = initial_soft_config_entries - 1; i >= 0; --i) {
+		initial_soft_config_entry_t *p = &initial_soft_config_entry[i];
+		crypto_mech_name_t	*mechsp;
+		char			*namep;
+		uint_t			namelen, alloc_size;
+		int			mech_count, r;
+
+		/* allocate/initialize memory for name and mechanism list */
+		namelen = strlen(p->name) + 1;
+		namep = kmem_alloc(namelen, KM_SLEEP);
+		(void) strlcpy(namep, p->name, namelen);
+		mech_count = count_mechanisms(p->mechs);
+		alloc_size = mech_count * CRYPTO_MAX_MECH_NAME;
+		mechsp = kmem_alloc(alloc_size, KM_SLEEP);
+		bcopy(p->mechs, mechsp, alloc_size);
+
+		r = add_soft_config(namep, mech_count, mechsp);
+		if (r != 0)
+			cmn_err(CE_WARN,
+			    "add_soft_config(%s) failed; returned %d\n",
+			    namep, r);
+	}
+#if DEBUG
+	if (kcf_frmwrk_debug >= 1)
+		kcf_soft_config_dump("kcf_soft_config_init");
+#endif /* DEBUG */
 }
 
 
+#if DEBUG
 /*
+ * Dump soft_config_list, containing a list of kernel software providers
+ * and (optionally) hardware providers, with updates from kcf.conf.
+ * Dump mechanism lists too if kcf_frmwrk_debug is >= 2.
+ */
+static void
+kcf_soft_config_dump(char *message)
+{
+	kcf_soft_conf_entry_t	*p;
+	uint_t			i;
+
+	mutex_enter(&soft_config_mutex);
+	printf("Soft provider config list soft_config_list: %s\n",
+	    message != NULL ? message : "");
+
+	for (p = soft_config_list; p != NULL; p = p->ce_next) {
+		printf("ce_name: %s, %d ce_mechs\n", p->ce_name, p->ce_count);
+		if (kcf_frmwrk_debug >= 2) {
+			printf("\tce_mechs: ");
+			for (i = 0; i < p->ce_count; i++) {
+				printf("%s ", p->ce_mechs[i]);
+			}
+			printf("\n");
+		}
+	}
+	printf("(end of soft_config_list)\n");
+
+	mutex_exit(&soft_config_mutex);
+}
+#endif /* DEBUG */
+
+
+/*
  * Utility routine to identify the providers to filter out and
  * present only one provider. This happens when a hardware provider
  * registers multiple units of the same device instance.
+ *
+ * Called from crypto_get_dev_list().
  */
 static void
 filter_providers(uint_t count, kcf_provider_desc_t **provider_array,
@@ -103,7 +278,11 @@
 }
 
 
-/* called from the CRYPTO_GET_DEV_LIST ioctl */
+/*
+ * Return a list of kernel hardware providers and a count of each
+ * provider's supported mechanisms.
+ * Called from the CRYPTO_GET_DEV_LIST ioctl.
+ */
 int
 crypto_get_dev_list(uint_t *count, crypto_dev_list_entry_t **array)
 {
@@ -119,7 +298,7 @@
 	 * Take snapshot of provider table returning only hardware providers
 	 * that are in a usable state. Logical providers not included.
 	 */
-	rval =  kcf_get_hw_prov_tab(&provider_count, &provider_array, KM_SLEEP,
+	rval = kcf_get_hw_prov_tab(&provider_count, &provider_array, KM_SLEEP,
 	    NULL, 0, B_FALSE);
 	if (rval != CRYPTO_SUCCESS)
 		return (rval);
@@ -161,9 +340,9 @@
 }
 
 /*
- * Called from the CRYPTO_GET_SOFT_LIST ioctl, this routine returns
- * a buffer containing the null terminated names of software providers
+ * Return a buffer containing the null terminated names of software providers
  * loaded by CRYPTO_LOAD_SOFT_CONFIG.
+ * Called from the CRYPTO_GET_SOFT_LIST ioctl.
  */
 int
 crypto_get_soft_list(uint_t *count, char **array, size_t *len)
@@ -225,6 +404,10 @@
 	return (CRYPTO_SUCCESS);
 }
 
+/*
+ * Check if a mechanism name is already in a mechanism name array
+ * Called by crypto_get_dev_info().
+ */
 static boolean_t
 duplicate(char *name, crypto_mech_name_t *array, int count)
 {
@@ -238,7 +421,11 @@
 	return (B_FALSE);
 }
 
-/* called from the CRYPTO_GET_DEV_INFO ioctl */
+/*
+ * Return a list of kernel hardware providers for a given name and instance.
+ * For each entry, also return a list of their supported mechanisms.
+ * Called from the CRYPTO_GET_DEV_INFO ioctl.
+ */
 int
 crypto_get_dev_info(char *name, uint_t instance, uint_t *count,
     crypto_mech_name_t **array)
@@ -256,7 +443,7 @@
 	 * Logical providers not included. NULL name matches
 	 * all hardware providers.
 	 */
-	rv =  kcf_get_hw_prov_tab(&provider_count, &provider_array, KM_SLEEP,
+	rv = kcf_get_hw_prov_tab(&provider_count, &provider_array, KM_SLEEP,
 	    name, instance, B_FALSE);
 	if (rv != CRYPTO_SUCCESS)
 		return (rv);
@@ -311,7 +498,11 @@
 	return (CRYPTO_SUCCESS);
 }
 
-/* called from the CRYPTO_GET_SOFT_INFO ioctl */
+/*
+ * Given a kernel software provider name, return a list of mechanisms
+ * it supports.
+ * Called from the CRYPTO_GET_SOFT_INFO ioctl.
+ */
 int
 crypto_get_soft_info(caddr_t name, uint_t *count, crypto_mech_name_t **array)
 {
@@ -321,29 +512,25 @@
 
 	provider = kcf_prov_tab_lookup_by_name(name);
 	if (provider == NULL) {
-		if (in_soft_config_list(name)) {
-			char *tmp;
-			int name_len;
+		char *tmp;
+		int name_len;
 
-			/* strlen("crypto/") + NULL terminator == 8 */
-			name_len = strlen(name);
-			tmp = kmem_alloc(name_len + 8, KM_SLEEP);
-			bcopy("crypto/", tmp, 7);
-			bcopy(name, &tmp[7], name_len);
-			tmp[name_len + 7] = '\0';
+		/* strlen("crypto/") + NULL terminator == 8 */
+		name_len = strlen(name);
+		tmp = kmem_alloc(name_len + 8, KM_SLEEP);
+		bcopy("crypto/", tmp, 7);
+		bcopy(name, &tmp[7], name_len);
+		tmp[name_len + 7] = '\0';
 
-			modh = ddi_modopen(tmp, KRTLD_MODE_FIRST, NULL);
-			kmem_free(tmp, name_len + 8);
+		modh = ddi_modopen(tmp, KRTLD_MODE_FIRST, NULL);
+		kmem_free(tmp, name_len + 8);
 
-			if (modh == NULL) {
-				return (CRYPTO_ARGUMENTS_BAD);
-			}
+		if (modh == NULL) {
+			return (CRYPTO_ARGUMENTS_BAD);
+		}
 
-			provider = kcf_prov_tab_lookup_by_name(name);
-			if (provider == NULL) {
-				return (CRYPTO_ARGUMENTS_BAD);
-			}
-		} else {
+		provider = kcf_prov_tab_lookup_by_name(name);
+		if (provider == NULL) {
 			return (CRYPTO_ARGUMENTS_BAD);
 		}
 	}
@@ -355,6 +542,13 @@
 	return (rv);
 }
 
+
+/*
+ * Change the mechanism list for a provider.
+ * If "direction" is CRYPTO_MECH_ADDED, add new mechanisms.
+ * If "direction" is CRYPTO_MECH_REMOVED, remove the mechanism list.
+ * Called from crypto_load_dev_disabled().
+ */
 static void
 kcf_change_mechs(kcf_provider_desc_t *provider, uint_t count,
     crypto_mech_name_t *array, crypto_event_change_t direction)
@@ -463,7 +657,7 @@
 	 * Get provider table entries matching name and instance
 	 * for providers that are are in a usable or unverified state.
 	 */
-	rv =  kcf_get_hw_prov_tab(&provider_count, &provider_array, KM_SLEEP,
+	rv = kcf_get_hw_prov_tab(&provider_count, &provider_array, KM_SLEEP,
 	    name, instance, B_TRUE);
 	if (rv != CRYPTO_SUCCESS)
 		return (rv);
@@ -561,7 +755,7 @@
 		 * This check assumes that enable and disable are separate
 		 * administrative actions and are not done in a single action.
 		 */
-		if (new_count < prev_count && (in_soft_config_list(name)) &&
+		if ((new_count < prev_count) &&
 		    (modload("crypto", name) != -1)) {
 			struct modctl *mcp;
 			boolean_t load_again = B_FALSE;
@@ -590,7 +784,10 @@
 	return (add_soft_config(name, count, array));
 }
 
-/* called from the CRYPTO_UNLOAD_SOFT_MODULE ioctl */
+/*
+ * Unload a kernel software crypto module.
+ * Called from the CRYPTO_UNLOAD_SOFT_MODULE ioctl.
+ */
 int
 crypto_unload_soft_module(caddr_t name)
 {
@@ -623,11 +820,14 @@
 	return (CRYPTO_SUCCESS);
 }
 
-/* called from CRYPTO_GET_DEV_LIST ioctl */
+/*
+ * Free the list of kernel hardware crypto providers.
+ * Called by get_dev_list() for the CRYPTO_GET_DEV_LIST ioctl.
+ */
 void
 crypto_free_dev_list(crypto_dev_list_entry_t *array, uint_t count)
 {
-	if (count ==  0 || array == NULL)
+	if (count == 0 || array == NULL)
 		return;
 
 	kmem_free(array, count * sizeof (crypto_dev_list_entry_t));
@@ -813,6 +1013,10 @@
 	return (CRYPTO_SUCCESS);
 }
 
+/*
+ * Free memory for elements in a kcf_soft_config_entry_t.  This entry must
+ * have been previously removed from the soft_config_list linked list.
+ */
 static void
 free_soft_config_entry(kcf_soft_conf_entry_t *p)
 {
@@ -822,14 +1026,18 @@
 }
 
 /*
- * Called from the CRYPTO_LOAD_SOFT_CONFIG ioctl, this routine stores
- * configuration information for software providers in a linked list.
+ * Store configuration information for software providers in a linked list.
  * If the list already contains an entry for the specified provider
  * and the specified mechanism list has at least one mechanism, then
  * the mechanism list for the provider is updated. If the mechanism list
  * is empty, the entry for the provider is removed.
  *
- * Important note: the array argument is consumed.
+ * Called from kcf_soft_config_init() (to initially populate the list
+ * with default kernel providers) and from crypto_load_soft_config() for
+ * the CRYPTO_LOAD_SOFT_CONFIG ioctl (for third-party kernel modules).
+ *
+ * Important note: the name and array arguments must be allocated memory
+ * and are consumed in soft_config_list.
  */
 static int
 add_soft_config(char *name, uint_t count, crypto_mech_name_t *array)
@@ -881,7 +1089,7 @@
 		soft_config_list = new_entry;
 		soft_config_count++;
 		entry = new_entry;
-	} else {
+	} else { /* mechanism already in list */
 		kmem_free(new_entry->ce_name, name_len);
 		kmem_free(new_entry, sizeof (kcf_soft_conf_entry_t));
 	}
@@ -950,25 +1158,4 @@
 	*name = kmem_alloc(name_len, KM_SLEEP);
 	bcopy(tmp_name, *name, name_len);
 	return (CRYPTO_SUCCESS);
-}
-
-/*
- * This routine searches the soft_config_list for the specified
- * software provider, returning B_TRUE if it is in the list.
- */
-boolean_t
-in_soft_config_list(char *provider_name)
-{
-	kcf_soft_conf_entry_t *p;
-	boolean_t rv = B_FALSE;
-
-	mutex_enter(&soft_config_mutex);
-	for (p = soft_config_list; p != NULL; p = p->ce_next) {
-		if (strcmp(provider_name, p->ce_name) == 0) {
-			rv = B_TRUE;
-			break;
-		}
-	}
-	mutex_exit(&soft_config_mutex);
-	return (rv);
 }
--- old/usr/src/uts/common/crypto/core/kcf_prov_tabs.c	Tue Oct 28 16:46:24 2008
+++ new/usr/src/uts/common/crypto/core/kcf_prov_tabs.c	Tue Oct 28 16:46:23 2008
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * This file is part of the core Kernel Cryptographic Framework.
  * It implements the management of tables of Providers. Entries to
@@ -54,19 +52,33 @@
 
 #define	KCF_MAX_PROVIDERS	512	/* max number of providers */
 
-static kmutex_t prov_tab_mutex; /* ensure exclusive access to the table */
+/*
+ * Prov_tab is an array of providers which is updated when
+ * a crypto provider registers with kcf. The provider calls the
+ * SPI routine, crypto_register_provider(), which in turn calls
+ * kcf_prov_tab_add_provider().
+ *
+ * A provider unregisters by calling crypto_unregister_provider()
+ * which triggers the removal of the prov_tab entry.
+ * It also calls kcf_remove_mech_provider().
+ *
+ * prov_tab entries are not updated from kcf.conf or by cryptoadm(1M).
+ */
 static kcf_provider_desc_t **prov_tab = NULL;
+static kmutex_t prov_tab_mutex; /* ensure exclusive access to the table */
 static uint_t prov_tab_num = 0; /* number of providers in table */
 static uint_t prov_tab_max = KCF_MAX_PROVIDERS;
 
 #if DEBUG
 extern int kcf_frmwrk_debug;
-static void kcf_prov_tab_dump(void);
+static void kcf_prov_tab_dump(char *message);
 #endif /* DEBUG */
 
+
 /*
- * Initialize the providers table. The providers table is dynamically
- * allocated with prov_tab_max entries.
+ * Initialize a mutex and the KCF providers table, prov_tab.
+ * The providers table is dynamically allocated with prov_tab_max entries.
+ * Called from kcf module _init().
  */
 void
 kcf_prov_tab_init(void)
@@ -124,7 +136,7 @@
 
 #if DEBUG
 	if (kcf_frmwrk_debug >= 1)
-		kcf_prov_tab_dump();
+		kcf_prov_tab_dump("kcf_prov_tab_add_provider");
 #endif /* DEBUG */
 
 	return (CRYPTO_SUCCESS);
@@ -170,7 +182,7 @@
 
 #if DEBUG
 	if (kcf_frmwrk_debug >= 1)
-		kcf_prov_tab_dump();
+		kcf_prov_tab_dump("kcf_prov_tab_rem_provider");
 #endif /* DEBUG */
 
 	return (CRYPTO_SUCCESS);
@@ -817,21 +829,34 @@
 }
 
 #if DEBUG
-
+/*
+ * Dump the Kernel crypto providers table, prov_tab.
+ * If kcf_frmwrk_debug is >=2, also dump the mechanism lists.
+ */
 static void
-kcf_prov_tab_dump(void)
+kcf_prov_tab_dump(char *message)
 {
-	uint_t i;
+	uint_t i, j;
 
 	mutex_enter(&prov_tab_mutex);
+	printf("Providers table prov_tab at %s:\n",
+	    message != NULL ? message : "");
 
-	printf("Providers table:\n");
 	for (i = 0; i < KCF_MAX_PROVIDERS; i++) {
-		if (prov_tab[i] != NULL) {
-			printf("[%d]: (%s) %s\n",
-			    i, (prov_tab[i]->pd_prov_type ==
-			    CRYPTO_HW_PROVIDER) ? "HW" : "SW",
-			    prov_tab[i]->pd_description);
+		kcf_provider_desc_t *p = prov_tab[i];
+		if (p != NULL) {
+			printf("[%d]: (%s) %d mechanisms, %s\n", i,
+			    (p->pd_prov_type == CRYPTO_HW_PROVIDER) ?
+			    "HW" : "SW",
+			    p->pd_mech_list_count, p->pd_description);
+			if (kcf_frmwrk_debug >= 2) {
+				printf("\tpd_mechanisms: ");
+				for (j = 0; j < p->pd_mech_list_count; ++j) {
+					printf("%s \n",
+					    p->pd_mechanisms[j].cm_mech_name);
+				}
+				printf("\n");
+			}
 		}
 	}
 	printf("(end of providers table)\n");
