Home | History | Annotate | Download | only in common
      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 2007 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 /*
     29  * Mechanism Manager - centralized knowledge of mechanisms.
     30  *
     31  * The core of the mechmanager is the "mechlist" data structure. It contains
     32  * information about all mechanisms available from providers that have been
     33  * exposed to the application.
     34  *
     35  * Each element in the array represents a particular mechanism type. The
     36  * array is sorted by type, so that searching by mechanism can be done
     37  * quickly. Each element also contains the mechanism data for each slot.
     38  *
     39  * The mechlist is constructed on an as-needed basis, entries are not added
     40  * until the application triggers an action that requires an entry to be
     41  * added (or updated).
     42  *
     43  */
     44 
     45 #include <string.h>
     46 #include <strings.h>
     47 #include "pkcs11Conf.h"
     48 #include "metaGlobal.h"
     49 
     50 
     51 /* Global data... */
     52 
     53 #define	INITIAL_MECHLIST_SIZE	256
     54 
     55 typedef struct mechliststruct {
     56 	CK_MECHANISM_TYPE type;
     57 	mechinfo_t *slots;
     58 } mechlist_t;
     59 
     60 static pthread_rwlock_t mechlist_lock = PTHREAD_RWLOCK_INITIALIZER;
     61 static mechlist_t *mechlist;
     62 static unsigned long num_mechs;
     63 static unsigned long true_mechlist_size;
     64 
     65 
     66 /* Prototypes... */
     67 static CK_RV meta_mechManager_update_mech(CK_MECHANISM_TYPE, boolean_t);
     68 static CK_RV meta_mechManager_update_slot(CK_ULONG);
     69 static CK_RV update_slotmech(CK_MECHANISM_TYPE, CK_ULONG, unsigned long);
     70 static CK_RV meta_mechManager_allocmechs(CK_MECHANISM_TYPE *, unsigned long,
     71 	unsigned long *);
     72 static boolean_t find_mech_index(CK_MECHANISM_TYPE, unsigned long *);
     73 static int qsort_mechtypes(const void *, const void *);
     74 
     75 
     76 /*
     77  * meta_mechManager_initialize
     78  *
     79  * Called from C_Initialize. Allocates and initializes storage needed
     80  * by the slot manager.
     81  */
     82 CK_RV
     83 meta_mechManager_initialize()
     84 {
     85 	/* The mechlist can dynamically grow, but let's preallocate space. */
     86 	mechlist = calloc(INITIAL_MECHLIST_SIZE, sizeof (mechlist_t));
     87 	if (mechlist == NULL)
     88 		return (CKR_HOST_MEMORY);
     89 
     90 	true_mechlist_size = INITIAL_MECHLIST_SIZE;
     91 	num_mechs = 0;
     92 
     93 	return (CKR_OK);
     94 }
     95 
     96 
     97 /*
     98  * meta_mechManager_finalize
     99  *
    100  * Called from C_Finalize. Deallocates any storage held by the slot manager.
    101  */
    102 void
    103 meta_mechManager_finalize()
    104 {
    105 	int i;
    106 
    107 	/* No need to lock list, we assume all sessions are closed. */
    108 	for (i = 0; i < num_mechs; i++) {
    109 		free(mechlist[i].slots);
    110 	}
    111 
    112 	free(mechlist);
    113 	mechlist = NULL;
    114 	num_mechs = 0;
    115 	true_mechlist_size = 0;
    116 }
    117 
    118 
    119 /*
    120  * meta_mechManager_get_mechs
    121  *
    122  * Get list of all available mechanisms.
    123  *
    124  * Follows PKCS#11 semantics, where list may be NULL to only request a
    125  * count of available mechanisms.
    126  */
    127 CK_RV
    128 meta_mechManager_get_mechs(CK_MECHANISM_TYPE *list, CK_ULONG *listsize)
    129 {
    130 	CK_RV rv = CKR_OK;
    131 	CK_ULONG num_found = 0;
    132 	CK_ULONG slotnum, num_slots;
    133 	unsigned long i;
    134 
    135 	/* get number of slots */
    136 	num_slots = meta_slotManager_get_slotcount();
    137 
    138 	/*
    139 	 * Update slot info. Ignore any errors.
    140 	 *
    141 	 * NOTE: Due to the PKCS#11 convention of calling C_GetMechanismList
    142 	 * twice (once to get the count, again to get the actual list), this
    143 	 * is somewhat inefficient... However, I don't see an easy way to fix
    144 	 * that without impacting other cases (eg, when the first call contains
    145 	 * an "optimistic" pre-allocated buffer).
    146 	 */
    147 	for (slotnum = 0; slotnum < num_slots; slotnum++) {
    148 		(void) meta_mechManager_update_slot(slotnum);
    149 	}
    150 
    151 
    152 	/*
    153 	 * Count the number of mechanisms. We can't just use num_mechs,
    154 	 * because some mechs may not currently be supported on any slot.
    155 	 * Also, it may not be allowed based on the mechanism policy.
    156 	 */
    157 
    158 	(void) pthread_rwlock_rdlock(&mechlist_lock);
    159 	for (i = 0; i < num_mechs; i++) {
    160 		CK_ULONG j;
    161 		boolean_t supported;
    162 
    163 		if (pkcs11_is_dismech(METASLOT_FRAMEWORK_ID,
    164 		    mechlist[i].type)) {
    165 			/* skip mechs disabled by policy */
    166 			continue;
    167 		}
    168 
    169 		supported = FALSE;
    170 		for (j = 0; j < num_slots; j++) {
    171 			if (!mechlist[i].slots[j].initialized)
    172 				continue;
    173 
    174 			if (mechlist[i].slots[j].supported) {
    175 				supported = B_TRUE;
    176 				break;
    177 			}
    178 		}
    179 
    180 		if (supported) {
    181 			num_found++;
    182 
    183 			if (list && *listsize >= num_found) {
    184 				list[num_found - 1] = mechlist[i].type;
    185 			}
    186 		}
    187 	}
    188 	(void) pthread_rwlock_unlock(&mechlist_lock);
    189 
    190 	if (num_found > *listsize)
    191 		rv = CKR_BUFFER_TOO_SMALL;
    192 
    193 	*listsize = num_found;
    194 
    195 	return (rv);
    196 }
    197 
    198 
    199 /*
    200  * meta_mechManager_get_slots
    201  *
    202  * Get list of all slots supporting the specified mechanism.
    203  *
    204  * The "mech_support_info" argument should have allocated enough
    205  * space to accomodate the list of slots that supports the
    206  * specified mechanism.  The "num_supporting_slots" field
    207  * in the "mech_support_info" structure will indicate how
    208  * many slots are found to support the mechanism.
    209  *
    210  * If any error occurred in getting the list, info in
    211  * mech_support_info argument is not updated.
    212  *
    213  */
    214 CK_RV
    215 meta_mechManager_get_slots(mech_support_info_t  *mech_support_info,
    216     boolean_t force_update, CK_MECHANISM_INFO *mech_info)
    217 {
    218 	CK_RV rv;
    219 	boolean_t found;
    220 	CK_ULONG i, num_slots;
    221 	unsigned long index, num_found = 0;
    222 	CK_MECHANISM_INFO info;
    223 
    224 	rv = meta_mechManager_update_mech(mech_support_info->mech,
    225 	    force_update);
    226 	if (rv != CKR_OK) {
    227 		return (rv);
    228 	}
    229 
    230 	(void) pthread_rwlock_rdlock(&mechlist_lock);
    231 
    232 	found = find_mech_index(mech_support_info->mech, &index);
    233 	if (!found) {
    234 		goto finish;
    235 	}
    236 
    237 	num_slots = meta_slotManager_get_slotcount();
    238 	for (i = 0; i < num_slots; i++) {
    239 		if (!mechlist[index].slots[i].initialized ||
    240 		    !mechlist[index].slots[i].supported)
    241 			continue;
    242 
    243 		if (mech_info) {
    244 			info = mechlist[index].slots[i].mechanism_info;
    245 			if (!(info.flags & mech_info->flags)) {
    246 				continue;
    247 			}
    248 		}
    249 
    250 		num_found++;
    251 		(mech_support_info->supporting_slots)[num_found - 1]
    252 		    = &mechlist[index].slots[i];
    253 	}
    254 
    255 finish:
    256 	(void) pthread_rwlock_unlock(&mechlist_lock);
    257 
    258 	if (num_found == 0) {
    259 		rv = CKR_MECHANISM_INVALID;
    260 	} else {
    261 		mech_support_info->num_supporting_slots = num_found;
    262 	}
    263 
    264 	return (rv);
    265 }
    266 
    267 
    268 /*
    269  * meta_mechManager_update_mech
    270  *
    271  * Updates a mechanism in the mechlist. If the mechanism is not
    272  * listed, all providers will be queried. If the mechanism
    273  * is present, but not initialized for some providers, those providers
    274  * will be queried. Existing entries will not be updated unless the
    275  * force_refresh flag is set.
    276  *
    277  * The force_refresh flag is used by C_GetMechanismInfo, to force an
    278  * update. Updates are not forced during the common usage by operations
    279  * [eg C_EncryptInit] to avoid poor performance.
    280  */
    281 static CK_RV
    282 meta_mechManager_update_mech(CK_MECHANISM_TYPE mech, boolean_t force_refresh)
    283 {
    284 	CK_RV rv;
    285 	CK_ULONG slot, num_slots;
    286 	unsigned long index = 0;
    287 	boolean_t found;
    288 
    289 	/* Ensure list contains the mechanism. */
    290 	rv = meta_mechManager_allocmechs(&mech, 1, &index);
    291 	if (rv != CKR_OK)
    292 		return (rv);
    293 
    294 	(void) pthread_rwlock_wrlock(&mechlist_lock);
    295 	/*
    296 	 * We didn't retain a lock after the first search, so it's possible
    297 	 * that the mechlist was updated. Search again, but use the last
    298 	 * index as a hint to quickly find the mechanism.
    299 	 */
    300 	found = find_mech_index(mech, &index);
    301 	if (!found) {
    302 		/* Shouldn't happen - entries are not removed from list. */
    303 		rv = CKR_GENERAL_ERROR;
    304 		goto finish;
    305 	}
    306 
    307 	num_slots = meta_slotManager_get_slotcount();
    308 	for (slot = 0; slot < num_slots; slot++) {
    309 		if (force_refresh || !mechlist[index].slots[slot].initialized) {
    310 			rv = update_slotmech(mech, slot, index);
    311 			if (rv != CKR_OK) {
    312 				/* Ignore error and continue with next slot. */
    313 				rv = CKR_OK;
    314 			}
    315 		}
    316 	}
    317 
    318 finish:
    319 	(void) pthread_rwlock_unlock(&mechlist_lock);
    320 
    321 	return (rv);
    322 }
    323 
    324 
    325 /*
    326  * meta_mechManager_update_slot
    327  *
    328  * Updates a slot in the mechlist. Called by C_GetMechanismList
    329  * [by way of meta_mechManager_get_mechs()]. Unlike
    330  * meta_mechManager_get_slots(), the context is always to force a refresh
    331  * of the mechlist.
    332  *
    333  */
    334 static CK_RV
    335 meta_mechManager_update_slot(CK_ULONG slotnum)
    336 {
    337 	unsigned long index = 0;
    338 	CK_MECHANISM_TYPE *slot_mechlist = NULL, *tmp_slot_mechlist = NULL;
    339 	CK_ULONG slot_mechlistsize, mechnum, tmp_mechlistsize;
    340 	CK_RV rv;
    341 	boolean_t found;
    342 	CK_SLOT_ID fw_st_id, true_id;
    343 	int i;
    344 
    345 	fw_st_id = meta_slotManager_get_framework_table_id(slotnum);
    346 	true_id = TRUEID(fw_st_id);
    347 
    348 	/* First, get the count. */
    349 	rv = FUNCLIST(fw_st_id)->C_GetMechanismList(true_id, NULL,
    350 	    &slot_mechlistsize);
    351 	if (rv != CKR_OK) {
    352 		goto finish;
    353 	}
    354 
    355 	tmp_slot_mechlist = malloc(
    356 	    slot_mechlistsize * sizeof (CK_MECHANISM_TYPE));
    357 	if (tmp_slot_mechlist == NULL) {
    358 		rv = CKR_HOST_MEMORY;
    359 		goto finish;
    360 	}
    361 
    362 	/* Next, get the actual list. */
    363 	rv = FUNCLIST(fw_st_id)->C_GetMechanismList(true_id,
    364 	    tmp_slot_mechlist, &slot_mechlistsize);
    365 	if (rv != CKR_OK) {
    366 		goto finish;
    367 	}
    368 
    369 	/*
    370 	 * filter the list of mechanisms returned by the underlying slot
    371 	 * to remove any mechanisms that are explicitly disabled
    372 	 * in the configuration file.
    373 	 */
    374 	slot_mechlist = malloc(slot_mechlistsize * sizeof (CK_MECHANISM_TYPE));
    375 	if (slot_mechlist == NULL) {
    376 		rv = CKR_HOST_MEMORY;
    377 		goto finish;
    378 	}
    379 
    380 	tmp_mechlistsize = 0;
    381 	for (i = 0; i < slot_mechlistsize; i++) {
    382 		/* filter out the disabled mechanisms */
    383 		if (pkcs11_is_dismech(fw_st_id, tmp_slot_mechlist[i])) {
    384 			continue;
    385 		}
    386 
    387 		slot_mechlist[tmp_mechlistsize] = tmp_slot_mechlist[i];
    388 		tmp_mechlistsize++;
    389 	}
    390 	slot_mechlistsize = tmp_mechlistsize;
    391 
    392 	/* Sort the mechanisms by value. */
    393 	qsort(slot_mechlist, slot_mechlistsize, sizeof (CK_MECHANISM_TYPE),
    394 	    qsort_mechtypes);
    395 
    396 	/* Ensure list contains the mechanisms. */
    397 	rv = meta_mechManager_allocmechs(slot_mechlist, slot_mechlistsize,
    398 	    &index);
    399 	if (rv != CKR_OK)
    400 		goto finish;
    401 
    402 	/* Update the mechanism info. */
    403 	(void) pthread_rwlock_wrlock(&mechlist_lock);
    404 	for (mechnum = 0; mechnum < slot_mechlistsize; mechnum++) {
    405 		found = find_mech_index(slot_mechlist[mechnum], &index);
    406 		if (!found) {
    407 			/* This shouldn't happen. */
    408 			rv = CKR_GENERAL_ERROR;
    409 			goto finish;
    410 		}
    411 
    412 		rv = update_slotmech(slot_mechlist[mechnum], slotnum, index);
    413 		if (rv != CKR_OK) {
    414 			/* Ignore error, make best effort to finish update. */
    415 			rv = CKR_OK;
    416 			continue;
    417 		}
    418 	}
    419 	(void) pthread_rwlock_unlock(&mechlist_lock);
    420 
    421 finish:
    422 	if (slot_mechlist) {
    423 		free(slot_mechlist);
    424 	}
    425 
    426 	if (tmp_slot_mechlist) {
    427 		free(tmp_slot_mechlist);
    428 	}
    429 
    430 	return (rv);
    431 }
    432 
    433 
    434 /*
    435  * update_slotmech
    436  *
    437  * Updates the information for a particular mechanism for a particular slot.
    438  * (ie, slotlist[foo].slots[bar])
    439  *
    440  * It is assumed that the caller to this function (all of which are
    441  * in this file) holds the write-lock to "mechlist_lock".
    442  *
    443  */
    444 static CK_RV
    445 update_slotmech(CK_MECHANISM_TYPE mech, CK_ULONG slotnum,
    446 	unsigned long index)
    447 {
    448 	CK_RV rv = CKR_OK;
    449 	CK_MECHANISM_INFO info;
    450 	CK_SLOT_ID fw_st_id, true_id;
    451 
    452 	mechlist[index].slots[slotnum].slotnum = slotnum;
    453 	fw_st_id = meta_slotManager_get_framework_table_id(slotnum);
    454 	true_id = TRUEID(fw_st_id);
    455 
    456 	/*
    457 	 * Check if the specified mechanism is in the disabled list
    458 	 * of the specified slot.  If so, we can immediately conclude
    459 	 * that it is not supported by the specified slot.
    460 	 */
    461 	if (pkcs11_is_dismech(fw_st_id, mech)) {
    462 		/*
    463 		 * we mark this as initialized so that we won't try
    464 		 * to do this check later
    465 		 */
    466 		mechlist[index].slots[slotnum].initialized = B_TRUE;
    467 		mechlist[index].slots[slotnum].supported = B_FALSE;
    468 		bzero(&mechlist[index].slots[slotnum].mechanism_info,
    469 		    sizeof (CK_MECHANISM_INFO));
    470 		goto finish;
    471 	}
    472 
    473 	rv = FUNCLIST(fw_st_id)->C_GetMechanismInfo(true_id, mech, &info);
    474 	if (rv == CKR_OK) {
    475 		mechlist[index].slots[slotnum].initialized = B_TRUE;
    476 		mechlist[index].slots[slotnum].supported = B_TRUE;
    477 		mechlist[index].slots[slotnum].mechanism_info = info;
    478 	} else {
    479 		/* record that the mechanism isn't supported for the slot */
    480 		mechlist[index].slots[slotnum].initialized = B_TRUE;
    481 		mechlist[index].slots[slotnum].supported = B_FALSE;
    482 		bzero(&mechlist[index].slots[slotnum].mechanism_info,
    483 		    sizeof (CK_MECHANISM_INFO));
    484 	}
    485 
    486 finish:
    487 	return (rv);
    488 }
    489 
    490 
    491 /*
    492  * meta_mechManager_allocmechs
    493  *
    494  * Ensures that all of the specified mechanisms are present in the
    495  * mechlist. If a mechanism is not present, an uninitialized entry is
    496  * added for it.
    497  *
    498  * The returned index can be used by the caller as a hint to where the
    499  * first mechanism was located.
    500  */
    501 static CK_RV
    502 meta_mechManager_allocmechs(CK_MECHANISM_TYPE *new_mechs,
    503 	unsigned long num_new_mechs, unsigned long *index_hint)
    504 {
    505 	CK_RV rv = CKR_OK;
    506 	unsigned long i, index = 0;
    507 	boolean_t found;
    508 
    509 	/* The optimistic assumption is that the mech is already present. */
    510 	(void) pthread_rwlock_rdlock(&mechlist_lock);
    511 	for (i = 0; i < num_new_mechs; i++) {
    512 		found = find_mech_index(new_mechs[i], &index);
    513 
    514 		if (i == 0)
    515 			*index_hint = index;
    516 
    517 		if (!found)
    518 			break;
    519 	}
    520 	(void) pthread_rwlock_unlock(&mechlist_lock);
    521 
    522 	if (found) {
    523 		return (CKR_OK);
    524 	}
    525 
    526 	/*
    527 	 * We stopped searching when the first unknown mech was found. Now
    528 	 * obtain a write-lock, and continue from where we left off, inserting
    529 	 * unknown mechanisms.
    530 	 */
    531 
    532 	(void) pthread_rwlock_wrlock(&mechlist_lock);
    533 	for (; i < num_new_mechs; i++) {
    534 		found = find_mech_index(new_mechs[i], &index);
    535 
    536 		if (!found) {
    537 			mechinfo_t *new_mechinfos;
    538 
    539 			new_mechinfos = calloc(meta_slotManager_get_slotcount(),
    540 			    sizeof (mechinfo_t));
    541 			if (new_mechinfos == NULL) {
    542 				rv = CKR_HOST_MEMORY;
    543 				goto finish;
    544 			}
    545 
    546 			/*
    547 			 * If the current storage for the mechlist is too
    548 			 * small, allocate a new list twice as large.
    549 			 */
    550 			if (num_mechs == true_mechlist_size) {
    551 				mechlist_t *newmechlist;
    552 
    553 				newmechlist = realloc(mechlist,
    554 				    2 * true_mechlist_size *
    555 				    sizeof (mechlist_t));
    556 
    557 				if (newmechlist == NULL) {
    558 					rv = CKR_HOST_MEMORY;
    559 					free(new_mechinfos);
    560 					goto finish;
    561 				}
    562 
    563 				mechlist = newmechlist;
    564 				true_mechlist_size *= 2;
    565 			}
    566 
    567 			/* Shift existing entries to make space. */
    568 			(void) memmove(&mechlist[index+1], &mechlist[index],
    569 			    (num_mechs - index) * sizeof (mechlist_t));
    570 			num_mechs++;
    571 
    572 			mechlist[index].type = new_mechs[i];
    573 			mechlist[index].slots = new_mechinfos;
    574 		}
    575 	}
    576 
    577 finish:
    578 	(void) pthread_rwlock_unlock(&mechlist_lock);
    579 
    580 	return (rv);
    581 }
    582 
    583 
    584 /*
    585  * find_mech_index
    586  *
    587  * Performs a search of mechlist for the specified mechanism, and
    588  * returns if the mechanism was found or not. The value of the "index"
    589  * argument will be where the mech is (if found), or where it should
    590  * be (if not found).
    591  *
    592  * The current value of "index" will be used as a starting point, if the
    593  * caller already knows where the mechanism is likely to be.
    594  *
    595  * The caller is assumed to have a lock on the mechlist, preventing it
    596  * from being changed while searching (also to ensure the returned index
    597  * will remain valid until the list is unlocked).
    598  *
    599  * FUTURE: convert to binary search [from O(N) to a O(log(N))].
    600  *
    601  * NOTES:
    602  * 1) This function assumes that mechMap is a sorted list.
    603  */
    604 static boolean_t
    605 find_mech_index(CK_MECHANISM_TYPE mechanism, unsigned long *index)
    606 {
    607 	boolean_t found = B_FALSE;
    608 	unsigned long i;
    609 
    610 	for (i = 0; i < num_mechs; i++) {
    611 
    612 		if (mechlist[i].type == mechanism) {
    613 			found = B_TRUE;
    614 			break;
    615 		}
    616 
    617 		if (mechlist[i].type > mechanism)
    618 			break;
    619 	}
    620 
    621 	*index = i;
    622 
    623 	return (found);
    624 }
    625 
    626 static int
    627 qsort_mechtypes(const void *arg1, const void *arg2)
    628 {
    629 	CK_MECHANISM_TYPE mech1 = *((CK_MECHANISM_TYPE *)arg1);
    630 	CK_MECHANISM_TYPE mech2 = *((CK_MECHANISM_TYPE *)arg2);
    631 
    632 	if (mech1 > mech2)
    633 		return (1);
    634 	if (mech1 < mech2)
    635 		return (-1);
    636 	return (0);
    637 }
    638 
    639 /*
    640  * Check if the specified mechanism is supported by the specified slot.
    641  * The result is returned in the "supports" argument.  If the "slot_info"
    642  * argument is not NULL, it will be filled with information about
    643  * the slot.
    644  */
    645 CK_RV
    646 meta_mechManager_slot_supports_mech(CK_MECHANISM_TYPE mechanism,
    647     CK_ULONG slotnum, boolean_t *supports, mechinfo_t **slot_info,
    648     boolean_t force_update, CK_MECHANISM_INFO *mech_info)
    649 {
    650 
    651 	boolean_t found;
    652 	CK_RV rv;
    653 	unsigned long index;
    654 	CK_MECHANISM_INFO info;
    655 
    656 	*supports = B_FALSE;
    657 
    658 	rv = meta_mechManager_update_mech(mechanism, force_update);
    659 	if (rv != CKR_OK)
    660 		return (rv);
    661 
    662 	(void) pthread_rwlock_rdlock(&mechlist_lock);
    663 
    664 	found = find_mech_index(mechanism, &index);
    665 	if (!found) {
    666 		goto finish;
    667 	}
    668 
    669 	if ((mechlist[index].slots[slotnum].initialized) &&
    670 	    (mechlist[index].slots[slotnum].supported)) {
    671 		if (mech_info) {
    672 			info = mechlist[index].slots[slotnum].mechanism_info;
    673 			if (!(info.flags & mech_info->flags)) {
    674 				goto finish;
    675 			}
    676 		}
    677 		*supports = B_TRUE;
    678 		if (slot_info) {
    679 			*slot_info = &(mechlist[index].slots[slotnum]);
    680 		}
    681 	}
    682 
    683 finish:
    684 	(void) pthread_rwlock_unlock(&mechlist_lock);
    685 
    686 	return (rv);
    687 }
    688