Print this page
6414175 kcf.conf's supportedlist not providing much usefulness

@@ -30,20 +30,21 @@
 #include <strings.h>
 #include <time.h>
 #include <unistd.h>
 #include <locale.h>
 #include <sys/types.h>
+#include <zone.h>
 #include <sys/stat.h>
 #include "cryptoadm.h"
 
 static int err; /* To store errno which may be overwritten by gettext() */
 static int build_entrylist(entry_t *, entrylist_t **);
 static entry_t *dup_entry(entry_t *);
 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 *);
 
 
 /*
  * Duplicate the mechanism list.  A null pointer is returned if the storage
  * space available is insufficient or the input argument is NULL.

@@ -93,14 +94,43 @@
                 plist = plist->next;
         }
         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)
 {
         entry_t *pent2 = NULL;

@@ -107,20 +137,18 @@
 
         if (pent1 == NULL) {
                 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) {
                         free_entry(pent2);
                         return (NULL);

@@ -148,14 +176,14 @@
  *      pent: the entry for the disabledlist.  This is an IN/OUT argument.
  *
  * 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;
+        mechlist_t      *pmech = NULL;
+        mechlist_t      *phead = NULL;
         char *next_token;
         char *value;
         int count;
         int supflag = B_FALSE;
         int disflag = B_FALSE;

@@ -217,53 +245,65 @@
 
         return (rc);
 }
 
 
-
 /*
- * 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;
+        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 */
                 free_entry(pent);
                 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);
         }
 
         *ppent = pent;

@@ -270,18 +310,19 @@
         return (SUCCESS);
 }
 
 
 /*
- * 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     *pcur = NULL;
 
         pentlist = malloc(sizeof (entrylist_t));
         if (pentlist == NULL) {
                 cryptodebug("out of memory.");
                 return (FAILURE);

@@ -303,11 +344,11 @@
 
 
 
 /*
  * 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)
 {
         boolean_t       found = B_FALSE;

@@ -333,11 +374,15 @@
         /* duplicate the entry to be returned */
         return (dup_entry(pent1));
 }
 
 
-
+/*
+ * Free memory in entry_t.
+ * That is, the supported and disabled lists for a provider
+ * from kcf.conf.
+ */
 void
 free_entry(entry_t  *pent)
 {
         if (pent == NULL) {
                 return;

@@ -347,10 +392,14 @@
                 free(pent);
         }
 }
 
 
+/*
+ * Free elements in a entrylist_t linked list,
+ * which lists providers in kcf.conf.
+ */
 void
 free_entrylist(entrylist_t *entrylist)
 {
         entrylist_t *pnext;
 

@@ -362,25 +411,31 @@
 }
 
 
 /*
  * 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;
+        mechlist_t      *pcur = NULL;
+        boolean_t       semicolon_separator = B_FALSE;
 
 
         if (pent == NULL) {
                 return (NULL);
         }

@@ -393,72 +448,88 @@
         if (strlcpy(buf, pent->name, BUFSIZ) >= BUFSIZ) {
                 free(buf);
                 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);
                                         return (NULL);
                                 }
                         }
                 }
+                semicolon_separator = B_TRUE;
         }
 
         /* convert the disabled list if any */
