xref: /titanic_44/usr/src/lib/pkcs11/pkcs11_softtoken/common/softSessionUtil.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
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 2004 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 <md5.h>
30 #include <pthread.h>
31 #include <syslog.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <strings.h>
35 #include <sys/sha1.h>
36 #include <security/cryptoki.h>
37 #include "softGlobal.h"
38 #include "softSession.h"
39 #include "softObject.h"
40 #include "softOps.h"
41 #include "softKeystore.h"
42 #include "softKeystoreUtil.h"
43 
44 
45 CK_ULONG soft_session_cnt = 0;		/* the number of opened sessions */
46 CK_ULONG soft_session_rw_cnt = 0;	/* the number of opened R/W sessions */
47 
48 /*
49  * Delete all the sessions. First, obtain the global session
50  * list lock. Then start to delete one session at a time.
51  * Release the global session list lock before returning to
52  * caller.
53  */
54 CK_RV
55 soft_delete_all_sessions()
56 {
57 
58 	CK_RV rv = CKR_OK;
59 	CK_RV rv1;
60 	soft_session_t *session_p;
61 	soft_session_t *session_p1;
62 
63 	/* Acquire the global session list lock */
64 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
65 
66 	session_p = soft_session_list;
67 
68 	/* Delete all the sessions in the session list */
69 	while (session_p) {
70 		session_p1 = session_p->next;
71 
72 		/*
73 		 * Delete a session by calling soft_delete_session()
74 		 * with a session pointer and a boolean arguments.
75 		 * Boolean value TRUE is used to indicate that the
76 		 * caller holds the lock on the global session list.
77 		 */
78 		rv1 = soft_delete_session(session_p, 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, boolean_t lock_held)
242 {
243 
244 	/*
245 	 * Check to see if the caller holds the lock on the global
246 	 * session list. If not, we need to acquire that lock in
247 	 * order to proceed.
248 	 */
249 	if (!lock_held) {
250 		/* Acquire the global session list lock */
251 		(void) pthread_mutex_lock(&soft_sessionlist_mutex);
252 	}
253 
254 	/*
255 	 * Remove the session from the session linked list first.
256 	 */
257 	if (soft_session_list == session_p) {
258 		/* Session is the first one in the list */
259 		if (session_p->next) {
260 			soft_session_list = session_p->next;
261 			session_p->next->prev = NULL;
262 		} else {
263 			/* Session is the only one in the list */
264 			soft_session_list = NULL;
265 		}
266 	} else {
267 		/* Session is not the first one in the list */
268 		if (session_p->next) {
269 			/* Session is in the middle of the list */
270 			session_p->prev->next = session_p->next;
271 			session_p->next->prev = session_p->prev;
272 		} else {
273 			/* Session is the last one in the list */
274 			session_p->prev->next = NULL;
275 		}
276 	}
277 
278 	--soft_session_cnt;
279 	if (session_p->flags & CKF_RW_SESSION)
280 		--soft_session_rw_cnt;
281 
282 	if (!lock_held) {
283 		/*
284 		 * If the global session list lock is obtained by
285 		 * this function, then release that lock after
286 		 * removing the session from session linked list.
287 		 * We want the releasing of the objects of the
288 		 * session, and freeing of the session itself to
289 		 * be done without holding the global session list
290 		 * lock.
291 		 */
292 		(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
293 	}
294 
295 
296 	/* Acquire the individual session lock */
297 	(void) pthread_mutex_lock(&session_p->session_mutex);
298 	/*
299 	 * Make sure another thread hasn't freed the session.
300 	 */
301 	if (session_p->magic_marker != SOFTTOKEN_SESSION_MAGIC) {
302 		(void) pthread_mutex_unlock(&session_p->session_mutex);
303 		return (CKR_OK);
304 	}
305 
306 	/*
307 	 * The deletion of a session must be blocked when the session
308 	 * reference count is not zero. This means if any session related
309 	 * operation starts prior to the session close operation gets in,
310 	 * the session closing thread must wait for the non-closing
311 	 * operation to be completed before it can proceed the close
312 	 * operation.
313 	 */
314 	while (session_p->ses_refcnt != 0) {
315 		/*
316 		 * We set the SESSION_REFCNT_WAITING flag before we put
317 		 * this closing thread in a wait state, so other non-closing
318 		 * operation thread will signal to wake it up only when
319 		 * the session reference count becomes zero and this flag
320 		 * is set.
321 		 */
322 		session_p->ses_close_sync |= SESSION_REFCNT_WAITING;
323 		(void) pthread_cond_wait(&session_p->ses_free_cond,
324 			&session_p->session_mutex);
325 	}
326 
327 	session_p->ses_close_sync &= ~SESSION_REFCNT_WAITING;
328 
329 	/* Mark session as no longer valid. */
330 	session_p->magic_marker = 0;
331 
332 	(void) pthread_cond_destroy(&session_p->ses_free_cond);
333 
334 	/*
335 	 * Remove all the objects created in this session.
336 	 */
337 	soft_delete_all_objects_in_session(session_p);
338 
339 	/* In case application did not call Final */
340 	if (session_p->digest.context != NULL)
341 		free(session_p->digest.context);
342 
343 	if (session_p->encrypt.context != NULL)
344 		/*
345 		 * 1st B_TRUE: encrypt
346 		 * 2nd B_TRUE: caller is holding session_mutex.
347 		 */
348 		soft_crypt_cleanup(session_p, B_TRUE, B_TRUE);
349 
350 	if (session_p->decrypt.context != NULL)
351 		/*
352 		 * 1st B_FALSE: decrypt
353 		 * 2nd B_TRUE: caller is holding session_mutex.
354 		 */
355 		soft_crypt_cleanup(session_p, B_FALSE, B_TRUE);
356 
357 	if (session_p->sign.context != NULL)
358 		free(session_p->sign.context);
359 
360 	if (session_p->verify.context != NULL)
361 		free(session_p->verify.context);
362 
363 	if (session_p->find_objects.context != NULL) {
364 		find_context_t *fcontext;
365 		fcontext = (find_context_t *)session_p->find_objects.context;
366 		free(fcontext->objs_found);
367 		free(fcontext);
368 	}
369 
370 	/* Reset SESSION_IS_CLOSIN flag. */
371 	session_p->ses_close_sync &= ~SESSION_IS_CLOSING;
372 
373 	(void) pthread_mutex_unlock(&session_p->session_mutex);
374 	/* Destroy the individual session lock */
375 	(void) pthread_mutex_destroy(&session_p->session_mutex);
376 
377 	/* Delay freeing the session */
378 	session_delay_free(session_p);
379 
380 	return (CKR_OK);
381 }
382 
383 
384 /*
385  * This function is used to type cast a session handle to a pointer to
386  * the session struct. Also, it does the following things:
387  * 1) Check to see if the session struct is tagged with a session
388  *    magic number. This is to detect when an application passes
389  *    a bogus session pointer.
390  * 2) Acquire the locks on the global session list and on the designated
391  *    session.
392  * 3) Check to see if the session is in the closing state that another
393  *    thread is performing.
394  * 4) Increment the session reference count by one. This is to prevent
395  *    this session from being closed by other thread.
396  * 5) Release the locks held on the designated session and on the global
397  *    session list.
398  */
399 CK_RV
400 handle2session(CK_SESSION_HANDLE hSession, soft_session_t **session_p)
401 {
402 
403 	soft_session_t *sp = (soft_session_t *)(hSession);
404 
405 	(void) pthread_mutex_lock(&soft_sessionlist_mutex);
406 	if (all_sessions_closing) {
407 		(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
408 		return (CKR_SESSION_CLOSED);
409 	}
410 	/*
411 	 * We need to free the global session list lock to prevent deadlock
412 	 * between C_CloseSession and C_DestroyObject. S1WS/NSS does
413 	 * explicit deletion (C_DestroyObject) after implicit deletion by
414 	 * C_CloseSession.
415 	 */
416 	(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
417 
418 	if ((sp == NULL) ||
419 	    (sp->magic_marker != SOFTTOKEN_SESSION_MAGIC)) {
420 		return (CKR_SESSION_HANDLE_INVALID);
421 	}
422 	(void) pthread_mutex_lock(&sp->session_mutex);
423 
424 	if (sp->ses_close_sync & SESSION_IS_CLOSING) {
425 		(void) pthread_mutex_unlock(&sp->session_mutex);
426 		return (CKR_SESSION_CLOSED);
427 	}
428 
429 	/* Increment session ref count. */
430 	sp->ses_refcnt++;
431 
432 	(void) pthread_mutex_unlock(&sp->session_mutex);
433 
434 	*session_p = sp;
435 
436 	return (CKR_OK);
437 }
438 
439 /*
440  * The format to be saved in the pOperationState will be:
441  * 1. internal_op_state_t
442  * 2. crypto_active_op_t
443  * 3. actual context of the active operation
444  */
445 CK_RV
446 soft_get_operationstate(soft_session_t *session_p, CK_BYTE_PTR pOperationState,
447     CK_ULONG_PTR pulOperationStateLen)
448 {
449 
450 	internal_op_state_t op_state;
451 	CK_ULONG op_data_len = 0;
452 
453 	/* Check to see if encrypt operation is active. */
454 	if (session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE) {
455 		return (CKR_STATE_UNSAVEABLE);
456 	}
457 
458 	/* Check to see if decrypt operation is active. */
459 	if (session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE) {
460 		return (CKR_STATE_UNSAVEABLE);
461 	}
462 
463 	/* Check to see if sign operation is active. */
464 	if (session_p->sign.flags & CRYPTO_OPERATION_ACTIVE) {
465 		return (CKR_STATE_UNSAVEABLE);
466 	}
467 
468 	/* Check to see if verify operation is active. */
469 	if (session_p->verify.flags & CRYPTO_OPERATION_ACTIVE) {
470 		return (CKR_STATE_UNSAVEABLE);
471 	}
472 
473 	/* Check to see if digest operation is active. */
474 	if (session_p->digest.flags & CRYPTO_OPERATION_ACTIVE) {
475 		op_data_len = sizeof (internal_op_state_t) +
476 		    sizeof (crypto_active_op_t);
477 
478 		switch (session_p->digest.mech.mechanism) {
479 		case CKM_MD5:
480 			op_data_len += sizeof (MD5_CTX);
481 			break;
482 		case CKM_SHA_1:
483 			op_data_len += sizeof (SHA1_CTX);
484 			break;
485 		default:
486 			return (CKR_STATE_UNSAVEABLE);
487 		}
488 
489 		if (pOperationState == NULL_PTR) {
490 			*pulOperationStateLen = op_data_len;
491 			return (CKR_OK);
492 		} else {
493 			if (*pulOperationStateLen < op_data_len) {
494 				*pulOperationStateLen = op_data_len;
495 				return (CKR_BUFFER_TOO_SMALL);
496 			}
497 		}
498 
499 		op_state.op_len = op_data_len;
500 		op_state.op_active = DIGEST_OP;
501 		op_state.op_session_state = session_p->state;
502 
503 		/* Save internal_op_state_t */
504 		(void) memcpy(pOperationState, (CK_BYTE_PTR)&op_state,
505 		    sizeof (internal_op_state_t));
506 
507 		/* Save crypto_active_op_t */
508 		(void) memcpy((CK_BYTE *)pOperationState +
509 		    sizeof (internal_op_state_t),
510 		    &session_p->digest,
511 		    sizeof (crypto_active_op_t));
512 
513 		switch (session_p->digest.mech.mechanism) {
514 		case CKM_MD5:
515 			/* Save MD5_CTX for the active digest operation */
516 			(void) memcpy((CK_BYTE *)pOperationState +
517 			    sizeof (internal_op_state_t) +
518 			    sizeof (crypto_active_op_t),
519 			    session_p->digest.context,
520 			    sizeof (MD5_CTX));
521 			break;
522 
523 		case CKM_SHA_1:
524 			/* Save SHA1_CTX for the active digest operation */
525 			(void) memcpy((CK_BYTE *)pOperationState +
526 			    sizeof (internal_op_state_t) +
527 			    sizeof (crypto_active_op_t),
528 			    session_p->digest.context,
529 			    sizeof (SHA1_CTX));
530 			break;
531 
532 		default:
533 			return (CKR_STATE_UNSAVEABLE);
534 		}
535 	}
536 
537 	*pulOperationStateLen = op_data_len;
538 	return (CKR_OK);
539 
540 }
541 
542 /*
543  * The format to be restored from the pOperationState will be:
544  * 1. internal_op_state_t
545  * 2. crypto_active_op_t
546  * 3. actual context of the saved operation
547  */
548 CK_RV
549 soft_set_operationstate(soft_session_t *session_p, CK_BYTE_PTR pOperationState,
550     CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey,
551     CK_OBJECT_HANDLE hAuthenticationKey)
552 {
553 
554 	CK_RV		rv;
555 	internal_op_state_t op_state;
556 	crypto_active_op_t crypto_tmp;
557 	CK_ULONG offset = 0;
558 
559 	/* Restore internal_op_state_t */
560 	(void) memcpy((CK_BYTE_PTR)&op_state, pOperationState,
561 	    sizeof (internal_op_state_t));
562 
563 	if (session_p->state != op_state.op_session_state) {
564 		/*
565 		 * The supplied session state does not match with
566 		 * the saved session state.
567 		 */
568 		return (CKR_SAVED_STATE_INVALID);
569 	}
570 
571 	if (op_state.op_len != ulOperationStateLen) {
572 		/*
573 		 * The supplied data length does not match with
574 		 * the saved data length.
575 		 */
576 		return (CKR_SAVED_STATE_INVALID);
577 	}
578 
579 	offset = sizeof (internal_op_state_t);
580 
581 	(void) memcpy((CK_BYTE *)&crypto_tmp,
582 	    (CK_BYTE *)pOperationState + offset,
583 	    sizeof (crypto_active_op_t));
584 
585 	switch (op_state.op_active) {
586 	case DIGEST_OP:
587 		if ((hAuthenticationKey != 0) || (hEncryptionKey != 0)) {
588 			return (CKR_KEY_NOT_NEEDED);
589 		}
590 
591 		/*
592 		 * If the destination session has the same mechanism
593 		 * as the source, we can reuse the memory allocated for
594 		 * the crypto context. Otherwise, we free the crypto
595 		 * context of the destination session now.
596 		 */
597 		if (session_p->digest.context) {
598 			if (session_p->digest.mech.mechanism !=
599 			    crypto_tmp.mech.mechanism) {
600 				(void) pthread_mutex_lock(&session_p->
601 				    session_mutex);
602 				free(session_p->digest.context);
603 				session_p->digest.context = NULL;
604 				(void) pthread_mutex_unlock(&session_p->
605 				    session_mutex);
606 			}
607 		}
608 		break;
609 
610 	default:
611 		return (CKR_SAVED_STATE_INVALID);
612 	}
613 
614 	/* Restore crypto_active_op_t */
615 	(void) pthread_mutex_lock(&session_p->session_mutex);
616 	session_p->digest.mech.mechanism = crypto_tmp.mech.mechanism;
617 	session_p->digest.flags = crypto_tmp.flags;
618 	(void) pthread_mutex_unlock(&session_p->session_mutex);
619 
620 	offset += sizeof (crypto_active_op_t);
621 
622 	/*
623 	 * Make sure the supplied crypto operation state is valid
624 	 */
625 	switch (op_state.op_active) {
626 	case DIGEST_OP:
627 
628 		switch (session_p->digest.mech.mechanism) {
629 		case CKM_MD5:
630 			(void) pthread_mutex_lock(&session_p->session_mutex);
631 			if (session_p->digest.context == NULL) {
632 				session_p->digest.context =
633 				    malloc(sizeof (MD5_CTX));
634 
635 				if (session_p->digest.context == NULL) {
636 					(void) pthread_mutex_unlock(
637 					    &session_p->session_mutex);
638 					return (CKR_HOST_MEMORY);
639 				}
640 			}
641 
642 			/* Restore MD5_CTX from the saved digest operation */
643 			(void) memcpy((CK_BYTE *)session_p->digest.context,
644 			    (CK_BYTE *)pOperationState + offset,
645 			    sizeof (MD5_CTX));
646 
647 			(void) pthread_mutex_unlock(&session_p->session_mutex);
648 
649 			rv = CKR_OK;
650 			break;
651 
652 		case CKM_SHA_1:
653 			(void) pthread_mutex_lock(&session_p->session_mutex);
654 			if (session_p->digest.context == NULL) {
655 				session_p->digest.context =
656 				    malloc(sizeof (SHA1_CTX));
657 
658 				if (session_p->digest.context == NULL) {
659 					(void) pthread_mutex_unlock(
660 					    &session_p->session_mutex);
661 					return (CKR_HOST_MEMORY);
662 				}
663 			}
664 
665 			/* Restore SHA1_CTX from the saved digest operation */
666 			(void) memcpy((CK_BYTE *)session_p->digest.context,
667 			    (CK_BYTE *)pOperationState + offset,
668 			    sizeof (SHA1_CTX));
669 
670 			(void) pthread_mutex_unlock(&session_p->session_mutex);
671 
672 			rv = CKR_OK;
673 			break;
674 
675 		default:
676 			rv = CKR_SAVED_STATE_INVALID;
677 			break;
678 		}
679 		break;
680 
681 	default:
682 		rv = CKR_SAVED_STATE_INVALID;
683 		break;
684 	}
685 
686 	return (rv);
687 
688 }
689 
690 
691 CK_RV
692 soft_login(CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
693 {
694 
695 	/*
696 	 * Authenticate the input PIN.
697 	 */
698 	return (soft_verify_pin(pPin, ulPinLen));
699 
700 }
701 
702 void
703 soft_logout(void)
704 {
705 
706 	/*
707 	 * Delete all the private token objects from the "token_object_list".
708 	 */
709 	soft_delete_all_in_core_token_objects(PRIVATE_TOKEN);
710 	return;
711 
712 }
713