xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_softtoken/common/softObject.c (revision 445f2479fe3d7435daab18bf2cdc310b86cd6738)
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 <stdlib.h>
31 #include <security/cryptoki.h>
32 #include "softGlobal.h"
33 #include "softObject.h"
34 #include "softSession.h"
35 #include "softKeystore.h"
36 #include "softKeystoreUtil.h"
37 
38 
39 CK_RV
40 C_CreateObject(CK_SESSION_HANDLE hSession,
41     CK_ATTRIBUTE_PTR pTemplate,
42     CK_ULONG ulCount,
43     CK_OBJECT_HANDLE_PTR phObject)
44 {
45 
46 	CK_RV rv;
47 	soft_session_t *session_p;
48 	boolean_t lock_held = B_FALSE;
49 
50 	if (!softtoken_initialized)
51 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
52 
53 	/*
54 	 * Obtain the session pointer. Also, increment the session
55 	 * reference count.
56 	 */
57 	rv = handle2session(hSession, &session_p);
58 	if (rv != CKR_OK)
59 		return (rv);
60 
61 	if ((pTemplate == NULL) || (ulCount == 0) ||
62 	    (phObject == NULL)) {
63 		rv = CKR_ARGUMENTS_BAD;
64 		goto clean_exit;
65 	}
66 
67 	/* Create a new object. */
68 	rv = soft_add_object(pTemplate, ulCount, phObject, session_p);
69 
70 clean_exit:
71 	/*
72 	 * Decrement the session reference count.
73 	 * We do not hold the session lock.
74 	 */
75 	SES_REFRELE(session_p, lock_held);
76 	return (rv);
77 }
78 
79 CK_RV
80 C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
81     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
82     CK_OBJECT_HANDLE_PTR phNewObject)
83 {
84 
85 	CK_RV rv;
86 	soft_session_t *session_p;
87 	boolean_t lock_held = B_FALSE;
88 	soft_object_t *old_object, *new_object = NULL;
89 	ulong_t i;
90 
91 	if (!softtoken_initialized)
92 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
93 
94 	/*
95 	 * Obtain the session pointer. Also, increment the session
96 	 * reference count.
97 	 */
98 	rv = handle2session(hSession, &session_p);
99 	if (rv != CKR_OK)
100 		return (rv);
101 
102 	/* Check arguments */
103 	if (((ulCount > 0) && (pTemplate == NULL)) ||
104 	    (phNewObject == NULL)) {
105 		rv = CKR_ARGUMENTS_BAD;
106 		goto clean_exit;
107 	}
108 
109 	/* Obtain the object pointer. */
110 	HANDLE2OBJECT(hObject, old_object, rv);
111 	if (rv != CKR_OK) {
112 		goto clean_exit;
113 	}
114 
115 	/*
116 	 * Copy the old object to a new object.
117 	 * The 3rd argument with SOFT_COPY_OBJ value indicates that
118 	 * everything in the object will be duplicated for C_CopyObject.
119 	 * The 4th argument has the session pointer that will be
120 	 * saved in the new copy of the session object.
121 	 */
122 	(void) pthread_mutex_lock(&old_object->object_mutex);
123 	rv = soft_copy_object(old_object, &new_object, SOFT_COPY_OBJECT,
124 	    session_p);
125 
126 	if ((rv != CKR_OK) || (new_object == NULL)) {
127 		/* Most likely we ran out of space. */
128 		(void) pthread_mutex_unlock(&old_object->object_mutex);
129 		goto clean_exit1;
130 	}
131 
132 	/* No need to hold the lock on the old object. */
133 	(void) pthread_mutex_unlock(&old_object->object_mutex);
134 
135 	/* Modifiy the objects if requested */
136 	for (i = 0; i < ulCount; i++) {
137 		/* Set the requested attribute into the new object. */
138 		rv = soft_set_attribute(new_object, &pTemplate[i], B_TRUE);
139 		if (rv != CKR_OK) {
140 			goto fail;
141 		}
142 	}
143 
144 	rv = soft_pin_expired_check(new_object);
145 	if (rv != CKR_OK) {
146 		goto fail;
147 	}
148 
149 	/*
150 	 * Does the new object violate the creation rule or access rule?
151 	 */
152 	rv = soft_object_write_access_check(session_p, new_object);
153 	if (rv != CKR_OK) {
154 		goto fail;
155 	}
156 
157 	/*
158 	 * If the new object is a token object, it will be added
159 	 * to token object list and write to disk.
160 	 */
161 	if (IS_TOKEN_OBJECT(new_object)) {
162 		new_object->version = 1;
163 		/*
164 		 * Write to the keystore file.
165 		 */
166 		rv = soft_put_object_to_keystore(new_object);
167 		if (rv != CKR_OK) {
168 			goto fail;
169 		}
170 
171 		new_object->session_handle = (CK_SESSION_HANDLE)NULL;
172 		/*
173 		 * Add the newly created token object to the global
174 		 * token object list in the slot struct.
175 		 */
176 		soft_add_token_object_to_slot(new_object);
177 		OBJ_REFRELE(old_object);
178 		SES_REFRELE(session_p, lock_held);
179 		*phNewObject = (CK_ULONG)new_object;
180 
181 		return (CKR_OK);
182 	}
183 
184 	/* Insert new object into this session's object list */
185 	soft_add_object_to_session(new_object, session_p);
186 
187 	/*
188 	 * Decrement the session reference count.
189 	 * We do not hold the session lock.
190 	 */
191 	OBJ_REFRELE(old_object);
192 	SES_REFRELE(session_p, lock_held);
193 
194 	/* set handle of the new object */
195 	*phNewObject = (CK_ULONG)new_object;
196 
197 	return (rv);
198 
199 fail:
200 	soft_cleanup_object(new_object);
201 	free(new_object);
202 
203 clean_exit1:
204 	OBJ_REFRELE(old_object);
205 clean_exit:
206 	SES_REFRELE(session_p, lock_held);
207 	return (rv);
208 }
209 
210 CK_RV
211 C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject)
212 {
213 
214 	CK_RV rv;
215 	soft_object_t *object_p;
216 	soft_session_t *session_p = (soft_session_t *)(hSession);
217 	boolean_t lock_held = B_FALSE;
218 	CK_SESSION_HANDLE creating_session;
219 
220 
221 	if (!softtoken_initialized)
222 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
223 
224 	/*
225 	 * The reason that we don't call handle2session is because
226 	 * the argument hSession may not be the creating_session of
227 	 * the object to be destroyed, and we want to avoid the lock
228 	 * contention. The handle2session will be called later for
229 	 * the creating_session.
230 	 */
231 	if ((session_p == NULL) ||
232 	    (session_p->magic_marker != SOFTTOKEN_SESSION_MAGIC)) {
233 		return (CKR_SESSION_HANDLE_INVALID);
234 	}
235 
236 	/* Obtain the object pointer. */
237 	HANDLE2OBJECT_DESTROY(hObject, object_p, rv);
238 	if (rv != CKR_OK) {
239 		return (rv);
240 	}
241 
242 	/* Obtain the session handle which object belongs to. */
243 	creating_session = object_p->session_handle;
244 
245 	if (creating_session == NULL) {
246 		/*
247 		 * This is a token object to be deleted.
248 		 * For token object, there is no creating session concept,
249 		 * therefore, creating_session is always NULL.
250 		 */
251 		rv = soft_pin_expired_check(object_p);
252 		if (rv != CKR_OK) {
253 			return (rv);
254 		}
255 
256 		/* Obtain the session pointer just for validity check. */
257 		rv = handle2session(hSession, &session_p);
258 		if (rv != CKR_OK) {
259 			return (rv);
260 		}
261 
262 		rv = soft_object_write_access_check(session_p, object_p);
263 		if (rv != CKR_OK) {
264 			SES_REFRELE(session_p, lock_held);
265 			return (rv);
266 		}
267 
268 		/*
269 		 * Set OBJECT_IS_DELETING flag so any access to this
270 		 * object will be rejected.
271 		 */
272 		(void) pthread_mutex_lock(&object_p->object_mutex);
273 		if (object_p->obj_delete_sync & OBJECT_IS_DELETING) {
274 			(void) pthread_mutex_unlock(&object_p->object_mutex);
275 			SES_REFRELE(session_p, lock_held);
276 			return (CKR_OBJECT_HANDLE_INVALID);
277 		}
278 		object_p->obj_delete_sync |= OBJECT_IS_DELETING;
279 		(void) pthread_mutex_unlock(&object_p->object_mutex);
280 		SES_REFRELE(session_p, lock_held);
281 
282 		/*
283 		 * Delete a token object by calling soft_delete_token_object()
284 		 * with the second argument B_TRUE indicating to delete the
285 		 * object from keystore and the third argument B_FALSE
286 		 * indicating that the caller does not hold the slot mutex.
287 		 */
288 		soft_delete_token_object(object_p, B_TRUE, B_FALSE);
289 		return (CKR_OK);
290 	}
291 
292 	/*
293 	 * Obtain the session pointer. Also, increment the session
294 	 * reference count.
295 	 */
296 	rv = handle2session(creating_session, &session_p);
297 	if (rv != CKR_OK) {
298 		return (rv);
299 	}
300 
301 	/*
302 	 * Set OBJECT_IS_DELETING flag so any access to this
303 	 * object will be rejected.
304 	 */
305 	(void) pthread_mutex_lock(&object_p->object_mutex);
306 	if (object_p->obj_delete_sync & OBJECT_IS_DELETING) {
307 		(void) pthread_mutex_unlock(&object_p->object_mutex);
308 		SES_REFRELE(session_p, lock_held);
309 		return (CKR_OBJECT_HANDLE_INVALID);
310 	}
311 	object_p->obj_delete_sync |= OBJECT_IS_DELETING;
312 	(void) pthread_mutex_unlock(&object_p->object_mutex);
313 
314 	/*
315 	 * Delete an object by calling soft_delete_object()
316 	 * with a FALSE boolean argument indicating that
317 	 * the caller does not hold the session lock.
318 	 */
319 	soft_delete_object(session_p, object_p, B_FALSE);
320 
321 	/*
322 	 * Decrement the session reference count.
323 	 * We do not hold the session lock.
324 	 */
325 	SES_REFRELE(session_p, lock_held);
326 
327 	return (rv);
328 }
329 
330 
331 CK_RV
332 C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
333     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
334 {
335 
336 	CK_RV rv = CKR_OK, rv1 = CKR_OK;
337 	soft_object_t *object_p;
338 	soft_session_t *session_p;
339 	boolean_t lock_held = B_FALSE;
340 	ulong_t i;
341 
342 	if (!softtoken_initialized)
343 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
344 
345 	/*
346 	 * Obtain the session pointer. Also, increment the session
347 	 * reference count.
348 	 */
349 	rv = handle2session(hSession, &session_p);
350 	if (rv != CKR_OK)
351 		return (rv);
352 
353 	if ((pTemplate == NULL) || (ulCount == 0)) {
354 		/*
355 		 * Decrement the session reference count.
356 		 * We do not hold the session lock.
357 		 */
358 		SES_REFRELE(session_p, lock_held);
359 		return (CKR_ARGUMENTS_BAD);
360 	}
361 
362 	/* Obtain the object pointer. */
363 	HANDLE2OBJECT(hObject, object_p, rv);
364 	if (rv != CKR_OK) {
365 		/*
366 		 * Decrement the session reference count.
367 		 * We do not hold the session lock.
368 		 */
369 		SES_REFRELE(session_p, lock_held);
370 		return (rv);
371 	}
372 
373 	if (IS_TOKEN_OBJECT(object_p)) {
374 
375 		rv = soft_keystore_load_latest_object(object_p);
376 		if (rv != CKR_OK) {
377 			OBJ_REFRELE(object_p);
378 			SES_REFRELE(session_p, lock_held);
379 			return (rv);
380 		}
381 	}
382 
383 	/* Acquire the lock on the object. */
384 	(void) pthread_mutex_lock(&object_p->object_mutex);
385 
386 	for (i = 0; i < ulCount; i++) {
387 		/*
388 		 * Get the value of each attribute in the template.
389 		 * (We must process EVERY attribute in the template.)
390 		 */
391 		rv = soft_get_attribute(object_p, &pTemplate[i]);
392 		if (rv != CKR_OK)
393 			/* At least we catch some type of error. */
394 			rv1 = rv;
395 	}
396 
397 	/* Release the object lock */
398 	(void) pthread_mutex_unlock(&object_p->object_mutex);
399 
400 	/*
401 	 * Decrement the session reference count.
402 	 * We do not hold the session lock.
403 	 */
404 	OBJ_REFRELE(object_p);
405 	SES_REFRELE(session_p, lock_held);
406 
407 	rv = rv1;
408 	return (rv);
409 }
410 
411 
412 CK_RV
413 C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
414     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
415 {
416 	CK_RV rv = CKR_OK;
417 	soft_object_t *object_p;
418 	soft_object_t *new_object = NULL;
419 	soft_session_t *session_p;
420 	boolean_t lock_held = B_FALSE;
421 	ulong_t i;
422 
423 	if (!softtoken_initialized)
424 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
425 
426 	/*
427 	 * Obtain the session pointer. Also, increment the session
428 	 * reference count.
429 	 */
430 	rv = handle2session(hSession, &session_p);
431 	if (rv != CKR_OK)
432 		return (rv);
433 
434 	if ((pTemplate == NULL) || (ulCount == 0)) {
435 		/*
436 		 * Decrement the session reference count.
437 		 * We do not hold the session lock.
438 		 */
439 		SES_REFRELE(session_p, lock_held);
440 		return (CKR_ARGUMENTS_BAD);
441 	}
442 
443 	/* Obtain the object pointer. */
444 	HANDLE2OBJECT(hObject, object_p, rv);
445 	if (rv != CKR_OK) {
446 		/*
447 		 * Decrement the session reference count.
448 		 * We do not hold the session lock.
449 		 */
450 		SES_REFRELE(session_p, lock_held);
451 		return (rv);
452 	}
453 
454 	if (object_p->bool_attr_mask & NOT_MODIFIABLE_BOOL_ON) {
455 		rv = CKR_ATTRIBUTE_READ_ONLY;
456 		goto fail_1;
457 	}
458 
459 	/*
460 	 * Start working on the object, so we need to set the write lock so that
461 	 * no one can write to it but still can read it.
462 	 */
463 	if (IS_TOKEN_OBJECT(object_p)) {
464 		rv = soft_keystore_load_latest_object(object_p);
465 		if (rv != CKR_OK) {
466 			goto fail_1;
467 		}
468 	}
469 
470 	/*
471 	 * Copy the old object to a new object. We work on the copied
472 	 * version because in case of error we still keep the old one
473 	 * intact.
474 	 * The 3rd argument with SOFT_SET_ATTR_VALUE value indicates that
475 	 * not everything will be duplicated for C_SetAttributeValue.
476 	 * Information not duplicated are those attributes that are not
477 	 * modifiable.
478 	 */
479 	(void) pthread_mutex_lock(&object_p->object_mutex);
480 	rv = soft_copy_object(object_p, &new_object, SOFT_SET_ATTR_VALUE, NULL);
481 
482 	if ((rv != CKR_OK) || (new_object == NULL)) {
483 		/* Most likely we ran out of space. */
484 		(void) pthread_mutex_unlock(&object_p->object_mutex);
485 		/*
486 		 * Decrement the session reference count.
487 		 * We do not hold the session lock.
488 		 */
489 		goto fail_1;
490 	}
491 
492 	/*
493 	 * No need to hold the lock on the old object, because we
494 	 * will be working on the new scratch object.
495 	 */
496 	(void) pthread_mutex_unlock(&object_p->object_mutex);
497 
498 	rv = soft_object_write_access_check(session_p, new_object);
499 	if (rv != CKR_OK) {
500 		goto fail;
501 	}
502 
503 	for (i = 0; i < ulCount; i++) {
504 		/* Set the requested attribute into the new object. */
505 		rv = soft_set_attribute(new_object, &pTemplate[i], B_FALSE);
506 
507 		if (rv != CKR_OK) {
508 			goto fail;
509 		}
510 	}
511 
512 	/*
513 	 * We've successfully set all the requested attributes.
514 	 * Merge the new object with the old object, then destory
515 	 * the new one. The reason to do the merging is because we
516 	 * have to keep the original object handle (address of object).
517 	 */
518 	(void) pthread_mutex_lock(&object_p->object_mutex);
519 
520 	soft_merge_object(object_p, new_object);
521 
522 	/*
523 	 * The object has been modified, so we write it back to keystore.
524 	 */
525 	if (IS_TOKEN_OBJECT(object_p)) {
526 		object_p->version++;
527 		rv = soft_modify_object_to_keystore(object_p);
528 	}
529 
530 	(void) pthread_mutex_unlock(&object_p->object_mutex);
531 	free(new_object);
532 
533 	/*
534 	 * Decrement the session reference count.
535 	 * We do not hold the session lock.
536 	 */
537 	OBJ_REFRELE(object_p);
538 	SES_REFRELE(session_p, lock_held);
539 	return (rv);
540 
541 fail:
542 	soft_cleanup_object(new_object);
543 	free(new_object);
544 
545 fail_1:
546 	OBJ_REFRELE(object_p);
547 	SES_REFRELE(session_p, lock_held);
548 
549 	return (rv);
550 }
551 
552 /*ARGSUSED*/
553 CK_RV
554 C_GetObjectSize(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
555     CK_ULONG_PTR pulSize)
556 {
557 	if (!softtoken_initialized)
558 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
559 
560 	return (CKR_FUNCTION_NOT_SUPPORTED);
561 }
562 
563 CK_RV
564 C_FindObjectsInit(CK_SESSION_HANDLE sh, CK_ATTRIBUTE_PTR pTemplate,
565     CK_ULONG ulCount)
566 {
567 
568 	CK_RV		rv;
569 	soft_session_t	*session_p;
570 	boolean_t lock_held = B_TRUE;
571 
572 	if (!softtoken_initialized)
573 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
574 
575 	/*
576 	 * Obtain the session pointer. Also, increment the session
577 	 * reference count.
578 	 */
579 	rv = handle2session(sh, &session_p);
580 	if (rv != CKR_OK)
581 		return (rv);
582 
583 	/* Check the arguments */
584 	if ((ulCount > 0) && (pTemplate == NULL)) {
585 		/* decrement the session count, we do not hold the lock */
586 		lock_held = B_FALSE;
587 		SES_REFRELE(session_p, lock_held);
588 		return (CKR_ARGUMENTS_BAD);
589 	}
590 
591 	/* Acquire the session lock */
592 	(void) pthread_mutex_lock(&session_p->session_mutex);
593 
594 	/* Check to see if find operation is already active */
595 	if (session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE) {
596 		/* decrement the session count, and unlock the mutex */
597 		SES_REFRELE(session_p, lock_held);
598 		return (CKR_OPERATION_ACTIVE);
599 	} else {
600 		/*
601 		 * This active flag will remain ON until application calls
602 		 * C_FindObjectsFinal.
603 		 */
604 		session_p->find_objects.flags = CRYPTO_OPERATION_ACTIVE;
605 	}
606 
607 	(void) pthread_mutex_unlock(&session_p->session_mutex);
608 
609 	rv = soft_find_objects_init(session_p,  pTemplate, ulCount);
610 
611 	if (rv != CKR_OK) {
612 		(void) pthread_mutex_lock(&session_p->session_mutex);
613 		session_p->find_objects.flags = 0;
614 		(void) pthread_mutex_unlock(&session_p->session_mutex);
615 	}
616 
617 	/* decrement the session count, and unlock the mutex */
618 	lock_held = B_FALSE;
619 	SES_REFRELE(session_p, lock_held);
620 	return (rv);
621 }
622 
623 CK_RV
624 C_FindObjects(CK_SESSION_HANDLE sh,
625     CK_OBJECT_HANDLE_PTR phObject,
626     CK_ULONG ulMaxObjectCount,
627     CK_ULONG_PTR pulObjectCount)
628 {
629 	soft_session_t	*session_p;
630 	CK_RV rv = CKR_OK;
631 	boolean_t lock_held = B_TRUE;
632 
633 	if (!softtoken_initialized)
634 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
635 
636 	/*
637 	 * Obtain the session pointer. Also, increment the session
638 	 * reference count.
639 	 */
640 	rv = handle2session(sh, &session_p);
641 	if (rv != CKR_OK)
642 		return (rv);
643 
644 	/* check for invalid arguments */
645 	if (((phObject == NULL) && (ulMaxObjectCount != 0)) ||
646 	    (pulObjectCount == NULL)) {
647 		/* decrement the session count, we do not hold the lock */
648 		lock_held = B_FALSE;
649 		SES_REFRELE(session_p, lock_held);
650 		return (CKR_ARGUMENTS_BAD);
651 	}
652 
653 	if (ulMaxObjectCount == 0) {
654 		/* don't need to do anything, just return */
655 		*pulObjectCount = 0;
656 		/* decrement the session count, we do not hold the lock */
657 		lock_held = B_FALSE;
658 		SES_REFRELE(session_p, lock_held);
659 		return (CKR_OK);
660 	}
661 
662 	/* Acquire the session lock */
663 	(void) pthread_mutex_lock(&session_p->session_mutex);
664 
665 	/* Check to see if find operation is active */
666 	if (!(session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE)) {
667 		SES_REFRELE(session_p, lock_held);
668 		return (CKR_OPERATION_NOT_INITIALIZED);
669 	}
670 
671 	soft_find_objects(session_p, phObject, ulMaxObjectCount,
672 	    pulObjectCount);
673 
674 	/* decrement the session count, and release the lock */
675 	SES_REFRELE(session_p, lock_held);
676 	return (rv);
677 }
678 
679 CK_RV
680 C_FindObjectsFinal(CK_SESSION_HANDLE sh)
681 {
682 	soft_session_t	*session_p;
683 	CK_RV rv;
684 	boolean_t lock_held = B_TRUE;
685 
686 	if (!softtoken_initialized)
687 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
688 
689 	/*
690 	 * Obtain the session pointer. Also, increment the session
691 	 * reference count.
692 	 */
693 	rv = handle2session(sh, &session_p);
694 	if (rv != CKR_OK)
695 		return (rv);
696 
697 	/* Acquire the session lock */
698 	(void) pthread_mutex_lock(&session_p->session_mutex);
699 
700 	/* Check to see if find operation is active */
701 	if (!(session_p->find_objects.flags & CRYPTO_OPERATION_ACTIVE)) {
702 		SES_REFRELE(session_p, lock_held);
703 		return (CKR_OPERATION_NOT_INITIALIZED);
704 	}
705 
706 	soft_find_objects_final(session_p);
707 
708 	/* decrement the session count, and release the lock */
709 	SES_REFRELE(session_p, lock_held);
710 	return (rv);
711 }
712