Home | History | Annotate | Download | only in cryptoadm
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <errno.h>
     27 #include <fcntl.h>
     28 #include <stdio.h>
     29 #include <stdlib.h>
     30 #include <strings.h>
     31 #include <time.h>
     32 #include <unistd.h>
     33 #include <locale.h>
     34 #include <sys/types.h>
     35 #include <zone.h>
     36 #include <sys/stat.h>
     37 #include "cryptoadm.h"
     38 
     39 static int err; /* To store errno which may be overwritten by gettext() */
     40 static int build_entrylist(entry_t *, entrylist_t **);
     41 static entry_t *dup_entry(entry_t *);
     42 static mechlist_t *dup_mechlist(mechlist_t *);
     43 static entry_t *getent(char *, entrylist_t *);
     44 static int interpret(char *, entry_t **);
     45 static int parse_sup_dis_list(const char *buf, entry_t *pent);
     46 
     47 
     48 /*
     49  * Duplicate the mechanism list.  A null pointer is returned if the storage
     50  * space available is insufficient or the input argument is NULL.
     51  */
     52 static mechlist_t *
     53 dup_mechlist(mechlist_t *plist)
     54 {
     55 	mechlist_t	*pres = NULL;
     56 	mechlist_t	*pcur;
     57 	mechlist_t	*ptmp;
     58 	int		rc = SUCCESS;
     59 
     60 	while (plist != NULL) {
     61 		if (!(ptmp = create_mech(plist->name))) {
     62 			rc = FAILURE;
     63 			break;
     64 		}
     65 
     66 		if (pres == NULL) {
     67 			pres = pcur = ptmp;
     68 		} else {
     69 			pcur->next = ptmp;
     70 			pcur = pcur->next;
     71 		}
     72 		plist = plist->next;
     73 	}
     74 
     75 	if (rc != SUCCESS) {
     76 		free_mechlist(pres);
     77 		return (NULL);
     78 	}
     79 
     80 	return (pres);
     81 }
     82 
     83 
     84 /*
     85  * Get the number of mechanisms in the mechanism list.
     86  */
     87 int
     88 get_mech_count(mechlist_t *plist)
     89 {
     90 	int count = 0;
     91 
     92 	while (plist != NULL) {
     93 		count++;
     94 		plist = plist->next;
     95 	}
     96 	return (count);
     97 }
     98 
     99 /*
    100  * Create one item of type entry_t with the provider name.
    101  * Return NULL if there's not enough memory or provname is NULL.
    102  */
    103 entry_t *
    104 create_entry(char *provname)
    105 {
    106 	entry_t		*pent = NULL;
    107 
    108 	if (provname == NULL) {
    109 		return (NULL);
    110 	}
    111 
    112 	pent = calloc(1, sizeof (entry_t));
    113 	if (pent == NULL) {
    114 		cryptodebug("out of memory.");
    115 		return (NULL);
    116 	}
    117 
    118 	(void) strlcpy(pent->name, provname, MAXNAMELEN);
    119 	pent->suplist = NULL;
    120 	pent->sup_count = 0;
    121 	pent->dislist = NULL;
    122 	pent->dis_count = 0;
    123 	pent->load = B_TRUE;
    124 
    125 	return (pent);
    126 }
    127 
    128 /*
    129  * Duplicate an entry for a provider from kcf.conf.
    130  * Return NULL if memory is insufficient or the input argument is NULL.
    131  * Called by getent().
    132  */
    133 static entry_t *
    134 dup_entry(entry_t *pent1)
    135 {
    136 	entry_t	*pent2 = NULL;
    137 
    138 	if (pent1 == NULL) {
    139 		return (NULL);
    140 	}
    141 
    142 	if ((pent2 = create_entry(pent1->name)) == NULL) {
    143 		cryptodebug("out of memory.");
    144 		return (NULL);
    145 	}
    146 
    147 	pent2->sup_count = pent1->sup_count;
    148 	pent2->dis_count = pent1->dis_count;
    149 	pent2->load = pent1->load;
    150 	if (pent1->suplist != NULL) {
    151 		pent2->suplist = dup_mechlist(pent1->suplist);
    152 		if (pent2->suplist == NULL) {
    153 			free_entry(pent2);
    154 			return (NULL);
    155 		}
    156 	}
    157 	if (pent1->dislist != NULL) {
    158 		pent2->dislist = dup_mechlist(pent1->dislist);
    159 		if (pent2->dislist == NULL) {
    160 			free_entry(pent2);
    161 			return (NULL);
    162 		}
    163 	}
    164 
    165 	return (pent2);
    166 }
    167 
    168 
    169 /*
    170  * This routine parses the disabledlist or the supportedlist of an entry
    171  * in the kcf.conf configuration file.
    172  *
    173  * Arguments:
    174  *	buf: an input argument which is a char string with the format of
    175  *	     "disabledlist=m1,m2,..." or "supportedlist=m1,m2,..."
    176  *	pent: the entry for the disabledlist.  This is an IN/OUT argument.
    177  *
    178  * Return value: SUCCESS or FAILURE.
    179  */
    180 static int
    181 parse_sup_dis_list(const char *buf, entry_t *pent)
    182 {
    183 	mechlist_t	*pmech = NULL;
    184 	mechlist_t	*phead = NULL;
    185 	char		*next_token;
    186 	char		*value;
    187 	int		count;
    188 	int		supflag = B_FALSE;
    189 	int		disflag = B_FALSE;
    190 	int		rc = SUCCESS;
    191 
    192 	if (strncmp(buf, EF_SUPPORTED, strlen(EF_SUPPORTED)) == 0) {
    193 		supflag = B_TRUE;
    194 	} else if (strncmp(buf, EF_DISABLED, strlen(EF_DISABLED)) == 0) {
    195 		disflag = B_TRUE;
    196 	} else {
    197 		/* should not come here */
    198 		return (FAILURE);
    199 	}
    200 
    201 	if (value = strpbrk(buf, SEP_EQUAL)) {
    202 		value++; /* get rid of = */
    203 	} else {
    204 		cryptodebug("failed to parse the kcf.conf file.");
    205 		return (FAILURE);
    206 	}
    207 
    208 	if ((next_token = strtok(value, SEP_COMMA)) == NULL) {
    209 		cryptodebug("failed to parse the kcf.conf file.");
    210 		return (FAILURE);
    211 	}
    212 
    213 	if ((pmech = create_mech(next_token)) == NULL) {
    214 		return (FAILURE);
    215 	}
    216 
    217 	if (supflag) {
    218 			if (pent->suplist != NULL) {
    219 				cryptodebug("multiple supportedlist entries "
    220 				    "for a mechanism in file kcf.conf.");
    221 				return (FAILURE);
    222 			} else {
    223 				pent->suplist = phead = pmech;
    224 			}
    225 	} else if (disflag) {
    226 			if (pent->dislist != NULL) {
    227 				cryptodebug("multiple disabledlist entries "
    228 				    "for a mechanism in file kcf.conf.");
    229 				return (FAILURE);
    230 			} else {
    231 				pent->dislist = phead = pmech;
    232 			}
    233 	}
    234 
    235 	count = 1;
    236 	while (next_token) {
    237 		if (next_token = strtok(NULL, SEP_COMMA)) {
    238 			if ((pmech = create_mech(next_token)) == NULL) {
    239 				rc = FAILURE;
    240 				break;
    241 			}
    242 			count++;
    243 			phead->next = pmech;
    244 			phead = phead->next;
    245 		}
    246 	}
    247 
    248 	if (rc == SUCCESS) {
    249 		if (supflag) {
    250 			pent->sup_count = count;
    251 		} else if (disflag) {
    252 			pent->dis_count = count;
    253 		}
    254 	} else {
    255 		free_mechlist(phead);
    256 	}
    257 
    258 	return (rc);
    259 }
    260 
    261 
    262 /*
    263  * Convert a char string containing a line about a provider
    264  * from kcf.conf into an entry_t structure.
    265  *
    266  * Note: the input string, buf, may be modified by this function.
    267  *
    268  * See ent2str(), the reverse of this function, for the format of
    269  * kcf.conf lines.
    270  */
    271 static int
    272 interpret(char *buf, entry_t **ppent)
    273 {
    274 	entry_t	*pent = NULL;
    275 	char	*token1;
    276 	char	*token2;
    277 	char	*token3;
    278 	int	rc;
    279 
    280 	/* Get provider name */
    281 	if ((token1 = strtok(buf, SEP_COLON)) == NULL) { /* buf is NULL */
    282 		return (FAILURE);
    283 	};
    284 
    285 	pent = create_entry(token1);
    286 	if (pent == NULL) {
    287 		cryptodebug("out of memory.");
    288 		return (FAILURE);
    289 	}
    290 
    291 	if ((token2 = strtok(NULL, SEP_SEMICOLON)) == NULL) {
    292 		/* The entry contains a provider name only */
    293 		free_entry(pent);
    294 		return (FAILURE);
    295 	}
    296 
    297 	if (strncmp(token2, EF_UNLOAD, strlen(EF_UNLOAD)) == 0) {
    298 		pent->load = B_FALSE; /* cryptoadm unload */
    299 		token2 = strtok(NULL, SEP_SEMICOLON);
    300 		/*
    301 		 * If token2 is NULL, the entry contains a
    302 		 * provider name:unload only
    303 		 */
    304 	}
    305 
    306 	if (token2 != NULL) {
    307 		/*
    308 		 * Either supportedlist or disabledlist or both are present.
    309 		 * Need to call strtok() to get token3 first, as function
    310 		 * parse_sup_dis_list() makes strtok() calls on the
    311 		 * token2 substring.
    312 		 */
    313 		token3 = strtok(NULL, SEP_SEMICOLON); /* optional */
    314 
    315 		/* parse supportedlist (or disabledlist if no supportedlist) */
    316 		if ((rc = parse_sup_dis_list(token2, pent)) != SUCCESS) {
    317 			free_entry(pent);
    318 			return (rc);
    319 		}
    320 
    321 		/* parse disabledlist (if there's a supportedlist) */
    322 		if ((token3 != NULL) && ((rc = parse_sup_dis_list(token3,
    323 		    pent)) != SUCCESS)) {
    324 			free_entry(pent);
    325 			return (rc);
    326 		}
    327 	}
    328 
    329 	*ppent = pent;
    330 	return (SUCCESS);
    331 }
    332 
    333 
    334 /*
    335  * Add an entry about a provider from kcf.conf to the end of an entry list.
    336  * If the entry list pplist is NULL, create the linked list with pent as the
    337  * first element.
    338  */
    339 static int
    340 build_entrylist(entry_t *pent, entrylist_t **pplist)
    341 {
    342 	entrylist_t	*pentlist;
    343 	entrylist_t	*pcur = NULL;
    344 
    345 	pentlist = malloc(sizeof (entrylist_t));
    346 	if (pentlist == NULL) {
    347 		cryptodebug("out of memory.");
    348 		return (FAILURE);
    349 	}
    350 	pentlist->pent = pent;
    351 	pentlist->next = NULL;
    352 
    353 	if (*pplist) {
    354 		pcur = *pplist;
    355 		while (pcur->next != NULL)
    356 			pcur = pcur->next;
    357 		pcur->next = pentlist;
    358 	} else { /* empty list */
    359 		*pplist = pentlist;
    360 	}
    361 
    362 	return (SUCCESS);
    363 }
    364 
    365 
    366 
    367 /*
    368  * Find the entry with the "provname" name from the entry list and duplicate
    369  * it.  Called by getent_kef().
    370  */
    371 static entry_t *
    372 getent(char *provname, entrylist_t *entrylist)
    373 {
    374 	boolean_t	found = B_FALSE;
    375 	entry_t		*pent1 = NULL;
    376 
    377 	if ((provname == NULL) || (entrylist == NULL)) {
    378 		return (NULL);
    379 	}
    380 
    381 	while (!found && entrylist) {
    382 		if (strcmp(entrylist->pent->name, provname) == 0) {
    383 			found = B_TRUE;
    384 			pent1 = entrylist->pent;
    385 		} else {
    386 			entrylist = entrylist->next;
    387 		}
    388 	}
    389 
    390 	if (!found) {
    391 		return (NULL);
    392 	}
    393 
    394 	/* duplicate the entry to be returned */
    395 	return (dup_entry(pent1));
    396 }
    397 
    398 
    399 /*
    400  * Free memory in entry_t.
    401  * That is, the supported and disabled lists for a provider
    402  * from kcf.conf.
    403  */
    404 void
    405 free_entry(entry_t  *pent)
    406 {
    407 	if (pent == NULL) {
    408 		return;
    409 	} else {
    410 		free_mechlist(pent->suplist);
    411 		free_mechlist(pent->dislist);
    412 		free(pent);
    413 	}
    414 }
    415 
    416 
    417 /*
    418  * Free elements in a entrylist_t linked list,
    419  * which lists providers in kcf.conf.
    420  */
    421 void
    422 free_entrylist(entrylist_t *entrylist)
    423 {
    424 	entrylist_t *pnext;
    425 
    426 	while (entrylist != NULL) {
    427 		pnext = entrylist->next;
    428 		free_entry(entrylist->pent);
    429 		entrylist = pnext;
    430 	}
    431 }
    432 
    433 
    434 /*
    435  * Convert an entry to a string.  This routine builds a string for the entry
    436  * to be inserted in the kcf.conf file.  Based on the content of each entry,
    437  * the result string can be one of these 7 forms:
    438  *  - name:supportedlist=m1,m2,...,mj
    439  *  - name:disabledlist=m1,m2,...,mj
    440  *  - name:supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk
    441  *
    442  *  - name:unload
    443  *  - name:unload;supportedlist=m1,m2,...,mj
    444  *  - name:unload;disabledlist=m1,m2,...,mj
    445  *  - name:unload;supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk
    446  *
    447  * Note that the caller is responsible for freeing the returned string
    448  * (with free_entry()).
    449  * See interpret() for the reverse of this function: converting a string
    450  * to an entry_t.
    451  */
    452 char *
    453 ent2str(entry_t *pent)
    454 {
    455 	char		*buf;
    456 	mechlist_t	*pcur = NULL;
    457 	boolean_t	semicolon_separator = B_FALSE;
    458 
    459 
    460 	if (pent == NULL) {
    461 		return (NULL);
    462 	}
    463 
    464 	if ((buf = malloc(BUFSIZ)) == NULL) {
    465 		return (NULL);
    466 	}
    467 
    468 	/* convert the provider name */
    469 	if (strlcpy(buf, pent->name, BUFSIZ) >= BUFSIZ) {
    470 		free(buf);
    471 		return (NULL);
    472 	}
    473 
    474 	if (!pent->load) { /* add "unload" keyword */
    475 		if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) {
    476 			free(buf);
    477 			return (NULL);
    478 		}
    479 
    480 		if (strlcat(buf, EF_UNLOAD, BUFSIZ) >= BUFSIZ) {
    481 			free(buf);
    482 			return (NULL);
    483 		}
    484 
    485 		semicolon_separator = B_TRUE;
    486 	}
    487 
    488 	/* convert the supported list if any */
    489 	pcur = pent->suplist;
    490 	if (pcur != NULL) {
    491 		if (strlcat(buf,
    492 		    semicolon_separator ? SEP_SEMICOLON : SEP_COLON,
    493 		    BUFSIZ) >= BUFSIZ) {
    494 			free(buf);
    495 			return (NULL);
    496 		}
    497 
    498 		if (strlcat(buf, EF_SUPPORTED, BUFSIZ) >= BUFSIZ) {
    499 			free(buf);
    500 			return (NULL);
    501 		}
    502 
    503 		while (pcur != NULL) {
    504 			if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) {
    505 				free(buf);
    506 				return (NULL);
    507 			}
    508 
    509 			pcur = pcur->next;
    510 			if (pcur != NULL) {
    511 				if (strlcat(buf, SEP_COMMA, BUFSIZ)
    512 				    >= BUFSIZ) {
    513 					free(buf);
    514 					return (NULL);
    515 				}
    516 			}
    517 		}
    518 		semicolon_separator = B_TRUE;
    519 	}
    520 
    521 	/* convert the disabled list if any */
    522 	pcur = pent->dislist;
    523 	if (pcur != NULL) {
    524 		if (strlcat(buf,
    525 		    semicolon_separator ? SEP_SEMICOLON : SEP_COLON,
    526 		    BUFSIZ) >= BUFSIZ) {
    527 			free(buf);
    528 			return (NULL);
    529 		}
    530 
    531 		if (strlcat(buf, EF_DISABLED, BUFSIZ) >= BUFSIZ) {
    532 			free(buf);
    533 			return (NULL);
    534 		}
    535 
    536 		while (pcur != NULL) {
    537 			if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) {
    538 				free(buf);
    539 				return (NULL);
    540 			}
    541 
    542 			pcur = pcur->next;
    543 			if (pcur != NULL) {
    544 				if (strlcat(buf, SEP_COMMA, BUFSIZ)
    545 				    >= BUFSIZ) {
    546 					free(buf);
    547 					return (NULL);
    548 				}
    549 			}
    550 		}
    551 		semicolon_separator = B_TRUE;
    552 	}
    553 
    554 	if (strlcat(buf, "\n", BUFSIZ) >= BUFSIZ) {
    555 		free(buf);
    556 		return (NULL);
    557 	}
    558 
    559 	return (buf);
    560 }
    561 
    562 
    563 /*
    564  * Enable the mechanisms for the provider pointed by *ppent.  If allflag is
    565  * TRUE, enable all.  Otherwise, enable the mechanisms specified in the 3rd
    566  * argument "mlist".  The result will be stored in ppent also.
    567  */
    568 int
    569 enable_mechs(entry_t **ppent, boolean_t allflag, mechlist_t *mlist)
    570 {
    571 	entry_t		*pent;
    572 	mechlist_t	*phead; /* the current and resulting disabled list */
    573 	mechlist_t	*ptr = NULL;
    574 	mechlist_t	*pcur = NULL;
    575 	boolean_t	found;
    576 
    577 	pent = *ppent;
    578 	if (pent == NULL) {
    579 		return (FAILURE);
    580 	}
    581 
    582 	if (allflag) {
    583 		free_mechlist(pent->dislist);
    584 		pent->dis_count = 0;
    585 		pent->dislist = NULL;
    586 		return (SUCCESS);
    587 	}
    588 
    589 	/*
    590 	 * for each mechanism in the to-be-enabled mechanism list,
    591 	 * -	check if it is in the current disabled list
    592 	 * -	if found, delete it from the disabled list
    593 	 *	otherwise, give a warning.
    594 	 */
    595 	ptr = mlist;
    596 	while (ptr != NULL) {
    597 		found = B_FALSE;
    598 		phead = pcur =  pent->dislist;
    599 		while (!found && pcur) {
    600 			if (strcmp(pcur->name, ptr->name) == 0) {
    601 				found = B_TRUE;
    602 			} else {
    603 				phead = pcur;
    604 				pcur = pcur->next;
    605 			}
    606 		}
    607 
    608 		if (found) {
    609 			if (phead == pcur) {
    610 				pent->dislist = pent->dislist->next;
    611 				free(pcur);
    612 			} else {
    613 				phead->next = pcur->next;
    614 				free(pcur);
    615 			}
    616 			pent->dis_count--;
    617 		} else {
    618 			cryptoerror(LOG_STDERR, gettext(
    619 			    "(Warning) %1$s is either enabled already or not "
    620 			    "a valid mechanism for %2$s"), ptr->name,
    621 			    pent->name);
    622 		}
    623 		ptr = ptr->next;
    624 	}
    625 
    626 	if (pent->dis_count == 0) {
    627 		pent->dislist = NULL;
    628 	}
    629 
    630 	return (SUCCESS);
    631 
    632 }
    633 
    634 
    635 /*
    636  * Determine if the kernel provider name, path, is a device
    637  * (that is, it contains a slash character (e.g., "mca/0").
    638  * If so, it is a hardware provider; otherwise it is a software provider.
    639  */
    640 boolean_t
    641 is_device(char *path)
    642 {
    643 	if (strchr(path, SEP_SLASH) != NULL) {
    644 		return (B_TRUE);
    645 	} else {
    646 		return (B_FALSE);
    647 	}
    648 }
    649 
    650 /*
    651  * Split a hardware provider name with the "name/inst_num" format into
    652  * a name and a number (e.g., split "mca/0" into "mca" instance 0).
    653  */
    654 int
    655 split_hw_provname(char *provname, char *pname, int *inst_num)
    656 {
    657 	char	name[MAXNAMELEN];
    658 	char	*inst_str;
    659 
    660 	if (provname == NULL) {
    661 		return (FAILURE);
    662 	}
    663 
    664 	(void) strlcpy(name, provname, MAXNAMELEN);
    665 	if (strtok(name, "/") == NULL) {
    666 		return (FAILURE);
    667 	}
    668 
    669 	if ((inst_str = strtok(NULL, "/")) == NULL) {
    670 		return (FAILURE);
    671 	}
    672 
    673 	(void) strlcpy(pname, name, MAXNAMELEN);
    674 	*inst_num = atoi(inst_str);
    675 
    676 	return (SUCCESS);
    677 }
    678 
    679 
    680 /*
    681  * Retrieve information from kcf.conf and build a hardware device entry list
    682  * and a software entry list of kernel crypto providers.
    683  *
    684  * This list is usually incomplete, as kernel crypto providers only have to
    685  * be listed in kcf.conf if a mechanism is disabled (by cryptoadm) or
    686  * if the kernel provider module is not one of the default kernel providers.
    687  *
    688  * The kcf.conf file is available only in the global zone.
    689  */
    690 int
    691 get_kcfconf_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist)
    692 {
    693 	FILE	*pfile = NULL;
    694 	char	buffer[BUFSIZ];
    695 	int	len;
    696 	entry_t	*pent = NULL;
    697 	int	rc = SUCCESS;
    698 
    699 	if ((pfile = fopen(_PATH_KCF_CONF, "r")) == NULL) {
    700 		cryptodebug("failed to open the kcf.conf file for read only");
    701 		return (FAILURE);
    702 	}
    703 
    704 	*ppdevlist = NULL;
    705 	*ppsoftlist = NULL;
    706 	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
    707 		if (buffer[0] == '#' || buffer[0] == ' ' ||
    708 		    buffer[0] == '\n'|| buffer[0] == '\t') {
    709 			continue;   /* ignore comment lines */
    710 		}
    711 
    712 		len = strlen(buffer);
    713 		if (buffer[len - 1] == '\n') { /* get rid of trailing '\n' */
    714 			len--;
    715 		}
    716 		buffer[len] = '\0';
    717 
    718 		if ((rc = interpret(buffer,  &pent)) == SUCCESS) {
    719 			if (is_device(pent->name)) {
    720 				rc = build_entrylist(pent, ppdevlist);
    721 			} else {
    722 				rc = build_entrylist(pent, ppsoftlist);
    723 			}
    724 		} else {
    725 			cryptoerror(LOG_STDERR, gettext(
    726 			    "failed to parse configuration."));
    727 		}
    728 
    729 		if (rc != SUCCESS) {
    730 			free_entrylist(*ppdevlist);
    731 			free_entrylist(*ppsoftlist);
    732 			free_entry(pent);
    733 			break;
    734 		}
    735 	}
    736 
    737 	(void) fclose(pfile);
    738 	return (rc);
    739 }
    740 
    741 /*
    742  * Retrieve information from admin device and build a device entry list and
    743  * a software entry list.  This is used where there is no kcf.conf, e.g., the
    744  * non-global zone.
    745  */
    746 int
    747 get_admindev_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist)
    748 {
    749 	crypto_get_dev_list_t	*pdevlist_kernel = NULL;
    750 	crypto_get_soft_list_t	*psoftlist_kernel = NULL;
    751 	char			*devname;
    752 	int			inst_num;
    753 	int			mcount;
    754 	mechlist_t		*pmech = NULL;
    755 	entry_t			*pent_dev = NULL, *pent_soft = NULL;
    756 	int			i;
    757 	char			*psoftname;
    758 	entrylist_t		*tmp_pdev = NULL;
    759 	entrylist_t		*tmp_psoft = NULL;
    760 	entrylist_t		*phardlist = NULL, *psoftlist = NULL;
    761 
    762 	/*
    763 	 * Get hardware providers
    764 	 */
    765 	if (get_dev_list(&pdevlist_kernel) != SUCCESS) {
    766 		cryptodebug("failed to get hardware provider list from kernel");
    767 		return (FAILURE);
    768 	}
    769 
    770 	for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) {
    771 		devname = pdevlist_kernel->dl_devs[i].le_dev_name;
    772 		inst_num = pdevlist_kernel->dl_devs[i].le_dev_instance;
    773 		mcount = pdevlist_kernel->dl_devs[i].le_mechanism_count;
    774 
    775 		pmech = NULL;
    776 		if (get_dev_info(devname, inst_num, mcount, &pmech) !=
    777 		    SUCCESS) {
    778 			cryptodebug(
    779 			    "failed to retrieve the mechanism list for %s/%d.",
    780 			    devname, inst_num);
    781 			goto fail_out;
    782 		}
    783 
    784 		if ((pent_dev = create_entry(devname)) == NULL) {
    785 			cryptodebug("out of memory.");
    786 			free_mechlist(pmech);
    787 			goto fail_out;
    788 		}
    789 		pent_dev->suplist = pmech;
    790 		pent_dev->sup_count = mcount;
    791 
    792 		if (build_entrylist(pent_dev, &tmp_pdev) != SUCCESS) {
    793 			goto fail_out;
    794 		}
    795 	}
    796 
    797 	free(pdevlist_kernel);
    798 	pdevlist_kernel = NULL;
    799 
    800 	/*
    801 	 * Get software providers
    802 	 */
    803 	if (getzoneid() == GLOBAL_ZONEID) {
    804 		if (get_kcfconf_info(&phardlist, &psoftlist) != SUCCESS) {
    805 			goto fail_out;
    806 		}
    807 	}
    808 
    809 	if (get_soft_list(&psoftlist_kernel) != SUCCESS) {
    810 		cryptodebug("failed to get software provider list from kernel");
    811 		goto fail_out;
    812 	}
    813 
    814 	for (i = 0, psoftname = psoftlist_kernel->sl_soft_names;
    815 	    i < psoftlist_kernel->sl_soft_count;
    816 	    i++, psoftname = psoftname + strlen(psoftname) + 1) {
    817 		pmech = NULL;
    818 		if (get_soft_info(psoftname, &pmech, phardlist, psoftlist) !=
    819 		    SUCCESS) {
    820 			cryptodebug(
    821 			    "failed to retrieve the mechanism list for %s.",
    822 			    psoftname);
    823 			goto fail_out;
    824 		}
    825 
    826 		if ((pent_soft = create_entry(psoftname)) == NULL) {
    827 			cryptodebug("out of memory.");
    828 			free_mechlist(pmech);
    829 			goto fail_out;
    830 		}
    831 		pent_soft->suplist = pmech;
    832 		pent_soft->sup_count = get_mech_count(pmech);
    833 
    834 		if (build_entrylist(pent_soft, &tmp_psoft) != SUCCESS) {
    835 			goto fail_out;
    836 		}
    837 	}
    838 
    839 	free(psoftlist_kernel);
    840 	psoftlist_kernel = NULL;
    841 
    842 	*ppdevlist = tmp_pdev;
    843 	*ppsoftlist = tmp_psoft;
    844 
    845 	return (SUCCESS);
    846 
    847 fail_out:
    848 	if (pent_dev != NULL)
    849 		free_entry(pent_dev);
    850 	if (pent_soft != NULL)
    851 		free_entry(pent_soft);
    852 
    853 	free_entrylist(tmp_pdev);
    854 	free_entrylist(tmp_psoft);
    855 
    856 	if (pdevlist_kernel != NULL)
    857 		free(pdevlist_kernel);
    858 	if (psoftlist_kernel != NULL)
    859 		free(psoftlist_kernel);
    860 
    861 	return (FAILURE);
    862 }
    863 
    864 /*
    865  * Return configuration information for a kernel provider from kcf.conf.
    866  * For kernel software providers return a enabled list and disabled list.
    867  * For kernel hardware providers return just a disabled list.
    868  *
    869  * Parameters phardlist and psoftlist are supplied by get_kcfconf_info().
    870  * If NULL, this function calls get_kcfconf_info() internally.
    871  */
    872 entry_t *
    873 getent_kef(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist)
    874 {
    875 	entry_t		*pent = NULL;
    876 	boolean_t	memory_allocated = B_FALSE;
    877 
    878 	if ((phardlist == NULL) || (psoftlist == NULL)) {
    879 		if (get_kcfconf_info(&phardlist, &psoftlist) != SUCCESS) {
    880 			return (NULL);
    881 		}
    882 		memory_allocated = B_TRUE;
    883 	}
    884 
    885 	if (is_device(provname)) {
    886 		pent = getent(provname, phardlist);
    887 	} else {
    888 		pent = getent(provname, psoftlist);
    889 	}
    890 
    891 	if (memory_allocated) {
    892 		free_entrylist(phardlist);
    893 		free_entrylist(psoftlist);
    894 	}
    895 
    896 	return (pent);
    897 }
    898 
    899 /*
    900  * Print out the provider name and the mechanism list.
    901  */
    902 void
    903 print_mechlist(char *provname, mechlist_t *pmechlist)
    904 {
    905 	mechlist_t *ptr = NULL;
    906 
    907 	if (provname == NULL) {
    908 		return;
    909 	}
    910 
    911 	(void) printf("%s: ", provname);
    912 	if (pmechlist == NULL) {
    913 		(void) printf(gettext("No mechanisms presented.\n"));
    914 		return;
    915 	}
    916 
    917 	ptr = pmechlist;
    918 	while (ptr != NULL) {
    919 		(void) printf("%s", ptr->name);
    920 		ptr = ptr->next;
    921 		if (ptr == NULL) {
    922 			(void) printf("\n");
    923 		} else {
    924 			(void) printf(",");
    925 		}
    926 	}
    927 }
    928 
    929 
    930 /*
    931  * Update the kcf.conf file based on the update mode:
    932  * - If update_mode is MODIFY_MODE, modify the entry with the same name.
    933  *   If not found, append a new entry to the kcf.conf file.
    934  * - If update_mode is DELETE_MODE, delete the entry with the same name.
    935  * - If update_mode is ADD_MODE, append a new entry to the kcf.conf file.
    936  */
    937 int
    938 update_kcfconf(entry_t *pent, int update_mode)
    939 {
    940 	boolean_t	add_it = B_FALSE;
    941 	boolean_t	delete_it = B_FALSE;
    942 	boolean_t	this_entry_matches = B_FALSE;
    943 	boolean_t	found_entry = B_FALSE;
    944 	FILE		*pfile = NULL;
    945 	FILE		*pfile_tmp = NULL;
    946 	char		buffer[BUFSIZ];
    947 	char		buffer2[BUFSIZ];
    948 	char		tmpfile_name[MAXPATHLEN];
    949 	char		*name;
    950 	char		*new_str = NULL;
    951 	int		rc = SUCCESS;
    952 
    953 	if (pent == NULL) {
    954 		cryptoerror(LOG_STDERR, gettext("internal error."));
    955 		return (FAILURE);
    956 	}
    957 
    958 	/* Check the update_mode */
    959 	switch (update_mode) {
    960 	case ADD_MODE:
    961 		add_it = B_TRUE;
    962 		/* FALLTHROUGH */
    963 	case MODIFY_MODE:
    964 		/* Convert the entry a string to add to kcf.conf  */
    965 		if ((new_str = ent2str(pent)) == NULL) {
    966 			return (FAILURE);
    967 		}
    968 		break;
    969 	case DELETE_MODE:
    970 		delete_it = B_TRUE;
    971 		break;
    972 	default:
    973 		cryptoerror(LOG_STDERR, gettext("internal error."));
    974 		return (FAILURE);
    975 	}
    976 
    977 	/* Open the kcf.conf file */
    978 	if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) {
    979 		err = errno;
    980 		cryptoerror(LOG_STDERR,
    981 		    gettext("failed to update the configuration - %s"),
    982 		    strerror(err));
    983 		cryptodebug("failed to open %s for write.", _PATH_KCF_CONF);
    984 		return (FAILURE);
    985 	}
    986 
    987 	/* Lock the kcf.conf file */
    988 	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
    989 		err = errno;
    990 		cryptoerror(LOG_STDERR,
    991 		    gettext("failed to update the configuration - %s"),
    992 		    strerror(err));
    993 		(void) fclose(pfile);
    994 		return (FAILURE);
    995 	}
    996 
    997 	/*
    998 	 * Create a temporary file in the /etc/crypto directory to save
    999 	 * updated configuration file first.
   1000 	 */
   1001 	(void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
   1002 	if (mkstemp(tmpfile_name) == -1) {
   1003 		err = errno;
   1004 		cryptoerror(LOG_STDERR,
   1005 		    gettext("failed to create a temporary file - %s"),
   1006 		    strerror(err));
   1007 		(void) fclose(pfile);
   1008 		return (FAILURE);
   1009 	}
   1010 
   1011 	if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
   1012 		err = errno;
   1013 		cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
   1014 		    tmpfile_name, strerror(err));
   1015 		(void) fclose(pfile);
   1016 		return (FAILURE);
   1017 	}
   1018 
   1019 	/*
   1020 	 * Loop thru the entire kcf.conf file, insert, modify or delete
   1021 	 * an entry.
   1022 	 */
   1023 	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
   1024 		if (add_it) {
   1025 			if (fputs(buffer, pfile_tmp) == EOF) {
   1026 				err = errno;
   1027 				cryptoerror(LOG_STDERR, gettext(
   1028 				    "failed to write to a temp file: %s."),
   1029 				    strerror(err));
   1030 				rc = FAILURE;
   1031 				break;
   1032 			}
   1033 
   1034 		} else { /* modify or delete */
   1035 			this_entry_matches = B_FALSE;
   1036 
   1037 			if (!(buffer[0] == '#' || buffer[0] == ' ' ||
   1038 			    buffer[0] == '\n'|| buffer[0] == '\t')) {
   1039 				/*
   1040 				 * Get the provider name from this line and
   1041 				 * check if this is the entry to be updated
   1042 				 * or deleted. Note: can not use "buffer"
   1043 				 * directly because strtok will change its
   1044 				 * value.
   1045 				 */
   1046 				(void) strlcpy(buffer2, buffer, BUFSIZ);
   1047 				if ((name = strtok(buffer2, SEP_COLON)) ==
   1048 				    NULL) {
   1049 					rc = FAILURE;
   1050 					break;
   1051 				}
   1052 
   1053 				if (strcmp(pent->name, name) == 0) {
   1054 					this_entry_matches = B_TRUE;
   1055 					found_entry = B_TRUE;
   1056 				}
   1057 			}
   1058 
   1059 
   1060 			if (!this_entry_matches || !delete_it) {
   1061 				/* write this entry */
   1062 				if (this_entry_matches) {
   1063 					/*
   1064 					 * Modify this entry: get the
   1065 					 * updated string and place into buffer.
   1066 					 */
   1067 					(void) strlcpy(buffer, new_str, BUFSIZ);
   1068 					free(new_str);
   1069 				}
   1070 				/* write the (unchanged or modified) entry */
   1071 				if (fputs(buffer, pfile_tmp) == EOF) {
   1072 					err = errno;
   1073 					cryptoerror(LOG_STDERR, gettext(
   1074 					    "failed to write to a temp file: "
   1075 					    "%s."), strerror(err));
   1076 					rc = FAILURE;
   1077 					break;
   1078 				}
   1079 			}
   1080 		}
   1081 	}
   1082 
   1083 	if ((!delete_it) && (rc != FAILURE)) {
   1084 		if (add_it || !found_entry) {
   1085 			/* append new entry to end of file */
   1086 			if (fputs(new_str, pfile_tmp) == EOF) {
   1087 				err = errno;
   1088 				cryptoerror(LOG_STDERR, gettext(
   1089 				    "failed to write to a temp file: %s."),
   1090 				    strerror(err));
   1091 				rc = FAILURE;
   1092 			}
   1093 			free(new_str);
   1094 		}
   1095 	}
   1096 
   1097 	(void) fclose(pfile);
   1098 	if (fclose(pfile_tmp) != 0) {
   1099 		err = errno;
   1100 		cryptoerror(LOG_STDERR,
   1101 		    gettext("failed to close %s: %s"), tmpfile_name,
   1102 		    strerror(err));
   1103 		return (FAILURE);
   1104 	}
   1105 
   1106 	/* Copy the temporary file to the kcf.conf file */
   1107 	if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) {
   1108 		err = errno;
   1109 		cryptoerror(LOG_STDERR,
   1110 		    gettext("failed to update the configuration - %s"),
   1111 		    strerror(err));
   1112 		cryptodebug("failed to rename %s to %s: %s", tmpfile,
   1113 		    _PATH_KCF_CONF, strerror(err));
   1114 		rc = FAILURE;
   1115 	} else if (chmod(_PATH_KCF_CONF,
   1116 	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
   1117 		err = errno;
   1118 		cryptoerror(LOG_STDERR,
   1119 		    gettext("failed to update the configuration - %s"),
   1120 		    strerror(err));
   1121 		cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF,
   1122 		    strerror(err));
   1123 		rc = FAILURE;
   1124 	} else {
   1125 		rc = SUCCESS;
   1126 	}
   1127 
   1128 	if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) {
   1129 		err = errno;
   1130 		cryptoerror(LOG_STDERR, gettext(
   1131 		    "(Warning) failed to remove %s: %s"),
   1132 		    tmpfile_name, strerror(err));
   1133 	}
   1134 
   1135 	return (rc);
   1136 }
   1137 
   1138 
   1139 /*
   1140  * Disable the mechanisms for the provider pointed by *ppent.  If allflag is
   1141  * TRUE, disable all.  Otherwise, disable the mechanisms specified in the
   1142  * dislist argument.  The "infolist" argument contains the mechanism list
   1143  * supported by this provider.
   1144  */
   1145 int
   1146 disable_mechs(entry_t **ppent, mechlist_t *infolist, boolean_t allflag,
   1147 mechlist_t *dislist)
   1148 {
   1149 	entry_t		*pent;
   1150 	mechlist_t	*plist = NULL;
   1151 	mechlist_t	*phead = NULL;
   1152 	mechlist_t	*pmech = NULL;
   1153 	int		rc = SUCCESS;
   1154 
   1155 	pent = *ppent;
   1156 	if (pent == NULL) {
   1157 		return (FAILURE);
   1158 	}
   1159 
   1160 	if (allflag) {
   1161 		free_mechlist(pent->dislist);
   1162 		pent->dis_count = get_mech_count(infolist);
   1163 		if (!(pent->dislist = dup_mechlist(infolist))) {
   1164 			return (FAILURE);
   1165 		} else {
   1166 			return (SUCCESS);
   1167 		}
   1168 	}
   1169 
   1170 	/*
   1171 	 * Not disable all. Now loop thru the mechanisms specified in the
   1172 	 * dislist.  If the mechanism is not supported by the provider,
   1173 	 * ignore it with a warning.  If the mechanism is disabled already,
   1174 	 * do nothing. Otherwise, prepend it to the beginning of the disabled
   1175 	 * list of the provider.
   1176 	 */
   1177 	plist = dislist;
   1178 	while (plist != NULL) {
   1179 		if (!is_in_list(plist->name, infolist)) {
   1180 			cryptoerror(LOG_STDERR, gettext("(Warning) "
   1181 			    "%1$s is not a valid mechanism for %2$s."),
   1182 			    plist->name, pent->name);
   1183 		} else if (!is_in_list(plist->name, pent->dislist)) {
   1184 			/* Add this mechanism into the disabled list */
   1185 			if ((pmech = create_mech(plist->name)) == NULL) {
   1186 				rc = FAILURE;
   1187 				break;
   1188 			}
   1189 
   1190 			if (pent->dislist == NULL) {
   1191 				pent->dislist = pmech;
   1192 			} else {
   1193 				phead = pent->dislist;
   1194 				pent->dislist = pmech;
   1195 				pmech->next = phead;
   1196 			}
   1197 			pent->dis_count++;
   1198 		}
   1199 		plist = plist->next;
   1200 	}
   1201 
   1202 	return (rc);
   1203 }
   1204 
   1205 /*
   1206  * Remove the mechanism passed, specified by mech, from the list of
   1207  * mechanisms, if present in the list. Else, do nothing.
   1208  *
   1209  * Returns B_TRUE if mechanism is present in the list.
   1210  */
   1211 boolean_t
   1212 filter_mechlist(mechlist_t **pmechlist, const char *mech)
   1213 {
   1214 	int		cnt = 0;
   1215 	mechlist_t	*ptr, *pptr;
   1216 	boolean_t	mech_present = B_FALSE;
   1217 
   1218 	ptr = pptr = *pmechlist;
   1219 
   1220 	while (ptr != NULL) {
   1221 		if (strncmp(ptr->name, mech, sizeof (mech_name_t)) == 0) {
   1222 			mech_present = B_TRUE;
   1223 			if (ptr == *pmechlist) {
   1224 				pptr = *pmechlist = ptr->next;
   1225 				free(ptr);
   1226 				ptr = pptr;
   1227 			} else {
   1228 				pptr->next = ptr->next;
   1229 				free(ptr);
   1230 				ptr = pptr->next;
   1231 			}
   1232 		} else {
   1233 			pptr = ptr;
   1234 			ptr = ptr->next;
   1235 			cnt++;
   1236 		}
   1237 	}
   1238 
   1239 	/* Only one entry is present */
   1240 	if (cnt == 0)
   1241 		*pmechlist = NULL;
   1242 
   1243 	return (mech_present);
   1244 }
   1245 
   1246 
   1247 
   1248 /*
   1249  * Print out the mechanism policy for a kernel provider that has an entry
   1250  * in the kcf.conf file.
   1251  *
   1252  * The flag has_random is set to B_TRUE if the provider does random
   1253  * numbers. The flag has_mechs is set by the caller to B_TRUE if the provider
   1254  * has some mechanisms.
   1255  *
   1256  * If pent is NULL, the provider doesn't have a kcf.conf entry.
   1257  */
   1258 void
   1259 print_kef_policy(char *provname, entry_t *pent, boolean_t has_random,
   1260     boolean_t has_mechs)
   1261 {
   1262 	mechlist_t	*ptr = NULL;
   1263 	boolean_t	rnd_disabled = B_FALSE;
   1264 
   1265 	if (pent != NULL) {
   1266 		rnd_disabled = filter_mechlist(&pent->dislist, RANDOM);
   1267 		ptr = pent->dislist;
   1268 	}
   1269 
   1270 	(void) printf("%s:", provname);
   1271 
   1272 	if (has_mechs == B_TRUE) {
   1273 		/*
   1274 		 * TRANSLATION_NOTE
   1275 		 * This code block may need to be modified a bit to avoid
   1276 		 * constructing the text message on the fly.
   1277 		 */
   1278 		(void) printf(gettext(" all mechanisms are enabled"));
   1279 		if (ptr != NULL)
   1280 			(void) printf(gettext(", except "));
   1281 		while (ptr != NULL) {
   1282 			(void) printf("%s", ptr->name);
   1283 			ptr = ptr->next;
   1284 			if (ptr != NULL)
   1285 				(void) printf(",");
   1286 		}
   1287 		if (ptr == NULL)
   1288 			(void) printf(".");
   1289 	}
   1290 
   1291 	/*
   1292 	 * TRANSLATION_NOTE
   1293 	 * "random" is a keyword and not to be translated.
   1294 	 */
   1295 	if (rnd_disabled)
   1296 		(void) printf(gettext(" %s is disabled."), "random");
   1297 	else if (has_random)
   1298 		(void) printf(gettext(" %s is enabled."), "random");
   1299 	(void) printf("\n");
   1300 }
   1301 
   1302 
   1303 /*
   1304  * Check if a kernel software provider is in the kernel.
   1305  *
   1306  * Parameters:
   1307  * provname		Provider name
   1308  * psoftlist_kernel	Optional software provider list.  If NULL, it will be
   1309  *			obtained from get_soft_list().
   1310  * in_kernel		Set to B_TRUE if device is in the kernel, else B_FALSE
   1311  */
   1312 int
   1313 check_kernel_for_soft(char *provname, crypto_get_soft_list_t *psoftlist_kernel,
   1314     boolean_t *in_kernel)
   1315 {
   1316 	char		*ptr;
   1317 	int		i;
   1318 	boolean_t	psoftlist_allocated = B_FALSE;
   1319 
   1320 	if (provname == NULL) {
   1321 		cryptoerror(LOG_STDERR, gettext("internal error."));
   1322 		return (FAILURE);
   1323 	}
   1324 
   1325 	if (psoftlist_kernel == NULL) {
   1326 		if (get_soft_list(&psoftlist_kernel) == FAILURE) {
   1327 			cryptodebug("failed to get the software provider list"
   1328 			" from kernel.");
   1329 			return (FAILURE);
   1330 		}
   1331 		psoftlist_allocated = B_TRUE;
   1332 	}
   1333 
   1334 	*in_kernel = B_FALSE;
   1335 	ptr = psoftlist_kernel->sl_soft_names;
   1336 	for (i = 0; i < psoftlist_kernel->sl_soft_count; i++) {
   1337 		if (strcmp(provname, ptr) == 0) {
   1338 			*in_kernel = B_TRUE;
   1339 			break;
   1340 		}
   1341 		ptr = ptr + strlen(ptr) + 1;
   1342 	}
   1343 
   1344 	if (psoftlist_allocated)
   1345 		free(psoftlist_kernel);
   1346 
   1347 	return (SUCCESS);
   1348 }
   1349 
   1350 
   1351 /*
   1352  * Check if a kernel hardware provider is in the kernel.
   1353  *
   1354  * Parameters:
   1355  * provname	Provider name
   1356  * pdevlist	Optional Hardware Crypto Device List.  If NULL, it will be
   1357  *		obtained from get_dev_list().
   1358  * in_kernel	Set to B_TRUE if device is in the kernel, otherwise B_FALSE
   1359  */
   1360 int
   1361 check_kernel_for_hard(char *provname,
   1362     crypto_get_dev_list_t *pdevlist, boolean_t *in_kernel)
   1363 {
   1364 	char		devname[MAXNAMELEN];
   1365 	int		inst_num;
   1366 	int		i;
   1367 	boolean_t	dev_list_allocated = B_FALSE;
   1368 
   1369 	if (provname == NULL) {
   1370 		cryptoerror(LOG_STDERR, gettext("internal error."));
   1371 		return (FAILURE);
   1372 	}
   1373 
   1374 	if (split_hw_provname(provname, devname, &inst_num) == FAILURE) {
   1375 		return (FAILURE);
   1376 	}
   1377 
   1378 	if (pdevlist == NULL) {
   1379 		if (get_dev_list(&pdevlist) == FAILURE) {
   1380 			cryptoerror(LOG_STDERR, gettext("internal error."));
   1381 			return (FAILURE);
   1382 		}
   1383 		dev_list_allocated = B_TRUE;
   1384 	}
   1385 
   1386 	*in_kernel = B_FALSE;
   1387 	for (i = 0; i < pdevlist->dl_dev_count; i++) {
   1388 		if ((strcmp(pdevlist->dl_devs[i].le_dev_name, devname) == 0) &&
   1389 		    (pdevlist->dl_devs[i].le_dev_instance == inst_num)) {
   1390 			*in_kernel = B_TRUE;
   1391 			break;
   1392 		}
   1393 	}
   1394 
   1395 	if (dev_list_allocated)
   1396 		free(pdevlist);
   1397 
   1398 	return (SUCCESS);
   1399 }
   1400