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