xref: /titanic_41/usr/src/lib/pkcs11/pkcs11_softtoken/common/softObjectUtil.c (revision f127cb91970601c2695eead0ee127f1cac48bb7a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <pthread.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <security/cryptoki.h>
33 #include "softGlobal.h"
34 #include "softObject.h"
35 #include "softSession.h"
36 #include "softKeystore.h"
37 #include "softKeystoreUtil.h"
38 
39 /*
40  * Add an object to the session's object list.
41  *
42  * This function will acquire the lock on the session, and release
43  * that lock after adding the object to the session's object list.
44  */
45 void
46 soft_add_object_to_session(soft_object_t *objp, soft_session_t *sp)
47 {
48 
49 	/* Acquire the session lock. */
50 	(void) pthread_mutex_lock(&sp->session_mutex);
51 
52 	/* Insert the new object in front of session's object list. */
53 	if (sp->object_list == NULL) {
54 		sp->object_list = objp;
55 		objp->next = NULL;
56 		objp->prev = NULL;
57 	} else {
58 		sp->object_list->prev = objp;
59 		objp->next = sp->object_list;
60 		objp->prev = NULL;
61 		sp->object_list = objp;
62 	}
63 
64 	/* Release the session lock. */
65 	(void) pthread_mutex_unlock(&sp->session_mutex);
66 }
67 
68 
69 /*
70  * Clean up and release the storage allocated to the object.
71  *
72  * The function is called either with the object lock being held
73  * (by caller soft_delete_object()), or there is no object lock
74  * yet (by soft_build_XXX_object() during creating an object).
75  */
76 void
77 soft_cleanup_object(soft_object_t *objp)
78 {
79 	/*
80 	 * Free the storage allocated to big integer attributes.
81 	 */
82 	soft_cleanup_object_bigint_attrs(objp);
83 
84 	/*
85 	 * Free the storage allocated to the extra attribute list.
86 	 */
87 	soft_cleanup_extra_attr(objp);
88 
89 	/*
90 	 * Free the storage allocated to certificate attributes.
91 	 */
92 	soft_cleanup_cert_object(objp);
93 }
94 
95 
96 /*
97  * Create a new object. Copy the attributes that can be modified
98  * (in the boolean attribute mask field and extra attribute list)
99  * from the old object to the new object.
100  *
101  * The caller of this function holds the lock on the old object.
102  */
103 CK_RV
104 soft_copy_object(soft_object_t *old_object, soft_object_t **new_object,
105     CK_ULONG object_func, soft_session_t *sp)
106 {
107 
108 	CK_RV rv = CKR_OK;
109 	soft_object_t *new_objp = NULL;
110 	CK_ATTRIBUTE_INFO_PTR attrp;
111 
112 	/* Allocate new object. */
113 	new_objp = calloc(1, sizeof (soft_object_t));
114 	if (new_objp == NULL)
115 		return (CKR_HOST_MEMORY);
116 
117 	new_objp->class = old_object->class;
118 	new_objp->bool_attr_mask = old_object->bool_attr_mask;
119 	new_objp->cert_type = old_object->cert_type;
120 	new_objp->object_type = old_object->object_type;
121 
122 	attrp = old_object->extra_attrlistp;
123 	while (attrp) {
124 		/*
125 		 * Copy the attribute_info struct from the old
126 		 * object to a new attribute_info struct, and add
127 		 * that new struct to the extra attribute list
128 		 * of the new object.
129 		 */
130 		rv = soft_copy_extra_attr(attrp, new_objp);
131 		if (rv != CKR_OK) {
132 			soft_cleanup_extra_attr(new_objp);
133 			free(new_objp);
134 			return (rv);
135 		}
136 		attrp = attrp->next;
137 	}
138 
139 	*new_object = new_objp;
140 
141 	if (object_func == SOFT_SET_ATTR_VALUE) {
142 		/* done with copying all information that can be modified */
143 		return (CKR_OK);
144 	}
145 
146 	/*
147 	 * Copy the rest of the object.
148 	 * Certain fields that are not appropriate for coping will be
149 	 * initialized.
150 	 */
151 	new_objp->key_type = old_object->key_type;
152 	new_objp->magic_marker = old_object->magic_marker;
153 	new_objp->mechanism = old_object->mechanism;
154 
155 	switch (object_func) {
156 	case SOFT_COPY_OBJ_ORIG_SH:
157 		new_objp->session_handle = old_object->session_handle;
158 		break;
159 	case SOFT_COPY_OBJECT:
160 		/*
161 		 * Save the session handle of the C_CopyObject function
162 		 * in the new copy of the session object.
163 		 */
164 		new_objp->session_handle = (CK_SESSION_HANDLE)sp;
165 		break;
166 	}
167 
168 	(void) pthread_cond_init(&(new_objp->obj_free_cond), NULL);
169 	(void) pthread_mutex_init(&(new_objp->object_mutex), NULL);
170 	/* copy key related information */
171 	switch (new_objp->class) {
172 		case CKO_PUBLIC_KEY:
173 			rv = soft_copy_public_key_attr(OBJ_PUB(old_object),
174 			    &(OBJ_PUB(new_objp)), new_objp->key_type);
175 			break;
176 		case CKO_PRIVATE_KEY:
177 			rv = soft_copy_private_key_attr(OBJ_PRI(old_object),
178 			    &(OBJ_PRI(new_objp)), new_objp->key_type);
179 			break;
180 		case CKO_SECRET_KEY:
181 			rv = soft_copy_secret_key_attr(OBJ_SEC(old_object),
182 			    &(OBJ_SEC(new_objp)));
183 			break;
184 		case CKO_DOMAIN_PARAMETERS:
185 			rv = soft_copy_domain_attr(OBJ_DOM(old_object),
186 			    &(OBJ_DOM(new_objp)), new_objp->key_type);
187 			break;
188 		case CKO_CERTIFICATE:
189 			rv = soft_copy_certificate(OBJ_CERT(old_object),
190 			    &(OBJ_CERT(new_objp)), new_objp->cert_type);
191 			break;
192 		default:
193 			/* should never be this case */
194 			break;
195 	}
196 	if (rv != CKR_OK) {
197 		/*
198 		 * don't need to cleanup the memory from failure of copying
199 		 * any key related stuff.  Each individual function for
200 		 * copying key attr will free the memory if it fails
201 		 */
202 		soft_cleanup_extra_attr(new_objp);
203 		free(new_objp);
204 	}
205 	return (rv);
206 }
207 
208 
209 /*
210  * Copy the attributes (in the boolean attribute mask field and
211  * extra attribute list) from the new object back to the original
212  * object. Also, clean up and release all the storage in the extra
213  * attribute list of the original object.
214  *
215  * The caller of this function holds the lock on the old object.
216  */
217 void
218 soft_merge_object(soft_object_t *old_object, soft_object_t *new_object)
219 {
220 	old_object->bool_attr_mask = new_object->bool_attr_mask;
221 	soft_cleanup_extra_attr(old_object);
222 	old_object->extra_attrlistp = new_object->extra_attrlistp;
223 }
224 
225 
226 /*
227  * Create a new object struct, and add it to the session's object list.
228  */
229 CK_RV
230 soft_add_object(CK_ATTRIBUTE_PTR pTemplate,  CK_ULONG ulCount,
231 	CK_ULONG *objecthandle_p, soft_session_t *sp)
232 {
233 
234 	CK_RV rv = CKR_OK;
235 	soft_object_t *new_objp = NULL;
236 
237 	new_objp = calloc(1, sizeof (soft_object_t));
238 	if (new_objp == NULL) {
239 		return (CKR_HOST_MEMORY);
240 	}
241 
242 	new_objp->extra_attrlistp = NULL;
243 
244 	/*
245 	 * Validate attribute template and fill in the attributes
246 	 * in the soft_object_t.
247 	 */
248 	rv = soft_build_object(pTemplate, ulCount, new_objp);
249 	if (rv != CKR_OK) {
250 		goto fail_cleanup1;
251 	}
252 
253 	rv = soft_pin_expired_check(new_objp);
254 	if (rv != CKR_OK) {
255 		goto fail_cleanup2;
256 	}
257 
258 	rv = soft_object_write_access_check(sp, new_objp);
259 	if (rv != CKR_OK) {
260 		goto fail_cleanup2;
261 	}
262 
263 	/* Initialize the rest of stuffs in soft_object_t. */
264 	(void) pthread_cond_init(&new_objp->obj_free_cond, NULL);
265 	(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
266 	new_objp->magic_marker = SOFTTOKEN_OBJECT_MAGIC;
267 	new_objp->obj_refcnt = 0;
268 	new_objp->obj_delete_sync = 0;
269 
270 	/* Write the new token object to the keystore */
271 	if (IS_TOKEN_OBJECT(new_objp)) {
272 		if (!soft_keystore_status(KEYSTORE_INITIALIZED)) {
273 			rv = CKR_DEVICE_REMOVED;
274 			goto fail_cleanup2;
275 		}
276 		new_objp->version = 1;
277 		rv = soft_put_object_to_keystore(new_objp);
278 		if (rv != CKR_OK) {
279 			(void) pthread_cond_destroy(&new_objp->obj_free_cond);
280 			(void) pthread_mutex_destroy(&new_objp->object_mutex);
281 			goto fail_cleanup2;
282 		}
283 		new_objp->session_handle = (CK_SESSION_HANDLE)NULL;
284 		soft_add_token_object_to_slot(new_objp);
285 		/*
286 		 * Type casting the address of an object struct to
287 		 * an object handle.
288 		 */
289 		*objecthandle_p = (CK_ULONG)new_objp;
290 
291 		return (CKR_OK);
292 	}
293 
294 	new_objp->session_handle = (CK_SESSION_HANDLE)sp;
295 
296 	/* Add the new object to the session's object list. */
297 	soft_add_object_to_session(new_objp, sp);
298 
299 	/* Type casting the address of an object struct to an object handle. */
300 	*objecthandle_p =  (CK_ULONG)new_objp;
301 
302 	return (CKR_OK);
303 
304 fail_cleanup2:
305 	/*
306 	 * When any error occurs after soft_build_object(), we will need to
307 	 * clean up the memory allocated by the soft_build_object().
308 	 */
309 	soft_cleanup_object(new_objp);
310 
311 fail_cleanup1:
312 	if (new_objp) {
313 		/*
314 		 * The storage allocated inside of this object should have
315 		 * been cleaned up by the soft_build_object() if it failed.
316 		 * Therefore, we can safely free the object.
317 		 */
318 		free(new_objp);
319 	}
320 
321 	return (rv);
322 
323 }
324 
325 
326 /*
327  * Remove an object from the session's object list.
328  *
329  * The caller of this function holds the session lock.
330  */
331 CK_RV
332 soft_remove_object_from_session(soft_object_t *objp, soft_session_t *sp)
333 {
334 	soft_object_t *tmp_objp;
335 	boolean_t found = B_FALSE;
336 
337 	/*
338 	 * Remove the object from the session's object list.
339 	 */
340 	if ((sp == NULL) ||
341 	    (sp->magic_marker != SOFTTOKEN_SESSION_MAGIC)) {
342 		return (CKR_SESSION_HANDLE_INVALID);
343 	}
344 
345 	if ((sp->object_list == NULL) || (objp == NULL) ||
346 	    (objp->magic_marker != SOFTTOKEN_OBJECT_MAGIC)) {
347 		return (CKR_OBJECT_HANDLE_INVALID);
348 	}
349 
350 	tmp_objp = sp->object_list;
351 	while (tmp_objp) {
352 		if (tmp_objp == objp) {
353 			found = B_TRUE;
354 			break;
355 		}
356 		tmp_objp = tmp_objp->next;
357 	}
358 	if (!found)
359 		return (CKR_OBJECT_HANDLE_INVALID);
360 
361 	if (sp->object_list == objp) {
362 		/* Object is the first one in the list. */
363 		if (objp->next) {
364 			sp->object_list = objp->next;
365 			objp->next->prev = NULL;
366 		} else {
367 			/* Object is the only one in the list. */
368 			sp->object_list = NULL;
369 		}
370 	} else {
371 		/* Object is not the first one in the list. */
372 		if (objp->next) {
373 			/* Object is in the middle of the list. */
374 			objp->prev->next = objp->next;
375 			objp->next->prev = objp->prev;
376 		} else {
377 			/* Object is the last one in the list. */
378 			objp->prev->next = NULL;
379 		}
380 	}
381 	return (CKR_OK);
382 }
383 
384 /*
385  * This function adds the to-be-freed session object to a linked list.
386  * When the number of objects queued in the linked list reaches the
387  * maximum threshold MAX_OBJ_TO_BE_FREED, it will free the first
388  * object (FIFO) in the list.
389  */
390 void
391 object_delay_free(soft_object_t *objp)
392 {
393 	soft_object_t *tmp;
394 
395 	(void) pthread_mutex_lock(&obj_delay_freed.obj_to_be_free_mutex);
396 
397 	/* Add the newly deleted object at the end of the list */
398 	objp->next = NULL;
399 	if (obj_delay_freed.first == NULL) {
400 		obj_delay_freed.last = objp;
401 		obj_delay_freed.first = objp;
402 	} else {
403 		obj_delay_freed.last->next = objp;
404 		obj_delay_freed.last = objp;
405 	}
406 
407 	if (++obj_delay_freed.count >= MAX_OBJ_TO_BE_FREED) {
408 		/*
409 		 * Free the first object in the list only if
410 		 * the total count reaches maximum threshold.
411 		 */
412 		obj_delay_freed.count--;
413 		tmp = obj_delay_freed.first->next;
414 		free(obj_delay_freed.first);
415 		obj_delay_freed.first = tmp;
416 	}
417 	(void) pthread_mutex_unlock(&obj_delay_freed.obj_to_be_free_mutex);
418 }
419 
420 static void
421 soft_delete_object_cleanup(soft_object_t *objp)
422 {
423 	/* Acquire the lock on the object. */
424 	(void) pthread_mutex_lock(&objp->object_mutex);
425 
426 	/*
427 	 * Make sure another thread hasn't freed the object.
428 	 */
429 	if (objp->magic_marker != SOFTTOKEN_OBJECT_MAGIC) {
430 		(void) pthread_mutex_unlock(&objp->object_mutex);
431 		return;
432 	}
433 
434 	/*
435 	 * The deletion of an object must be blocked when the object
436 	 * reference count is not zero. This means if any object related
437 	 * operation starts prior to the delete object operation gets in,
438 	 * the object deleting thread must wait for the non-deleting
439 	 * operation to be completed before it can proceed the delete
440 	 * operation.
441 	 */
442 	while (objp->obj_refcnt != 0) {
443 		/*
444 		 * We set the OBJECT_REFCNT_WAITING flag before we put
445 		 * this deleting thread in a wait state, so other non-deleting
446 		 * operation thread will signal to wake it up only when
447 		 * the object reference count becomes zero and this flag
448 		 * is set.
449 		 */
450 		objp->obj_delete_sync |= OBJECT_REFCNT_WAITING;
451 		(void) pthread_cond_wait(&objp->obj_free_cond,
452 			&objp->object_mutex);
453 	}
454 
455 	objp->obj_delete_sync &= ~OBJECT_REFCNT_WAITING;
456 
457 	/* Mark object as no longer valid. */
458 	objp->magic_marker = 0;
459 
460 	(void) pthread_cond_destroy(&objp->obj_free_cond);
461 
462 	/*
463 	 * Cleanup the contents of this object such as free all the
464 	 * storage allocated for this object.
465 	 */
466 	soft_cleanup_object(objp);
467 
468 	/* Reset OBJECT_IS_DELETING flag. */
469 	objp->obj_delete_sync &= ~OBJECT_IS_DELETING;
470 
471 	(void) pthread_mutex_unlock(&objp->object_mutex);
472 	/* Destroy the object lock */
473 	(void) pthread_mutex_destroy(&objp->object_mutex);
474 
475 	/* Free the object itself */
476 	if (IS_TOKEN_OBJECT(objp))
477 		free(objp);
478 	else
479 		/*
480 		 * Delay freeing the session object as S1WS/NSS uses session
481 		 * objects for its SSL Handshake.
482 		 */
483 		(void) object_delay_free(objp);
484 }
485 
486 /*
487  * Delete an object:
488  * - Remove the object from the session's object list.
489  *   Holding the lock on the session which the object was created at
490  *   is needed to do this.
491  * - Release the storage allocated to the object.
492  *
493  * The boolean argument lock_held is used to indicate that whether
494  * the caller holds the session lock or not.
495  * - When called by soft_delete_all_objects_in_session() -- the
496  *   lock_held = TRUE.
497  *
498  * When the caller does not hold the session lock, this function
499  * will acquire that lock in order to proceed, and also release
500  * that lock before returning to caller.
501  */
502 void
503 soft_delete_object(soft_session_t *sp, soft_object_t *objp, boolean_t lock_held)
504 {
505 
506 	/*
507 	 * Check to see if the caller holds the lock on the session.
508 	 * If not, we need to acquire that lock in order to proceed.
509 	 */
510 	if (!lock_held) {
511 		/* Acquire the session lock. */
512 		(void) pthread_mutex_lock(&sp->session_mutex);
513 	}
514 
515 	/* Remove the object from the session's object list first. */
516 	if (soft_remove_object_from_session(objp, sp) != CKR_OK) {
517 		if (!lock_held) {
518 			(void) pthread_mutex_unlock(&sp->session_mutex);
519 		}
520 		return;
521 	}
522 
523 	if (!lock_held) {
524 		/*
525 		 * If the session lock is obtained by this function,
526 		 * then release that lock after removing the object
527 		 * from session's object list.
528 		 * We want the releasing of the object storage to
529 		 * be done without holding the session lock.
530 		 */
531 		(void) pthread_mutex_unlock(&sp->session_mutex);
532 	}
533 
534 	soft_delete_object_cleanup(objp);
535 }
536 
537 
538 /*
539  * Delete all the objects in a session. The caller holds the lock
540  * on the session.
541  */
542 void
543 soft_delete_all_objects_in_session(soft_session_t *sp)
544 {
545 	soft_object_t *objp = sp->object_list;
546 	soft_object_t *objp1;
547 
548 	/* Delete all the objects in the session. */
549 	while (objp) {
550 		objp1 = objp->next;
551 
552 		/*
553 		 * Delete an object by calling soft_delete_object()
554 		 * with a TRUE boolean argument indicating that
555 		 * the caller holds the lock on the session.
556 		 */
557 		soft_delete_object(sp, objp, B_TRUE);
558 
559 		objp = objp1;
560 	}
561 }
562 
563 static CK_RV
564 add_to_search_result(soft_object_t *obj, find_context_t *fcontext,
565     CK_ULONG *num_result_alloc)
566 {
567 	/*
568 	 * allocate space for storing results if the currently
569 	 * allocated space is not enough
570 	 */
571 	if (*num_result_alloc <= fcontext->num_results) {
572 		fcontext->objs_found = realloc(fcontext->objs_found,
573 		    sizeof (soft_object_t *) * (*num_result_alloc + BUFSIZ));
574 		if (fcontext->objs_found == NULL) {
575 			return (CKR_HOST_MEMORY);
576 		}
577 		*num_result_alloc += BUFSIZ;
578 	}
579 
580 	(fcontext->objs_found)[(fcontext->num_results)++] = obj;
581 	return (CKR_OK);
582 }
583 
584 static CK_RV
585 search_for_objects(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
586     find_context_t *fcontext)
587 {
588 	soft_session_t *session_p;
589 	soft_object_t *obj;
590 	CK_OBJECT_CLASS pclasses[6]; /* classes attrs possiblely exist */
591 	CK_ULONG num_pclasses;	/* number of possible classes */
592 	CK_ULONG num_result_alloc = 0; /* spaces allocated for results */
593 	CK_RV rv = CKR_OK;
594 	/* whether CKA_TOKEN flag specified or not */
595 	boolean_t token_specified = B_FALSE;
596 	/* value of CKA_TOKEN flag, if specified */
597 	boolean_t token_flag_val = B_FALSE;
598 	CK_ULONG i;
599 
600 	if (ulCount > 0) {
601 		/* there are some search requirement */
602 		soft_process_find_attr(pclasses, &num_pclasses,
603 		    pTemplate, ulCount);
604 	}
605 
606 	for (i = 0; i < ulCount; i++) {
607 		if (pTemplate[i].type == CKA_PRIVATE) {
608 			(void) pthread_mutex_lock(&soft_giant_mutex);
609 			if (soft_slot.userpin_change_needed) {
610 				(void) pthread_mutex_unlock(&soft_giant_mutex);
611 				return (CKR_PIN_EXPIRED);
612 			}
613 			(void) pthread_mutex_unlock(&soft_giant_mutex);
614 		}
615 	}
616 
617 	/*
618 	 * look through template and see if it explicitly specifies
619 	 * whether we need to look for token objects or not
620 	 */
621 	for (i = 0; i < ulCount; i++) {
622 		if (pTemplate[i].type == CKA_TOKEN) {
623 			token_specified = B_TRUE;
624 			token_flag_val = *((CK_BBOOL *)pTemplate[i].pValue);
625 			break;
626 		}
627 	}
628 
629 	/*
630 	 * Need go through token objects if it explicitly say so, or
631 	 * it is not mentioned in the template.  And this will ONLY be
632 	 * done when the keystore exists. Otherwise, we will skip re-loading
633 	 * the token objects.
634 	 *
635 	 * If a session has not logged into the token, only public
636 	 * objects, if any, will be searched.  If a session is logged
637 	 * into the token, all public and private objects in the keystore
638 	 * are searched.
639 	 */
640 	if (((token_flag_val) || (!token_specified)) &&
641 	    soft_keystore_status(KEYSTORE_INITIALIZED)) {
642 		/* acquire token session lock */
643 		(void) pthread_mutex_lock(&soft_slot.slot_mutex);
644 		rv = refresh_token_objects();
645 		if (rv != CKR_OK) {
646 			(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
647 			return (rv);
648 		}
649 		obj = soft_slot.token_object_list;
650 		while (obj) {
651 			(void) pthread_mutex_lock(&obj->object_mutex);
652 			if (((token_specified) && (ulCount > 1)) ||
653 			    ((!token_specified) && (ulCount > 0))) {
654 				if (soft_find_match_attrs(obj, pclasses,
655 				    num_pclasses, pTemplate, ulCount)) {
656 					rv = add_to_search_result(
657 					    obj, fcontext, &num_result_alloc);
658 				}
659 			} else {
660 				/* no search criteria, just record the object */
661 				rv = add_to_search_result(obj, fcontext,
662 				    &num_result_alloc);
663 			}
664 			(void) pthread_mutex_unlock(&obj->object_mutex);
665 			if (rv != CKR_OK) {
666 				(void) pthread_mutex_unlock
667 				    (&soft_slot.slot_mutex);
668 				return (rv);
669 			}
670 			obj = obj->next;
671 		}
672 		(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
673 	}
674 
675 	if (token_flag_val) {
676 		/* no need to look through session objects */
677 		return (rv);
678 	}
679 
680 	/* Acquire the global session list lock */
681 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
682 
683 	/*
684 	 * Go through all objects in each session.
685 	 * Acquire individual session lock for the session
686 	 * we are searching.
687 	 */
688 	session_p = soft_session_list;
689 	while (session_p) {
690 		(void) pthread_mutex_lock(&session_p->session_mutex);
691 
692 		obj = session_p->object_list;
693 		while (obj) {
694 			(void) pthread_mutex_lock(&obj->object_mutex);
695 			if (ulCount > 0) {
696 				if (soft_find_match_attrs(obj, pclasses,
697 				    num_pclasses, pTemplate, ulCount)) {
698 					rv = add_to_search_result(
699 					    obj, fcontext, &num_result_alloc);
700 				}
701 			} else {
702 				/* no search criteria, just record the object */
703 				rv = add_to_search_result(obj, fcontext,
704 				    &num_result_alloc);
705 			}
706 			(void) pthread_mutex_unlock(&obj->object_mutex);
707 			if (rv != CKR_OK) {
708 				(void) pthread_mutex_unlock(
709 				    &session_p->session_mutex);
710 				goto cleanup;
711 			}
712 			obj = obj->next;
713 		}
714 		(void) pthread_mutex_unlock(&session_p->session_mutex);
715 		session_p = session_p->next;
716 	}
717 
718 cleanup:
719 	/* Release the global session list lock */
720 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
721 	return (rv);
722 }
723 
724 /*
725  * Initialize the context for C_FindObjects() calls
726  */
727 CK_RV
728 soft_find_objects_init(soft_session_t *sp, CK_ATTRIBUTE_PTR pTemplate,
729     CK_ULONG ulCount)
730 {
731 
732 	CK_RV rv = CKR_OK;
733 	CK_OBJECT_CLASS class; /* for soft_validate_attr(). Value unused */
734 	find_context_t *fcontext;
735 
736 	if (ulCount) {
737 		rv = soft_validate_attr(pTemplate, ulCount, &class);
738 		/* Make sure all attributes in template are valid */
739 		if (rv != CKR_OK) {
740 			return (rv);
741 		}
742 	}
743 
744 
745 	/* prepare the find context */
746 	fcontext = calloc(1, sizeof (find_context_t));
747 	if (fcontext == NULL) {
748 		return (CKR_HOST_MEMORY);
749 	}
750 
751 	rv = search_for_objects(pTemplate, ulCount, fcontext);
752 	if (rv != CKR_OK) {
753 		free(fcontext);
754 		return (rv);
755 	}
756 
757 	/* store the find_context in the session */
758 	sp->find_objects.context = (CK_VOID_PTR)fcontext;
759 
760 	return (rv);
761 }
762 
763 void
764 soft_find_objects_final(soft_session_t *sp)
765 {
766 	find_context_t *fcontext;
767 
768 	fcontext = sp->find_objects.context;
769 	sp->find_objects.context = NULL;
770 	sp->find_objects.flags = 0;
771 	if (fcontext->objs_found != NULL) {
772 		free(fcontext->objs_found);
773 	}
774 
775 	free(fcontext);
776 }
777 
778 void
779 soft_find_objects(soft_session_t *sp, CK_OBJECT_HANDLE *obj_found,
780     CK_ULONG max_obj_requested, CK_ULONG *found_obj_count)
781 {
782 	find_context_t *fcontext;
783 	CK_ULONG num_obj_found = 0;
784 	CK_ULONG i;
785 	soft_object_t *obj;
786 
787 	fcontext = sp->find_objects.context;
788 
789 	for (i = fcontext->next_result_index;
790 	    ((num_obj_found < max_obj_requested) &&
791 	    (i < fcontext->num_results));
792 	    i++) {
793 		obj = fcontext->objs_found[i];
794 		if (obj != NULL) {
795 			(void) pthread_mutex_lock(&obj->object_mutex);
796 			/* a sanity check to make sure the obj is still valid */
797 			if (obj->magic_marker == SOFTTOKEN_OBJECT_MAGIC) {
798 				obj_found[num_obj_found] =
799 				    (CK_OBJECT_HANDLE)obj;
800 				num_obj_found++;
801 			}
802 			(void) pthread_mutex_unlock(&obj->object_mutex);
803 		}
804 	}
805 	fcontext->next_result_index = i;
806 	*found_obj_count = num_obj_found;
807 }
808 
809 /*
810  * Below are the token object related functions
811  */
812 void
813 soft_add_token_object_to_slot(soft_object_t *objp)
814 {
815 
816 	(void) pthread_mutex_lock(&soft_slot.slot_mutex);
817 
818 	/* Insert the new object in front of slot's token object list. */
819 	if (soft_slot.token_object_list == NULL) {
820 		soft_slot.token_object_list = objp;
821 		objp->next = NULL;
822 		objp->prev = NULL;
823 	} else {
824 		soft_slot.token_object_list->prev = objp;
825 		objp->next = soft_slot.token_object_list;
826 		objp->prev = NULL;
827 		soft_slot.token_object_list = objp;
828 	}
829 
830 	(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
831 
832 }
833 
834 void
835 soft_remove_token_object_from_slot(soft_object_t *objp, boolean_t lock_held)
836 {
837 
838 	if (!lock_held)
839 		(void) pthread_mutex_lock(&soft_slot.slot_mutex);
840 
841 	/*
842 	 * Remove the object from the slot's token object list.
843 	 */
844 	if (soft_slot.token_object_list == objp) {
845 		/* Object is the first one in the list. */
846 		if (objp->next) {
847 			soft_slot.token_object_list = objp->next;
848 			objp->next->prev = NULL;
849 		} else {
850 			/* Object is the only one in the list. */
851 			soft_slot.token_object_list = NULL;
852 		}
853 	} else {
854 		/* Object is not the first one in the list. */
855 		if (objp->next) {
856 			/* Object is in the middle of the list. */
857 			objp->prev->next = objp->next;
858 			objp->next->prev = objp->prev;
859 		} else {
860 			/* Object is the last one in the list. */
861 			objp->prev->next = NULL;
862 		}
863 	}
864 
865 	if (!lock_held)
866 		(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
867 }
868 
869 void
870 soft_delete_token_object(soft_object_t *objp, boolean_t persistent,
871     boolean_t lock_held)
872 {
873 
874 	if (!lock_held)
875 		(void) pthread_mutex_lock(&soft_slot.slot_mutex);
876 	if (persistent)
877 		/* Delete the object from the keystore. */
878 		(void) soft_keystore_del_obj(&objp->ks_handle, B_FALSE);
879 
880 	/* Remove the object from the slot's token object list. */
881 	soft_remove_token_object_from_slot(objp, B_TRUE);
882 	if (!lock_held)
883 		(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
884 
885 	soft_delete_object_cleanup(objp);
886 }
887 
888 void
889 soft_delete_all_in_core_token_objects(token_obj_type_t type)
890 {
891 
892 	soft_object_t *objp;
893 	soft_object_t *objp1;
894 
895 	(void) pthread_mutex_lock(&soft_slot.slot_mutex);
896 	objp = soft_slot.token_object_list;
897 
898 	switch (type) {
899 	case PRIVATE_TOKEN:
900 		while (objp) {
901 			objp1 = objp->next;
902 			if (objp->object_type == TOKEN_PRIVATE) {
903 				soft_delete_token_object(objp, B_FALSE, B_TRUE);
904 			}
905 			objp = objp1;
906 		}
907 		break;
908 
909 	case PUBLIC_TOKEN:
910 		while (objp) {
911 			objp1 = objp->next;
912 			if (objp->object_type == TOKEN_PUBLIC) {
913 				soft_delete_token_object(objp, B_FALSE, B_TRUE);
914 			}
915 			objp = objp1;
916 		}
917 		break;
918 
919 	case ALL_TOKEN:
920 		while (objp) {
921 			objp1 = objp->next;
922 			soft_delete_token_object(objp, B_FALSE, B_TRUE);
923 			objp = objp1;
924 		}
925 		break;
926 	}
927 
928 	(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
929 
930 }
931 
932 /*
933  * Mark all the token objects in the global list to be valid.
934  */
935 void
936 soft_validate_token_objects(boolean_t validate)
937 {
938 
939 	soft_object_t *objp;
940 
941 	(void) pthread_mutex_lock(&soft_slot.slot_mutex);
942 
943 	objp = soft_slot.token_object_list;
944 
945 	while (objp) {
946 		if (validate)
947 			objp->magic_marker = SOFTTOKEN_OBJECT_MAGIC;
948 		else
949 			objp->magic_marker = 0;
950 
951 		objp = objp->next;
952 	}
953 
954 	(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
955 
956 }
957 
958 /*
959  * Verify user's write access rule to the token object.
960  */
961 CK_RV
962 soft_object_write_access_check(soft_session_t *sp, soft_object_t *objp)
963 {
964 
965 	/*
966 	 * This function is called by C_CreateObject, C_CopyObject,
967 	 * C_DestroyObject, C_SetAttributeValue, C_GenerateKey,
968 	 * C_GenerateKeyPairs, C_DeriveKey. All of them will write
969 	 * the token object to the keystore.
970 	 */
971 	(void) pthread_mutex_lock(&soft_giant_mutex);
972 	if (!soft_slot.authenticated) {
973 		(void) pthread_mutex_unlock(&soft_giant_mutex);
974 		/* User is not logged in */
975 		if (sp->flags & CKF_RW_SESSION) {
976 			/*
977 			 * For R/W Public Session:
978 			 * we allow write access to public session or token
979 			 * object, but not for private token/session object.
980 			 */
981 			if ((objp->object_type == TOKEN_PRIVATE) ||
982 				(objp->object_type == SESSION_PRIVATE)) {
983 				return (CKR_USER_NOT_LOGGED_IN);
984 			}
985 		} else {
986 			/*
987 			 * For R/O Public Session:
988 			 * we allow write access to public session object.
989 			 */
990 			if (objp->object_type != SESSION_PUBLIC)
991 				return (CKR_SESSION_READ_ONLY);
992 		}
993 	} else {
994 		(void) pthread_mutex_unlock(&soft_giant_mutex);
995 		/* User is logged in */
996 		if (!(sp->flags & CKF_RW_SESSION)) {
997 			/*
998 			 * For R/O User Function Session:
999 			 * we allow write access to public or private
1000 			 * session object, but not for public or private
1001 			 * token object.
1002 			 */
1003 			if ((objp->object_type == TOKEN_PUBLIC) ||
1004 			    (objp->object_type == TOKEN_PRIVATE)) {
1005 				return (CKR_SESSION_READ_ONLY);
1006 			}
1007 		}
1008 	}
1009 
1010 	return (CKR_OK);
1011 }
1012 
1013 /*
1014  * Verify if user is required to setpin when accessing the
1015  * private token/session object.
1016  */
1017 CK_RV
1018 soft_pin_expired_check(soft_object_t *objp)
1019 {
1020 
1021 	/*
1022 	 * This function is called by C_CreateObject, C_CopyObject,
1023 	 * C_DestroyObject, C_GenerateKey,
1024 	 * C_GenerateKeyPairs, C_DeriveKey.
1025 	 * All of them will return CKR_PIN_EXPIRED if the
1026 	 * "userpin_change_needed" is set.
1027 	 *
1028 	 * The following functions will not be necessary to call
1029 	 * this routine even though CKR_PIN_EXPIRED is one of the
1030 	 * valid error code they might return. These functions are:
1031 	 * C_EncryptInit, C_DecryptInit, C_DigestInit, C_SignInit,
1032 	 * C_SignRecoverInit, C_VerifyInit, C_VerifyRecoverInit.
1033 	 * This is because they will not get the object handle
1034 	 * before the above functions are called.
1035 	 */
1036 
1037 	(void) pthread_mutex_lock(&soft_giant_mutex);
1038 	if (soft_slot.userpin_change_needed) {
1039 		/*
1040 		 * Access private token/session object but user's
1041 		 * PIN is expired or never set.
1042 		 */
1043 		if ((objp->object_type == TOKEN_PRIVATE) ||
1044 		    (objp->object_type == SESSION_PRIVATE)) {
1045 			(void) pthread_mutex_unlock(&soft_giant_mutex);
1046 			return (CKR_PIN_EXPIRED);
1047 		}
1048 	}
1049 
1050 	(void) pthread_mutex_unlock(&soft_giant_mutex);
1051 	return (CKR_OK);
1052 }
1053 
1054 /*
1055  * Copy the selected fields from new token object to old
1056  * token object.
1057  */
1058 CK_RV
1059 soft_copy_to_old_object(soft_object_t *new, soft_object_t *old)
1060 {
1061 
1062 	CK_RV rv = CKR_OK;
1063 	CK_ATTRIBUTE_INFO_PTR attrp;
1064 
1065 	old->class = new->class;
1066 	old->bool_attr_mask = new->bool_attr_mask;
1067 	soft_cleanup_extra_attr(old);
1068 	attrp = new->extra_attrlistp;
1069 	while (attrp) {
1070 		rv = soft_copy_extra_attr(attrp, old);
1071 		if (rv != CKR_OK) {
1072 			soft_cleanup_extra_attr(old);
1073 			return (rv);
1074 		}
1075 		attrp = attrp->next;
1076 	}
1077 
1078 	/* Done with copying all information that can be modified */
1079 	return (CKR_OK);
1080 }
1081 
1082 /*
1083  * Update an existing object with new data from keystore.
1084  */
1085 CK_RV
1086 soft_update_object(ks_obj_t *ks_obj, soft_object_t *old_obj)
1087 {
1088 
1089 	soft_object_t *new_object;
1090 	CK_RV rv;
1091 
1092 	new_object = calloc(1, sizeof (soft_object_t));
1093 	if (new_object == NULL)
1094 		return (CKR_HOST_MEMORY);
1095 
1096 	rv = soft_keystore_unpack_obj(new_object, ks_obj);
1097 	if (rv != CKR_OK) {
1098 		soft_cleanup_object(new_object);
1099 		free(new_object);
1100 		return (rv);
1101 	}
1102 	rv = soft_copy_to_old_object(new_object, old_obj);
1103 
1104 	soft_cleanup_object(new_object);
1105 	free(new_object);
1106 	return (CKR_OK);
1107 }
1108 
1109 
1110 CK_RV
1111 soft_keystore_load_latest_object(soft_object_t *old_obj)
1112 {
1113 
1114 	uint_t version;
1115 	ks_obj_t *ks_obj = NULL;
1116 	CK_RV rv = CKR_OK;
1117 
1118 	/*
1119 	 * Get the current version number from the keystore for
1120 	 * the specified token object.
1121 	 */
1122 	if (soft_keystore_get_object_version(&old_obj->ks_handle, &version,
1123 	    B_FALSE) == 1)
1124 		return (CKR_FUNCTION_FAILED);
1125 
1126 	/*
1127 	 * If the keystore version is newer than the in-core version,
1128 	 * re-read the token object from the keystore.
1129 	 */
1130 	if (old_obj->version != version) {
1131 		rv = soft_keystore_get_single_obj(&old_obj->ks_handle,
1132 		    &ks_obj, B_FALSE);
1133 		if (rv != CKR_OK)
1134 			return (rv);
1135 		old_obj->version = version;
1136 
1137 		/*
1138 		 * Update an existing object with new data from keystore.
1139 		 */
1140 		rv = soft_update_object(ks_obj, old_obj);
1141 		free(ks_obj->buf);
1142 		free(ks_obj);
1143 	}
1144 
1145 	return (rv);
1146 }
1147 
1148 /*
1149  * Insert an object into a list of soft_object_t objects.  It is assumed
1150  * that the object to be inserted doesn't previously belong to any list
1151  */
1152 static void
1153 insert_into_list(soft_object_t **list, soft_object_t **end_of_list,
1154     soft_object_t *objp)
1155 {
1156 	if (*list == NULL) {
1157 		*list = objp;
1158 		objp->next = NULL;
1159 		objp->prev = NULL;
1160 		*end_of_list = objp;
1161 	} else {
1162 		(*list)->prev = objp;
1163 		objp->next = *list;
1164 		objp->prev = NULL;
1165 		*list = objp;
1166 	}
1167 }
1168 
1169 /*
1170  * Move an object from an existing list into a new list of
1171  * soft_object_t objects.
1172  */
1173 static void
1174 move_into_list(soft_object_t **existing_list, soft_object_t **new_list,
1175     soft_object_t **end_of_list, soft_object_t *objp)
1176 {
1177 
1178 	/* first, remove object from existing list */
1179 	if (objp == *existing_list) {
1180 		/* first item in list */
1181 		if (objp->next) {
1182 			*existing_list = objp->next;
1183 			objp->next->prev = NULL;
1184 		} else {
1185 			*existing_list = NULL;
1186 		}
1187 	} else {
1188 		if (objp->next) {
1189 			objp->prev->next = objp->next;
1190 			objp->next->prev = objp->prev;
1191 		} else {
1192 			objp->prev->next = NULL;
1193 		}
1194 	}
1195 
1196 	/* then, add into new list */
1197 	insert_into_list(new_list, end_of_list, objp);
1198 }
1199 
1200 /*
1201  * Insert "new_list" into "existing_list", new list will always be inserted
1202  * into the front of existing list
1203  */
1204 static void
1205 insert_list_into_list(soft_object_t **existing_list,
1206     soft_object_t *new_list, soft_object_t *end_new_list)
1207 {
1208 
1209 	if (new_list == NULL) {
1210 		return;
1211 	}
1212 
1213 	if (*existing_list == NULL) {
1214 		*existing_list = new_list;
1215 	} else {
1216 		(*existing_list)->prev = end_new_list;
1217 		end_new_list->next = *existing_list;
1218 		*existing_list = new_list;
1219 	}
1220 }
1221 
1222 static void
1223 delete_all_objs_in_list(soft_object_t *list)
1224 {
1225 	soft_object_t *objp, *objp_next;
1226 
1227 	if (list == NULL) {
1228 		return;
1229 	}
1230 
1231 	objp = list;
1232 	while (objp) {
1233 		objp_next = objp->next;
1234 		soft_delete_object_cleanup(objp);
1235 		objp = objp_next;
1236 	}
1237 }
1238 
1239 /*
1240  * Makes sure that the list of in-core token objects are up to date
1241  * with respect to the on disk keystore.  Other process/applications
1242  * might have modified the keystore since the objects are last loaded
1243  *
1244  * If there's any error from refreshing the token object list (eg: unable
1245  * to read, unable to unpack and object...etc), the in-core list
1246  * will be restored back to the state before the refresh.  An error
1247  * will be returned to indicate the failure.
1248  *
1249  * It is assumed that the caller holds the lock for the token slot
1250  */
1251 CK_RV
1252 refresh_token_objects()
1253 {
1254 	uint_t on_disk_ks_version;
1255 	ks_obj_t *on_disk_list = NULL, *tmp_on_disk, *next_on_disk;
1256 	soft_object_t *in_core_obj, *tmp_incore_obj, *new_objp = NULL;
1257 	CK_RV rv = CKR_OK;
1258 
1259 			/* deleted in-core objects */
1260 	soft_object_t	*del_objs_list = NULL,
1261 			*end_del_objs_list = NULL,
1262 
1263 			/* modified in-core objects */
1264 			*mod_objs_list = NULL,
1265 			*end_mod_objs_list = NULL,
1266 
1267 			/*
1268 			 * copy of modified in-core objects, in case we need
1269 			 * undo the change
1270 			 */
1271 			*copy_of_mod_objs_list = NULL,
1272 			*end_copy_of_mod_objs_list = NULL,
1273 
1274 			/* objects to be added to the in-core list */
1275 			*added_objs_list = NULL,
1276 			*end_added_objs_list = NULL;
1277 
1278 	if (soft_keystore_get_version(&on_disk_ks_version, B_FALSE) != 0) {
1279 		return (CKR_FUNCTION_FAILED);
1280 	}
1281 
1282 	(void) pthread_mutex_lock(&soft_giant_mutex);
1283 	if (on_disk_ks_version == soft_slot.ks_version) {
1284 		/* no change */
1285 		(void) pthread_mutex_unlock(&soft_giant_mutex);
1286 		return (CKR_OK);
1287 	}
1288 
1289 	if (soft_slot.authenticated) {
1290 		/* get both public and private objects */
1291 		(void) pthread_mutex_unlock(&soft_giant_mutex);
1292 		rv = soft_keystore_get_objs(ALL_TOKENOBJS, &on_disk_list,
1293 		    B_FALSE);
1294 	} else {
1295 		/* get both public objects only */
1296 		(void) pthread_mutex_unlock(&soft_giant_mutex);
1297 		rv = soft_keystore_get_objs(PUB_TOKENOBJS, &on_disk_list,
1298 		    B_FALSE);
1299 	}
1300 	if (rv != CKR_OK) {
1301 		return (rv);
1302 	}
1303 
1304 	/*
1305 	 * The in-core tokens list will be updated as follows:
1306 	 *
1307 	 * Go through each item in the in-core tokens list.
1308 	 * Try to match the in-core object with one of the
1309 	 * objects from the on-disk list.  If a match is made,
1310 	 * check the version number, and update in-core object
1311 	 * as necessary.
1312 	 *
1313 	 * If there's no match between in-core object with on-disk
1314 	 * object, that means the object is deleted since
1315 	 * last loaded.  Will remove object from in-core list.
1316 	 *
1317 	 * When doing the matching of on-disk object list above,
1318 	 * Delete every matched on-disk object from the on-disk list
1319 	 * regardless the in-core object need to be deleted or not
1320 	 *
1321 	 * At the end of matching the in-core tokens list, if
1322 	 * any object is still left on the on-disk object list,
1323 	 * those are all new objects added since last load,
1324 	 * include all of them to the in-core list
1325 	 *
1326 	 * Since we need to be able to revert the in-core list
1327 	 * back to original state if there's any error with the refresh,
1328 	 * we need to do the following.
1329 	 * When an in-core object is "deleted", it is not immediately
1330 	 * deleted.  It is moved to the list of "deleted_objects".
1331 	 * When an in-core object is "modified", a copy of the
1332 	 * unmodified object is made.  After the object is modified,
1333 	 * it is temporarily moved to the "mod_objects" list
1334 	 * from the in-core list.
1335 	 * When the refresh is completed without any error,
1336 	 * the actual deleted objects and unmodified objects is deleted.
1337 	 */
1338 	in_core_obj = soft_slot.token_object_list;
1339 	while (in_core_obj) {
1340 		/* try to match object with on_disk_list */
1341 		ks_obj_t *ondisk_obj, *prev_ondisk_obj;
1342 		boolean_t found = B_FALSE;
1343 		soft_object_t *obj_copy;
1344 
1345 		ondisk_obj = on_disk_list;
1346 		prev_ondisk_obj = NULL;
1347 
1348 		/* larval object that has not been written to disk */
1349 		if (in_core_obj->ks_handle.name[0] == '\0') {
1350 			in_core_obj = in_core_obj->next;
1351 			continue;
1352 		}
1353 
1354 		while ((!found) && (ondisk_obj != NULL)) {
1355 
1356 			if (strcmp((char *)((ondisk_obj->ks_handle).name),
1357 			    (char *)((in_core_obj->ks_handle).name)) == 0) {
1358 
1359 				/* found a match */
1360 				found = B_TRUE;
1361 
1362 				/* update in-core obj if necessary */
1363 				if (ondisk_obj->obj_version !=
1364 				    in_core_obj->version) {
1365 					/* make a copy of before updating */
1366 					rv = soft_copy_object(in_core_obj,
1367 					    &obj_copy, SOFT_COPY_OBJ_ORIG_SH,
1368 					    NULL);
1369 					if (rv != CKR_OK) {
1370 						goto cleanup;
1371 					}
1372 					insert_into_list(
1373 					    &copy_of_mod_objs_list,
1374 					    &end_copy_of_mod_objs_list,
1375 					    obj_copy);
1376 
1377 					rv = soft_update_object(ondisk_obj,
1378 					    in_core_obj);
1379 					if (rv != CKR_OK) {
1380 						goto cleanup;
1381 					}
1382 					move_into_list(
1383 					    &(soft_slot.token_object_list),
1384 					    &mod_objs_list, &end_mod_objs_list,
1385 					    in_core_obj);
1386 				}
1387 
1388 				/* remove processed obj from on disk list */
1389 				if (ondisk_obj == on_disk_list) {
1390 					/* first item */
1391 					on_disk_list = ondisk_obj->next;
1392 				} else {
1393 					prev_ondisk_obj->next =
1394 					    ondisk_obj->next;
1395 				}
1396 				free(ondisk_obj->buf);
1397 				free(ondisk_obj);
1398 			} else {
1399 				prev_ondisk_obj = ondisk_obj;
1400 				ondisk_obj = ondisk_obj->next;
1401 			}
1402 		}
1403 
1404 		if (!found) {
1405 			tmp_incore_obj = in_core_obj->next;
1406 			move_into_list(&(soft_slot.token_object_list),
1407 			    &del_objs_list, &end_del_objs_list, in_core_obj);
1408 			in_core_obj = tmp_incore_obj;
1409 		} else {
1410 			in_core_obj = in_core_obj->next;
1411 		}
1412 	}
1413 
1414 	/*
1415 	 * At this point, if there's still anything on the on_disk_list, they
1416 	 * are all newly added objects since in-core list last loaded.
1417 	 * include all of them into the in-core list
1418 	 */
1419 	next_on_disk = on_disk_list;
1420 	while (next_on_disk) {
1421 		new_objp = calloc(1, sizeof (soft_object_t));
1422 		if (new_objp == NULL) {
1423 			rv = CKR_HOST_MEMORY;
1424 			goto cleanup;
1425 		}
1426 
1427 		/* Convert the keystore format to memory format */
1428 		rv = soft_keystore_unpack_obj(new_objp, next_on_disk);
1429 		if (rv != CKR_OK) {
1430 			soft_cleanup_object(new_objp);
1431 			free(new_objp);
1432 			goto cleanup;
1433 		}
1434 
1435 		insert_into_list(&added_objs_list, &end_added_objs_list,
1436 		    new_objp);
1437 
1438 		/* free the on_disk object */
1439 		tmp_on_disk = next_on_disk;
1440 		next_on_disk = tmp_on_disk->next;
1441 		free(tmp_on_disk->buf);
1442 		free(tmp_on_disk);
1443 	}
1444 
1445 	if (rv == CKR_OK) {
1446 		(void) pthread_mutex_lock(&soft_giant_mutex);
1447 		soft_slot.ks_version = on_disk_ks_version;
1448 		(void) pthread_mutex_unlock(&soft_giant_mutex);
1449 
1450 		/* add the new objects into in-core list */
1451 		insert_list_into_list(&(soft_slot.token_object_list),
1452 		    added_objs_list, end_added_objs_list);
1453 
1454 		/* add modified objects back into the in-core list */
1455 		insert_list_into_list(&(soft_slot.token_object_list),
1456 		    mod_objs_list, end_mod_objs_list);
1457 
1458 		/* actually remove deleted objs, and copy of modified objs */
1459 		delete_all_objs_in_list(copy_of_mod_objs_list);
1460 		delete_all_objs_in_list(del_objs_list);
1461 	}
1462 
1463 	return (rv);
1464 
1465 cleanup:
1466 	next_on_disk = on_disk_list;
1467 	while (next_on_disk) {
1468 		tmp_on_disk = next_on_disk;
1469 		next_on_disk = tmp_on_disk->next;
1470 		free(tmp_on_disk->buf);
1471 		free(tmp_on_disk);
1472 	}
1473 
1474 	/*
1475 	 * restore the in-core list back to the original state by adding
1476 	 * copy of original objects and deleted objects back to list
1477 	 */
1478 	insert_list_into_list(&(soft_slot.token_object_list),
1479 	    del_objs_list, end_del_objs_list);
1480 	insert_list_into_list(&(soft_slot.token_object_list),
1481 	    copy_of_mod_objs_list, end_copy_of_mod_objs_list);
1482 
1483 	/*
1484 	 * remove the modified objects, and newly objects list
1485 	 */
1486 	delete_all_objs_in_list(mod_objs_list);
1487 	delete_all_objs_in_list(added_objs_list);
1488 	return (rv);
1489 }
1490