xref: /titanic_50/usr/src/lib/pkcs11/pkcs11_softtoken/common/softSessionUtil.c (revision 356f72340a69936724c69f2f87fffa6f5887f885)
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 <md5.h>
27 #include <pthread.h>
28 #include <syslog.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <strings.h>
32 #include <sys/sha1.h>
33 #include <security/cryptoki.h>
34 #include "softGlobal.h"
35 #include "softSession.h"
36 #include "softObject.h"
37 #include "softOps.h"
38 #include "softKeystore.h"
39 #include "softKeystoreUtil.h"
40 
41 
42 CK_ULONG soft_session_cnt = 0;		/* the number of opened sessions */
43 CK_ULONG soft_session_rw_cnt = 0;	/* the number of opened R/W sessions */
44 
45 #define	DIGEST_MECH_OK(_m_)	((_m_) == CKM_MD5 || (_m_) == CKM_SHA_1)
46 
47 /*
48  * Delete all the sessions. First, obtain the global session
49  * list lock. Then start to delete one session at a time.
50  * Release the global session list lock before returning to
51  * caller.
52  */
53 CK_RV
54 soft_delete_all_sessions(boolean_t force)
55 {
56 
57 	CK_RV rv = CKR_OK;
58 	CK_RV rv1;
59 	soft_session_t *session_p;
60 	soft_session_t *session_p1;
61 
62 	/* Acquire the global session list lock */
63 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
64 
65 	session_p = soft_session_list;
66 
67 	/* Delete all the sessions in the session list */
68 	while (session_p) {
69 		session_p1 = session_p->next;
70 
71 		/*
72 		 * Delete a session by calling soft_delete_session()
73 		 * with a session pointer and a boolean arguments.
74 		 * Boolean value TRUE is used to indicate that the
75 		 * caller holds the lock on the global session list.
76 		 *
77 		 */
78 		rv1 = soft_delete_session(session_p, force, B_TRUE);
79 
80 		/* Record the very first error code */
81 		if (rv == CKR_OK) {
82 			rv = rv1;
83 		}
84 
85 		session_p = session_p1;
86 	}
87 
88 	/* No session left */
89 	soft_session_list = NULL;
90 
91 	/* Release the global session list lock */
92 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
93 
94 	return (rv);
95 
96 }
97 
98 
99 /*
100  * Create a new session struct, and add it to the session linked list.
101  *
102  * This function will acquire the global session list lock, and release
103  * it after adding the session to the session linked list.
104  */
105 CK_RV
106 soft_add_session(CK_FLAGS flags, CK_VOID_PTR pApplication,
107 	CK_NOTIFY notify, CK_ULONG *sessionhandle_p)
108 {
109 
110 	soft_session_t *new_sp = NULL;
111 
112 	/* Allocate a new session struct */
113 	new_sp = calloc(1, sizeof (soft_session_t));
114 	if (new_sp == NULL) {
115 		return (CKR_HOST_MEMORY);
116 	}
117 
118 	new_sp->magic_marker = SOFTTOKEN_SESSION_MAGIC;
119 	new_sp->pApplication = pApplication;
120 	new_sp->Notify = notify;
121 	new_sp->flags = flags;
122 	new_sp->state = CKS_RO_PUBLIC_SESSION;
123 	new_sp->object_list = NULL;
124 	new_sp->ses_refcnt = 0;
125 	new_sp->ses_close_sync = 0;
126 
127 	(void) pthread_mutex_lock(&soft_giant_mutex);
128 	if (soft_slot.authenticated) {
129 		(void) pthread_mutex_unlock(&soft_giant_mutex);
130 		if (flags & CKF_RW_SESSION) {
131 			new_sp->state = CKS_RW_USER_FUNCTIONS;
132 		} else {
133 			new_sp->state = CKS_RO_USER_FUNCTIONS;
134 		}
135 	} else {
136 		(void) pthread_mutex_unlock(&soft_giant_mutex);
137 		if (flags & CKF_RW_SESSION) {
138 			new_sp->state = CKS_RW_PUBLIC_SESSION;
139 		} else {
140 			new_sp->state = CKS_RO_PUBLIC_SESSION;
141 		}
142 	}
143 
144 	/* Initialize the lock for the newly created session */
145 	if (pthread_mutex_init(&new_sp->session_mutex, NULL) != 0) {
146 		free(new_sp);
147 		return (CKR_CANT_LOCK);
148 	}
149 
150 	(void) pthread_cond_init(&new_sp->ses_free_cond, NULL);
151 
152 	/* Acquire the global session list lock */
153 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
154 
155 	/* Insert the new session in front of session list */
156 	if (soft_session_list == NULL) {
157 		soft_session_list = new_sp;
158 		new_sp->next = NULL;
159 		new_sp->prev = NULL;
160 	} else {
161 		soft_session_list->prev = new_sp;
162 		new_sp->next = soft_session_list;
163 		new_sp->prev = NULL;
164 		soft_session_list = new_sp;
165 	}
166 
167 	/* Type casting the address of a session struct to a session handle */
168 	*sessionhandle_p =  (CK_ULONG)new_sp;
169 	++soft_session_cnt;
170 	if (flags & CKF_RW_SESSION)
171 		++soft_session_rw_cnt;
172 
173 	if (soft_session_cnt == 1)
174 		/*
175 		 * This is the first session to be opened, so we can set
176 		 * validate the public token objects in token list now.
177 		 */
178 		soft_validate_token_objects(B_TRUE);
179 
180 	/* Release the global session list lock */
181 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
182 
183 	return (CKR_OK);
184 
185 }
186 
187 /*
188  * This function adds the to-be-freed session to a linked list.
189  * When the number of sessions queued in the linked list reaches the
190  * maximum threshold MAX_SES_TO_BE_FREED, it will free the first
191  * session (FIFO) in the list.
192  */
193 void
194 session_delay_free(soft_session_t *sp)
195 {
196 	soft_session_t *tmp;
197 
198 	(void) pthread_mutex_lock(&ses_delay_freed.ses_to_be_free_mutex);
199 
200 	/* Add the newly deleted session at the end of the list */
201 	sp->next = NULL;
202 	if (ses_delay_freed.first == NULL) {
203 		ses_delay_freed.last = sp;
204 		ses_delay_freed.first = sp;
205 	} else {
206 		ses_delay_freed.last->next = sp;
207 		ses_delay_freed.last = sp;
208 	}
209 
210 	if (++ses_delay_freed.count >= MAX_SES_TO_BE_FREED) {
211 		/*
212 		 * Free the first session in the list only if
213 		 * the total count reaches maximum threshold.
214 		 */
215 		ses_delay_freed.count--;
216 		tmp = ses_delay_freed.first->next;
217 		free(ses_delay_freed.first);
218 		ses_delay_freed.first = tmp;
219 	}
220 	(void) pthread_mutex_unlock(&ses_delay_freed.ses_to_be_free_mutex);
221 }
222 
223 /*
224  * Delete a session:
225  * - Remove the session from the session linked list.
226  *   Holding the lock on the global session list is needed to do this.
227  * - Release all the objects created by the session.
228  *
229  * The boolean argument lock_held is used to indicate that whether
230  * the caller of this function holds the lock on the global session
231  * list or not.
232  * - When called by soft_delete_all_sessions(), which is called by
233  *   C_Finalize() or C_CloseAllSessions() -- the lock_held = TRUE.
234  * - When called by C_CloseSession() -- the lock_held = FALSE.
235  *
236  * When the caller does not hold the lock on the global session
237  * list, this function will acquire that lock in order to proceed,
238  * and also release that lock before returning to caller.
239  */
240 CK_RV
241 soft_delete_session(soft_session_t *session_p,
242     boolean_t force, boolean_t lock_held)
243 {
244 
245 	/*
246 	 * Check to see if the caller holds the lock on the global
247 	 * session list. If not, we need to acquire that lock in
248 	 * order to proceed.
249 	 */
250 	if (!lock_held) {
251 		/* Acquire the global session list lock */
252 		(void) pthread_mutex_lock(&soft_sessionlist_mutex);
253 	}
254 
255 	/*
256 	 * Remove the session from the session linked list first.
257 	 */
258 	if (soft_session_list == session_p) {
259 		/* Session is the first one in the list */
260 		if (session_p->next) {
261 			soft_session_list = session_p->next;
262 			session_p->next->prev = NULL;
263 		} else {
264 			/* Session is the only one in the list */
265 			soft_session_list = NULL;
266 		}
267 	} else {
268 		/* Session is not the first one in the list */
269 		if (session_p->next) {
270 			/* Session is in the middle of the list */
271 			session_p->prev->next = session_p->next;
272 			session_p->next->prev = session_p->prev;
273 		} else {
274 			/* Session is the last one in the list */
275 			session_p->prev->next = NULL;
276 		}
277 	}
278 
279 	--soft_session_cnt;
280 	if (session_p->flags & CKF_RW_SESSION)
281 		--soft_session_rw_cnt;
282 
283 	if (!lock_held) {
284 		/*
285 		 * If the global session list lock is obtained by
286 		 * this function, then release that lock after
287 		 * removing the session from session linked list.
288 		 * We want the releasing of the objects of the
289 		 * session, and freeing of the session itself to
290 		 * be done without holding the global session list
291 		 * lock.
292 		 */
293 		(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
294 	}
295 
296 
297 	/* Acquire the individual session lock */
298 	(void) pthread_mutex_lock(&session_p->session_mutex);
299 	/*
300 	 * Make sure another thread hasn't freed the session.
301 	 */
302 	if (session_p->magic_marker != SOFTTOKEN_SESSION_MAGIC) {
303 		(void) pthread_mutex_unlock(&session_p->session_mutex);
304 		return (CKR_OK);
305 	}
306 
307 	/*
308 	 * The deletion of a session must be blocked when the session
309 	 * reference count is not zero. This means if any session related
310 	 * operation starts prior to the session close operation gets in,
311 	 * the session closing thread must wait for the non-closing
312 	 * operation to be completed before it can proceed the close
313 	 * operation.
314 	 *
315 	 * Unless we are being forced to shut everything down, this only
316 	 * happens if the libraries _fini() is running not of someone
317 	 * explicitly called C_Finalize().
318 	 */
319 	if (force)
320 		session_p->ses_refcnt = 0;
321 
322 	while (session_p->ses_refcnt != 0) {
323 		/*
324 		 * We set the SESSION_REFCNT_WAITING flag before we put
325 		 * this closing thread in a wait state, so other non-closing
326 		 * operation thread will signal to wake it up only when
327 		 * the session reference count becomes zero and this flag
328 		 * is set.
329 		 */
330 		session_p->ses_close_sync |= SESSION_REFCNT_WAITING;
331 		(void) pthread_cond_wait(&session_p->ses_free_cond,
332 		    &session_p->session_mutex);
333 	}
334 
335 	session_p->ses_close_sync &= ~SESSION_REFCNT_WAITING;
336 
337 	/*
338 	 * Remove all the objects created in this session.
339 	 */
340 	soft_delete_all_objects_in_session(session_p, force);
341 
342 	/*
343 	 * Mark session as no longer valid. This can only be done after all
344 	 * objects created by this session are free'd since the marker is
345 	 * still needed in the process of removing objects from the session.
346 	 */
347 	session_p->magic_marker = 0;
348 
349 	(void) pthread_cond_destroy(&session_p->ses_free_cond);
350 
351 	/* In case application did not call Final */
352 	if (session_p->digest.context != NULL)
353 		free(session_p->digest.context);
354 
355 	if (session_p->encrypt.context != NULL)
356 		/*
357 		 * 1st B_TRUE: encrypt
358 		 * 2nd B_TRUE: caller is holding session_mutex.
359 		 */
360 		soft_crypt_cleanup(session_p, B_TRUE, B_TRUE);
361 
362 	if (session_p->decrypt.context != NULL)
363 		/*
364 		 * 1st B_FALSE: decrypt
365 		 * 2nd B_TRUE: caller is holding session_mutex.
366 		 */
367 		soft_crypt_cleanup(session_p, B_FALSE, B_TRUE);
368 
369 	if (session_p->sign.context != NULL)
370 		free(session_p->sign.context);
371 
372 	if (session_p->verify.context != NULL)
373 		free(session_p->verify.context);
374 
375 	if (session_p->find_objects.context != NULL) {
376 		find_context_t *fcontext;
377 		fcontext = (find_context_t *)session_p->find_objects.context;
378 		free(fcontext->objs_found);
379 		free(fcontext);
380 	}
381 
382 	/* Reset SESSION_IS_CLOSIN flag. */
383 	session_p->ses_close_sync &= ~SESSION_IS_CLOSING;
384 
385 	(void) pthread_mutex_unlock(&session_p->session_mutex);
386 	/* Destroy the individual session lock */
387 	(void) pthread_mutex_destroy(&session_p->session_mutex);
388 
389 	/* Delay freeing the session */
390 	session_delay_free(session_p);
391 
392 	return (CKR_OK);
393 }
394 
395 
396 /*
397  * This function is used to type cast a session handle to a pointer to
398  * the session struct. Also, it does the following things:
399  * 1) Check to see if the session struct is tagged with a session
400  *    magic number. This is to detect when an application passes
401  *    a bogus session pointer.
402  * 2) Acquire the lock on the designated session.
403  * 3) Check to see if the session is in the closing state that another
404  *    thread is performing.
405  * 4) Increment the session reference count by one. This is to prevent
406  *    this session from being closed by other thread.
407  * 5) Release the lock held on the designated session.
408  */
409 CK_RV
410 handle2session(CK_SESSION_HANDLE hSession, soft_session_t **session_p)
411 {
412 
413 	soft_session_t *sp = (soft_session_t *)(hSession);
414 
415 	/*
416 	 * No need to hold soft_sessionlist_mutex as we are
417 	 * just reading the value and 32-bit reads are atomic.
418 	 */
419 	if (all_sessions_closing) {
420 		return (CKR_SESSION_CLOSED);
421 	}
422 
423 	if ((sp == NULL) ||
424 	    (sp->magic_marker != SOFTTOKEN_SESSION_MAGIC)) {
425 		return (CKR_SESSION_HANDLE_INVALID);
426 	}
427 	(void) pthread_mutex_lock(&sp->session_mutex);
428 
429 	if (sp->ses_close_sync & SESSION_IS_CLOSING) {
430 		(void) pthread_mutex_unlock(&sp->session_mutex);
431 		return (CKR_SESSION_CLOSED);
432 	}
433 
434 	/* Increment session ref count. */
435 	sp->ses_refcnt++;
436 
437 	(void) pthread_mutex_unlock(&sp->session_mutex);
438 
439 	*session_p = sp;
440 
441 	return (CKR_OK);
442 }
443 
444 /*
445  * The format to be saved in the pOperationState will be:
446  * 1. internal_op_state_t
447  * 2. crypto_active_op_t
448  * 3. actual context of the active operation
449  */
450 CK_RV
451 soft_get_operationstate(soft_session_t *session_p, CK_BYTE_PTR pOperationState,
452     CK_ULONG_PTR pulOperationStateLen)
453 {
454 
455 	internal_op_state_t *p_op_state;
456 	CK_ULONG op_data_len = 0;
457 	CK_RV rv = CKR_OK;
458 
459 	if (pulOperationStateLen == NULL)
460 		return (CKR_ARGUMENTS_BAD);
461 
462 	(void) pthread_mutex_lock(&session_p->session_mutex);
463 
464 	/* Check to see if encrypt operation is active. */
465 	if (session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE) {
466 		rv = CKR_STATE_UNSAVEABLE;
467 		goto unlock_session;
468 	}
469 
470 	/* Check to see if decrypt operation is active. */
471 	if (session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE) {
472 		rv = CKR_STATE_UNSAVEABLE;
473 		goto unlock_session;
474 	}
475 
476 	/* Check to see if sign operation is active. */
477 	if (session_p->sign.flags & CRYPTO_OPERATION_ACTIVE) {
478 		rv = CKR_STATE_UNSAVEABLE;
479 		goto unlock_session;
480 	}
481 
482 	/* Check to see if verify operation is active. */
483 	if (session_p->verify.flags & CRYPTO_OPERATION_ACTIVE) {
484 		rv = CKR_STATE_UNSAVEABLE;
485 		goto unlock_session;
486 	}
487 
488 	/* Check to see if digest operation is active. */
489 	if (session_p->digest.flags & CRYPTO_OPERATION_ACTIVE) {
490 		op_data_len = sizeof (internal_op_state_t) +
491 		    sizeof (crypto_active_op_t);
492 
493 		switch (session_p->digest.mech.mechanism) {
494 		case CKM_MD5:
495 			op_data_len += sizeof (MD5_CTX);
496 			break;
497 		case CKM_SHA_1:
498 			op_data_len += sizeof (SHA1_CTX);
499 			break;
500 		default:
501 			rv = CKR_STATE_UNSAVEABLE;
502 			goto unlock_session;
503 		}
504 
505 		if (pOperationState == NULL_PTR) {
506 			*pulOperationStateLen = op_data_len;
507 			goto unlock_session;
508 		} else {
509 			if (*pulOperationStateLen < op_data_len) {
510 				*pulOperationStateLen = op_data_len;
511 				rv = CKR_BUFFER_TOO_SMALL;
512 				goto unlock_session;
513 			}
514 		}
515 
516 		/* Save internal_op_state_t */
517 		/* LINTED E_BAD_PTR_CAST_ALIGN */
518 		p_op_state = (internal_op_state_t *)pOperationState;
519 		p_op_state->op_len = op_data_len;
520 		p_op_state->op_active = DIGEST_OP;
521 		p_op_state->op_session_state = session_p->state;
522 
523 		/* Save crypto_active_op_t */
524 		(void) memcpy((CK_BYTE *)pOperationState +
525 		    sizeof (internal_op_state_t),
526 		    &session_p->digest,
527 		    sizeof (crypto_active_op_t));
528 
529 		switch (session_p->digest.mech.mechanism) {
530 		case CKM_MD5:
531 			/* Save MD5_CTX for the active digest operation */
532 			(void) memcpy((CK_BYTE *)pOperationState +
533 			    sizeof (internal_op_state_t) +
534 			    sizeof (crypto_active_op_t),
535 			    session_p->digest.context,
536 			    sizeof (MD5_CTX));
537 			break;
538 
539 		case CKM_SHA_1:
540 			/* Save SHA1_CTX for the active digest operation */
541 			(void) memcpy((CK_BYTE *)pOperationState +
542 			    sizeof (internal_op_state_t) +
543 			    sizeof (crypto_active_op_t),
544 			    session_p->digest.context,
545 			    sizeof (SHA1_CTX));
546 			break;
547 
548 		default:
549 			rv = CKR_STATE_UNSAVEABLE;
550 		}
551 	} else {
552 		rv = CKR_OPERATION_NOT_INITIALIZED;
553 		goto unlock_session;
554 	}
555 
556 	*pulOperationStateLen = op_data_len;
557 
558 unlock_session:
559 	(void) pthread_mutex_unlock(&session_p->session_mutex);
560 
561 	return (rv);
562 
563 }
564 
565 static CK_BYTE_PTR alloc_digest(CK_ULONG mech)
566 {
567 	CK_BYTE_PTR	ret_val;
568 
569 	switch (mech) {
570 		case CKM_MD5:
571 			ret_val = (CK_BYTE_PTR) malloc(sizeof (MD5_CTX));
572 			break;
573 		case CKM_SHA_1:
574 			ret_val = (CK_BYTE_PTR) malloc(sizeof (SHA1_CTX));
575 			break;
576 		default: ret_val = NULL;
577 	}
578 
579 	return (ret_val);
580 }
581 
582 /*
583  * The format to be restored from the pOperationState will be:
584  * 1. internal_op_state_t
585  * 2. crypto_active_op_t
586  * 3. actual context of the saved operation
587  */
588 CK_RV
589 soft_set_operationstate(soft_session_t *session_p, CK_BYTE_PTR pOperationState,
590     CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey,
591     CK_OBJECT_HANDLE hAuthenticationKey)
592 {
593 
594 	CK_RV		rv = CKR_OK;
595 	internal_op_state_t *p_op_state;
596 	crypto_active_op_t *p_active_op;
597 	CK_ULONG offset = 0;
598 	CK_ULONG mech;
599 	void *free_it = NULL;
600 
601 	/* LINTED E_BAD_PTR_CAST_ALIGN */
602 	p_op_state = (internal_op_state_t *)pOperationState;
603 
604 	if (p_op_state->op_len != ulOperationStateLen) {
605 		/*
606 		 * The supplied data length does not match with
607 		 * the saved data length.
608 		 */
609 		return (CKR_SAVED_STATE_INVALID);
610 	}
611 
612 	if (p_op_state->op_active != DIGEST_OP)
613 		return (CKR_SAVED_STATE_INVALID);
614 
615 	if ((hAuthenticationKey != 0) || (hEncryptionKey != 0)) {
616 		return (CKR_KEY_NOT_NEEDED);
617 	}
618 
619 	offset = sizeof (internal_op_state_t);
620 	/* LINTED E_BAD_PTR_CAST_ALIGN */
621 	p_active_op = (crypto_active_op_t *)(pOperationState + offset);
622 	offset += sizeof (crypto_active_op_t);
623 	mech = p_active_op->mech.mechanism;
624 
625 	if (!DIGEST_MECH_OK(mech)) {
626 		return (CKR_SAVED_STATE_INVALID);
627 	}
628 
629 	/*
630 	 * We may reuse digest.context in case the digest mechanisms (the one,
631 	 * which belongs to session and the operation, which we are restoring)
632 	 * are the same. If digest mechanisms are different, we have to release
633 	 * the digest context, which belongs to session and allocate a new one.
634 	 */
635 	(void) pthread_mutex_lock(&session_p->session_mutex);
636 
637 	if (session_p->state != p_op_state->op_session_state) {
638 		/*
639 		 * The supplied session state does not match with
640 		 * the saved session state.
641 		 */
642 		rv = CKR_SAVED_STATE_INVALID;
643 		goto unlock_session;
644 	}
645 
646 	if (session_p->digest.context &&
647 	    (session_p->digest.mech.mechanism != mech)) {
648 		free_it = session_p->digest.context;
649 		session_p->digest.context = NULL;
650 	}
651 
652 	if (session_p->digest.context == NULL) {
653 		session_p->digest.context = alloc_digest(mech);
654 
655 		if (session_p->digest.context == NULL) {
656 			/*
657 			 * put back original context into session in case
658 			 * allocation of new context has failed.
659 			 */
660 			session_p->digest.context = free_it;
661 			free_it = NULL;
662 			rv = CKR_HOST_MEMORY;
663 			goto unlock_session;
664 		}
665 	}
666 
667 	/* Restore crypto_active_op_t */
668 	session_p->digest.mech.mechanism = mech;
669 	session_p->digest.flags = p_active_op->flags;
670 
671 	switch (mech) {
672 		case CKM_MD5:
673 			/* Restore MD5_CTX from the saved digest operation */
674 			(void) memcpy((CK_BYTE *)session_p->digest.context,
675 			    (CK_BYTE *)pOperationState + offset,
676 			    sizeof (MD5_CTX));
677 			break;
678 		case CKM_SHA_1:
679 			/* Restore SHA1_CTX from the saved digest operation */
680 			(void) memcpy((CK_BYTE *)session_p->digest.context,
681 			    (CK_BYTE *)pOperationState + offset,
682 			    sizeof (SHA1_CTX));
683 			break;
684 		default:
685 			/* never reached */
686 			rv = CKR_SAVED_STATE_INVALID;
687 	}
688 
689 unlock_session:
690 	(void) pthread_mutex_unlock(&session_p->session_mutex);
691 
692 	if (free_it != NULL)
693 		free(free_it);
694 
695 	return (rv);
696 }
697 
698 
699 CK_RV
700 soft_login(CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
701 {
702 
703 	/*
704 	 * Authenticate the input PIN.
705 	 */
706 	return (soft_verify_pin(pPin, ulPinLen));
707 
708 }
709 
710 void
711 soft_logout(void)
712 {
713 
714 	/*
715 	 * Delete all the private token objects from the "token_object_list".
716 	 */
717 	soft_delete_all_in_core_token_objects(PRIVATE_TOKEN);
718 	return;
719 
720 }
721 
722 void
723 soft_acquire_all_session_mutexes(soft_session_t *session_p)
724 {
725 	/* Iterate through sessions acquiring all mutexes */
726 	while (session_p) {
727 		soft_object_t *object_p;
728 
729 		(void) pthread_mutex_lock(&session_p->session_mutex);
730 		object_p = session_p->object_list;
731 
732 		/* Lock also all objects related to session */
733 		while (object_p) {
734 			(void) pthread_mutex_lock(&object_p->object_mutex);
735 			object_p = object_p->next;
736 		}
737 		session_p = session_p->next;
738 	}
739 }
740 
741 void
742 soft_release_all_session_mutexes(soft_session_t *session_p)
743 {
744 	/* Iterate through sessions releasing all mutexes */
745 	while (session_p) {
746 		/*
747 		 * N.B. Ideally, should go in opposite order to guarantee
748 		 * lock-order requirements but there is no tail pointer.
749 		 */
750 		soft_object_t *object_p = session_p->object_list;
751 
752 		/* Unlock also all objects related to session */
753 		while (object_p) {
754 			(void) pthread_mutex_unlock(&object_p->object_mutex);
755 			object_p = object_p->next;
756 		}
757 		(void) pthread_mutex_unlock(&session_p->session_mutex);
758 		session_p = session_p->next;
759 	}
760 }
761