root/usr/src/lib/pkcs11/pkcs11_tpm/common/api_interface.c
/*
 *              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)
{
        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);
        }
}