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