OpenSolaris_b135/lib/pkcs11/pkcs11_tpm/common/api_interface.c

Compare this file to the similar file:
Show the results in this format:

/*
 *		Common Public License Version 0.5
 *
 *		THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF
 *		THIS COMMON PUBLIC LICENSE ("AGREEMENT"). ANY USE,
 *		REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES
 *		RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
 *
 *		1. DEFINITIONS
 *
 *		"Contribution" means:
 *		      a) in the case of the initial Contributor, the
 *		      initial code and documentation distributed under
 *		      this Agreement, and
 *
 *		      b) in the case of each subsequent Contributor:
 *		      i) changes to the Program, and
 *		      ii) additions to the Program;
 *
 *		      where such changes and/or additions to the Program
 *		      originate from and are distributed by that
 *		      particular Contributor. A Contribution 'originates'
 *		      from a Contributor if it was added to the Program
 *		      by such Contributor itself or anyone acting on such
 *		      Contributor's behalf. Contributions do not include
 *		      additions to the Program which: (i) are separate
 *		      modules of software distributed in conjunction with
 *		      the Program under their own license agreement, and
 *		      (ii) are not derivative works of the Program.
 *
 *
 *		"Contributor" means any person or entity that distributes
 *		the Program.
 *
 *		"Licensed Patents " mean patent claims licensable by a
 *		Contributor which are necessarily infringed by the use or
 *		sale of its Contribution alone or when combined with the
 *		Program.
 *
 *		"Program" means the Contributions distributed in
 *		accordance with this Agreement.
 *
 *		"Recipient" means anyone who receives the Program under
 *		this Agreement, including all Contributors.
 *
 *		2. GRANT OF RIGHTS
 *
 *		      a) Subject to the terms of this Agreement, each
 *		      Contributor hereby grants Recipient a
 *		      no - exclusive, worldwide, royalt - free copyright
 *		      license to reproduce, prepare derivative works of,
 *		      publicly display, publicly perform, distribute and
 *		      sublicense the Contribution of such Contributor, if
 *		      any, and such derivative works, in source code and
 *		      object code form.
 *
 *		      b) Subject to the terms of this Agreement, each
 *		      Contributor hereby grants Recipient a
 *		      no - exclusive, worldwide, royalt - free patent
 *		      license under Licensed Patents to make, use, sell,
 *		      offer to sell, import and otherwise transfer the
 *		      Contribution of such Contributor, if any, in source
 *		      code and object code form. This patent license
 *		      shall apply to the combination of the Contribution
 *		      and the Program if, at the time the Contribution is
 *		      added by the Contributor, such addition of the
 *		      Contribution causes such combination to be covered
 *		      by the Licensed Patents. The patent license shall
 *		      not apply to any other combinations which include
 *		      the Contribution. No hardware per se is licensed
 *		      hereunder.
 *
 *		      c) Recipient understands that although each
 *		      Contributor grants the licenses to its
 *		      Contributions set forth herein, no assurances are
 *		      provided by any Contributor that the Program does
 *		      not infringe the patent or other intellectual
 *		      property rights of any other entity. Each
 *		      Contributor disclaims any liability to Recipient
 *		      for claims brought by any other entity based on
 *		      infringement of intellectual property rights or
 *		      otherwise. As a condition to exercising the rights
 *		      and licenses granted hereunder, each Recipient
 *		      hereby assumes sole responsibility to secure any
 *		      other intellectual property rights needed, if any.
 *
 *		      For example, if a third party patent license is
 *		      required to allow Recipient to distribute the
 *		      Program, it is Recipient's responsibility to
 *		      acquire that license before distributing the
 *		      Program.
 *
 *		      d) Each Contributor represents that to its
 *		      knowledge it has sufficient copyright rights in its
 *		      Contribution, if any, to grant the copyright
 *		      license set forth in this Agreement.
 *
 *		3. REQUIREMENTS
 *
 *		A Contributor may choose to distribute the Program in
 *		object code form under its own license agreement, provided
 *		that:
 *		      a) it complies with the terms and conditions of
 *		      this Agreement; and
 *
 *		      b) its license agreement:
 *		      i) effectively disclaims on behalf of all
 *		      Contributors all warranties and conditions, express
 *		      and implied, including warranties or conditions of
 *		      title and no - infringement, and implied warranties
 *		      or conditions of merchantability and fitness for a
 *		      particular purpose;
 *
 *		      ii) effectively excludes on behalf of all
 *		      Contributors all liability for damages, including
 *		      direct, indirect, special, incidental and
 *		      consequential damages, such as lost profits;
 *
 *		      iii) states that any provisions which differ from
 *		      this Agreement are offered by that Contributor
 *		      alone and not by any other party; and
 *
 *		      iv) states that source code for the Program is
 *		      available from such Contributor, and informs
 *		      licensees how to obtain it in a reasonable manner
 *		      on or through a medium customarily used for
 *		      software exchange.
 *
 *		When the Program is made available in source code form:
 *		      a) it must be made available under this Agreement;
 *		      and
 *		      b) a copy of this Agreement must be included with
 *		      each copy of the Program.
 *
 *		Contributors may not remove or alter any copyright notices
 *		contained within the Program.
 *
 *		Each Contributor must identify itself as the originator of
 *		its Contribution, if any, in a manner that reasonably
 *		allows subsequent Recipients to identify the originator of
 *		the Contribution.
 *
 *
 *		4. COMMERCIAL DISTRIBUTION
 *
 *		Commercial distributors of software may accept certain
 *		responsibilities with respect to end users, business
 *		partners and the like. While this license is intended to
 *		facilitate the commercial use of the Program, the
 *		Contributor who includes the Program in a commercial
 *		product offering should do so in a manner which does not
 *		create potential liability for other Contributors.
 *		Therefore, if a Contributor includes the Program in a
 *		commercial product offering, such Contributor ("Commercial
 *		Contributor") hereby agrees to defend and indemnify every
 *		other Contributor ("Indemnified Contributor") against any
 *		losses, damages and costs (collectively "Losses") arising
 *		from claims, lawsuits and other legal actions brought by a
 *		third party against the Indemnified Contributor to the
 *		extent caused by the acts or omissions of such Commercial
 *		Contributor in connection with its distribution of the
 *		Program in a commercial product offering. The obligations
 *		in this section do not apply to any claims or Losses
 *		relating to any actual or alleged intellectual property
 *		infringement. In order to qualify, an Indemnified
 *		Contributor must: a) promptly notify the Commercial
 *		Contributor in writing of such claim, and b) allow the
 *		Commercial Contributor to control, and cooperate with the
 *		Commercial Contributor in, the defense and any related
 *		settlement negotiations. The Indemnified Contributor may
 *		participate in any such claim at its own expense.
 *
 *
 *		For example, a Contributor might include the Program in a
 *		commercial product offering, Product X. That Contributor
 *		is then a Commercial Contributor. If that Commercial
 *		Contributor then makes performance claims, or offers
 *		warranties related to Product X, those performance claims
 *		and warranties are such Commercial Contributor's
 *		responsibility alone. Under this section, the Commercial
 *		Contributor would have to defend claims against the other
 *		Contributors related to those performance claims and
 *		warranties, and if a court requires any other Contributor
 *		to pay any damages as a result, the Commercial Contributor
 *		must pay those damages.
 *
 *
 *		5. NO WARRANTY
 *
 *		EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE
 *		PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT
 *		WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
 *		IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR
 *		CONDITIONS OF TITLE, NO - INFRINGEMENT, MERCHANTABILITY OR
 *		FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
 *		responsible for determining the appropriateness of using
 *		and distributing the Program and assumes all risks
 *		associated with its exercise of rights under this
 *		Agreement, including but not limited to the risks and
 *		costs of program errors, compliance with applicable laws,
 *		damage to or loss of data, programs or equipment, and
 *		unavailability or interruption of operations.
 *
 *		6. DISCLAIMER OF LIABILITY
 *		EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER
 *		RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY
 *		FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 *		OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
 *		LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
 *		LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *		(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 *		OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE
 *		OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
 *		POSSIBILITY OF SUCH DAMAGES.
 *
 *		7. GENERAL
 *
 *		If any provision of this Agreement is invalid or
 *		unenforceable under applicable law, it shall not affect
 *		the validity or enforceability of the remainder of the
 *		terms of this Agreement, and without further action by the
 *		parties hereto, such provision shall be reformed to the
 *		minimum extent necessary to make such provision valid and
 *		enforceable.
 *
 *
 *		If Recipient institutes patent litigation against a
 *		Contributor with respect to a patent applicable to
 *		software (including a cros - claim or counterclaim in a
 *		lawsuit), then any patent licenses granted by that
 *		Contributor to such Recipient under this Agreement shall
 *		terminate as of the date such litigation is filed. In
 *		addition, If Recipient institutes patent litigation
 *		against any entity (including a cros - claim or
 *		counterclaim in a lawsuit) alleging that the Program
 *		itself (excluding combinations of the Program with other
 *		software or hardware) infringes such Recipient's
 *		patent(s), then such Recipient's rights granted under
 *		Section 2(b) shall terminate as of the date such
 *		litigation is filed.
 *
 *		All Recipient's rights under this Agreement shall
 *		terminate if it fails to comply with any of the material
 *		terms or conditions of this Agreement and does not cure
 *		such failure in a reasonable period of time after becoming
 *		aware of such noncompliance. If all Recipient's rights
 *		under this Agreement terminate, Recipient agrees to cease
 *		use and distribution of the Program as soon as reasonably
 *		practicable. However, Recipient's obligations under this
 *		Agreement and any licenses granted by Recipient relating
 *		to the Program shall continue and survive.
 *
 *		Everyone is permitted to copy and distribute copies of
 *		this Agreement, but in order to avoid inconsistency the
 *		Agreement is copyrighted and may only be modified in the
 *		following manner. The Agreement Steward reserves the right
 *		to publish new versions (including revisions) of this
 *		Agreement from time to time. No one other than the
 *		Agreement Steward has the right to modify this Agreement.
 *
 *		IBM is the initial Agreement Steward. IBM may assign the
 *		responsibility to serve as the Agreement Steward to a
 *		suitable separate entity. Each new version of the
 *		Agreement will be given a distinguishing version number.
 *		The Program (including Contributions) may always be
 *		distributed subject to the version of the Agreement under
 *		which it was received. In addition, after a new version of
 *		the Agreement is published, Contributor may elect to
 *		distribute the Program (including its Contributions) under
 *		the new version. Except as expressly stated in Sections
 *		2(a) and 2(b) above, Recipient receives no rights or
 *		licenses to the intellectual property of any Contributor
 *		under this Agreement, whether expressly, by implication,
 *		estoppel or otherwise. All rights in the Program not
 *		expressly granted under this Agreement are reserved.
 *
 *
 *		This Agreement is governed by the laws of the State of New
 *		York and the intellectual property laws of the United
 *		States of America. No party to this Agreement will bring a
 *		legal action under this Agreement more than one year after
 *		the cause of action arose. Each party waives its rights to
 *		a jury trial in any resulting litigation.
 *
 *
 *
 * (C) COPYRIGHT International Business Machines Corp. 2001, 2002
 */
