dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / pkcs11 / libpkcs11 / common / metaObject.c
blob2ba1ab2d16aaffb2cf46c29eafd1e66b712d56d6
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Object Management Functions
28 * (as defined in PKCS#11 spec section 11.7)
31 #include <strings.h>
32 #include "metaGlobal.h"
33 #include <stdio.h>
35 #define FIND_OBJ_BUF_SIZE 512 /* size of buf used for C_FindObjects */
38 * Argument related return codes. Will return to the caller immediately,
39 * and not try the operation on another slot.
41 static CK_RV stop_rv[] = {
42 CKR_ARGUMENTS_BAD,
43 CKR_ATTRIBUTE_TYPE_INVALID,
44 CKR_DOMAIN_PARAMS_INVALID,
45 CKR_TEMPLATE_INCOMPLETE
47 static int num_stop_rv = sizeof (stop_rv) / sizeof (CK_RV);
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.
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.
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);
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.
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
85 static int num_other_rv = sizeof (other_rv) / sizeof (CK_RV);
88 * This function is only used by the C_CreateObject and C_CopyObject.
90 * It is used to determine if the operation should be tried on another slot
91 * based on the return code
93 static boolean_t
94 try_again(CK_RV rv)
96 int i;
98 for (i = 0; i < num_stop_rv; i++) {
99 if (rv == stop_rv[i]) {
100 return (B_FALSE);
103 return (B_TRUE);
108 * meta_CreateObject
111 CK_RV
112 meta_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate,
113 CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject)
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;
124 if (pTemplate == NULL || ulCount < 1 || phObject == NULL)
125 return (CKR_ARGUMENTS_BAD);
127 rv = meta_handle2session(hSession, &session);
128 if (rv != CKR_OK)
129 return (rv);
131 rv = meta_object_alloc(session, &object);
132 if (rv != CKR_OK)
133 goto cleanup;
136 * Create a clone of the object
138 rv = meta_slot_object_alloc(&slot_object);
139 if (rv != CKR_OK)
140 goto cleanup;
143 * Set to true (token object) if template has CKA_TOKEN=true;
144 * otherwise, it is false (session object).
146 (void) get_template_boolean(CKA_TOKEN, pTemplate, ulCount,
147 &(object->isToken));
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;
156 * Set to true (private object) if template has CKA_PRIVATE=true;
157 * otherwise, it is false (public object).
159 (void) get_template_boolean(CKA_PRIVATE, pTemplate, ulCount,
160 &(object->isPrivate));
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));
168 * Set to true (sensitive object) if template has CKA_SENSITIVE=true;
169 * otherwise, it is false.
171 (void) get_template_boolean(CKA_SENSITIVE, pTemplate, ulCount,
172 &(object->isSensitive));
175 * Check if this can be a FreeObject.
177 * For creating objects, this check is mostly for preventing
178 * non-keystore hardware from creating CKA_PRIVATE objects without
179 * logging in.
182 if (meta_freeobject_check(session, object, NULL, pTemplate, ulCount,
183 0)) {
185 * Make sure we are logged into the keystore if this is a
186 * private freetoken object.
188 if (object->isPrivate && !metaslot_logged_in())
189 return (CKR_USER_NOT_LOGGED_IN);
191 if (!meta_freeobject_set(object, pTemplate, ulCount, B_TRUE))
192 goto cleanup;
196 keystore_slotnum = get_keystore_slotnum();
198 if (object->isToken || object->isFreeToken == FREE_ENABLED) {
201 * If this is a token object or a FreeToken then create it
202 * on the keystore slot.
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;
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);
215 if (rv != CKR_OK)
216 goto cleanup;
218 } else {
221 * Create a clone of the object in the first available slot.
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.
229 CK_ULONG num_slots = meta_slotManager_get_slotcount();
231 for (slot_num = 0; slot_num < num_slots; slot_num++) {
233 * If this is a free token and we are on the keystore
234 * slot, bypass this because it was already created
237 rv = meta_get_slot_session(slot_num, &slot_session,
238 session->session_flags);
239 if (rv != CKR_OK)
240 goto cleanup;
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;
249 if (!try_again(rv))
250 goto cleanup;
252 /* save first rv for other errors */
253 if (slot_num == 0)
254 first_rv = rv;
256 meta_release_slot_session(slot_session);
257 slot_session = NULL;
262 if (rv == CKR_OK) {
263 slot_object->hObject = hNewObject;
264 object->clones[slot_num] = slot_object;
265 object->master_clone_slotnum = slot_num;
267 /* Allow FreeToken to activate onto token obj list */
268 if (object->isFreeToken == FREE_ENABLED)
269 object->isToken = B_TRUE;
271 meta_slot_object_activate(slot_object, slot_session,
272 object->isToken);
274 slot_object = NULL;
275 meta_release_slot_session(slot_session);
276 slot_session = NULL;
278 } else {
280 * return either first error code or
281 * CKR_FUNCTION_FAILED depending on the failure
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;
290 /* need to return first rv */
291 rv = first_rv;
292 goto cleanup;
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.
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);
316 meta_object_activate(object);
317 *phObject = (CK_OBJECT_HANDLE) object;
319 REFRELEASE(session);
321 return (CKR_OK);
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);
331 REFRELEASE(session);
333 return (rv);
338 * meta_CopyObject
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)
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;
356 if (pTemplate == NULL && ulCount != 0)
357 return (CKR_ARGUMENTS_BAD);
358 if (phNewObject == NULL)
359 return (CKR_ARGUMENTS_BAD);
361 rv = meta_handle2session(hSession, &session);
362 if (rv != CKR_OK)
363 return (rv);
365 rv = meta_handle2object(hObject, &src_object);
366 if (rv != CKR_OK) {
367 REFRELEASE(session);
368 return (rv);
371 rv = meta_object_alloc(session, &dst_object);
372 if (rv != CKR_OK)
373 goto finish;
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;
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;
392 if (dst_object->isToken) {
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
400 if ((!src_object->isExtractable) &&
401 (src_object->master_clone_slotnum
402 != get_keystore_slotnum())) {
403 rv = CKR_FUNCTION_FAILED;
404 goto finish;
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;
415 slotnum = get_keystore_slotnum();
416 } else {
418 /* try create the obj in the same slot as the source obj */
419 slotnum = src_object->master_clone_slotnum;
422 rv = meta_slot_object_alloc(&dst_slot_object);
423 if (rv != CKR_OK)
424 goto finish;
426 rv = meta_get_slot_session(slotnum, &slot_session,
427 session->session_flags);
428 if (rv != CKR_OK)
429 goto finish;
431 rv = meta_object_get_clone(src_object, slotnum,
432 slot_session, &src_slot_object);
433 if (rv != CKR_OK)
434 goto finish;
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));
441 if (rv != CKR_OK) {
442 if (dst_object->isToken) {
444 * token obj can only be created in the
445 * token slot. No need to try anywhere else
447 goto finish;
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;
456 if (!try_again(rv)) {
457 goto finish;
460 first_rv = rv;
462 meta_release_slot_session(slot_session);
463 slot_session = NULL;
465 num_slots = meta_slotManager_get_slotcount();
467 /* Try operation on other slots if the object is clonable */
468 for (slotnum = 0; slotnum < num_slots; slotnum++) {
470 if (slotnum == src_object->master_clone_slotnum) {
471 /* already tried, don't need to try again */
472 continue;
475 rv = meta_get_slot_session(slotnum, &slot_session,
476 session->session_flags);
477 if (rv != CKR_OK) {
478 goto finish;
481 rv = meta_object_get_clone(src_object, slotnum,
482 slot_session, &src_slot_object);
483 if (rv != CKR_OK)
484 goto finish;
486 dst_object->tried_create_clone[slotnum] = B_TRUE;
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);
492 if (rv == CKR_OK) {
493 break;
496 if (!try_again(rv)) {
497 goto finish;
499 meta_release_slot_session(slot_session);
500 slot_session = NULL;
504 if (rv == CKR_OK) {
506 rv = meta_object_get_attr(slot_session,
507 dst_slot_object->hObject, dst_object);
508 if (rv != CKR_OK) {
509 goto finish;
512 if (src_object->attributes != NULL) {
514 /* Keep a copy of the template for the future */
517 * Don't allow attributes to change while
518 * we look at them.
520 (void) pthread_rwlock_rdlock(
521 &src_object->attribute_lock);
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);
529 (void) pthread_rwlock_unlock(
530 &src_object->attribute_lock);
532 if (rv != CKR_OK)
533 goto finish;
535 for (i = 0; i < ulCount; i++) {
536 rv = attribute_set_value(pTemplate + i,
537 dst_object->attributes,
538 dst_object->num_attributes);
540 if (rv != CKR_OK)
541 goto finish;
545 /* Allow FreeToken to activate onto token obj list */
546 if (dst_object->isFreeToken == FREE_ENABLED)
547 dst_object->isToken = TRUE;
549 meta_slot_object_activate(dst_slot_object,
550 slot_session, dst_object->isToken);
552 dst_object->clones[slotnum] = dst_slot_object;
553 dst_object->master_clone_slotnum = slotnum;
554 dst_slot_object = NULL; /* for error cleanup */
556 meta_release_slot_session(slot_session);
557 slot_session = NULL; /* for error cleanup */
559 } else {
561 * return either first error code or
562 * CKR_FUNCTION_FAILED depending on the failure
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;
571 /* need to return first rv */
572 rv = first_rv;
573 goto finish;
575 meta_object_activate(dst_object);
576 *phNewObject = (CK_OBJECT_HANDLE) dst_object;
578 finish:
579 if (rv != CKR_OK) {
580 if (dst_slot_object)
581 meta_slot_object_dealloc(dst_slot_object);
583 if (dst_object)
584 (void) meta_object_dealloc(session, dst_object,
585 B_TRUE);
587 if (slot_session)
588 meta_release_slot_session(slot_session);
591 OBJRELEASE(src_object);
592 REFRELEASE(session);
594 return (rv);
599 * meta_DestroyObject
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.
606 CK_RV
607 meta_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject)
609 CK_RV rv;
610 meta_session_t *session;
611 meta_object_t *object;
613 rv = meta_handle2session(hSession, &session);
614 if (rv != CKR_OK)
615 return (rv);
617 rv = meta_handle2object(hObject, &object);
618 if (rv != CKR_OK) {
619 REFRELEASE(session);
620 return (rv);
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);
631 /* Remove object from list of valid meta_objects */
632 rv = meta_object_deactivate(object, B_FALSE, B_TRUE);
635 * Actually call C_DestroyObject on all the slots on which we have
636 * created a clone of this object.
638 if (rv == CKR_OK)
639 rv = meta_object_dealloc(session, object, B_TRUE);
641 REFRELEASE(session);
643 return (rv);
648 * meta_GetObjectSize
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.
656 /* ARGSUSED */
657 CK_RV
658 meta_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
659 CK_ULONG_PTR pulSize)
661 return (CKR_FUNCTION_NOT_SUPPORTED);
666 * meta_GetAttributeValue
669 CK_RV
670 meta_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
671 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
673 CK_RV rv;
674 meta_session_t *session;
675 meta_object_t *object;
676 CK_ULONG slotnum;
677 slot_session_t *slot_session;
679 if (pTemplate == NULL || ulCount < 1)
680 return (CKR_ARGUMENTS_BAD);
682 rv = meta_handle2session(hSession, &session);
683 if (rv != CKR_OK)
684 return (rv);
686 rv = meta_handle2object(hObject, &object);
687 if (rv != CKR_OK) {
688 REFRELEASE(session);
689 return (rv);
692 slotnum = object->master_clone_slotnum;
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);
701 meta_release_slot_session(slot_session);
704 OBJRELEASE(object);
705 REFRELEASE(session);
707 return (rv);
713 * meta_SetAttributeValue
715 * Call C_SetAttributeValue on all the clones. If the operation fails on
716 * all clones, return the failure.
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.
722 * If the operation is successful and the master template already exists,
723 * update the master template with new values.
725 CK_RV
726 meta_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
727 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
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;
740 if (pTemplate == NULL || ulCount < 1)
741 return (CKR_ARGUMENTS_BAD);
743 rv = meta_handle2session(hSession, &session);
744 if (rv != CKR_OK)
745 return (rv);
747 rv = meta_handle2object(hObject, &object);
748 if (rv != CKR_OK) {
749 REFRELEASE(session);
750 return (rv);
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;
759 if ((!object->isExtractable) && (object->attributes == NULL)) {
761 * object has no clone, just need to do the operation
762 * in the master clone slot
764 slot_session_t *slot_session;
765 slotnum = object->master_clone_slotnum;
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);
775 meta_release_slot_session(slot_session);
777 goto finish;
781 num_slots = meta_slotManager_get_slotcount();
784 * object might have clones, need to do operation in all clones
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.
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.
800 clone_failed_op = calloc(num_slots, sizeof (boolean_t));
801 if (clone_failed_op == NULL) {
802 rv = CKR_HOST_MEMORY;
803 goto finish;
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;
814 rv = FUNCLIST(slot_session->fw_st_id)->\
815 C_SetAttributeValue(slot_session->hSession,
816 object->clones[slotnum]->hObject, pTemplate,
817 ulCount);
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;
826 meta_release_slot_session(slot_session);
830 if (num_clones_failed == num_clones) {
831 /* all operations failed */
832 rv = save_rv;
833 goto finish;
836 if (num_clones_failed > 0) {
838 * C_SetAttributeValue in some of the clones failed.
839 * Find out which ones failed, and delete the clones
840 * in those failed slots
842 for (slotnum = 0; slotnum < num_slots; slotnum++) {
843 if (clone_failed_op[slotnum]) {
845 slot_object_t *clone = object->clones[slotnum];
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);
856 meta_release_slot_session(slot_session);
860 meta_slot_object_deactivate(clone);
861 meta_slot_object_dealloc(clone);
862 object->clones[slotnum] = NULL;
864 if (slotnum == object->master_clone_slotnum) {
865 need_update_master_clone = B_TRUE;
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;
881 if (need_update_master_clone) {
883 * something is very wrong, can't continue
884 * it should never be this case.
886 rv = CKR_FUNCTION_FAILED;
887 goto finish;
889 rv = CKR_OK;
893 * Update the attribute information we keep in our metaslot object
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);
904 /* if there's a copy of the attributes, keep it up to date */
905 if (object->attributes != NULL) {
907 CK_ULONG i;
909 /* Make sure no one else is looking at attributes. */
910 (void) pthread_rwlock_wrlock(&object->attribute_lock);
912 for (i = 0; i < ulCount; i++) {
913 (void) attribute_set_value(pTemplate + i,
914 object->attributes, object->num_attributes);
917 (void) pthread_rwlock_unlock(&object->attribute_lock);
920 finish:
921 if (clone_failed_op) {
922 free(clone_failed_op);
924 OBJRELEASE(object);
925 REFRELEASE(session);
927 return (rv);
930 static boolean_t
931 meta_object_in_list(meta_object_t *obj, meta_object_t **objs_list, int num_objs)
933 int i;
935 for (i = 0; i < num_objs; i++) {
936 if (objs_list[i] == obj) {
937 return (B_TRUE);
940 return (B_FALSE);
943 static CK_RV
944 add_to_search_result(meta_object_t *object, find_objs_info_t *info,
945 int *num_results_alloc)
948 * allocate space for storing results if the currently
949 * allocated space is not enough
951 if (*num_results_alloc <= info->num_matched_objs) {
952 *num_results_alloc += FIND_OBJ_BUF_SIZE;
953 info->matched_objs = reallocarray(info->matched_objs,
954 *num_results_alloc, sizeof (meta_object_t *));
955 if (info->matched_objs == NULL) {
956 return (CKR_HOST_MEMORY);
959 (info->matched_objs)[(info->num_matched_objs)++] = object;
960 return (CKR_OK);
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)
969 CK_ULONG i;
970 meta_object_t *object;
971 CK_RV rv;
973 for (i = 0; i < num_results; i++) {
975 object = meta_object_find_by_handle(results[i], slotnum,
976 token_only);
979 * a token object is found from the keystore,
980 * need to create a meta object for it
982 if (object == NULL) {
983 slot_object_t *slot_object;
985 rv = meta_object_alloc(session, &object);
986 if (rv != CKR_OK) {
987 return (rv);
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);
997 slot_object->hObject = results[i];
998 object->master_clone_slotnum = slotnum;
999 object->clones[slotnum] = slot_object;
1001 /* get in the attributes we keep in meta_object */
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);
1011 meta_slot_object_activate(slot_object, slot_session,
1012 B_TRUE);
1013 meta_object_activate(object);
1014 slot_object = NULL;
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);
1026 return (CKR_OK);
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)
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;
1041 rv = FUNCLIST(fw_st_id)->C_FindObjectsInit(hSession,
1042 pTemplate, ulCount);
1044 if (rv != CKR_OK) {
1045 return (rv);
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);
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);
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);
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);
1078 rv = FUNCLIST(fw_st_id)->C_FindObjectsFinal(hSession);
1079 return (rv);
1084 * meta_FindObjectsInit
1086 * This function actually will do ALL the work of searching for objects
1087 * that match all requirements specified in the template.
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.
1094 CK_RV
1095 meta_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate,
1096 CK_ULONG ulCount)
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;
1106 rv = meta_handle2session(hSession, &session);
1107 if (rv != CKR_OK)
1108 return (rv);
1110 if ((session->find_objs_info).op_active) {
1111 REFRELEASE(session);
1112 return (CKR_OPERATION_ACTIVE);
1115 (session->find_objs_info).op_active = B_TRUE;
1117 REFRELEASE(session);
1119 /* see if the template indicates token object only or not */
1120 have_token_attr = get_template_boolean(CKA_TOKEN, pTemplate, ulCount,
1121 &tokenTrue);
1123 keystore_slotnum = get_keystore_slotnum();
1125 if (have_token_attr && tokenTrue) {
1129 * only interested in token objects, just need to search
1130 * token object slot
1132 rv = meta_get_slot_session(keystore_slotnum,
1133 &slot_find_session, session->session_flags);
1134 if (rv != CKR_OK) {
1135 goto finish;
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;
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;
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.
1161 if ((slot_num != keystore_slotnum) &&
1162 (!have_token_attr)) {
1163 CK_BBOOL false = FALSE;
1164 CK_ATTRIBUTE_PTR newTemplate;
1166 newTemplate = malloc((ulCount + 1) *
1167 sizeof (CK_ATTRIBUTE));
1168 if (newTemplate == NULL) {
1169 rv = CKR_HOST_MEMORY;
1170 goto finish;
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);
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);
1192 if (rv != CKR_OK) {
1193 goto finish;
1195 meta_release_slot_session(slot_find_session);
1196 slot_find_session = NULL;
1200 finish:
1201 if (slot_find_session != NULL) {
1202 meta_release_slot_session(slot_find_session);
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);
1209 bzero(&(session->find_objs_info), sizeof (find_objs_info_t));
1210 (void) pthread_rwlock_unlock(&(session->session_lock));
1213 return (rv);
1217 * meta_FindObjects
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.
1225 CK_RV
1226 meta_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject,
1227 CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount)
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;
1236 rv = meta_handle2session(hSession, &session);
1237 if (rv != CKR_OK)
1238 return (rv);
1240 info = &(session->find_objs_info);
1242 if (!(info->op_active)) {
1243 REFRELEASE(session);
1244 return (CKR_OPERATION_NOT_INITIALIZED);
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;
1259 (void) pthread_rwlock_unlock(&obj->object_lock);
1262 info->next_result_index = i;
1263 *pulObjectCount = num_objs_found;
1264 REFRELEASE(session);
1265 return (rv);
1270 * meta_FindObjectsFinal
1273 CK_RV
1274 meta_FindObjectsFinal(CK_SESSION_HANDLE hSession)
1276 CK_RV rv;
1277 find_objs_info_t *info;
1278 meta_session_t *session;
1280 rv = meta_handle2session(hSession, &session);
1281 if (rv != CKR_OK)
1282 return (rv);
1284 info = &(session->find_objs_info);
1286 if (!info->op_active) {
1287 REFRELEASE(session);
1288 return (CKR_OPERATION_NOT_INITIALIZED);
1291 if (info->matched_objs) {
1292 free(info->matched_objs);
1295 bzero(info, sizeof (find_objs_info_t));
1296 REFRELEASE(session);
1297 return (rv);