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