/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include "tpmtok_int.h"

#define	LOG(x)  logit(LOG_DEBUG, x)

/*
 * NOTES:
 * In many cases the specificaiton does not allow returns
 * of CKR_ARGUMENTSB_BAD.  We break the spec, since validation of parameters
 * to the function are best represented by this return code (where
 * specific RC's such as CKR_INVALID_SESSION do not exist).
 * NOTE NOTE NOTE NOTE
 *    The parameter checking on the update operations may need to be
 *    modified (as well as the encrypt/decrypt) to call the std API
 *    anyway with sanatized parameters since on error, the encrypt/decrypt
 *    sign operations are all supposed to complete.
 *    Therefor the parameter checking here might need to be done in
 *    the STDLL instead of the API.
 *    This would affect ALL the Multipart operations which have
 *    an init followed by one or more operations.
 *
 * Globals for the API
 */
API_Proc_Struct_t  *Anchor = NULL;
static unsigned int   Initialized = 0;
static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
struct ST_FCN_LIST FuncList;
CK_FUNCTION_LIST PK11_Functions;
extern pthread_rwlock_t obj_list_rw_mutex;


static void
tpmtoken_fork_prepare()
{
	(void) pthread_mutex_lock(&global_mutex);
	(void) pthread_mutex_lock(&pkcs_mutex);
	(void) pthread_mutex_lock(&obj_list_mutex);
	(void) pthread_rwlock_wrlock(&obj_list_rw_mutex);
	(void) pthread_mutex_lock(&sess_list_mutex);
	(void) pthread_mutex_lock(&login_mutex);
	if (Anchor) {
		(void) pthread_mutex_lock(&Anchor->ProcMutex);
		(void) pthread_mutex_lock(&Anchor->SessListMutex);
	}
}

static void
tpmtoken_fork_parent()
{
	if (Anchor) {
		(void) pthread_mutex_unlock(&Anchor->SessListMutex);
		(void) pthread_mutex_unlock(&Anchor->ProcMutex);
	}
	(void) pthread_mutex_unlock(&login_mutex);
	(void) pthread_mutex_unlock(&sess_list_mutex);
	(void) pthread_rwlock_unlock(&obj_list_rw_mutex);
	(void) pthread_mutex_unlock(&obj_list_mutex);
	(void) pthread_mutex_unlock(&pkcs_mutex);
	(void) pthread_mutex_unlock(&global_mutex);
}

