17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54daf2311Srupertk  * Common Development and Distribution License (the "License").
64daf2311Srupertk  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*83140133SZdenek Kotala  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <unistd.h>
277c478bd9Sstevel@tonic-gate #include <string.h>
287c478bd9Sstevel@tonic-gate #include <cryptoutil.h>
297c478bd9Sstevel@tonic-gate #include <pthread.h>
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
327c478bd9Sstevel@tonic-gate #include "pkcs11Global.h"
337c478bd9Sstevel@tonic-gate #include "pkcs11Slot.h"
347c478bd9Sstevel@tonic-gate #include "pkcs11Conf.h"
357c478bd9Sstevel@tonic-gate #include "pkcs11Session.h"
3651ed222cSwyllys #include "metaGlobal.h"
377c478bd9Sstevel@tonic-gate 
38*83140133SZdenek Kotala #pragma init(pkcs11_init)
397c478bd9Sstevel@tonic-gate #pragma fini(pkcs11_fini)
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate static struct CK_FUNCTION_LIST functionList = {
42f66d273dSizick 	{ 2, 20 },	/* version */
437c478bd9Sstevel@tonic-gate 	C_Initialize,
447c478bd9Sstevel@tonic-gate 	C_Finalize,
457c478bd9Sstevel@tonic-gate 	C_GetInfo,
467c478bd9Sstevel@tonic-gate 	C_GetFunctionList,
477c478bd9Sstevel@tonic-gate 	C_GetSlotList,
487c478bd9Sstevel@tonic-gate 	C_GetSlotInfo,
497c478bd9Sstevel@tonic-gate 	C_GetTokenInfo,
507c478bd9Sstevel@tonic-gate 	C_GetMechanismList,
517c478bd9Sstevel@tonic-gate 	C_GetMechanismInfo,
527c478bd9Sstevel@tonic-gate 	C_InitToken,
537c478bd9Sstevel@tonic-gate 	C_InitPIN,
547c478bd9Sstevel@tonic-gate 	C_SetPIN,
557c478bd9Sstevel@tonic-gate 	C_OpenSession,
567c478bd9Sstevel@tonic-gate 	C_CloseSession,
577c478bd9Sstevel@tonic-gate 	C_CloseAllSessions,
587c478bd9Sstevel@tonic-gate 	C_GetSessionInfo,
597c478bd9Sstevel@tonic-gate 	C_GetOperationState,
607c478bd9Sstevel@tonic-gate 	C_SetOperationState,
617c478bd9Sstevel@tonic-gate 	C_Login,
627c478bd9Sstevel@tonic-gate 	C_Logout,
637c478bd9Sstevel@tonic-gate 	C_CreateObject,
647c478bd9Sstevel@tonic-gate 	C_CopyObject,
657c478bd9Sstevel@tonic-gate 	C_DestroyObject,
667c478bd9Sstevel@tonic-gate 	C_GetObjectSize,
677c478bd9Sstevel@tonic-gate 	C_GetAttributeValue,
687c478bd9Sstevel@tonic-gate 	C_SetAttributeValue,
697c478bd9Sstevel@tonic-gate 	C_FindObjectsInit,
707c478bd9Sstevel@tonic-gate 	C_FindObjects,
717c478bd9Sstevel@tonic-gate 	C_FindObjectsFinal,
727c478bd9Sstevel@tonic-gate 	C_EncryptInit,
737c478bd9Sstevel@tonic-gate 	C_Encrypt,
747c478bd9Sstevel@tonic-gate 	C_EncryptUpdate,
757c478bd9Sstevel@tonic-gate 	C_EncryptFinal,
767c478bd9Sstevel@tonic-gate 	C_DecryptInit,
777c478bd9Sstevel@tonic-gate 	C_Decrypt,
787c478bd9Sstevel@tonic-gate 	C_DecryptUpdate,
797c478bd9Sstevel@tonic-gate 	C_DecryptFinal,
807c478bd9Sstevel@tonic-gate 	C_DigestInit,
817c478bd9Sstevel@tonic-gate 	C_Digest,
827c478bd9Sstevel@tonic-gate 	C_DigestUpdate,
837c478bd9Sstevel@tonic-gate 	C_DigestKey,
847c478bd9Sstevel@tonic-gate 	C_DigestFinal,
857c478bd9Sstevel@tonic-gate 	C_SignInit,
867c478bd9Sstevel@tonic-gate 	C_Sign,
877c478bd9Sstevel@tonic-gate 	C_SignUpdate,
887c478bd9Sstevel@tonic-gate 	C_SignFinal,
897c478bd9Sstevel@tonic-gate 	C_SignRecoverInit,
907c478bd9Sstevel@tonic-gate 	C_SignRecover,
917c478bd9Sstevel@tonic-gate 	C_VerifyInit,
927c478bd9Sstevel@tonic-gate 	C_Verify,
937c478bd9Sstevel@tonic-gate 	C_VerifyUpdate,
947c478bd9Sstevel@tonic-gate 	C_VerifyFinal,
957c478bd9Sstevel@tonic-gate 	C_VerifyRecoverInit,
967c478bd9Sstevel@tonic-gate 	C_VerifyRecover,
977c478bd9Sstevel@tonic-gate 	C_DigestEncryptUpdate,
987c478bd9Sstevel@tonic-gate 	C_DecryptDigestUpdate,
997c478bd9Sstevel@tonic-gate 	C_SignEncryptUpdate,
1007c478bd9Sstevel@tonic-gate 	C_DecryptVerifyUpdate,
1017c478bd9Sstevel@tonic-gate 	C_GenerateKey,
1027c478bd9Sstevel@tonic-gate 	C_GenerateKeyPair,
1037c478bd9Sstevel@tonic-gate 	C_WrapKey,
1047c478bd9Sstevel@tonic-gate 	C_UnwrapKey,
1057c478bd9Sstevel@tonic-gate 	C_DeriveKey,
1067c478bd9Sstevel@tonic-gate 	C_SeedRandom,
1077c478bd9Sstevel@tonic-gate 	C_GenerateRandom,
1087c478bd9Sstevel@tonic-gate 	C_GetFunctionStatus,
1097c478bd9Sstevel@tonic-gate 	C_CancelFunction,
1107c478bd9Sstevel@tonic-gate 	C_WaitForSlotEvent
1117c478bd9Sstevel@tonic-gate };
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate boolean_t pkcs11_initialized = B_FALSE;
1147c478bd9Sstevel@tonic-gate boolean_t pkcs11_cant_create_threads = B_FALSE;
1157c478bd9Sstevel@tonic-gate boolean_t fini_called = B_FALSE;
1164daf2311Srupertk static boolean_t pkcs11_atfork_initialized = B_FALSE;
1177c478bd9Sstevel@tonic-gate static pid_t pkcs11_pid = 0;
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate /* protects pkcs11_[initialized|pid], and fastpath */
1207c478bd9Sstevel@tonic-gate static pthread_mutex_t globalmutex = PTHREAD_MUTEX_INITIALIZER;
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate static CK_RV finalize_common(CK_VOID_PTR pReserved);
123*83140133SZdenek Kotala static void pkcs11_init();
1247c478bd9Sstevel@tonic-gate static void pkcs11_fini();
1257c478bd9Sstevel@tonic-gate 
1269e1a718fSdarrenm /*
1274daf2311Srupertk  * Ensure that before a fork, all mutexes are taken.
128*83140133SZdenek Kotala  * We cannot acquire globalmutex, because it can cause deadlock when
129*83140133SZdenek Kotala  * atfork() and fork() are called in parallel. It can happen when
130*83140133SZdenek Kotala  * C_Ininitialize() tries to dlopen() a provider. The dlopen() operation
131*83140133SZdenek Kotala  * is protected by globalmutex and when another thread calls fork()
132*83140133SZdenek Kotala  * pkcs11_fork_prepare cannot acquire the mutex again and thus it must wait.
133*83140133SZdenek Kotala  * When a provider tries to register its atfork handler, atfork() must
134*83140133SZdenek Kotala  * wait on fork(). See the comment in fork() libc function for more details.
135*83140133SZdenek Kotala  *
1364daf2311Srupertk  * Order:
137*83140133SZdenek Kotala  * 1. slottable->st_mutex
138*83140133SZdenek Kotala  * 2. all slottable->st_slots' mutexes
1399e1a718fSdarrenm  */
1409e1a718fSdarrenm static void
pkcs11_fork_prepare(void)1419e1a718fSdarrenm pkcs11_fork_prepare(void)
1429e1a718fSdarrenm {
1434daf2311Srupertk 	int i;
144*83140133SZdenek Kotala 	if (pkcs11_initialized) {
145*83140133SZdenek Kotala 		if (slottable != NULL) {
146*83140133SZdenek Kotala 			(void) pthread_mutex_lock(&slottable->st_mutex);
147*83140133SZdenek Kotala 
148*83140133SZdenek Kotala 			/* Take the sl_mutex of all slots */
149*83140133SZdenek Kotala 			for (i = slottable->st_first;
150*83140133SZdenek Kotala 			    i <= slottable->st_last; i++) {
151*83140133SZdenek Kotala 				if (slottable->st_slots[i] != NULL) {
152*83140133SZdenek Kotala 					(void) pthread_mutex_lock(
153*83140133SZdenek Kotala 					    &slottable->st_slots[i]->sl_mutex);
154*83140133SZdenek Kotala 				}
1554daf2311Srupertk 			}
1564daf2311Srupertk 		}
1574daf2311Srupertk 	}
1589e1a718fSdarrenm }
1599e1a718fSdarrenm 
1609e1a718fSdarrenm 
1619e1a718fSdarrenm /*
1624daf2311Srupertk  * Ensure that after a fork, in the parent, all mutexes are released in opposite
1634daf2311Srupertk  * order to pkcs11_fork_prepare().
1649e1a718fSdarrenm  */
1659e1a718fSdarrenm static void
pkcs11_fork_parent(void)1669e1a718fSdarrenm pkcs11_fork_parent(void)
1679e1a718fSdarrenm {
1684daf2311Srupertk 	int i;
169*83140133SZdenek Kotala 	if (pkcs11_initialized) {
170*83140133SZdenek Kotala 		if (slottable != NULL) {
171*83140133SZdenek Kotala 			/* Release the sl_mutex of all slots */
172*83140133SZdenek Kotala 			for (i = slottable->st_first;
173*83140133SZdenek Kotala 			    i <= slottable->st_last; i++) {
174*83140133SZdenek Kotala 				if (slottable->st_slots[i] != NULL) {
175*83140133SZdenek Kotala 					(void) pthread_mutex_unlock(
176*83140133SZdenek Kotala 					    &slottable->st_slots[i]->sl_mutex);
177*83140133SZdenek Kotala 				}
1784daf2311Srupertk 			}
1794daf2311Srupertk 		}
1804daf2311Srupertk 		(void) pthread_mutex_unlock(&slottable->st_mutex);
1814daf2311Srupertk 	}
1829e1a718fSdarrenm }
1839e1a718fSdarrenm 
1849e1a718fSdarrenm 
1859e1a718fSdarrenm /*
1864daf2311Srupertk  * Ensure that after a fork, in the child, all mutexes are released in opposite
1874daf2311Srupertk  * order to pkcs11_fork_prepare() and cleanup is done.
188*83140133SZdenek Kotala  * Because we need to handle fork correctly before library is initialized two
189*83140133SZdenek Kotala  * handlers are necessary.
190*83140133SZdenek Kotala  *
191*83140133SZdenek Kotala  * 1) pkcs11_fork_child() - unlock mutexes
192*83140133SZdenek Kotala  * 2) pkcs11_fork_child_fini() - cleanup library after fork, it is registered in
193*83140133SZdenek Kotala  *                               C_Initialize() after providers initialization.
1949e1a718fSdarrenm  */
1959e1a718fSdarrenm static void
pkcs11_fork_child(void)1969e1a718fSdarrenm pkcs11_fork_child(void)
1979e1a718fSdarrenm {
1984daf2311Srupertk 	int i;
199*83140133SZdenek Kotala 	if (pkcs11_initialized) {
200*83140133SZdenek Kotala 		if (slottable != NULL) {
201*83140133SZdenek Kotala 			/* Release the sl_mutex of all slots */
202*83140133SZdenek Kotala 			for (i = slottable->st_first;
203*83140133SZdenek Kotala 			    i <= slottable->st_last; i++) {
204*83140133SZdenek Kotala 				if (slottable->st_slots[i] != NULL) {
205*83140133SZdenek Kotala 					(void) pthread_mutex_unlock(
206*83140133SZdenek Kotala 					    &slottable->st_slots[i]->sl_mutex);
207*83140133SZdenek Kotala 				}
2084daf2311Srupertk 			}
2094daf2311Srupertk 		}
2104daf2311Srupertk 		(void) pthread_mutex_unlock(&slottable->st_mutex);
2114daf2311Srupertk 	}
212*83140133SZdenek Kotala 
213*83140133SZdenek Kotala 	(void) pthread_mutex_destroy(&globalmutex);
214*83140133SZdenek Kotala 	(void) pthread_mutex_init(&globalmutex, NULL);
215*83140133SZdenek Kotala }
216*83140133SZdenek Kotala 
217*83140133SZdenek Kotala /* Library cleanup have to be last afterfork child handler. */
218*83140133SZdenek Kotala static void
pkcs11_fork_child_fini(void)219*83140133SZdenek Kotala pkcs11_fork_child_fini(void)
220*83140133SZdenek Kotala {
2219e1a718fSdarrenm 	pkcs11_fini();
2229e1a718fSdarrenm }
2239e1a718fSdarrenm 
2247c478bd9Sstevel@tonic-gate CK_RV
C_Initialize(CK_VOID_PTR pInitArgs)2257c478bd9Sstevel@tonic-gate C_Initialize(CK_VOID_PTR pInitArgs)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate 	CK_RV rv;
2287c478bd9Sstevel@tonic-gate 	uentrylist_t *pliblist = NULL;
2297c478bd9Sstevel@tonic-gate 	int initialize_pid;
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	/*
2327c478bd9Sstevel@tonic-gate 	 * Grab lock to insure only one thread enters
2337c478bd9Sstevel@tonic-gate 	 * this function at a time.
2347c478bd9Sstevel@tonic-gate 	 */
2357c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&globalmutex);
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	initialize_pid = getpid();
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	/* Make sure function hasn't been called twice */
2407c478bd9Sstevel@tonic-gate 	if (pkcs11_initialized) {
2417c478bd9Sstevel@tonic-gate 		if (initialize_pid == pkcs11_pid) {
2427c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&globalmutex);
2437c478bd9Sstevel@tonic-gate 			return (CKR_CRYPTOKI_ALREADY_INITIALIZED);
2447c478bd9Sstevel@tonic-gate 		} else {
2457c478bd9Sstevel@tonic-gate 			/*
2467c478bd9Sstevel@tonic-gate 			 * A fork has happened and the child is
2477c478bd9Sstevel@tonic-gate 			 * reinitializing.  Do a finalize_common() to close
2487c478bd9Sstevel@tonic-gate 			 * out any state from the parent, and then
2497c478bd9Sstevel@tonic-gate 			 * continue on.
2507c478bd9Sstevel@tonic-gate 			 */
2517c478bd9Sstevel@tonic-gate 			(void) finalize_common(NULL);
2527c478bd9Sstevel@tonic-gate 		}
2537c478bd9Sstevel@tonic-gate 	}
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	/* Check if application has provided mutex-handling functions */
2567c478bd9Sstevel@tonic-gate 	if (pInitArgs != NULL) {
2577c478bd9Sstevel@tonic-gate 		CK_C_INITIALIZE_ARGS_PTR initargs =
25851ed222cSwyllys 		    (CK_C_INITIALIZE_ARGS_PTR) pInitArgs;
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 		/* pReserved should not be set */
2617c478bd9Sstevel@tonic-gate 		if (initargs->pReserved != NULL) {
2627c478bd9Sstevel@tonic-gate 			rv = CKR_ARGUMENTS_BAD;
2637c478bd9Sstevel@tonic-gate 			goto errorexit;
2647c478bd9Sstevel@tonic-gate 		}
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 		/*
2677c478bd9Sstevel@tonic-gate 		 * Make sure function pointers are either all NULL or
2687c478bd9Sstevel@tonic-gate 		 * all set.
2697c478bd9Sstevel@tonic-gate 		 */
2707c478bd9Sstevel@tonic-gate 		if (!(((initargs->CreateMutex   != NULL) &&
27151ed222cSwyllys 		    (initargs->LockMutex    != NULL) &&
27251ed222cSwyllys 		    (initargs->UnlockMutex  != NULL) &&
27351ed222cSwyllys 		    (initargs->DestroyMutex != NULL)) ||
27451ed222cSwyllys 		    ((initargs->CreateMutex == NULL) &&
27551ed222cSwyllys 		    (initargs->LockMutex    == NULL) &&
27651ed222cSwyllys 		    (initargs->UnlockMutex  == NULL) &&
27751ed222cSwyllys 		    (initargs->DestroyMutex == NULL)))) {
2787c478bd9Sstevel@tonic-gate 			rv = CKR_ARGUMENTS_BAD;
2797c478bd9Sstevel@tonic-gate 			goto errorexit;
2807c478bd9Sstevel@tonic-gate 		}
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 		if (!(initargs->flags & CKF_OS_LOCKING_OK)) {
2837c478bd9Sstevel@tonic-gate 			if (initargs->CreateMutex != NULL) {
2847c478bd9Sstevel@tonic-gate 				/*
2857c478bd9Sstevel@tonic-gate 				 * Do not accept application supplied
2867c478bd9Sstevel@tonic-gate 				 * locking primitives.
2877c478bd9Sstevel@tonic-gate 				 */
2887c478bd9Sstevel@tonic-gate 				rv = CKR_CANT_LOCK;
2897c478bd9Sstevel@tonic-gate 				goto errorexit;
2907c478bd9Sstevel@tonic-gate 			}
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 		}
2937c478bd9Sstevel@tonic-gate 		if (initargs->flags & CKF_LIBRARY_CANT_CREATE_OS_THREADS) {
2947c478bd9Sstevel@tonic-gate 			/*
2957c478bd9Sstevel@tonic-gate 			 * Calling application does not want the library
2967c478bd9Sstevel@tonic-gate 			 * to create threads.  This will effect
2977c478bd9Sstevel@tonic-gate 			 * C_WaitForSlotEvent().
2987c478bd9Sstevel@tonic-gate 			 */
2997c478bd9Sstevel@tonic-gate 			pkcs11_cant_create_threads = B_TRUE;
3007c478bd9Sstevel@tonic-gate 		}
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	/* Initialize slot table */
3047c478bd9Sstevel@tonic-gate 	rv = pkcs11_slottable_initialize();
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
3077c478bd9Sstevel@tonic-gate 		goto errorexit;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	/* Get the list of providers */
3107c478bd9Sstevel@tonic-gate 	if (get_pkcs11conf_info(&pliblist) != SUCCESS) {
3117c478bd9Sstevel@tonic-gate 		rv = CKR_FUNCTION_FAILED;
3127c478bd9Sstevel@tonic-gate 		goto errorexit;
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	/*
3167c478bd9Sstevel@tonic-gate 	 * Load each provider, check for accessible slots,
3177c478bd9Sstevel@tonic-gate 	 * and populate slottable.  If metaslot is enabled,
3187c478bd9Sstevel@tonic-gate 	 * it will be initialized as well.
3197c478bd9Sstevel@tonic-gate 	 */
3207c478bd9Sstevel@tonic-gate 	rv = pkcs11_slot_mapping(pliblist, pInitArgs);
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK)
3237c478bd9Sstevel@tonic-gate 		goto errorexit;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	pkcs11_initialized = B_TRUE;
3267c478bd9Sstevel@tonic-gate 	pkcs11_pid = initialize_pid;
3274daf2311Srupertk 	/* Children inherit parent's atfork handlers */
3284daf2311Srupertk 	if (!pkcs11_atfork_initialized) {
329*83140133SZdenek Kotala 		(void) pthread_atfork(NULL, NULL, pkcs11_fork_child_fini);
3304daf2311Srupertk 		pkcs11_atfork_initialized = B_TRUE;
3314daf2311Srupertk 	}
332*83140133SZdenek Kotala 
3337c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&globalmutex);
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	/* Cleanup data structures no longer needed */
3367c478bd9Sstevel@tonic-gate 	free_uentrylist(pliblist);
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	return (CKR_OK);
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate errorexit:
3417c478bd9Sstevel@tonic-gate 	/* Cleanup any data structures that have already been allocated */
3427c478bd9Sstevel@tonic-gate 	if (slottable)
3437c478bd9Sstevel@tonic-gate 		(void) pkcs11_slottable_delete();
3447c478bd9Sstevel@tonic-gate 	if (pliblist)
3457c478bd9Sstevel@tonic-gate 		(void) free_uentrylist(pliblist);
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&globalmutex);
3487c478bd9Sstevel@tonic-gate 	return (rv);
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate /*
3537c478bd9Sstevel@tonic-gate  * C_Finalize is a wrapper around finalize_common. The
3547c478bd9Sstevel@tonic-gate  * globalmutex should be locked by C_Finalize().
3557c478bd9Sstevel@tonic-gate  *
3567c478bd9Sstevel@tonic-gate  * When an explicit C_Finalize() call is received, all
3577c478bd9Sstevel@tonic-gate  * plugins currently in the slottable will also be
3587c478bd9Sstevel@tonic-gate  * finalized.  This must occur, even if libpkcs11(3lib)
3597c478bd9Sstevel@tonic-gate  * was not the first one to initialize the plugins, since it
3607c478bd9Sstevel@tonic-gate  * is the only way in PKCS#11 to force a refresh of the
3617c478bd9Sstevel@tonic-gate  * slot listings (ie to get new hardware devices).
3627c478bd9Sstevel@tonic-gate  */
3637c478bd9Sstevel@tonic-gate CK_RV
C_Finalize(CK_VOID_PTR pReserved)3647c478bd9Sstevel@tonic-gate C_Finalize(CK_VOID_PTR pReserved)
3657c478bd9Sstevel@tonic-gate {
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	CK_RV rv;
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&globalmutex);
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	rv = finalize_common(pReserved);
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&globalmutex);
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	return (rv);
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate /*
3797c478bd9Sstevel@tonic-gate  * finalize_common() does the work for C_Finalize.  globalmutex
3807c478bd9Sstevel@tonic-gate  * must be held before calling this function.
3817c478bd9Sstevel@tonic-gate  */
3827c478bd9Sstevel@tonic-gate static CK_RV
finalize_common(CK_VOID_PTR pReserved)3837c478bd9Sstevel@tonic-gate finalize_common(CK_VOID_PTR pReserved)
3847c478bd9Sstevel@tonic-gate {
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	CK_RV rv;
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	if (!pkcs11_initialized) {
3897c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	if (pReserved != NULL) {
3937c478bd9Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
3947c478bd9Sstevel@tonic-gate 	}
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	purefastpath = B_FALSE;
3977c478bd9Sstevel@tonic-gate 	policyfastpath = B_FALSE;
3987c478bd9Sstevel@tonic-gate 	fast_funcs = NULL;
3997c478bd9Sstevel@tonic-gate 	fast_slot = 0;
4007c478bd9Sstevel@tonic-gate 	pkcs11_initialized = B_FALSE;
4017c478bd9Sstevel@tonic-gate 	pkcs11_cant_create_threads = B_FALSE;
4027c478bd9Sstevel@tonic-gate 	pkcs11_pid = 0;
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	/* Check if C_WaitForSlotEvent() is currently active */
4057c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&slottable->st_mutex);
4067c478bd9Sstevel@tonic-gate 	if (slottable->st_wfse_active) {
4077c478bd9Sstevel@tonic-gate 		/*
4087c478bd9Sstevel@tonic-gate 		 * Wait for this thread to proceed far enough to block or
4097c478bd9Sstevel@tonic-gate 		 * end on its own.  Otherwise, teardown of slottable may
4107c478bd9Sstevel@tonic-gate 		 * occurr before this active function completes.
4117c478bd9Sstevel@tonic-gate 		 */
4127c478bd9Sstevel@tonic-gate 		while (slottable->st_wfse_active) {
4137c478bd9Sstevel@tonic-gate 			/*
4147c478bd9Sstevel@tonic-gate 			 * If C_WaitForSlotEvent is blocking, wake it up and
4157c478bd9Sstevel@tonic-gate 			 * return error to calling application.
4167c478bd9Sstevel@tonic-gate 			 */
4177c478bd9Sstevel@tonic-gate 			if (slottable->st_blocking) {
4187c478bd9Sstevel@tonic-gate 				slottable->st_list_signaled = B_TRUE;
4197c478bd9Sstevel@tonic-gate 				(void) pthread_cond_signal(
42051ed222cSwyllys 				    &slottable->st_wait_cond);
4217c478bd9Sstevel@tonic-gate 				(void) pthread_mutex_unlock(
42251ed222cSwyllys 				    &slottable->st_mutex);
4237c478bd9Sstevel@tonic-gate 				(void) pthread_join(slottable->st_tid, NULL);
4247c478bd9Sstevel@tonic-gate 			}
4257c478bd9Sstevel@tonic-gate 		}
4267c478bd9Sstevel@tonic-gate 	} else {
4277c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&slottable->st_mutex);
4287c478bd9Sstevel@tonic-gate 	}
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	rv = pkcs11_slottable_delete();
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	return (rv);
4337c478bd9Sstevel@tonic-gate }
4347c478bd9Sstevel@tonic-gate 
435*83140133SZdenek Kotala static void
pkcs11_init()436*83140133SZdenek Kotala pkcs11_init()
437*83140133SZdenek Kotala {
438*83140133SZdenek Kotala 	(void) pthread_atfork(pkcs11_fork_prepare,
439*83140133SZdenek Kotala 	    pkcs11_fork_parent, pkcs11_fork_child);
440*83140133SZdenek Kotala }
441*83140133SZdenek Kotala 
4427c478bd9Sstevel@tonic-gate /*
4437c478bd9Sstevel@tonic-gate  * pkcs11_fini() function required to make sure complete cleanup
4447c478bd9Sstevel@tonic-gate  * is done of plugins if the framework is ever unloaded without
4457c478bd9Sstevel@tonic-gate  * a C_Finalize() call.  This would be common when applications
4467c478bd9Sstevel@tonic-gate  * load and unload other libraries that use libpkcs11(3lib), since
4477c478bd9Sstevel@tonic-gate  * shared libraries should not call C_Finalize().
4487c478bd9Sstevel@tonic-gate  *
4497c478bd9Sstevel@tonic-gate  * If pkcs11_fini() is used, we set fini_called to B_TRUE so that
4507c478bd9Sstevel@tonic-gate  * pkcs11_slottable_delete() will not call C_Finalize() on the plugins.
4517c478bd9Sstevel@tonic-gate  *
4527c478bd9Sstevel@tonic-gate  * This is to protect in cases where the application has dlopened
4537c478bd9Sstevel@tonic-gate  * an object (for example, dlobj) that links to libpkcs11(3lib), but
4547c478bd9Sstevel@tonic-gate  * the application is unaware that the object is doing PKCS#11 calls
4557c478bd9Sstevel@tonic-gate  * underneath.  This application may later directly dlopen one of the
4567c478bd9Sstevel@tonic-gate  * plugins (like pkcs11_softtoken.so, or any other 3rd party provided
4577c478bd9Sstevel@tonic-gate  * plugin) in order to directly perform PKCS#11 operations.
4587c478bd9Sstevel@tonic-gate  *
4597c478bd9Sstevel@tonic-gate  * While it is still actively using the PKCS#11 plugin directly,
4607c478bd9Sstevel@tonic-gate  * the application may finish with dlobj and dlclose it.  As the
4617c478bd9Sstevel@tonic-gate  * reference count for libpkcs11(3lib) has become 0, pkcs11_fini()
4627c478bd9Sstevel@tonic-gate  * will be run by the linker.  Even though libpkcs11(3lib) was the
4637c478bd9Sstevel@tonic-gate  * first to initialize the plugin in this case, it is not safe for
4647c478bd9Sstevel@tonic-gate  * libpkcs11(3lib) to finalize the plugin, as the application would
4657c478bd9Sstevel@tonic-gate  * lose state.
4667c478bd9Sstevel@tonic-gate  */
4677c478bd9Sstevel@tonic-gate static void
pkcs11_fini()4687c478bd9Sstevel@tonic-gate pkcs11_fini()
4697c478bd9Sstevel@tonic-gate {
4707c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&globalmutex);
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	/* if we're not initilized, do not attempt to finalize */
4737c478bd9Sstevel@tonic-gate 	if (!pkcs11_initialized) {
4747c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&globalmutex);
4757c478bd9Sstevel@tonic-gate 		return;
4767c478bd9Sstevel@tonic-gate 	}
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	fini_called = B_TRUE;
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	(void) finalize_common(NULL_PTR);
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&globalmutex);
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate CK_RV
C_GetInfo(CK_INFO_PTR pInfo)4877c478bd9Sstevel@tonic-gate C_GetInfo(CK_INFO_PTR pInfo)
4887c478bd9Sstevel@tonic-gate {
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	/* Check for a fastpath */
4917c478bd9Sstevel@tonic-gate 	if (purefastpath || policyfastpath) {
4927c478bd9Sstevel@tonic-gate 		return (fast_funcs->C_GetInfo(pInfo));
4937c478bd9Sstevel@tonic-gate 	}
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	if (!pkcs11_initialized)
4967c478bd9Sstevel@tonic-gate 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	if (pInfo == NULL) {
4997c478bd9Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	/*
5037c478bd9Sstevel@tonic-gate 	 * Copy data into the provided buffer, use strncpy() instead
5047c478bd9Sstevel@tonic-gate 	 * of strlcpy() so that the strings are NOT NULL terminated,
5057c478bd9Sstevel@tonic-gate 	 * as required by the PKCS#11 standard
5067c478bd9Sstevel@tonic-gate 	 */
5077c478bd9Sstevel@tonic-gate 	(void) strncpy((char *)pInfo->manufacturerID, MANUFACTURER_ID,
5087c478bd9Sstevel@tonic-gate 	    PKCS11_STRING_LENGTH);
5097c478bd9Sstevel@tonic-gate 	(void) strncpy((char *)pInfo->libraryDescription,
5107c478bd9Sstevel@tonic-gate 	    LIBRARY_DESCRIPTION, PKCS11_STRING_LENGTH);
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	pInfo->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR;
5137c478bd9Sstevel@tonic-gate 	pInfo->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR;
5147c478bd9Sstevel@tonic-gate 	pInfo->flags = 0;
5157c478bd9Sstevel@tonic-gate 	pInfo->libraryVersion.major = LIBRARY_VERSION_MAJOR;
5167c478bd9Sstevel@tonic-gate 	pInfo->libraryVersion.minor = LIBRARY_VERSION_MINOR;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	return (CKR_OK);
5197c478bd9Sstevel@tonic-gate }
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate /*
5227c478bd9Sstevel@tonic-gate  * This function is unaffected by the fast-path, since it is likely
5237c478bd9Sstevel@tonic-gate  * called before C_Initialize is, so we will not yet know the status
5247c478bd9Sstevel@tonic-gate  * of the fast-path.  Additionally, policy will still need to be
5257c478bd9Sstevel@tonic-gate  * enforced if applicable.
5267c478bd9Sstevel@tonic-gate  */
5277c478bd9Sstevel@tonic-gate CK_RV
C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)5287c478bd9Sstevel@tonic-gate C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
5297c478bd9Sstevel@tonic-gate {
5307c478bd9Sstevel@tonic-gate 	if (ppFunctionList == NULL) {
5317c478bd9Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
5327c478bd9Sstevel@tonic-gate 	}
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	*ppFunctionList = &functionList;
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	return (CKR_OK);
5377c478bd9Sstevel@tonic-gate }
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate /*
5417c478bd9Sstevel@tonic-gate  * This function is no longer supported in this revision of the PKCS#11
5427c478bd9Sstevel@tonic-gate  * standard.  It is maintained for backwards compatibility only.
5437c478bd9Sstevel@tonic-gate  */
5447c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5457c478bd9Sstevel@tonic-gate CK_RV
C_GetFunctionStatus(CK_SESSION_HANDLE hSession)5467c478bd9Sstevel@tonic-gate C_GetFunctionStatus(CK_SESSION_HANDLE hSession)
5477c478bd9Sstevel@tonic-gate {
5487c478bd9Sstevel@tonic-gate 	return (CKR_FUNCTION_NOT_PARALLEL);
5497c478bd9Sstevel@tonic-gate }
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate /*
5537c478bd9Sstevel@tonic-gate  * This function is no longer supported in this revision of the PKCS#11
5547c478bd9Sstevel@tonic-gate  * standard.  It is maintained for backwards compatibility only.
5557c478bd9Sstevel@tonic-gate  */
5567c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5577c478bd9Sstevel@tonic-gate CK_RV
C_CancelFunction(CK_SESSION_HANDLE hSession)5587c478bd9Sstevel@tonic-gate C_CancelFunction(CK_SESSION_HANDLE hSession)
5597c478bd9Sstevel@tonic-gate {
5607c478bd9Sstevel@tonic-gate 	return (CKR_FUNCTION_NOT_PARALLEL);
5617c478bd9Sstevel@tonic-gate }
562