-        phead = pent->dislist;
-        if (phead != NULL) {
-                if (supflag) {
-                        if (strlcat(buf, ";disabledlist=", BUFSIZ) >= BUFSIZ) {
+        pcur = pent->dislist;
+        if (pcur != NULL) {
+                if (strlcat(buf,
+                    semicolon_separator ? SEP_SEMICOLON : SEP_COLON,
+                    BUFSIZ) >= BUFSIZ) {
                                 free(buf);
                                 return (NULL);
                         }
-                } else {
-                        if (strlcat(buf, ":disabledlist=", BUFSIZ) >= BUFSIZ) {
+
+                if (strlcat(buf, EF_DISABLED, 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);
                                         return (NULL);
                                 }
                         }
                 }
+                semicolon_separator = B_TRUE;
         }
 
         if (strlcat(buf, "\n", BUFSIZ) >= BUFSIZ) {
                 free(buf);
                 return (NULL);

@@ -476,12 +547,12 @@
 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;
+        mechlist_t      *ptr = NULL;
+        mechlist_t      *pcur = NULL;
         boolean_t found;
 
         pent = *ppent;
         if (pent == NULL) {
                 return (FAILURE);

@@ -538,10 +609,15 @@
         return (SUCCESS);
 
 }
 
 
+/*
+ * 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)
 {
         if (strchr(path, SEP_SLASH) != NULL) {
                 return (B_TRUE);

@@ -550,11 +626,11 @@
         }
 }
 
 /*
  * 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)
 {
         char    name[MAXNAMELEN];

@@ -579,17 +655,23 @@
         return (SUCCESS);
 }
 
 
 /*
- * 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;
+        FILE    *pfile = NULL;
         char buffer[BUFSIZ];
         int len;
         entry_t *pent = NULL;
         int rc = SUCCESS;
 

@@ -605,11 +687,11 @@
                     buffer[0] == '\n'|| buffer[0] == '\t') {
                         continue;   /* ignore comment lines */
                 }
 
                 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';
 
                 if ((rc = interpret(buffer,  &pent)) == SUCCESS) {

@@ -635,11 +717,11 @@
         return (rc);
 }
 
 /*
  * 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)
 {

@@ -646,17 +728,21 @@
         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;
+        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);
         }
 

@@ -672,62 +758,61 @@
                             "failed to retrieve the mechanism list for %s/%d.",
                             devname, inst_num);
                         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;
         }
 
         for (i = 0, psoftname = psoftlist_kernel->sl_soft_names;
             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);
                         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;
                 }
         }
 
         free(psoftlist_kernel);

@@ -737,12 +822,14 @@
         *ppsoftlist = tmp_psoft;
 
         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);
 
         if (pdevlist_kernel != NULL)

@@ -752,32 +839,40 @@
 
         return (FAILURE);
 }
 
 /*
- * 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;
+        boolean_t       memory_allocated = B_FALSE;
 
-        if (get_kcfconf_info(&pdevlist, &psoftlist) != SUCCESS) {
+        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);
+        if (memory_allocated) {
+                free_entrylist(phardlist);
         free_entrylist(psoftlist);
+        }
 
         return (pent);
 }
 
 /*

@@ -784,11 +879,11 @@
  * Print out the provider name and the mechanism list.
  */
 void
 print_mechlist(char *provname, mechlist_t *pmechlist)
 {
-        mechlist_t *ptr;
+        mechlist_t *ptr = NULL;
 
         if (provname == NULL) {
                 return;
         }
 

@@ -810,63 +905,55 @@
         }
 }
 
 
 /*
- * 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)
 {
         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;
+        FILE            *pfile = NULL;
+        FILE            *pfile_tmp = NULL;
         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;
 
-
         if (pent == NULL) {
                 cryptoerror(LOG_STDERR, gettext("internal error."));
                 return (FAILURE);
         }
 
         /* 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;
                 cryptoerror(LOG_STDERR,
                     gettext("failed to update the configuration - %s"),

@@ -911,40 +998,22 @@
          * Loop thru the entire kcf.conf file, insert, modify or delete
          * an entry.
          */
         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(
                                     "failed to write to a temp file: %s."),
                                     strerror(err));
                                 rc = FAILURE;
                                 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')) {
                                 /*
                                  * Get the provider name from this line and
                                  * check if this is the entry to be updated

@@ -967,18 +1036,13 @@
                         if (found_entry && !delete_it) {
                                 /*
                                  * 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)) {
                                 /* This is the entry to be updated/reserved */
                                 if (fputs(buffer, pfile_tmp) == EOF) {
                                         err = errno;

@@ -990,31 +1054,23 @@
                                 }
                         }
                 }
         }
 
-        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."));
-                }
-
-                (void) fclose(pfile);
-                (void) fclose(pfile_tmp);
-                if (unlink(tmpfile_name) != 0) {
+        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(
-                            "(Warning) failed to remove %s: %s"),
-                            tmpfile_name, strerror(err));
+                                    "failed to write to a temp file: %s."),
+                                    strerror(err));
+                                rc = FAILURE;
                 }
-                return (FAILURE);
+                        free(new_str);
         }
+        }
 
         (void) fclose(pfile);
         if (fclose(pfile_tmp) != 0) {
                 err = errno;
                 cryptoerror(LOG_STDERR,

@@ -1065,13 +1121,13 @@
 int
 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;
+        mechlist_t      *plist = NULL;
+        mechlist_t      *phead = NULL;
+        mechlist_t      *pmech = NULL;
         int rc = SUCCESS;
 
         pent = *ppent;
         if (pent == NULL) {
                 return (FAILURE);

@@ -1170,25 +1226,26 @@
  * in the kcf.conf file.
  *
  * 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;
+        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;
+        }
 
-        (void) printf("%s:", pent->name);
+        (void) printf("%s:", provname);
 
         if (has_mechs == B_TRUE) {
                 /*
                  * TRANSLATION_NOTE
                  * This code block may need to be modified a bit to avoid

@@ -1216,56 +1273,76 @@
         else if (has_random)
                 (void) printf(gettext(" %s is enabled."), "random");
         (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;
+        boolean_t       psoftlist_allocated = B_FALSE;
 
         if (provname == NULL) {
                 cryptoerror(LOG_STDERR, gettext("internal error."));
                 return (FAILURE);
         }
 
+        if (psoftlist_kernel == NULL) {
         if (get_soft_list(&psoftlist_kernel) == FAILURE) {
-                cryptodebug("failed to get the software provider list from"
-                    "kernel.");
+                        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;
         }
+
+        if (psoftlist_allocated)
         free(psoftlist_kernel);
 
         return (SUCCESS);
 }
 
 
 /*
  * 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;
+        boolean_t       dev_list_allocated = B_FALSE;
 
         if (provname == NULL) {
                 cryptoerror(LOG_STDERR, gettext("internal error."));
                 return (FAILURE);
         }

@@ -1272,22 +1349,27 @@
 
         if (split_hw_provname(provname, devname, &inst_num) == FAILURE) {
                 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;
                 }
         }
+
+        if (dev_list_allocated)
         free(pdevlist);
 
         return (SUCCESS);
 }