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 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * Object Management Functions
     28  * (as defined in PKCS#11 spec section 11.7)
     29  */
     30 
     31 #include <strings.h>
     32 #include "metaGlobal.h"
     33 #include <stdio.h>
     34 
     35 #define	FIND_OBJ_BUF_SIZE	512	/* size of buf used for C_FindObjects */
     36 
     37 /*
     38  * Argument related return codes. Will return to the caller immediately,
     39  * and not try the operation on another slot.
     40  */
     41 static CK_RV stop_rv[] = {
     42 	CKR_ARGUMENTS_BAD,
     43 	CKR_ATTRIBUTE_TYPE_INVALID,
     44 	CKR_DOMAIN_PARAMS_INVALID,
     45 	CKR_TEMPLATE_INCOMPLETE
     46 };
     47 static int num_stop_rv = sizeof (stop_rv) / sizeof (CK_RV);
     48 
     49 /*
     50  * Return codes that are related to a specific slot.
     51  * Will try to perform the operation in the next available slot.
     52  * If all attempts failed, will return the error code from the first slot.
     53  *
     54  * This list is here for reference only, it is commented out because
     55  * it doesn't need to be used by the code at this point.
     56  *
     57  * static CK_RV try_again_rv[] = {
     58  * 	CKR_DEVICE_ERROR,
     59  * 	CKR_DEVICE_MEMORY,
     60  * 	CKR_DEVICE_REMOVED,
     61  * 	CKR_FUNCTION_FAILED,
     62  * 	CKR_GENERAL_ERROR,
     63  * 	CKR_HOST_MEMORY,
     64  * 	CKR_TEMPLATE_INCONSISTENT,
     65  * 	CKR_ATTRIBUTE_READ_ONLY,
     66  * 	CKR_ATTRIBUTE_VALUE_INVALID
     67  * };
     68  * static int num_try_again_rv = sizeof (try_again_rv) / sizeof (CK_RV);
     69  */
     70 
     71 /*
     72  * We should never get these return codes because
     73  * MetaSlot is the one that actually created the
     74  * sessions.  When we get these errors in C_CreateObject,
     75  * will try to create the object in the next available slot.
     76  * If all attempts failed, will return CKR_FUNCTION_FAILED
     77  * to the caller.
     78  */
     79 static CK_RV other_rv[] = {
     80 	CKR_CRYPTOKI_NOT_INITIALIZED,
     81 	CKR_SESSION_CLOSED,
     82 	CKR_SESSION_HANDLE_INVALID,
     83 	CKR_SESSION_READ_ONLY
     84 };
     85 static int num_other_rv = sizeof (other_rv) / sizeof (CK_RV);
     86 
     87 /*
     88  * This function is only used by the C_CreateObject and C_CopyObject.
     89  *
     90  * It is used to determine if the operation should be tried on another slot
     91  * based on the return code
     92  */
     93 static boolean_t
     94 try_again(CK_RV rv)
     95 {
     96 	int i;
     97 
     98 	for (i = 0; i < num_stop_rv; i++) {
     99 		if (rv == stop_rv[i]) {
    100 			return (B_FALSE);
    101 		}
    102 	}
    103 	return (B_TRUE);
    104 }
    105 
    106 
    107 /*
    108  * meta_CreateObject
    109  *
    110  */
    111 CK_RV
    112 meta_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate,
    113     CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject)
    114 {
    115 	CK_RV rv;
    116 	meta_session_t *session;
    117 	slot_session_t *slot_session = NULL;
    118 	meta_object_t *object = NULL;
    119 	slot_object_t *slot_object = NULL;
    120 	CK_OBJECT_HANDLE hNewObject;
    121 	CK_ULONG slot_num, keystore_slotnum;
    122 	CK_RV first_rv;
    123 
    124 	if (pTemplate == NULL || ulCount < 1 || phObject == NULL)
    125 		return (CKR_ARGUMENTS_BAD);
    126 
    127 	rv = meta_handle2session(hSession, &session);
    128 	if (rv != CKR_OK)
    129 		return (rv);
    130 
    131 	rv = meta_object_alloc(session, &object);
    132 	if (rv != CKR_OK)
    133 		goto cleanup;
    134 
    135 	/*
    136 	 * Create a clone of the object
    137 	 */
    138 	rv = meta_slot_object_alloc(&slot_object);
    139 	if (rv != CKR_OK)
    140 		goto cleanup;
    141 
    142 	/*
    143 	 * Set to true (token object) if template has CKA_TOKEN=true;
    144 	 * otherwise, it is false (session object).
    145 	 */
    146 	(void) get_template_boolean(CKA_TOKEN, pTemplate, ulCount,
    147 	    &(object->isToken));
    148 
    149 	/* Can't create token objects in a read-only session. */
    150 	if ((IS_READ_ONLY_SESSION(session->session_flags)) && object->isToken) {
    151 		rv = CKR_SESSION_READ_ONLY;
    152 		goto cleanup;
    153 	}
    154 
    155 	/*
    156 	 * Set to true (private object) if template has CKA_PRIVATE=true;
    157 	 * otherwise, it is false (public object).
    158 	 */
    159 	(void) get_template_boolean(CKA_PRIVATE, pTemplate, ulCount,
    160 	    &(object->isPrivate));
    161 
    162 	/* Assume object is extractable unless template has otherwise */
    163 	object->isExtractable = B_TRUE;
    164 	(void) get_template_boolean(CKA_EXTRACTABLE, pTemplate, ulCount,
    165 	    &(object->isExtractable));
    166 
    167 	/*
    168 	 * Set to true (sensitive object) if template has CKA_SENSITIVE=true;
    169 	 * otherwise, it is false.
    170 	 */
    171 	(void) get_template_boolean(CKA_SENSITIVE, pTemplate, ulCount,
    172 	    &(object->isSensitive));
    173 
    174 	/*
    175 	 * Check if this can be a FreeObject.
    176 	 *
    177 	 * For creating objects, this check is mostly for preventing
    178 	 * non-keystore hardware from creating CKA_PRIVATE objects without
    179 	 * logging in.
    180 	 */
    181 
    182 	if (meta_freeobject_check(session, object, NULL, pTemplate, ulCount,
    183 	    NULL)) {
    184 		/*
    185 		 * Make sure we are logged into the keystore if this is a
    186 		 * private freetoken object.
    187 		 */
    188 		if (object->isPrivate && !metaslot_logged_in())
    189 			return (CKR_USER_NOT_LOGGED_IN);
    190 
    191 		if (!meta_freeobject_set(object, pTemplate, ulCount, B_TRUE))
    192 			goto cleanup;
    193 	}
    194 
    195 
    196 	keystore_slotnum = get_keystore_slotnum();
    197 
    198 	if (object->isToken || object->isFreeToken == FREE_ENABLED) {
    199 
    200 		/*
    201 		 * If this is a token object or a FreeToken then create it
    202 		 * on the keystore slot.
    203 		 */
    204 
    205 		slot_num = keystore_slotnum;
    206 		rv = meta_get_slot_session(slot_num, &slot_session,
    207 		    session->session_flags);
    208 		if (rv != CKR_OK)
    209 			goto cleanup;
    210 
    211 		object->tried_create_clone[slot_num] = B_TRUE;
    212 		rv = FUNCLIST(slot_session->fw_st_id)->C_CreateObject(
    213 		    slot_session->hSession, pTemplate, ulCount, &hNewObject);
    214 
    215 		if (rv != CKR_OK)
    216 			goto cleanup;
    217 
    218 	} else {
    219 
    220 		/*
    221 		 * Create a clone of the object in the first available slot.
    222 		 *
    223 		 * If creating a clone in a specific slot failed, it will
    224 		 * either stop and return the error to the user, or try
    225 		 * again in the next available slot until it succeeds.  The
    226 		 * decision to stop or continue is made based on the return
    227 		 * code.
    228 		 */
    229 		CK_ULONG num_slots = meta_slotManager_get_slotcount();
    230 
    231 		for (slot_num = 0; slot_num < num_slots; slot_num++) {
    232 			/*
    233 			 * If this is a free token and we are on the keystore
    234 			 * slot, bypass this because it was already created
    235 			 */
    236 
    237 			rv = meta_get_slot_session(slot_num, &slot_session,
    238 			    session->session_flags);
    239 			if (rv != CKR_OK)
    240 				goto cleanup;
    241 
    242 			object->tried_create_clone[slot_num] = B_TRUE;
    243 			rv = FUNCLIST(slot_session->fw_st_id)->C_CreateObject(
    244 			    slot_session->hSession, pTemplate, ulCount,
    245 			    &hNewObject);
    246 			if (rv == CKR_OK)
    247 				break;
    248 
    249 			if (!try_again(rv))
    250 				goto cleanup;
    251 
    252 			/* save first rv for other errors */
    253 			if (slot_num == 0)
    254 				first_rv = rv;
    255 
    256 			meta_release_slot_session(slot_session);
    257 			slot_session = NULL;
    258 
    259 		}
    260 	}
    261 
    262 	if (rv == CKR_OK) {
    263 		slot_object->hObject = hNewObject;
    264 		object->clones[slot_num] = slot_object;
    265 		object->master_clone_slotnum = slot_num;
    266 
    267 		/* Allow FreeToken to activate onto token obj list */
    268 		if (object->isFreeToken == FREE_ENABLED)
    269 			object->isToken = B_TRUE;
    270 
    271 		meta_slot_object_activate(slot_object, slot_session,
    272 		    object->isToken);
    273 
    274 		slot_object = NULL;
    275 		meta_release_slot_session(slot_session);
    276 		slot_session = NULL;
    277 
    278 	} else {
    279 		/*
    280 		 * return either first error code or
    281 		 * CKR_FUNCTION_FAILED depending on the failure
    282 		 */
    283 		int i;
    284 		for (i = 0; i < num_other_rv; i++) {
    285 			if (rv == other_rv[i]) {
    286 				rv = CKR_FUNCTION_FAILED;
    287 				goto cleanup;
    288 			}
    289 		}
    290 		/* need to return first rv */
    291 		rv = first_rv;
    292 		goto cleanup;
    293 	}
    294 
    295 
    296 	/*
    297 	 * always keep a copy of the template for C_CreateObject,
    298 	 * so clones can be created on other slots if necessary.
    299 	 * This is done even when the CKA_EXTRACTABLE=FALSE flag
    300 	 * is set for the object.  The supplied template is
    301 	 * "owned" by metaslot.  The application should not be
    302 	 * penalized just because metaslot choose to try creating
    303 	 * the object in a slot that's not capable of performing
    304 	 * any future operation.
    305 	 */
    306 	rv = get_master_attributes_by_template(pTemplate, ulCount,
    307 	    &object->attributes, &object->num_attributes);
    308 	if (rv == CKR_OK) {
    309 		CK_ULONG i;
    310 		for (i = 0; i < ulCount; i++) {
    311 			rv = attribute_set_value(&(pTemplate[i]),
    312 			    object->attributes, object->num_attributes);
    313 		}
    314 	}
    315 
    316 	meta_object_activate(object);
    317 	*phObject = (CK_OBJECT_HANDLE) object;
    318 
    319 	REFRELEASE(session);
    320 
    321 	return (CKR_OK);
    322 
    323 cleanup:
    324 	if (slot_object)
    325 		meta_slot_object_dealloc(slot_object);
    326 	if (slot_session)
    327 		meta_release_slot_session(slot_session);
    328 	if (object)
    329 		(void) meta_object_dealloc(session, object, B_TRUE);
    330 
    331 	REFRELEASE(session);
    332 
    333 	return (rv);
    334 }
    335 
    336 
    337 /*
    338  * meta_CopyObject
    339  *
    340  */
    341 CK_RV
    342 meta_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
    343     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
    344     CK_OBJECT_HANDLE_PTR phNewObject)
    345 {
    346 	CK_RV rv, first_rv;
    347 	meta_session_t *session;
    348 	meta_object_t *src_object, *dst_object = NULL;
    349 	slot_session_t *slot_session = NULL;
    350 	slot_object_t *dst_slot_object = NULL;
    351 	CK_ULONG i;
    352 	slot_object_t *src_slot_object;
    353 	CK_ULONG slotnum, num_slots;
    354 	boolean_t found;
    355 
    356 	if (pTemplate == NULL && ulCount != 0)
    357 		return (CKR_ARGUMENTS_BAD);
    358 	if (phNewObject == NULL)
    359 		return (CKR_ARGUMENTS_BAD);
    360 
    361 	rv = meta_handle2session(hSession, &session);
    362 	if (rv != CKR_OK)
    363 		return (rv);
    364 
    365 	rv = meta_handle2object(hObject, &src_object);
    366 	if (rv != CKR_OK) {
    367 		REFRELEASE(session);
    368 		return (rv);
    369 	}
    370 
    371 	rv = meta_object_alloc(session, &dst_object);
    372 	if (rv != CKR_OK)
    373 		goto finish;
    374 
    375 	found = get_template_boolean(CKA_TOKEN,
    376 	    pTemplate, ulCount, &(dst_object->isToken));
    377 	if (!found) {
    378 		dst_object->isToken = src_object->isToken;
    379 		if (src_object->isFreeToken == FREE_ENABLED)
    380 			dst_object->isToken = TRUE;
    381 		else
    382 			dst_object->isToken = src_object->isToken;
    383 	}
    384 
    385 	/* Can't create token objects in a read-only session. */
    386 	if ((IS_READ_ONLY_SESSION(session->session_flags)) &&
    387 	    (dst_object->isToken)) {
    388 		rv = CKR_SESSION_READ_ONLY;
    389 		goto finish;
    390 	}
    391 
    392 	if (dst_object->isToken) {
    393 
    394 		/*
    395 		 * if the dst object is a token object, and the source
    396 		 * object is not, the source object needs to be extractable.
    397 		 * Otherwise, the source object needs to reside in the
    398 		 * token object slot
    399 		 */
    400 		if ((!src_object->isExtractable) &&
    401 		    (src_object->master_clone_slotnum
    402 		    != get_keystore_slotnum())) {
    403 			rv = CKR_FUNCTION_FAILED;
    404 			goto finish;
    405 		}
    406 
    407 		/* determine if dst is going to be private object or not */
    408 		found = get_template_boolean(CKA_PRIVATE,
    409 		    pTemplate, ulCount, &(dst_object->isPrivate));
    410 		if (!found) {
    411 			/* will be the same as the source object */
    412 			dst_object->isPrivate = src_object->isPrivate;
    413 		}
    414 
    415 		slotnum = get_keystore_slotnum();
    416 	} else {
    417 
    418 		/* try create the obj in the same slot as the source obj */
    419 		slotnum = src_object->master_clone_slotnum;
    420 	}
    421 
    422 	rv = meta_slot_object_alloc(&dst_slot_object);
    423 	if (rv != CKR_OK)
    424 		goto finish;
    425 
    426 	rv = meta_get_slot_session(slotnum, &slot_session,
    427 	    session->session_flags);
    428 	if (rv != CKR_OK)
    429 		goto finish;
    430 
    431 	rv = meta_object_get_clone(src_object, slotnum,
    432 	    slot_session, &src_slot_object);
    433 	if (rv != CKR_OK)
    434 		goto finish;
    435 
    436 	dst_object->tried_create_clone[slotnum] = B_TRUE;
    437 	rv = FUNCLIST(slot_session->fw_st_id)->C_CopyObject(
    438 	    slot_session->hSession, src_slot_object->hObject, pTemplate,
    439 	    ulCount, &(dst_slot_object->hObject));
    440 
    441 	if (rv != CKR_OK) {
    442 		if (dst_object->isToken) {
    443 			/*
    444 			 * token obj can only be created in the
    445 			 * token slot.  No need to try anywhere else
    446 			 */
    447 			goto finish;
    448 		}
    449 		if ((!src_object->isExtractable) ||
    450 		    ((src_object->isSensitive) && (src_object->isToken) &&
    451 		    (!metaslot_auto_key_migrate))) {
    452 			/* source object isn't clonable in another slot */
    453 			goto finish;
    454 		}
    455 
    456 		if (!try_again(rv)) {
    457 			goto finish;
    458 		}
    459 
    460 		first_rv = rv;
    461 
    462 		meta_release_slot_session(slot_session);
    463 		slot_session = NULL;
    464 
    465 		num_slots = meta_slotManager_get_slotcount();
    466 
    467 		/* Try operation on other slots if the object is clonable */
    468 		for (slotnum = 0; slotnum < num_slots; slotnum++) {
    469 
    470 			if (slotnum == src_object->master_clone_slotnum) {
    471 				/* already tried, don't need to try again */
    472 				continue;
    473 			}
    474 
    475 			rv = meta_get_slot_session(slotnum, &slot_session,
    476 			    session->session_flags);
    477 			if (rv != CKR_OK) {
    478 				goto finish;
    479 			}
    480 
    481 			rv = meta_object_get_clone(src_object, slotnum,
    482 			    slot_session, &src_slot_object);
    483 			if (rv != CKR_OK)
    484 				goto finish;
    485 
    486 			dst_object->tried_create_clone[slotnum] = B_TRUE;
    487 
    488 			rv = FUNCLIST(slot_session->fw_st_id)->C_CopyObject(
    489 			    slot_session->hSession, src_slot_object->hObject,
    490 			    pTemplate, ulCount, &dst_slot_object->hObject);
    491 
    492 			if (rv == CKR_OK) {
    493 				break;
    494 			}
    495 
    496 			if (!try_again(rv)) {
    497 				goto finish;
    498 			}
    499 			meta_release_slot_session(slot_session);
    500 			slot_session = NULL;
    501 		}
    502 	}
    503 
    504 	if (rv == CKR_OK) {
    505 
    506 		rv = meta_object_get_attr(slot_session,
    507 		    dst_slot_object->hObject, dst_object);
    508 		if (rv != CKR_OK) {
    509 			goto finish;
    510 		}
    511 
    512 		if (src_object->attributes != NULL) {
    513 
    514 			/* Keep a copy of the template for the future */
    515 
    516 			/*
    517 			 * Don't allow attributes to change while
    518 			 * we look at them.
    519 			 */
    520 			(void) pthread_rwlock_rdlock(
    521 			    &src_object->attribute_lock);
    522 
    523 			rv = get_master_attributes_by_duplication(
    524 			    src_object->attributes,
    525 			    src_object->num_attributes,
    526 			    &dst_object->attributes,
    527 			    &dst_object->num_attributes);
    528 
    529 			(void) pthread_rwlock_unlock(
    530 			    &src_object->attribute_lock);
    531 
    532 			if (rv != CKR_OK)
    533 				goto finish;
    534 
    535 			for (i = 0; i < ulCount; i++) {
    536 				rv = attribute_set_value(pTemplate + i,
    537 				    dst_object->attributes,
    538 				    dst_object->num_attributes);
    539 
    540 				if (rv != CKR_OK)
    541 					goto finish;
    542 			}
    543 		}
    544 
    545 		/* Allow FreeToken to activate onto token obj list */
    546 		if (dst_object->isFreeToken == FREE_ENABLED)
    547 			dst_object->isToken = TRUE;
    548 
    549 		meta_slot_object_activate(dst_slot_object,
    550 		    slot_session, dst_object->isToken);
    551 
    552 		dst_object->clones[slotnum] = dst_slot_object;
    553 		dst_object->master_clone_slotnum = slotnum;
    554 		dst_slot_object = NULL; /* for error cleanup */
    555 
    556 		meta_release_slot_session(slot_session);
    557 		slot_session = NULL; /* for error cleanup */
    558 
    559 	} else {
    560 		/*
    561 		 * return either first error code or
    562 		 * CKR_FUNCTION_FAILED depending on the failure
    563 		 */
    564 		int j;
    565 		for (j = 0; j < num_other_rv; j++) {
    566 			if (rv == other_rv[j]) {
    567 				rv = CKR_FUNCTION_FAILED;
    568 				goto finish;
    569 			}
    570 		}
    571 		/* need to return first rv */
    572 		rv = first_rv;
    573 		goto finish;
    574 	}
    575 	meta_object_activate(dst_object);
    576 	*phNewObject = (CK_OBJECT_HANDLE) dst_object;
    577 
    578 finish:
    579 	if (rv != CKR_OK) {
    580 		if (dst_slot_object)
    581 			meta_slot_object_dealloc(dst_slot_object);
    582 
    583 		if (dst_object)
    584 			(void) meta_object_dealloc(session, dst_object,
    585 			    B_TRUE);
    586 
    587 		if (slot_session)
    588 			meta_release_slot_session(slot_session);
    589 	}
    590 
    591 	OBJRELEASE(src_object);
    592 	REFRELEASE(session);
    593 
    594 	return (rv);
    595 }
    596 
    597 
    598 /*
    599  * meta_DestroyObject
    600  *
    601  * This function destroys an object by first removing it from the
    602  * list of valid objects for a given session (if session object) or
    603  * the global token object list.  And then, calling C_DestroyObject
    604  * on all the slots on which we have created a clone of this object.
    605  */
    606 CK_RV
    607 meta_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject)
    608 {
    609 	CK_RV rv;
    610 	meta_session_t *session;
    611 	meta_object_t *object;
    612 
    613 	rv = meta_handle2session(hSession, &session);
    614 	if (rv != CKR_OK)
    615 		return (rv);
    616 
    617 	rv = meta_handle2object(hObject, &object);
    618 	if (rv != CKR_OK) {
    619 		REFRELEASE(session);
    620 		return (rv);
    621 	}
    622 
    623 	/* Can't delete token objects from a read-only session. */
    624 	if ((IS_READ_ONLY_SESSION(session->session_flags)) &&
    625 	    (object->isToken || object->isFreeToken == FREE_ENABLED)) {
    626 		OBJRELEASE(object);
    627 		REFRELEASE(session);
    628 		return (CKR_SESSION_READ_ONLY);
    629 	}
    630 
    631 	/* Remove object from list of valid meta_objects */
    632 	rv = meta_object_deactivate(object, B_FALSE, B_TRUE);
    633 
    634 	/*
    635 	 * Actually call C_DestroyObject on all the slots on which we have
    636 	 * created a clone of this object.
    637 	 */
    638 	if (rv == CKR_OK)
    639 		rv = meta_object_dealloc(session, object, B_TRUE);
    640 
    641 	REFRELEASE(session);
    642 
    643 	return (rv);
    644 }
    645 
    646 
    647 /*
    648  * meta_GetObjectSize
    649  *
    650  * NOTES:
    651  * 1) Because the "size" is so poorly defined in the spec, we have deemed
    652  *    it useless and won't support it. This is especially true for the
    653  *    metaslot, because the mulitple providers it uses may each interpret
    654  *    the size differently.
    655  */
    656 /* ARGSUSED */
    657 CK_RV
    658 meta_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
    659     CK_ULONG_PTR pulSize)
    660 {
    661 	return (CKR_FUNCTION_NOT_SUPPORTED);
    662 }
    663 
    664 
    665 /*
    666  * meta_GetAttributeValue
    667  *
    668  */
    669 CK_RV
    670 meta_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
    671     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
    672 {
    673 	CK_RV rv;
    674 	meta_session_t *session;
    675 	meta_object_t *object;
    676 	CK_ULONG slotnum;
    677 	slot_session_t *slot_session;
    678 
    679 	if (pTemplate == NULL || ulCount < 1)
    680 		return (CKR_ARGUMENTS_BAD);
    681 
    682 	rv = meta_handle2session(hSession, &session);
    683 	if (rv != CKR_OK)
    684 		return (rv);
    685 
    686 	rv = meta_handle2object(hObject, &object);
    687 	if (rv != CKR_OK) {
    688 		REFRELEASE(session);
    689 		return (rv);
    690 	}
    691 
    692 	slotnum = object->master_clone_slotnum;
    693 
    694 	rv = meta_get_slot_session(slotnum, &slot_session,
    695 	    session->session_flags);
    696 	if (rv == CKR_OK) {
    697 		rv = FUNCLIST(slot_session->fw_st_id)->C_GetAttributeValue(
    698 		    slot_session->hSession, object->clones[slotnum]->hObject,
    699 		    pTemplate, ulCount);
    700 
    701 		meta_release_slot_session(slot_session);
    702 	}
    703 
    704 	OBJRELEASE(object);
    705 	REFRELEASE(session);
    706 
    707 	return (rv);
    708 
    709 }
    710 
    711 
    712 /*
    713  * meta_SetAttributeValue
    714  *
    715  * Call C_SetAttributeValue on all the clones.  If the operation fails on
    716  * all clones, return the failure.
    717  *
    718  * If the operation fails on some clones and not the others, delete all the
    719  * clones that have failed the operation.  If any of the deleted clone is the
    720  * master clone, use one of the remaining clone as the master clone.
    721  *
    722  * If the operation is successful and the master template already exists,
    723  * update the master template with new values.
    724  */
    725 CK_RV
    726 meta_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
    727     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
    728 {
    729 	CK_RV rv = CKR_OK, save_rv = CKR_OK;
    730 	meta_session_t *session;
    731 	meta_object_t *object;
    732 	CK_ULONG slotnum, num_slots;
    733 	/* Keep track of which slot's SetAttributeValue failed */
    734 	boolean_t *clone_failed_op = NULL;
    735 	int num_clones = 0, num_clones_failed = 0;
    736 	slot_session_t *slot_session;
    737 	slot_object_t *slot_object;
    738 	boolean_t need_update_master_clone = B_FALSE;
    739 
    740 	if (pTemplate == NULL || ulCount < 1)
    741 		return (CKR_ARGUMENTS_BAD);
    742 
    743 	rv = meta_handle2session(hSession, &session);
    744 	if (rv != CKR_OK)
    745 		return (rv);
    746 
    747 	rv = meta_handle2object(hObject, &object);
    748 	if (rv != CKR_OK) {
    749 		REFRELEASE(session);
    750 		return (rv);
    751 	}
    752 
    753 	if ((IS_READ_ONLY_SESSION(session->session_flags)) &&
    754 	    (object->isToken || object->isFreeToken == FREE_ENABLED)) {
    755 		rv = CKR_SESSION_READ_ONLY;
    756 		goto finish;
    757 	}
    758 
    759 	if ((!object->isExtractable) && (object->attributes == NULL)) {
    760 		/*
    761 		 * object has no clone, just need to do the operation
    762 		 * in the master clone slot
    763 		 */
    764 		slot_session_t *slot_session;
    765 		slotnum = object->master_clone_slotnum;
    766 
    767 		rv = meta_get_slot_session(slotnum, &slot_session,
    768 		    session->session_flags);
    769 		if (rv == CKR_OK) {
    770 			rv = FUNCLIST(slot_session->fw_st_id)->\
    771 			    C_SetAttributeValue(slot_session->hSession,
    772 			    object->clones[slotnum]->hObject, pTemplate,
    773 			    ulCount);
    774 
    775 			meta_release_slot_session(slot_session);
    776 		}
    777 		goto finish;
    778 	}
    779 
    780 
    781 	num_slots = meta_slotManager_get_slotcount();
    782 
    783 	/*
    784 	 * object might have clones, need to do operation in all clones
    785 	 *
    786 	 * If the C_SetAttributeValue() call fails in a clone, the
    787 	 * clone that failed the operation can not be deleted right
    788 	 * away.  The clone with the failed operation is recorded, and
    789 	 * the deletion will happen in a separate loop.
    790 	 *
    791 	 * This is necessary because if ALL the clones failed
    792 	 * C_SetAttributeVAlue(), then, the app's call to C_SetAttributeValue()
    793 	 * is considered failed, and there shouldn't be any changes to the
    794 	 * object, none of the clones should be deleted.
    795 	 * On the other hand, if C_SetAttributeValue() fails in some clones
    796 	 * and succeeds in other clones, the C_SetAttributeValue() operation
    797 	 * is considered successful, and those clones that failed the
    798 	 * operation is deleted.
    799 	 */
    800 	clone_failed_op = calloc(num_slots, sizeof (boolean_t));
    801 	if (clone_failed_op == NULL) {
    802 		rv = CKR_HOST_MEMORY;
    803 		goto finish;
    804 	}
    805 	for (slotnum = 0; slotnum < num_slots; slotnum++) {
    806 		if (object->clones[slotnum] != NULL) {
    807 			num_clones++;
    808 			rv = meta_get_slot_session(slotnum, &slot_session,
    809 			    session->session_flags);
    810 			if (rv != CKR_OK) {
    811 				goto finish;
    812 			}
    813 
    814 			rv = FUNCLIST(slot_session->fw_st_id)->\
    815 			    C_SetAttributeValue(slot_session->hSession,
    816 			    object->clones[slotnum]->hObject, pTemplate,
    817 			    ulCount);
    818 
    819 			if (rv != CKR_OK) {
    820 				num_clones_failed++;
    821 				clone_failed_op[slotnum] = B_TRUE;
    822 				if (save_rv == CKR_OK) {
    823 					save_rv = rv;
    824 				}
    825 			}
    826 			meta_release_slot_session(slot_session);
    827 		}
    828 	}
    829 
    830 	if (num_clones_failed == num_clones) {
    831 		/* all operations failed */
    832 		rv = save_rv;
    833 		goto finish;
    834 	}
    835 
    836 	if (num_clones_failed > 0) {
    837 		/*
    838 		 * C_SetAttributeValue in some of the clones failed.
    839 		 * Find out which ones failed, and delete the clones
    840 		 * in those failed slots
    841 		 */
    842 		for (slotnum = 0; slotnum < num_slots; slotnum++) {
    843 			if (clone_failed_op[slotnum]) {
    844 
    845 				slot_object_t *clone = object->clones[slotnum];
    846 
    847 				rv = meta_get_slot_session(slotnum,
    848 				    &slot_session, session->session_flags);
    849 				if (rv == CKR_OK) {
    850 					(void) FUNCLIST(
    851 					    slot_session->fw_st_id)->
    852 					    C_DestroyObject(
    853 					    slot_session->hSession,
    854 					    clone->hObject);
    855 
    856 					meta_release_slot_session(slot_session);
    857 
    858 				}
    859 
    860 				meta_slot_object_deactivate(clone);
    861 				meta_slot_object_dealloc(clone);
    862 				object->clones[slotnum] = NULL;
    863 
    864 				if (slotnum == object->master_clone_slotnum) {
    865 					need_update_master_clone = B_TRUE;
    866 				}
    867 			}
    868 		}
    869 
    870 		if (need_update_master_clone) {
    871 			/* make first available clone the master */
    872 			for (slotnum = 0; slotnum < num_slots; slotnum++) {
    873 				if (object->clones[slotnum]) {
    874 					object->master_clone_slotnum = slotnum;
    875 					need_update_master_clone = B_FALSE;
    876 					break;
    877 				}
    878 			}
    879 
    880 		}
    881 		if (need_update_master_clone) {
    882 			/*
    883 			 * something is very wrong, can't continue
    884 			 * it should never be this case.
    885 			 */
    886 			rv = CKR_FUNCTION_FAILED;
    887 			goto finish;
    888 		}
    889 		rv = CKR_OK;
    890 	}
    891 
    892 	/*
    893 	 * Update the attribute information we keep in our metaslot object
    894 	 */
    895 	slot_object = object->clones[object->master_clone_slotnum];
    896 	rv = meta_get_slot_session(object->master_clone_slotnum,
    897 	    &slot_session, session->session_flags);
    898 	if (rv == CKR_OK) {
    899 		(void) meta_object_get_attr(slot_session,
    900 		    slot_object->hObject, object);
    901 		meta_release_slot_session(slot_session);
    902 	}
    903 
    904 	/* if there's a copy of the attributes, keep it up to date */
    905 	if (object->attributes != NULL) {
    906 
    907 		CK_ULONG i;
    908 
    909 		/* Make sure no one else is looking at attributes. */
    910 		(void) pthread_rwlock_wrlock(&object->attribute_lock);
    911 
    912 		for (i = 0; i < ulCount; i++) {
    913 			(void) attribute_set_value(pTemplate + i,
    914 			    object->attributes, object->num_attributes);
    915 
    916 		}
    917 		(void) pthread_rwlock_unlock(&object->attribute_lock);
    918 	}
    919 
    920 finish:
    921 	if (clone_failed_op) {
    922 		free(clone_failed_op);
    923 	}
    924 	OBJRELEASE(object);
    925 	REFRELEASE(session);
    926 
    927 	return (rv);
    928 }
    929 
    930 static boolean_t
    931 meta_object_in_list(meta_object_t *obj, meta_object_t **objs_list, int num_objs)
    932 {
    933 	int i;
    934 
    935 	for (i = 0; i < num_objs; i++) {
    936 		if (objs_list[i] == obj) {
    937 			return (B_TRUE);
    938 		}
    939 	}
    940 	return (B_FALSE);
    941 }
    942 
    943 static CK_RV
    944 add_to_search_result(meta_object_t *object, find_objs_info_t *info,
    945     int *num_results_alloc)
    946 {
    947 	/*
    948 	 * allocate space for storing results if the currently
    949 	 * allocated space is not enough
    950 	 */
    951 	if (*num_results_alloc <= info->num_matched_objs) {
    952 		*num_results_alloc += FIND_OBJ_BUF_SIZE;
    953 		info->matched_objs = realloc(info->matched_objs,
    954 		    sizeof (meta_object_t *) * (*num_results_alloc));
    955 		if (info->matched_objs == NULL) {
    956 			return (CKR_HOST_MEMORY);
    957 		}
    958 	}
    959 	(info->matched_objs)[(info->num_matched_objs)++] = object;
    960 	return (CKR_OK);
    961 }
    962 
    963 static CK_RV
    964 process_find_results(CK_OBJECT_HANDLE *results, CK_ULONG num_results,
    965     int *num_results_allocated, find_objs_info_t *info, CK_ULONG slotnum,
    966     boolean_t token_only, slot_session_t *slot_session,
    967     meta_session_t *session)
    968 {
    969 	CK_ULONG i;
    970 	meta_object_t *object;
    971 	CK_RV rv;
    972 
    973 	for (i = 0; i < num_results; i++) {
    974 
    975 		object = meta_object_find_by_handle(results[i], slotnum,
    976 		    token_only);
    977 
    978 		/*
    979 		 * a token object is found from the keystore,
    980 		 * need to create a meta object for it
    981 		 */
    982 		if (object == NULL) {
    983 			slot_object_t *slot_object;
    984 
    985 			rv = meta_object_alloc(session, &object);
    986 			if (rv != CKR_OK) {
    987 				return (rv);
    988 			}
    989 
    990 			rv = meta_slot_object_alloc(&slot_object);
    991 			if (rv != CKR_OK) {
    992 				(void) meta_object_dealloc(session, object,
    993 				    B_TRUE);
    994 				return (rv);
    995 			}
    996 
    997 			slot_object->hObject = results[i];
    998 			object->master_clone_slotnum = slotnum;
    999 			object->clones[slotnum] = slot_object;
   1000 
   1001 			/* get in the attributes we keep in meta_object */
   1002 
   1003 			rv = meta_object_get_attr(slot_session,
   1004 			    slot_object->hObject, object);
   1005 			if (rv != CKR_OK) {
   1006 				(void) meta_object_dealloc(session, object,
   1007 				    B_TRUE);
   1008 				return (rv);
   1009 			}
   1010 
   1011 			meta_slot_object_activate(slot_object, slot_session,
   1012 			    B_TRUE);
   1013 			meta_object_activate(object);
   1014 			slot_object = NULL;
   1015 		}
   1016 
   1017 		if (!meta_object_in_list(object, info->matched_objs,
   1018 		    info->num_matched_objs)) {
   1019 			rv = add_to_search_result(object, info,
   1020 			    num_results_allocated);
   1021 			if (rv != CKR_OK) {
   1022 				return (rv);
   1023 			}
   1024 		}
   1025 	}
   1026 	return (CKR_OK);
   1027 }
   1028 
   1029 static CK_RV
   1030 meta_search_for_objects(meta_session_t *session, find_objs_info_t *info,
   1031     slot_session_t *slot_session, CK_ATTRIBUTE_PTR pTemplate,
   1032     CK_ULONG ulCount, CK_ULONG slotnum, boolean_t token_only,
   1033     int *num_results_alloc)
   1034 {
   1035 	CK_ULONG tmp_num_results;
   1036 	CK_OBJECT_HANDLE tmp_results[FIND_OBJ_BUF_SIZE];
   1037 	CK_SESSION_HANDLE hSession = slot_session->hSession;
   1038 	CK_RV rv;
   1039 	CK_SLOT_ID fw_st_id = slot_session->fw_st_id;
   1040 
   1041 	rv = FUNCLIST(fw_st_id)->C_FindObjectsInit(hSession,
   1042 	    pTemplate, ulCount);
   1043 
   1044 	if (rv != CKR_OK) {
   1045 		return (rv);
   1046 	}
   1047 
   1048 	tmp_num_results = 0;
   1049 	rv = FUNCLIST(fw_st_id)->C_FindObjects(hSession, tmp_results,
   1050 	    FIND_OBJ_BUF_SIZE, &tmp_num_results);
   1051 	if (rv != CKR_OK) {
   1052 		return (rv);
   1053 	}
   1054 
   1055 	rv = process_find_results(tmp_results, tmp_num_results,
   1056 	    num_results_alloc, info, slotnum, token_only,
   1057 	    slot_session, session);
   1058 	if (rv != CKR_OK) {
   1059 		return (rv);
   1060 	}
   1061 
   1062 	while (tmp_num_results == FIND_OBJ_BUF_SIZE) {
   1063 		/* might be more results, need to call C_FindObjects again */
   1064 		rv = FUNCLIST(fw_st_id)->C_FindObjects(hSession, tmp_results,
   1065 		    FIND_OBJ_BUF_SIZE, &tmp_num_results);
   1066 		if (rv != CKR_OK) {
   1067 			return (rv);
   1068 		}
   1069 
   1070 		rv = process_find_results(tmp_results, tmp_num_results,
   1071 		    num_results_alloc, info, slotnum, token_only,
   1072 		    slot_session, session);
   1073 		if (rv != CKR_OK) {
   1074 			return (rv);
   1075 		}
   1076 	}
   1077 
   1078 	rv = FUNCLIST(fw_st_id)->C_FindObjectsFinal(hSession);
   1079 	return (rv);
   1080 }
   1081 
   1082 
   1083 /*
   1084  * meta_FindObjectsInit
   1085  *
   1086  * This function actually will do ALL the work of searching for objects
   1087  * that match all requirements specified in the template.
   1088  *
   1089  * Objects that matched the template will be stored in the
   1090  * session's data structure.  When the subsequent C_FindObjects()
   1091  * calls are made, results saved will be returned.
   1092  *
   1093  */
   1094 CK_RV
   1095 meta_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate,
   1096     CK_ULONG ulCount)
   1097 {
   1098 	CK_RV rv;
   1099 	meta_session_t *session;
   1100 	CK_ULONG slot_num = 0;
   1101 	boolean_t have_token_attr, tokenTrue = B_FALSE;
   1102 	slot_session_t *slot_find_session = NULL;
   1103 	int num_results_allocated = 0;
   1104 	CK_ULONG keystore_slotnum;
   1105 
   1106 	rv = meta_handle2session(hSession, &session);
   1107 	if (rv != CKR_OK)
   1108 		return (rv);
   1109 
   1110 	if ((session->find_objs_info).op_active) {
   1111 		REFRELEASE(session);
   1112 		return (CKR_OPERATION_ACTIVE);
   1113 	}
   1114 
   1115 	(session->find_objs_info).op_active = B_TRUE;
   1116 
   1117 	REFRELEASE(session);
   1118 
   1119 	/* see if the template indicates token object only or not */
   1120 	have_token_attr = get_template_boolean(CKA_TOKEN, pTemplate, ulCount,
   1121 	    &tokenTrue);
   1122 
   1123 	keystore_slotnum = get_keystore_slotnum();
   1124 
   1125 	if (have_token_attr && tokenTrue) {
   1126 
   1127 
   1128 		/*
   1129 		 * only interested in token objects, just need to search
   1130 		 * token object slot
   1131 		 */
   1132 		rv = meta_get_slot_session(keystore_slotnum,
   1133 		    &slot_find_session, session->session_flags);
   1134 		if (rv != CKR_OK)  {
   1135 			goto finish;
   1136 		}
   1137 		rv = meta_search_for_objects(session,
   1138 		    &(session->find_objs_info), slot_find_session, pTemplate,
   1139 		    ulCount, keystore_slotnum, B_TRUE, &num_results_allocated);
   1140 		if (rv != CKR_OK) {
   1141 			goto finish;
   1142 		}
   1143 	} else {
   1144 		CK_ULONG num_slots = meta_slotManager_get_slotcount();
   1145 		for (slot_num = 0; slot_num < num_slots; slot_num++) {
   1146 			rv = meta_get_slot_session(slot_num,
   1147 			    &slot_find_session, session->session_flags);
   1148 			if (rv != CKR_OK) {
   1149 				goto finish;
   1150 			}
   1151 
   1152 			/*
   1153 			 * if the slot is NOT the token object slot, and
   1154 			 * CKA_TOKEN is not specified, need to specified
   1155 			 * it to be false explicitly.  This will prevent
   1156 			 * us from using token objects that doesn't
   1157 			 * belong to the token slot in the case that
   1158 			 * more than one slot supports token objects.
   1159 			 */
   1160 
   1161 			if ((slot_num != keystore_slotnum) &&
   1162 			    (!have_token_attr)) {
   1163 				CK_BBOOL false = FALSE;
   1164 				CK_ATTRIBUTE_PTR newTemplate;
   1165 
   1166 				newTemplate = malloc((ulCount + 1) *
   1167 				    sizeof (CK_ATTRIBUTE));
   1168 				if (newTemplate == NULL) {
   1169 					rv = CKR_HOST_MEMORY;
   1170 					goto finish;
   1171 				}
   1172 				(void) memcpy(newTemplate + 1, pTemplate,
   1173 				    ulCount * sizeof (CK_ATTRIBUTE));
   1174 				newTemplate[0].type = CKA_TOKEN;
   1175 				newTemplate[0].pValue = &false;
   1176 				newTemplate[0].ulValueLen = sizeof (false);
   1177 
   1178 				rv = meta_search_for_objects(session,
   1179 				    &(session->find_objs_info),
   1180 				    slot_find_session, newTemplate,
   1181 				    ulCount+1, slot_num, B_FALSE,
   1182 				    &num_results_allocated);
   1183 				free(newTemplate);
   1184 			} else {
   1185 				rv = meta_search_for_objects(session,
   1186 				    &(session->find_objs_info),
   1187 				    slot_find_session, pTemplate, ulCount,
   1188 				    slot_num, B_FALSE,
   1189 				    &num_results_allocated);
   1190 			}
   1191 
   1192 			if (rv != CKR_OK) {
   1193 				goto finish;
   1194 			}
   1195 			meta_release_slot_session(slot_find_session);
   1196 			slot_find_session = NULL;
   1197 		}
   1198 	}
   1199 
   1200 finish:
   1201 	if (slot_find_session != NULL) {
   1202 		meta_release_slot_session(slot_find_session);
   1203 	}
   1204 	if (rv != CKR_OK) {
   1205 		(void) pthread_rwlock_wrlock(&session->session_lock);
   1206 		if (((session->find_objs_info).matched_objs) != NULL) {
   1207 			free((session->find_objs_info).matched_objs);
   1208 		}
   1209 		bzero(&(session->find_objs_info), sizeof (find_objs_info_t));
   1210 		(void) pthread_rwlock_unlock(&(session->session_lock));
   1211 	}
   1212 
   1213 	return (rv);
   1214 }
   1215 
   1216 /*
   1217  * meta_FindObjects
   1218  *
   1219  * This function actually doesn't do any real work in search for the
   1220  * matching object.  All the work is done in FindObjectsInit().  This
   1221  * function will only return the matching objects store in the session's
   1222  * "find_objs_info" variable.
   1223  *
   1224  */
   1225 CK_RV
   1226 meta_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject,
   1227     CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount)
   1228 {
   1229 	CK_RV rv;
   1230 	find_objs_info_t *info;
   1231 	CK_ULONG num_objs_found = 0;
   1232 	meta_object_t *obj;
   1233 	meta_session_t *session;
   1234 	int i;
   1235 
   1236 	rv = meta_handle2session(hSession, &session);
   1237 	if (rv != CKR_OK)
   1238 		return (rv);
   1239 
   1240 	info = &(session->find_objs_info);
   1241 
   1242 	if (!(info->op_active)) {
   1243 		REFRELEASE(session);
   1244 		return (CKR_OPERATION_NOT_INITIALIZED);
   1245 	}
   1246 
   1247 	for (i = info->next_result_index;
   1248 	    ((num_objs_found < ulMaxObjectCount) &&
   1249 	    (i < info->num_matched_objs));
   1250 	    i++) {
   1251 		obj = info->matched_objs[i];
   1252 		if (obj != NULL) {
   1253 			/* sanity check to see if object is still valid */
   1254 			(void) pthread_rwlock_rdlock(&obj->object_lock);
   1255 			if (obj->magic_marker == METASLOT_OBJECT_MAGIC) {
   1256 				phObject[num_objs_found++] =
   1257 				    (CK_OBJECT_HANDLE)obj;
   1258 			}
   1259 			(void) pthread_rwlock_unlock(&obj->object_lock);
   1260 		}
   1261 	}
   1262 	info->next_result_index = i;
   1263 	*pulObjectCount	= num_objs_found;
   1264 	REFRELEASE(session);
   1265 	return (rv);
   1266 }
   1267 
   1268 
   1269 /*
   1270  * meta_FindObjectsFinal
   1271  *
   1272  */
   1273 CK_RV
   1274 meta_FindObjectsFinal(CK_SESSION_HANDLE hSession)
   1275 {
   1276 	CK_RV rv;
   1277 	find_objs_info_t *info;
   1278 	meta_session_t *session;
   1279 
   1280 	rv = meta_handle2session(hSession, &session);
   1281 	if (rv != CKR_OK)
   1282 		return (rv);
   1283 
   1284 	info = &(session->find_objs_info);
   1285 
   1286 	if (!info->op_active) {
   1287 		REFRELEASE(session);
   1288 		return (CKR_OPERATION_NOT_INITIALIZED);
   1289 	}
   1290 
   1291 	if (info->matched_objs) {
   1292 		free(info->matched_objs);
   1293 	}
   1294 
   1295 	bzero(info, sizeof (find_objs_info_t));
   1296 	REFRELEASE(session);
   1297 	return (rv);
   1298 }
   1299