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