static void
tpmtoken_fork_child()
{
	if (Anchor) {
		(void) pthread_mutex_unlock(&Anchor->SessListMutex);
		(void) pthread_mutex_unlock(&Anchor->ProcMutex);
	}

	(void) pthread_mutex_unlock(&login_mutex);
	(void) pthread_mutex_unlock(&sess_list_mutex);
	(void) pthread_rwlock_unlock(&obj_list_rw_mutex);
	(void) pthread_mutex_unlock(&obj_list_mutex);
	(void) pthread_mutex_unlock(&pkcs_mutex);
	(void) pthread_mutex_unlock(&global_mutex);

	if (Anchor) {
		Terminate_All_Process_Sessions();
		free(Anchor);
		Anchor = NULL;
	}
	if (FuncList.ST_Finalize)
		FuncList.ST_Finalize(0);

	logterm();
	loginit();
}

/*ARGSUSED*/
CK_RV
C_CancelFunction(CK_SESSION_HANDLE hSession)
{
	LOG("C_CancelFunction");
	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	return (CKR_FUNCTION_NOT_PARALLEL);
}

CK_RV
C_CloseAllSessions(CK_SLOT_ID slotID)
{
	Session_Struct_t *pCur, *pPrev;
	CK_RV    rv;
	/*
	 * Although why does modutil do a close all sessions.  It is a single
	 * application it can only close its sessions...
	 * And all sessions should be closed anyhow.
	 */
	LOG("CloseAllSessions");
	if (API_Initialized() == FALSE)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	if (!global_shm->token_available || (slotID > NUMBER_SLOTS_MANAGED))
		return (CKR_SLOT_ID_INVALID);
	/*
	 * Proc Mutex is locked when we remove from the seesion list in
	 * Close SEssion.  Therefore we don't need to do any locking
	 * the atomic operations are controled when we use the linked list
	 */
	pCur = (Anchor ? Anchor->SessListBeg : NULL);
	while (pCur) {
		/*
		 * Session owned by the slot we are working on
		 * There is a basic problem here.  We are using th pCur
		 * to point to the current one, however we delete it from
		 * the linked list and can no longer go Forward.  So we
		 * have to use the fact that this is a doubly linked list
		 * and get the previous pointer.  After deletion, the next
		 * pointer of this block will point to the next one in the
		 * list.
		 * If the value is Null, then this was the first one in
		 * the list and we just set pCur to the SessListBeg.
		 */
		if (pCur->SltId == slotID) {
			pPrev = pCur->Previous;
			rv = C_CloseSession((CK_SESSION_HANDLE)pCur);
			if (rv == CKR_OK ||
			    rv == CKR_SESSION_CLOSED ||
			    rv == CKR_SESSION_HANDLE_INVALID) {
				if (pPrev == NULL) {
					pCur = Anchor->SessListBeg;
				} else {
					pCur = pPrev->Next;
				}
			} else {
				return (rv);
			}
		} else {
			pCur = pCur->Next;
		}
	}
	LOG("CloseAllSessions OK");
	return (CKR_OK);
}
CK_RV
C_CloseSession(CK_SESSION_HANDLE hSession)
{
	CK_RV rv;
	Session_Struct_t *sessp;
	ST_SESSION_T rSession;
	LOG("C_CloseSession");
	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	/* Validate Session */
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}

	if (FuncList.ST_CloseSession) {
		/* Map the Session to the slot session */
		rv = FuncList.ST_CloseSession(rSession);

		if (rv == CKR_OK) {
			sessp = (Session_Struct_t *)hSession;
			RemoveFromSessionList(sessp);
		}
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_CopyObject(
	CK_SESSION_HANDLE	hSession,
	CK_OBJECT_HANDLE	hObject,
	CK_ATTRIBUTE_PTR	pTemplate,
	CK_ULONG		ulCount,
	CK_OBJECT_HANDLE_PTR	phNewObject)
{
	CK_RV rv;
	ST_SESSION_T rSession;
	LOG("C_CopyObject");
	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (!Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (!phNewObject) {
		return (CKR_ARGUMENTS_BAD);
	}
	/*
	 * A null template with a count will cause the lower layer
	 * to have problems.
	 * Template with 0 count is not a problem.
	 */
	if (!pTemplate && ulCount) {
		return (CKR_ARGUMENTS_BAD);
	}
	if (FuncList.ST_CopyObject) {
		rv = FuncList.ST_CopyObject(rSession, hObject, pTemplate,
		    ulCount, phNewObject);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_CreateObject(
	CK_SESSION_HANDLE	hSession,
	CK_ATTRIBUTE_PTR	pTemplate,
	CK_ULONG		ulCount,
	CK_OBJECT_HANDLE_PTR	phObject)
{
	CK_RV	rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (! pTemplate) {
		return (CKR_TEMPLATE_INCOMPLETE);
	}
	if (ulCount == 0) {
		return (CKR_TEMPLATE_INCOMPLETE);
	}
	if (! phObject) {
		return (CKR_ARGUMENTS_BAD);
	}
	if (FuncList.ST_CreateObject) {
		// Map the Session to the slot session
		rv = FuncList.ST_CreateObject(rSession, pTemplate,
		    ulCount, phObject);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_Decrypt(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR	pEncryptedData,
	CK_ULONG	ulEncryptedDataLen,
	CK_BYTE_PTR	pData,
	CK_ULONG_PTR	pulDataLen)
{
	CK_RV	rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (!Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_Decrypt) {
		rv = FuncList.ST_Decrypt(rSession, pEncryptedData,
		    ulEncryptedDataLen, pData, pulDataLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_DecryptDigestUpdate(
	CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR	pEncryptedPart,
	CK_ULONG	ulEncryptedPartLen,
	CK_BYTE_PTR	pPart,
	CK_ULONG_PTR	pulPartLen)
{
	CK_RV	rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (! pEncryptedPart || ! pulPartLen) {
		return (CKR_ARGUMENTS_BAD);
	}
	if (FuncList.ST_DecryptDigestUpdate) {
		rv = FuncList.ST_DecryptDigestUpdate(rSession, pEncryptedPart,
		    ulEncryptedPartLen, pPart, pulPartLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_DecryptFinal(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR	pLastPart,
	CK_ULONG_PTR	pulLastPartLen)
{
	CK_RV	rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	/*
	 * It is acceptable to have a Null pointer for the data since
	 * it is trying to get the length of the last part....
	 * The spec is unclear if a second call to Final is needed
	 * if there is no data in the last part.
	 */
	if (! pulLastPartLen) {
		return (CKR_ARGUMENTS_BAD);
	}
	if (FuncList.ST_DecryptFinal) {
		rv = FuncList.ST_DecryptFinal(rSession, pLastPart,
		    pulLastPartLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_DecryptInit(CK_SESSION_HANDLE hSession,
	CK_MECHANISM_PTR pMechanism,
	CK_OBJECT_HANDLE hKey)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (! pMechanism) {
		return (CKR_MECHANISM_INVALID);
	}
	if (FuncList.ST_DecryptInit) {
		rv = FuncList.ST_DecryptInit(rSession, pMechanism, hKey);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_DecryptUpdate(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR	pEncryptedPart,
	CK_ULONG	ulEncryptedPartLen,
	CK_BYTE_PTR	pPart,
	CK_ULONG_PTR	pulPartLen)
{
	CK_RV	rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (!Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (!pEncryptedPart || !pulPartLen) {
		return (CKR_ARGUMENTS_BAD);
	}
	if (FuncList.ST_DecryptUpdate) {
		rv = FuncList.ST_DecryptUpdate(rSession, pEncryptedPart,
		    ulEncryptedPartLen, pPart, pulPartLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_DecryptVerifyUpdate(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR	pEncryptedPart,
	CK_ULONG	ulEncryptedPartLen,
	CK_BYTE_PTR	pPart,
	CK_ULONG_PTR	pulPartLen)
{
	CK_RV	rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	// Validate Session
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	// May have to let these go through and let the STDLL handle them
	if (! pEncryptedPart || ! pulPartLen) {
		return (CKR_ARGUMENTS_BAD);
	}
	// Get local pointers to session
	if (FuncList.ST_DecryptVerifyUpdate) {
		// Map the Session to the slot session
		rv = FuncList.ST_DecryptVerifyUpdate(rSession,
		    pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_DeriveKey(CK_SESSION_HANDLE	hSession,
	CK_MECHANISM_PTR	pMechanism,
	CK_OBJECT_HANDLE	hBaseKey,
	CK_ATTRIBUTE_PTR	pTemplate,
	CK_ULONG		ulAttributeCount,
	CK_OBJECT_HANDLE_PTR	phKey)
{
	CK_RV	rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (!Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}

	if (!pMechanism) {
		return (CKR_MECHANISM_INVALID);
	}
	if (!pTemplate && ulAttributeCount) {
		return (CKR_ARGUMENTS_BAD);
	}
	if (FuncList.ST_DeriveKey) {
		rv = FuncList.ST_DeriveKey(rSession, pMechanism,
		    hBaseKey, pTemplate, ulAttributeCount, phKey);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_DestroyObject(CK_SESSION_HANDLE hSession,
	CK_OBJECT_HANDLE hObject)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (!Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_DestroyObject) {
		rv = FuncList.ST_DestroyObject(rSession, hObject);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_Digest(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR	pData,
	CK_ULONG	ulDataLen,
	CK_BYTE_PTR	pDigest,
	CK_ULONG_PTR	pulDigestLen)
{
	CK_RV	rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (!Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_Digest) {
		rv = FuncList.ST_Digest(rSession, pData, ulDataLen,
		    pDigest, pulDigestLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_DigestEncryptUpdate(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR	pPart,
	CK_ULONG	ulPartLen,
	CK_BYTE_PTR	pEncryptedPart,
	CK_ULONG_PTR	pulEncryptedPartLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pPart || ! pulEncryptedPartLen) {
		return (CKR_ARGUMENTS_BAD);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_DigestEncryptUpdate) {
		rv = FuncList.ST_DigestEncryptUpdate(rSession, pPart,
		    ulPartLen, pEncryptedPart, pulEncryptedPartLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_DigestFinal(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR	pDigest,
	CK_ULONG_PTR	pulDigestLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pulDigestLen) {
		return (CKR_ARGUMENTS_BAD);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_DigestFinal) {
		rv = FuncList.ST_DigestFinal(rSession, pDigest, pulDigestLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_DigestInit(CK_SESSION_HANDLE hSession,
	CK_MECHANISM_PTR pMechanism)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pMechanism) {
		return (CKR_MECHANISM_INVALID);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_DigestInit) {
		rv = FuncList.ST_DigestInit(rSession, pMechanism);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_DigestKey(CK_SESSION_HANDLE hSession,
	CK_OBJECT_HANDLE hKey)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_DigestKey) {
		rv = FuncList.ST_DigestKey(rSession, hKey);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_DigestUpdate(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR pPart,
	CK_ULONG ulPartLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;
	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_DigestUpdate) {
		rv = FuncList.ST_DigestUpdate(rSession, pPart, ulPartLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_Encrypt(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR pData,
	CK_ULONG ulDataLen,
	CK_BYTE_PTR pEncryptedData,
	CK_ULONG_PTR pulEncryptedDataLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	// Get local pointers to session
	if (FuncList.ST_Encrypt) {
		// Map the Session to the slot session
		rv = FuncList.ST_Encrypt(rSession, pData, ulDataLen,
		    pEncryptedData, pulEncryptedDataLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_EncryptFinal(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR pLastEncryptedPart,
	CK_ULONG_PTR pulLastEncryptedPartLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_EncryptFinal) {
		rv = FuncList.ST_EncryptFinal(rSession,
		    pLastEncryptedPart, pulLastEncryptedPartLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_EncryptInit(CK_SESSION_HANDLE hSession,
	CK_MECHANISM_PTR pMechanism,
	CK_OBJECT_HANDLE hKey)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pMechanism) {
		return (CKR_MECHANISM_INVALID);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_EncryptInit) {
		rv = FuncList.ST_EncryptInit(rSession, pMechanism, hKey);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_EncryptUpdate(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR pPart,
	CK_ULONG ulPartLen,
	CK_BYTE_PTR pEncryptedPart,
	CK_ULONG_PTR pulEncryptedPartLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (!pPart || !pulEncryptedPartLen) {
		return (CKR_ARGUMENTS_BAD);
	}
	if (!Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_EncryptUpdate) {
		rv = FuncList.ST_EncryptUpdate(rSession, pPart, ulPartLen,
		    pEncryptedPart, pulEncryptedPartLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
do_finalize(CK_VOID_PTR pReserved)
{
	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (pReserved != NULL) {
		return (CKR_ARGUMENTS_BAD);
	}
	(void) pthread_mutex_lock(&global_mutex);
	if (Anchor)
		Terminate_All_Process_Sessions();

	if (FuncList.ST_Finalize)
		FuncList.ST_Finalize(0);

	free(Anchor);
	Anchor = NULL;

	(void) pthread_mutex_unlock(&global_mutex);
	return (CKR_OK);
}

CK_RV
C_Finalize(CK_VOID_PTR pReserved) {
	return (do_finalize(pReserved));
}

CK_RV
C_FindObjects(CK_SESSION_HANDLE    hSession,
	CK_OBJECT_HANDLE_PTR phObject,
	CK_ULONG ulMaxObjectCount,
	CK_ULONG_PTR pulObjectCount)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! phObject || ! pulObjectCount) {
		return (CKR_ARGUMENTS_BAD);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_FindObjects) {
		rv = FuncList.ST_FindObjects(rSession, phObject,
		    ulMaxObjectCount, pulObjectCount);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_FindObjectsFinal(CK_SESSION_HANDLE hSession)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_FindObjectsFinal) {
		rv = FuncList.ST_FindObjectsFinal(rSession);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_FindObjectsInit(CK_SESSION_HANDLE hSession,
	CK_ATTRIBUTE_PTR pTemplate,
	CK_ULONG ulCount)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_FindObjectsInit) {
		rv = FuncList.ST_FindObjectsInit(rSession, pTemplate, ulCount);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_GenerateKey(CK_SESSION_HANDLE    hSession,
	CK_MECHANISM_PTR pMechanism,
	CK_ATTRIBUTE_PTR pTemplate,
	CK_ULONG ulCount,
	CK_OBJECT_HANDLE_PTR phKey)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pMechanism) {
		return (CKR_MECHANISM_INVALID);
	}
	if (! phKey) {
		return (CKR_ARGUMENTS_BAD);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_GenerateKey) {
		rv = FuncList.ST_GenerateKey(rSession, pMechanism,
		    pTemplate, ulCount, phKey);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_GenerateKeyPair(CK_SESSION_HANDLE    hSession,
	CK_MECHANISM_PTR pMechanism,
	CK_ATTRIBUTE_PTR pPublicKeyTemplate,
	CK_ULONG ulPublicKeyAttributeCount,
	CK_ATTRIBUTE_PTR pPrivateKeyTemplate,
	CK_ULONG ulPrivateKeyAttributeCount,
	CK_OBJECT_HANDLE_PTR phPublicKey,
	CK_OBJECT_HANDLE_PTR phPrivateKey)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pMechanism) {
		return (CKR_MECHANISM_INVALID);
	}
	if (! phPublicKey || ! phPrivateKey) {
		return (CKR_ARGUMENTS_BAD);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_GenerateKeyPair) {
		rv = FuncList.ST_GenerateKeyPair(rSession,
		    pMechanism, pPublicKeyTemplate,
		    ulPublicKeyAttributeCount, pPrivateKeyTemplate,
		    ulPrivateKeyAttributeCount, phPublicKey, phPrivateKey);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_GenerateRandom(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR RandomData,
	CK_ULONG ulRandomLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! RandomData)
		return (CKR_ARGUMENTS_BAD);

	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_GenerateRandom) {
		rv = FuncList.ST_GenerateRandom(rSession, RandomData,
		    ulRandomLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_GetAttributeValue(CK_SESSION_HANDLE hSession,
	CK_OBJECT_HANDLE hObject,
	CK_ATTRIBUTE_PTR pTemplate,
	CK_ULONG ulCount)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pTemplate) {
		return (CKR_TEMPLATE_INCOMPLETE);
	}
	if (ulCount == 0) {
		return (CKR_TEMPLATE_INCOMPLETE);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_GetAttributeValue) {
		rv = FuncList.ST_GetAttributeValue(rSession, hObject,
		    pTemplate, ulCount);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
{
	_init();

	PK11_Functions.version.major = VERSION_MAJOR;
	PK11_Functions.version.minor = VERSION_MINOR;
	PK11_Functions.C_Initialize = C_Initialize;
	PK11_Functions.C_Finalize = C_Finalize;
	PK11_Functions.C_GetInfo = C_GetInfo;
	PK11_Functions.C_GetFunctionList = C_GetFunctionList;
	PK11_Functions.C_GetSlotList = C_GetSlotList;
	PK11_Functions.C_GetSlotInfo = C_GetSlotInfo;
	PK11_Functions.C_GetTokenInfo = C_GetTokenInfo;
	PK11_Functions.C_GetMechanismList = C_GetMechanismList;
	PK11_Functions.C_GetMechanismInfo = C_GetMechanismInfo;
	PK11_Functions.C_InitToken = C_InitToken;
	PK11_Functions.C_InitPIN = C_InitPIN;
	PK11_Functions.C_SetPIN = C_SetPIN;
	PK11_Functions.C_OpenSession = C_OpenSession;
	PK11_Functions.C_CloseSession = C_CloseSession;
	PK11_Functions.C_CloseAllSessions = C_CloseAllSessions;
	PK11_Functions.C_GetSessionInfo = C_GetSessionInfo;
	PK11_Functions.C_GetOperationState = C_GetOperationState;
	PK11_Functions.C_SetOperationState = C_SetOperationState;
	PK11_Functions.C_Login = C_Login;
	PK11_Functions.C_Logout = C_Logout;
	PK11_Functions.C_CreateObject = C_CreateObject;
	PK11_Functions.C_CopyObject = C_CopyObject;
	PK11_Functions.C_DestroyObject = C_DestroyObject;
	PK11_Functions.C_GetObjectSize = C_GetObjectSize;
	PK11_Functions.C_GetAttributeValue = C_GetAttributeValue;
	PK11_Functions.C_SetAttributeValue = C_SetAttributeValue;
	PK11_Functions.C_FindObjectsInit = C_FindObjectsInit;
	PK11_Functions.C_FindObjects = C_FindObjects;
	PK11_Functions.C_FindObjectsFinal = C_FindObjectsFinal;
	PK11_Functions.C_EncryptInit = C_EncryptInit;
	PK11_Functions.C_Encrypt = C_Encrypt;
	PK11_Functions.C_EncryptUpdate = C_EncryptUpdate;
	PK11_Functions.C_EncryptFinal = C_EncryptFinal;
	PK11_Functions.C_DecryptInit = C_DecryptInit;
	PK11_Functions.C_Decrypt = C_Decrypt;
	PK11_Functions.C_DecryptUpdate = C_DecryptUpdate;
	PK11_Functions.C_DecryptFinal = C_DecryptFinal;
	PK11_Functions.C_DigestInit = C_DigestInit;
	PK11_Functions.C_Digest = C_Digest;
	PK11_Functions.C_DigestUpdate = C_DigestUpdate;
	PK11_Functions.C_DigestKey = C_DigestKey;
	PK11_Functions.C_DigestFinal = C_DigestFinal;
	PK11_Functions.C_SignInit = C_SignInit;
	PK11_Functions.C_Sign = C_Sign;
	PK11_Functions.C_SignUpdate = C_SignUpdate;
	PK11_Functions.C_SignFinal = C_SignFinal;
	PK11_Functions.C_SignRecoverInit = C_SignRecoverInit;
	PK11_Functions.C_SignRecover = C_SignRecover;
	PK11_Functions.C_VerifyInit = C_VerifyInit;
	PK11_Functions.C_Verify = C_Verify;
	PK11_Functions.C_VerifyUpdate = C_VerifyUpdate;
	PK11_Functions.C_VerifyFinal = C_VerifyFinal;
	PK11_Functions.C_VerifyRecoverInit = C_VerifyRecoverInit;
	PK11_Functions.C_VerifyRecover = C_VerifyRecover;
	PK11_Functions.C_DigestEncryptUpdate = C_DigestEncryptUpdate;
	PK11_Functions.C_DecryptDigestUpdate = C_DecryptDigestUpdate;
	PK11_Functions.C_SignEncryptUpdate = C_SignEncryptUpdate;
	PK11_Functions.C_DecryptVerifyUpdate = C_DecryptVerifyUpdate;
	PK11_Functions.C_GenerateKey = C_GenerateKey;
	PK11_Functions.C_GenerateKeyPair = C_GenerateKeyPair;
	PK11_Functions.C_WrapKey = C_WrapKey;
	PK11_Functions.C_UnwrapKey = C_UnwrapKey;
	PK11_Functions.C_DeriveKey = C_DeriveKey;
	PK11_Functions.C_SeedRandom = C_SeedRandom;
	PK11_Functions.C_GenerateRandom = C_GenerateRandom;
	PK11_Functions.C_GetFunctionStatus = C_GetFunctionStatus;
	PK11_Functions.C_CancelFunction = C_CancelFunction;
	PK11_Functions.C_WaitForSlotEvent = C_WaitForSlotEvent;
	if (ppFunctionList) {
		(*ppFunctionList) = &PK11_Functions;
		return (CKR_OK);
	} else {
		return (CKR_ARGUMENTS_BAD);
	}
}

/*ARGSUSED*/
CK_RV
C_GetFunctionStatus(CK_SESSION_HANDLE hSession)
{
	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	return (CKR_FUNCTION_NOT_PARALLEL); // PER Specification PG 170
}

CK_RV
C_GetInfo(CK_INFO_PTR pInfo)
{
	TOKEN_DATA td;
	TSS_HCONTEXT hContext;

	if (! API_Initialized()) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pInfo) {
		return (CKR_FUNCTION_FAILED);
	}
	(void) memset(pInfo, 0, sizeof (*pInfo));
	pInfo->cryptokiVersion.major = 2;
	pInfo->cryptokiVersion.minor = 20;

	if (open_tss_context(&hContext) == 0) {
		/*
		 * Only populate the TPM info if we can establish
		 * a context, but don't return failure because
		 * the framework needs to know some of the info.
		 */
		(void) token_get_tpm_info(hContext, &td);

		(void) Tspi_Context_Close(hContext);

		(void) memcpy(pInfo->manufacturerID,
		    &(td.token_info.manufacturerID),
		    sizeof (pInfo->manufacturerID) - 1);

		pInfo->flags = td.token_info.flags;
	}
	(void) strcpy((char *)pInfo->libraryDescription,
	    "PKCS11 Interface for TPM");

	pInfo->libraryVersion.major = 1;
	pInfo->libraryVersion.minor = 0;

	return (CKR_OK);
}

CK_RV
C_GetMechanismInfo(CK_SLOT_ID	slotID,
	CK_MECHANISM_TYPE	type,
	CK_MECHANISM_INFO_PTR	pInfo)
{
	CK_RV rv;
	if (API_Initialized() == FALSE)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	if (!global_shm->token_available || (slotID > NUMBER_SLOTS_MANAGED))
		return (CKR_SLOT_ID_INVALID);

	if (FuncList.ST_GetMechanismInfo) {
		rv = FuncList.ST_GetMechanismInfo(slotID, type, pInfo);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_GetMechanismList(CK_SLOT_ID slotID,
	CK_MECHANISM_TYPE_PTR pMechanismList,
	CK_ULONG_PTR pulCount)
{
	CK_RV rv;

	if (API_Initialized() == FALSE)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	if (! pulCount)
		return (CKR_ARGUMENTS_BAD);

	if (!global_shm->token_available || (slotID > NUMBER_SLOTS_MANAGED))
		return (CKR_SLOT_ID_INVALID);

	if (FuncList.ST_GetMechanismList) {
		rv = FuncList.ST_GetMechanismList(slotID,
		    pMechanismList, pulCount);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	if (rv == CKR_OK) {
		if (pMechanismList) {
			unsigned long i;
			for (i = 0; i < *pulCount; i++) {
				logit(LOG_DEBUG, "Mechanism[%d] 0x%08X ",
				    i, pMechanismList[i]);
			}
		}
	}
	return (rv);
}

CK_RV
C_GetObjectSize(CK_SESSION_HANDLE hSession,
	CK_OBJECT_HANDLE hObject,
	CK_ULONG_PTR pulSize)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pulSize) {
		return (CKR_ARGUMENTS_BAD);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_GetObjectSize) {
		rv = FuncList.ST_GetObjectSize(rSession, hObject, pulSize);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_GetOperationState(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR pOperationState,
	CK_ULONG_PTR pulOperationStateLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pulOperationStateLen) {
		return (CKR_ARGUMENTS_BAD);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_GetOperationState) {
		rv = FuncList.ST_GetOperationState(rSession,
		    pOperationState, pulOperationStateLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_GetSessionInfo(CK_SESSION_HANDLE hSession,
	CK_SESSION_INFO_PTR pInfo)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pInfo) {
		return (CKR_ARGUMENTS_BAD);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_GetSessionInfo) {
		rv = FuncList.ST_GetSessionInfo(rSession, pInfo);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_GetSlotInfo(CK_SLOT_ID slotID,
	CK_SLOT_INFO_PTR pInfo)
{
	if (API_Initialized() == FALSE)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	if (!pInfo)
		return (CKR_FUNCTION_FAILED);

	if (!global_shm->token_available || (slotID > NUMBER_SLOTS_MANAGED))
		return (CKR_SLOT_ID_INVALID);

	copy_slot_info(slotID, pInfo);
	return (CKR_OK);
}

/*ARGSUSED*/
CK_RV
C_GetSlotList(CK_BBOOL tokenPresent,
	CK_SLOT_ID_PTR pSlotList,
	CK_ULONG_PTR pulCount)
{
	CK_ULONG count;
	CK_SLOT_INFO slotInfo;

	if (API_Initialized() == FALSE)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	if (pulCount == NULL)
		return (CKR_FUNCTION_FAILED);

	count = 0;
	/*
	 * If we can't talk to the TPM, present no slots
	 */
	if (!global_shm->token_available) {
		*pulCount = 0;
		return (CKR_OK);
	}

	copy_slot_info(TPM_SLOTID, &slotInfo);
	if ((slotInfo.flags & CKF_TOKEN_PRESENT))
		count++;

	*pulCount = count;

	if (pSlotList == NULL) {
		return (CKR_OK);
	} else {
		if (*pulCount < count)
			return (CKR_BUFFER_TOO_SMALL);
		pSlotList[0] = TPM_SLOTID;
	}
	return (CKR_OK);
}

CK_RV
C_GetTokenInfo(CK_SLOT_ID slotID,
	CK_TOKEN_INFO_PTR pInfo)
{
	CK_RV rv;

	if (API_Initialized() == FALSE)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	if (!pInfo)
		return (CKR_ARGUMENTS_BAD);

	if (!global_shm->token_available || (slotID > NUMBER_SLOTS_MANAGED))
		return (CKR_SLOT_ID_INVALID);

	slotID = TPM_SLOTID;
	if (FuncList.ST_GetTokenInfo) {
		rv = FuncList.ST_GetTokenInfo(slotID, pInfo);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_Initialize(CK_VOID_PTR pVoid)
{
	CK_RV rv = CKR_OK;
	CK_C_INITIALIZE_ARGS *pArg;
	extern CK_RV ST_Initialize(void *,
	    CK_SLOT_ID, unsigned char *);

	(void) pthread_mutex_lock(&global_mutex);
	if (! Anchor) {
		Anchor = (API_Proc_Struct_t *)malloc(
		    sizeof (API_Proc_Struct_t));
		if (Anchor == NULL) {
			(void) pthread_mutex_unlock(&global_mutex);
			return (CKR_HOST_MEMORY);
		}
	} else {
		(void) pthread_mutex_unlock(&global_mutex);
		return (CKR_CRYPTOKI_ALREADY_INITIALIZED);
	}
	/*
	 * if pVoid is NULL, then everything is OK.  The applicaiton
	 * will not be doing multi thread accesses.  We can use the OS
	 * locks anyhow.
	 */
	if (pVoid != NULL) {
		int supplied_ok;
		pArg = (CK_C_INITIALIZE_ARGS *)pVoid;

		/*
		 * ALL supplied function pointers need to have the value
		 * either NULL or no - NULL.
		 */
		supplied_ok = (pArg->CreateMutex == NULL &&
		    pArg->DestroyMutex == NULL &&
		    pArg->LockMutex == NULL &&
		    pArg->UnlockMutex == NULL) ||
		    (pArg->CreateMutex != NULL &&
		    pArg->DestroyMutex != NULL &&
		    pArg->LockMutex != NULL &&
		    pArg->UnlockMutex != NULL);

		if (!supplied_ok) {
			(void) pthread_mutex_unlock(&global_mutex);
			return (CKR_ARGUMENTS_BAD);
		}
		/* Check for a pReserved set */
		if (pArg->pReserved != NULL) {
			free(Anchor);
			Anchor = NULL;
			(void) pthread_mutex_unlock(&global_mutex);
			return (CKR_ARGUMENTS_BAD);
		}
		/*
		 * When the CKF_OS_LOCKING_OK flag isn't set and mutex
		 * function pointers are supplied by an application,
		 * return (an error.  We must be able to use our own primitives.
		 */
		if (!(pArg->flags & CKF_OS_LOCKING_OK) &&
		    (pArg->CreateMutex != NULL)) {
			(void) pthread_mutex_unlock(&global_mutex);
			return (CKR_CANT_LOCK);
		}
	}
	(void) memset((char *)Anchor, 0, sizeof (API_Proc_Struct_t));
	(void) pthread_mutex_init(&(Anchor->ProcMutex), NULL);
	(void) pthread_mutex_init(&(Anchor->SessListMutex), NULL);
	Anchor->Pid = getpid();

	rv = ST_Initialize((void *)&FuncList, 0, NULL);
	(void) pthread_mutex_unlock(&global_mutex);
	return (rv);
}

CK_RV
C_InitPIN(CK_SESSION_HANDLE hSession,
	CK_CHAR_PTR pPin,
	CK_ULONG ulPinLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	if (! pPin && ulPinLen)
		return (CKR_ARGUMENTS_BAD);

	if (! Valid_Session((Session_Struct_t *)hSession, &rSession))
		return (CKR_SESSION_HANDLE_INVALID);

	if (rSession.slotID > NUMBER_SLOTS_MANAGED)
		return (CKR_SLOT_ID_INVALID);

	if (FuncList.ST_InitPIN)
		rv = FuncList.ST_InitPIN(rSession, pPin, ulPinLen);
	else
		rv = CKR_FUNCTION_NOT_SUPPORTED;

	return (rv);
}

CK_RV
C_InitToken(CK_SLOT_ID  slotID,
	CK_CHAR_PTR pPin,
	CK_ULONG    ulPinLen,
	CK_CHAR_PTR pLabel)
{
	CK_RV rv;

	if (API_Initialized() == FALSE)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	if (! pPin && ulPinLen)
		return (CKR_ARGUMENTS_BAD);

	if (! pLabel)
		return (CKR_ARGUMENTS_BAD);

	if (!global_shm->token_available)
		return (CKR_SLOT_ID_INVALID);

	if (FuncList.ST_InitToken)
		rv = FuncList.ST_InitToken(slotID, pPin, ulPinLen, pLabel);
	else
		rv = CKR_FUNCTION_NOT_SUPPORTED;

	return (rv);
}

CK_RV
C_Login(CK_SESSION_HANDLE hSession,
	CK_USER_TYPE userType,
	CK_CHAR_PTR pPin,
	CK_ULONG ulPinLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_Login) {
		rv = FuncList.ST_Login(rSession, userType, pPin, ulPinLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_Logout(CK_SESSION_HANDLE hSession)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_Logout) {
		rv = FuncList.ST_Logout(rSession);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

/*ARGSUSED*/
CK_RV
C_OpenSession(
	CK_SLOT_ID slotID,
	CK_FLAGS flags,
	CK_VOID_PTR pApplication,
	CK_NOTIFY Notify,
	CK_SESSION_HANDLE_PTR phSession)
{
	CK_RV rv;
	Session_Struct_t  *apiSessp;

	if (API_Initialized() == FALSE)
		return (CKR_CRYPTOKI_NOT_INITIALIZED);

	if (!global_shm->token_available || (slotID > NUMBER_SLOTS_MANAGED))
		return (CKR_SLOT_ID_INVALID);

	if (! phSession)
		return (CKR_FUNCTION_FAILED);

	if ((flags & CKF_SERIAL_SESSION) == 0)
		return (CKR_SESSION_PARALLEL_NOT_SUPPORTED);

	if ((apiSessp = (Session_Struct_t *)malloc(
	    sizeof (Session_Struct_t))) == NULL)
		return (CKR_HOST_MEMORY);

	if (FuncList.ST_OpenSession) {
		rv = FuncList.ST_OpenSession(slotID, flags,
		    &(apiSessp->RealHandle));

		if (rv == CKR_OK) {
			*phSession = (CK_SESSION_HANDLE)apiSessp;
			apiSessp->SltId = slotID;

			AddToSessionList(apiSessp);
		} else {
			free(apiSessp);
		}
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_SeedRandom(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR pSeed,
	CK_ULONG ulSeedLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pSeed && ulSeedLen) {
		return (CKR_ARGUMENTS_BAD);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_SeedRandom) {
		rv = FuncList.ST_SeedRandom(rSession, pSeed, ulSeedLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_SetAttributeValue(CK_SESSION_HANDLE hSession,
	CK_OBJECT_HANDLE hObject,
	CK_ATTRIBUTE_PTR pTemplate,
	CK_ULONG ulCount)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (! pTemplate) {
		return (CKR_TEMPLATE_INCOMPLETE);
	}
	if (! ulCount) {
		return (CKR_TEMPLATE_INCOMPLETE);
	}
	// Get local pointers to session
	if (FuncList.ST_SetAttributeValue) {
		rv = FuncList.ST_SetAttributeValue(rSession, hObject,
		    pTemplate, ulCount);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_SetOperationState(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR pOperationState,
	CK_ULONG ulOperationStateLen,
	CK_OBJECT_HANDLE hEncryptionKey,
	CK_OBJECT_HANDLE hAuthenticationKey)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (! pOperationState || ulOperationStateLen == 0) {
		return (CKR_ARGUMENTS_BAD);
	}
	if (FuncList.ST_SetOperationState) {
		rv = FuncList.ST_SetOperationState(rSession, pOperationState,
		    ulOperationStateLen, hEncryptionKey, hAuthenticationKey);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_SetPIN(CK_SESSION_HANDLE hSession,
	CK_CHAR_PTR pOldPin,
	CK_ULONG ulOldLen,
	CK_CHAR_PTR pNewPin,
	CK_ULONG ulNewLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pOldPin || ! pNewPin)
		return (CKR_PIN_INVALID);
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_SetPIN) {
		rv = FuncList.ST_SetPIN(rSession, pOldPin, ulOldLen,
		    pNewPin, ulNewLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_Sign(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR pData,
	CK_ULONG ulDataLen,
	CK_BYTE_PTR pSignature,
	CK_ULONG_PTR pulSignatureLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_Sign) {
		rv = FuncList.ST_Sign(rSession, pData, ulDataLen,
		    pSignature, pulSignatureLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_SignEncryptUpdate(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR pPart,
	CK_ULONG ulPartLen,
	CK_BYTE_PTR pEncryptedPart,
	CK_ULONG_PTR pulEncryptedPartLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;
	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pPart || ! pulEncryptedPartLen) {
		return (CKR_ARGUMENTS_BAD);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_SignEncryptUpdate) {
		rv = FuncList.ST_SignEncryptUpdate(rSession, pPart,
		    ulPartLen, pEncryptedPart, pulEncryptedPartLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_SignFinal(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR pSignature,
	CK_ULONG_PTR pulSignatureLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pulSignatureLen) {
		return (CKR_ARGUMENTS_BAD);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_SignFinal) {
		rv = FuncList.ST_SignFinal(rSession, pSignature,
		    pulSignatureLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_SignInit(CK_SESSION_HANDLE hSession,
	CK_MECHANISM_PTR pMechanism,
	CK_OBJECT_HANDLE hKey)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pMechanism) {
		return (CKR_MECHANISM_INVALID);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_SignInit) {
		rv = FuncList.ST_SignInit(rSession, pMechanism, hKey);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_SignRecover(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR pData,
	CK_ULONG ulDataLen,
	CK_BYTE_PTR pSignature,
	CK_ULONG_PTR pulSignatureLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_SignRecover) {
		rv = FuncList.ST_SignRecover(rSession, pData,
		    ulDataLen, pSignature, pulSignatureLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_SignRecoverInit(CK_SESSION_HANDLE hSession,
	CK_MECHANISM_PTR pMechanism,
	CK_OBJECT_HANDLE hKey)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pMechanism) {
		return (CKR_MECHANISM_INVALID);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_SignRecoverInit) {
		rv = FuncList.ST_SignRecoverInit(rSession, pMechanism, hKey);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_SignUpdate(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR pPart,
	CK_ULONG ulPartLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_SignUpdate) {
		rv = FuncList.ST_SignUpdate(rSession, pPart, ulPartLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_UnwrapKey(CK_SESSION_HANDLE hSession,
	CK_MECHANISM_PTR pMechanism,
	CK_OBJECT_HANDLE hUnwrappingKey,
	CK_BYTE_PTR pWrappedKey,
	CK_ULONG ulWrappedKeyLen,
	CK_ATTRIBUTE_PTR pTemplate,
	CK_ULONG ulAttributeCount,
	CK_OBJECT_HANDLE_PTR phKey)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (!pMechanism) {
		return (CKR_MECHANISM_INVALID);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_UnwrapKey) {
		rv = FuncList.ST_UnwrapKey(rSession, pMechanism,
		    hUnwrappingKey, pWrappedKey, ulWrappedKeyLen,
		    pTemplate, ulAttributeCount, phKey);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_Verify(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR pData,
	CK_ULONG ulDataLen,
	CK_BYTE_PTR pSignature,
	CK_ULONG ulSignatureLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_Verify) {
		rv = FuncList.ST_Verify(rSession, pData, ulDataLen,
		    pSignature, ulSignatureLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_VerifyFinal(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR pSignature,
	CK_ULONG ulSignatureLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pSignature) {
		return (CKR_ARGUMENTS_BAD);
	}

	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_VerifyFinal) {
		rv = FuncList.ST_VerifyFinal(rSession, pSignature,
		    ulSignatureLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_VerifyInit(CK_SESSION_HANDLE hSession,
	CK_MECHANISM_PTR pMechanism,
	CK_OBJECT_HANDLE hKey)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pMechanism) {
		return (CKR_MECHANISM_INVALID);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}

	if (FuncList.ST_VerifyInit) {
		rv = FuncList.ST_VerifyInit(rSession, pMechanism, hKey);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_VerifyRecover(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR pSignature,
	CK_ULONG ulSignatureLen,
	CK_BYTE_PTR pData,
	CK_ULONG_PTR pulDataLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_VerifyRecover) {
		rv = FuncList.ST_VerifyRecover(rSession, pSignature,
		    ulSignatureLen, pData, pulDataLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_VerifyRecoverInit(CK_SESSION_HANDLE hSession,
	CK_MECHANISM_PTR pMechanism,
	CK_OBJECT_HANDLE hKey)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pMechanism) {
		return (CKR_MECHANISM_INVALID);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_VerifyRecoverInit) {
		rv = FuncList.ST_VerifyRecoverInit(rSession, pMechanism, hKey);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

CK_RV
C_VerifyUpdate(CK_SESSION_HANDLE hSession,
	CK_BYTE_PTR pPart,
	CK_ULONG ulPartLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_VerifyUpdate) {
		rv = FuncList.ST_VerifyUpdate(rSession, pPart, ulPartLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

/*ARGSUSED*/
CK_RV
C_WaitForSlotEvent(CK_FLAGS flags,
	CK_SLOT_ID_PTR pSlot,
	CK_VOID_PTR pReserved)
{
	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	return (CKR_FUNCTION_NOT_SUPPORTED);
}

CK_RV
C_WrapKey(CK_SESSION_HANDLE hSession,
	CK_MECHANISM_PTR pMechanism,
	CK_OBJECT_HANDLE hWrappingKey,
	CK_OBJECT_HANDLE hKey,
	CK_BYTE_PTR pWrappedKey,
	CK_ULONG_PTR pulWrappedKeyLen)
{
	CK_RV rv;
	ST_SESSION_T rSession;

	if (API_Initialized() == FALSE) {
		return (CKR_CRYPTOKI_NOT_INITIALIZED);
	}
	if (! pMechanism) {
		return (CKR_MECHANISM_INVALID);
	}
	if (! Valid_Session((Session_Struct_t *)hSession, &rSession)) {
		return (CKR_SESSION_HANDLE_INVALID);
	}
	if (FuncList.ST_WrapKey) {
		rv = FuncList.ST_WrapKey(rSession, pMechanism, hWrappingKey,
		    hKey, pWrappedKey, pulWrappedKeyLen);
	} else {
		rv = CKR_FUNCTION_NOT_SUPPORTED;
	}
	return (rv);
}

#pragma init(api_init)
#pragma fini(api_fini)

static void
api_init(void)
{
	loginit();
	if (! Initialized) {
		(void) pthread_atfork(tpmtoken_fork_prepare,
		    tpmtoken_fork_parent, tpmtoken_fork_child);
		Initialized = 1;
	}
}

static void
api_fini()
{
	logterm();
	if (API_Initialized() == TRUE) {
		(void) do_finalize(NULL);
	}
}