/* SCCSID: fwk/cssm/addmgr.c, dss_cdsa_fwk, fwk_rel1, rel1_level1 1.19 8/10/97 10:42:32 */

/* ***************************************************************** *
 * Copyright 1998 International Business Machines Corporation. All   *
 * Rights Reserved.                                                  *
 *                                                                   *
 * Please read this carefully.  Your use of this reference           *
 * implementation of certain of the IETF public-key infrastructure   *
 * specifications ("Software") indicates your acceptance of the      *
 * following.  If you do not agree to the following, do not install  *
 * or use any of the Software.                                       *
 *                                                                   *
 * Permission to use, reproduce, distribute and create derivative    *
 * works from the Software ("Software Derivative Works"), and to     *
 * distribute such Software Derivative Works is hereby granted to    *
 * you by International Business Machines Corporation ("IBM").  This *
 * permission includes a license under the patents of IBM that are   *
 * necessarily infringed by your use of the Software as provided by  *
 * IBM.                                                              *
 *                                                                   *
 * IBM licenses the Software to you on an "AS IS" basis, without     *
 * warranty of any kind.  IBM HEREBY EXPRESSLY DISCLAIMS ALL         *
 * WARRANTIES OR CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING,   *
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OR CONDITIONS OF       *
 * MERCHANTABILITY, NON INFRINGEMENT AND FITNESS FOR A PARTICULAR    *
 * PURPOSE.  You are solely responsible for determining the          *
 * appropriateness of using this Software and assume all risks       *
 * associated with the use of this Software, including but not       *
 * limited to the risks of program errors, damage to or loss of      *
 * data, programs or equipment, and unavailability or interruption   *
 * of operations.                                                    *
 *                                                                   *
 * IBM WILL NOT BE LIABLE FOR ANY DIRECT DAMAGES OR FOR ANY SPECIAL, *
 * INCIDENTAL, OR  INDIRECT DAMAGES OR FOR ANY ECONOMIC              *
 * CONSEQUENTIAL DAMAGES (INCLUDING LOST PROFITS OR SAVINGS), EVEN   *
 * IF IBM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  IBM  *
 * will not be liable for the loss of, or damage to, your records or *
 * data, or any damages claimed by you based on a third party claim. *
 *                                                                   *
 * IBM wishes to obtain your feedback to assist in improving the     *
 * Software.  You grant IBM a world-wide, royalty-free right to use, *
 * copy, distribute, sublicense and prepare derivative works based   *
 * upon any feedback, including materials, error corrections,        *
 * Software Derivatives, enhancements, suggestions and the like that *
 * you provide to IBM relating to the Software (this does not        *
 * include products for which you charge a royalty and distribute to *
 * IBM under other terms and conditions).                            *
 *                                                                   *
 * You agree to distribute the Software and any Software Derivatives *
 * under a license agreement that: 1) is sufficient to notify all    *
 * licensees of the Software and Software Derivatives that IBM       *
 * assumes no liability for any claim that may arise regarding the   *
 * Software or Software Derivatives, and 2) that disclaims all       *
 * warranties, both express and implied, from IBM regarding the      *
 * Software and Software Derivatives.  (If you include this          *
 * Agreement with any distribution of the Software or Software       *
 * Derivatives you will have met this requirement.)  You agree that  *
 * you will not delete any copyright notices in the Software.        *
 *                                                                   *
 * This Agreement is the exclusive statement of your rights in the   *
 * Software as provided by IBM.   Except for the rights granted to   *
 * you in the second paragraph above, You are not granted any other  *
 * patent rights, including but not limited to the right to make     *
 * combinations of the Software with products that infringe IBM      *
 * patents. You agree to comply with all applicable laws and         *
 * regulations, including all export and import laws and regulation. *
 * This Agreement is governed by the laws of the State of New York.  *
 * This Agreement supersedes all other communications,               *
 * understandings or agreements we may have had prior to this        *
 * Agreement.                                                        *
 * ***************************************************************** */

/*-----------------------------------------------------------------------
 *      File:   ADDGMGR.C
 *
 * This file contains the code used to manage plug-in modules by the CSSM.
 *
 * Copyright (c) 1995, 1996 Intel Corporation. All rights reserved.
 *-----------------------------------------------------------------------
 */
/*
 * (C) COPYRIGHT International Business Machines Corp. 1996, 1997
 * All Rights Reserved
 * Licensed Materials - Property of IBM
 *
 * Copyright (c) 1995, 1996, 1997 Intel Corporation. All rights reserved.
 *
 * US Government Users Restricted Rights - Use, duplication or
 * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 *
 */
/*
 * WARNING: EXPORT RESTRICTED.
 * This software listing contains cryptographic methods and technology.
 * It is export restricted by the Office of Defense Trade Controls, United
 * States Department of State and cannot be downloaded or otherwise
 * exported or re-exported (i) into (or to a national or resident of) Cuba,
 * Iraq, Libya, Yugoslavia, North Korea, Iran, Syria or any other country
 * to which the US has embargoed goods; or (ii) to anyone on the US
 * Treasury Department's list of Specially Designated Nationals or the US
 * Commerce Department's Table of Denial Orders. By downloading or using
 * this product, you are agreeing to the foregoing and you are representing
 * and warranting that you are not located in, under the control of, or a
 * national or resident of any such country or on any such list.
 */

#include "cssm.h"
#include "cssmport.h"
#include "internal.h"
#include "context.h"
#include "vendor.h"
#include "cssmdli.h"
#include "cssmcli.h"
#include "cssmcspi.h"
#include "cssmtpi.h"

extern HANDLE hCssmAddinMutex;

/* Linked list tracking pointers */
cssm_INTERNALMODULELIST_PTR ModuleListHead = NULL;
cssm_INTERNALMODULELIST_PTR ModuleListTail = NULL;

cssm_INTERNALMEMORYJT_PTR cache_mem_ptr = NULL;


/*---------------------------------------------------------------
 *
 *Name: GUIDcmp
 *
 *Description:
 *   Comparing the guid structure
 *
 *Parameters:
 *   GUID1 - the first guid
 *   GUID2 - the second guid
 *
 *Returns:
 *  1 - guids are different
 *  0 - guids are similar
 *
 *----------------------------------------------------------------*/
CSSM_RETURN GUIDcmp (const CSSM_GUID_PTR GUID1, const CSSM_GUID GUID2)
{
    sint16 i;

    if (GUID1->Data1 != GUID2.Data1)
         return(1);

    if (GUID1->Data2 != GUID2.Data2)
        return(1);

    if (GUID1->Data3 != GUID2.Data3)
        return(1);

    for (i=0; i<8; i++)
        if (GUID1->Data4[i] != GUID2.Data4[i])
            return(1);

    return(0);
}

/*-----------------------------------------------------------------------
 *
 *Name: cssm_GetModuleRecordByGUID
 *
 *Description:
 * General query function that will return just the name associated with
 * the given logical name, the complete record or neither (used to query
 * if an AddIn is loaded or not). If either of the return value pointers
 * are NULL, that value will not be returned. The internal tracking
 * record obtained by this functions should NOT be modified by the caller.
 *
 *Parameters:
 * pAddInName(input) - Logical name of the AddIn to query.
 * phAddIn(output) - Pointer to an AddIn handle value in which to place the
 *  handle of the AddIn.
 * ppAddInRecord(output) - Pointer to an internal tracking record for the
 *  requested handle.
 *
 *Returns:
 * CSSM_OK - Requested values have been found and returned.
 * CSSM_AddIn_NOT_LOADED - The AddIn requested is not loaded.
 *---------------------------------------------------------------------*/
CSSM_RETURN cssm_GetModuleRecordByGUID (const CSSM_GUID_PTR GUID,
                                       cssm_INTERNALMODULELIST_PTR *ppAddInRecord)
{
    cssm_INTERNALMODULELIST_PTR tempListPtr;
    sint32 AddInFound = 0;

    /* Interate through the list looking for the AddIn */

    tempListPtr = ModuleListHead;

    while (tempListPtr && !AddInFound) {
        if (GUIDcmp (GUID,tempListPtr->GUID) == 0) {
            AddInFound = 1;
        } else {
            tempListPtr = tempListPtr->Next;
        }
    }

    if (!AddInFound)
        return(CSSM_FAIL);
/* Add in not loaded */

    if (ppAddInRecord != NULL) {
        *ppAddInRecord = tempListPtr;
    }

    return(CSSM_OK);
}

/*-----------------------------------------------------------------------
 *
 *Name: NewModuleRecord
 *
 *Description:
 * Used to add an AddIn to the internal list of loaded plug-ins. This
 * should be used in registration functions such as AddInRegisterServices.
 * Assigns a unique handle to the AddIn. Does not keep track of the
 * library handle since that is returned by the CSSMLoadLibrary function
 * which will indirectly cause this function to be invoked.LoadAddInByName
 * will add the library handle data to the record.
 *
 *Parameters:
 * pAddInName(input) - Logical name of the AddIn. Should match the name
 *  registered with CSSM.
 * AddInCallback(input) - Pointer to the AddIn callback function.
 * phAddIn(output) - AddIn handle value in which to receive the assigned
 *  handle for the AddIn.
 *
 *Returns:
 * CSSM_ALREADY_LOADED - An AddIn with the same logical name is already
 *  loaded.
 * CSSM_MALLOC_FAILED - Memory could not be allocated to track the AddIn.
 * CSSM_OK - Library added successfully.
 *---------------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_NewModuleRecord (
                                 const CSSM_GUID_PTR GUID,
                                 const CSSM_REGISTRATION_INFO_PTR FunctionTable)
{
    CSSM_RETURN dwRtn;
    cssm_INTERNALMODULELIST_PTR tempRecord;
    uint32 iCnt, i;
    CSSM_MODULE_FUNCS_PTR Src, Dest;

    /* Check to see if the name given already exists */

    if ((dwRtn = cssm_GetModuleRecordByGUID (GUID, &tempRecord)) != CSSM_FAIL)
        return(CSSM_FAIL);
/* Module already loaded not loaded */

    /* Allocate memory for the new record */
    if ((tempRecord = cssm_malloc(sizeof(cssm_INTERNALMODULELIST), 0)) == NULL) {
         CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
         return(CSSM_FAIL);
     }

    /* Copy the jumptable into new record */
    if ((tempRecord->AddInJT = cssm_malloc(sizeof(CSSM_REGISTRATION_INFO),
                   0)) == NULL) {
        cssm_free(tempRecord, 0);
        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
        return(CSSM_FAIL);
    }

    tempRecord->ServiceSummary = FunctionTable->ServiceSummary;
    tempRecord->ThreadSafe = FunctionTable->ThreadSafe;
    tempRecord->AddInJT->Initialize = FunctionTable->Initialize;
    tempRecord->AddInJT->Terminate = FunctionTable->Terminate;
    tempRecord->AddInJT->EventNotify = FunctionTable->EventNotify;
    tempRecord->AddInJT->GetModuleInfo = FunctionTable->GetModuleInfo;
    tempRecord->AddInJT->FreeModuleInfo = FunctionTable->FreeModuleInfo;
    tempRecord->AddInJT->NumberOfServiceTables = FunctionTable->NumberOfServiceTables;

    if ((tempRecord->AddInJT->Services = cssm_malloc(sizeof(CSSM_MODULE_FUNCS) *
              FunctionTable->NumberOfServiceTables, 0)) == NULL) {
        cssm_free(tempRecord->AddInJT, 0);
        cssm_free(tempRecord, 0);
        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
        return(CSSM_FAIL);
    }

    Src = FunctionTable->Services;
    Dest = tempRecord->AddInJT->Services;
    for (i=0; i<FunctionTable->NumberOfServiceTables; i++) {
        Dest[i].ServiceType = Src[i].ServiceType;

        switch (Src[i].ServiceType) {
            case CSSM_SERVICE_TP :
                if ((Dest[i].ServiceFuncs = cssm_malloc (sizeof (CSSM_SPI_TP_FUNCS), 0)) == NULL) {
                    cssm_free(tempRecord->AddInJT->Services, 0);
                    cssm_free(tempRecord->AddInJT, 0);
                    cssm_free(tempRecord, 0);
                    CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
                    return(CSSM_FAIL);
                }

                if (cssm_CheckCopy (Dest[i].ServiceFuncs, Src[i].ServiceFuncs, sizeof (CSSM_SPI_TP_FUNCS)) == CSSM_FAIL) {
                    cssm_free(Dest[i].ServiceFuncs, 0);
                    cssm_free(tempRecord->AddInJT->Services, 0);
                    cssm_free(tempRecord->AddInJT, 0);
                    cssm_free(tempRecord, 0);
                    return(CSSM_FAIL);
                }
            break;

            case CSSM_SERVICE_CSP :
                if ((Dest[i].ServiceFuncs = cssm_malloc (sizeof (CSSM_SPI_CSP_FUNCS), 0)) == NULL) {
                    cssm_free(tempRecord->AddInJT->Services, 0);
                    cssm_free(tempRecord->AddInJT, 0);
                    cssm_free(tempRecord, 0);
                    CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
                    return(CSSM_FAIL);
                }
                if (cssm_CheckCopy (Dest[i].ServiceFuncs, Src[i].ServiceFuncs, sizeof (CSSM_SPI_CSP_FUNCS)) == CSSM_FAIL) {
                    cssm_free(Dest[i].ServiceFuncs, 0);
                    cssm_free(tempRecord->AddInJT->Services, 0);
                    cssm_free(tempRecord->AddInJT, 0);
                    cssm_free(tempRecord, 0);
                    return(CSSM_FAIL);
                }
            break;

            case CSSM_SERVICE_CL :
                if ((Dest[i].ServiceFuncs = cssm_malloc (sizeof (CSSM_SPI_CL_FUNCS), 0)) == NULL) {
                    cssm_free(tempRecord->AddInJT->Services, 0);
                    cssm_free(tempRecord->AddInJT, 0);
                    cssm_free(tempRecord, 0);
                    CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
                    return(CSSM_FAIL);
                }

                if (cssm_CheckCopy (Dest[i].ServiceFuncs, Src[i].ServiceFuncs, sizeof (CSSM_SPI_CL_FUNCS)) == CSSM_FAIL) {
                    cssm_free(Dest[i].ServiceFuncs, 0);
                    cssm_free(tempRecord->AddInJT->Services, 0);
                    cssm_free(tempRecord->AddInJT, 0);
                    cssm_free(tempRecord, 0);
                    return(CSSM_FAIL);
                }
            break;

            case CSSM_SERVICE_DL :
                if ((Dest[i].ServiceFuncs = cssm_malloc (sizeof (CSSM_SPI_DL_FUNCS), 0)) == NULL) {
                    cssm_free(tempRecord->AddInJT->Services, 0);
                    cssm_free(tempRecord->AddInJT, 0);
                    cssm_free(tempRecord, 0);
                    CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
                    return(CSSM_FAIL);
                }
                if (cssm_CheckCopy (Dest[i].ServiceFuncs, Src[i].ServiceFuncs, sizeof (CSSM_SPI_DL_FUNCS)) == CSSM_FAIL) {
                    cssm_free(Dest[i].ServiceFuncs, 0);
                    cssm_free(tempRecord->AddInJT->Services, 0);
                    cssm_free(tempRecord->AddInJT, 0);
                    cssm_free(tempRecord, 0);
                    return(CSSM_FAIL);
                }
            break;
        }
    }

    tempRecord->GUID.Data1 = GUID->Data1;
    tempRecord->GUID.Data2 = GUID->Data2;
    tempRecord->GUID.Data3 = GUID->Data3;
    for (iCnt=0; iCnt<8; iCnt++)
        tempRecord->GUID.Data4[iCnt] = GUID->Data4[iCnt];

    tempRecord->LibHandle = 0;
    tempRecord->Next = NULL;
    tempRecord->AppMemory = NULL;

    /* Insert the new record into the library chain */
    if (ModuleListHead == NULL) {
        ModuleListHead = ModuleListTail = tempRecord;
    } else {
        ((cssm_INTERNALMODULELIST_PTR)(ModuleListTail))->Next = tempRecord;
        ModuleListTail = tempRecord;
    }

    return(CSSM_OK);
}

/*-----------------------------------------------------------------------
 *
 *Name: cssm_IncrementAddInAppMemory
 *
 *Description:
 * Used to implement garbage collection on the loaded AddIns. Whenever
 * the LoadAddInByName function is called, it includes data about the
 * client of the add-in. When there are no clients of the add-in
 * the library is automatically unloaded.
 *
 *Parameters:
 * record(input) - Internal tracking record pointer of the AddIn that
 *  should have the reference count increased.
 *
 *Returns:
 * CSSM_OK - Reference incremented.
 * CSSM_FAIL - Memory error.
 *---------------------------------------------------------------------*/
CSSM_RETURN cssm_IncrementAddInAppMemory (
                                    cssm_INTERNALMODULELIST_PTR AddInRecord,
                                    CSSM_HANDLE *Handle,
                                    const CSSM_API_MEMORY_FUNCS_PTR MemoryFunc,
                                    uint32 SlotID,
                                    uint32 SessionFlags,
                                    uint32 Application,
                                    const CSSM_NOTIFY_CALLBACK Notification)
{

    cssm_INTERNALMEMORYJT_PTR TempInfo;

    /* allocate memory for AppMemory */
    /* Generate a handle for the library; make sure it is unique */

    TempInfo = cssm_malloc (sizeof (cssm_INTERNALMEMORYJT), 0);
    if (TempInfo == NULL) {
        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
        return(CSSM_FAIL);
    }

    TempInfo->MemoryFunctions = cssm_malloc (sizeof (CSSM_API_MEMORY_FUNCS), 0);
    if (TempInfo->MemoryFunctions == NULL) {
        cssm_free (TempInfo, 0);
        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
        return(CSSM_FAIL);
    }

    TempInfo->Handle = (CSSM_HANDLE)cssm_Rand (CSSM_ADDIN);
    *Handle = TempInfo->Handle;

    TempInfo->MemoryFunctions->malloc_func = MemoryFunc->malloc_func;
    TempInfo->MemoryFunctions->realloc_func = MemoryFunc->realloc_func;
    TempInfo->MemoryFunctions->free_func = MemoryFunc->free_func;
    TempInfo->MemoryFunctions->calloc_func = MemoryFunc->calloc_func;
    TempInfo->MemoryFunctions->AllocRef = MemoryFunc->AllocRef;

    TempInfo->SubServiceID = SlotID;
    TempInfo->SubServiceFlags = SessionFlags;
    TempInfo->Application = Application;
    TempInfo->Notification = Notification;

    TempInfo->Next = NULL;

    /* append to the end of AppMemory list */
    if (AddInRecord->AppMemory != NULL)
        TempInfo->Next = AddInRecord->AppMemory;

    AddInRecord->AppMemory = TempInfo;

    return(CSSM_OK);

}

/*-----------------------------------------------------------------------
 *
 *Name: cssm_GetAddInNameByHandle
 *
 *Description:
 * General query function that will return just the name associated with
 * the given handle, the complete record or neither (used to query if a
 * handle is valid or not). If either of the return value pointers are
 * NULL, that value will not be returned. The internal tracking record
 * obtained by this functions should NOT be modified by the caller.
 *
 *Parameters:
 * hAddIn(input) - Handle of the AddIn to query.
 * ppAddInName(output) - Pointer to a character string that will be
 *  allocated for the AddIn name.
 * ppAddInRecord(output) - Pointer to an internal tracking record for the
 *  requested handle.
 *
 *Returns:
 * CSSM_OK - Requested values have been found and returned.
 * CSSM_MALLOC_FAILED - memory could not be allocated for the name string
 * CSSM_INVALID_AddIn_HANDLE - The handle passed is invalid
 *---------------------------------------------------------------------*/
CSSM_RETURN cssm_GetModuleByHandle (CSSM_HANDLE hAddIn,
                                   uint32 *ServiceID,
                                   cssm_INTERNALMODULELIST_PTR *ModuleRecord)
{
    cssm_INTERNALMODULELIST_PTR tempListPtr;
    sint32 AddInFound = 0;

    /* Interate through the list looking for the AddIn */

    tempListPtr = ModuleListHead;
    while (tempListPtr && !AddInFound) {
        cssm_INTERNALMEMORYJT_PTR HandleInfo = tempListPtr->AppMemory;

        while (HandleInfo != NULL && !AddInFound) {
            if (hAddIn == HandleInfo->Handle) {
                AddInFound = 1;

                if (ServiceID != NULL)
                    *ServiceID = HandleInfo->SubServiceID;
            } else
                HandleInfo = HandleInfo->Next;
        }

        if (!AddInFound)
            tempListPtr = tempListPtr->Next;
    }

    if (!AddInFound) {
        CSSM_SetError (&cssm_GUID, CSSM_INVALID_ADDIN_HANDLE);
        return(CSSM_FAIL);
    }

    if (ModuleRecord != NULL) {
        *ModuleRecord = tempListPtr;
    }

    return(CSSM_OK);
}

/*-----------------------------------------------------------------------
 *
 *Name: cssm_CheckMultiTaskEnabled
 *
 *Description:
 * Interface function that allows an API function to check if the addin is thread safe
 *
 *Parameters:
 * hAddIn(input) - AddIn handle of library to query
 *    AddinType
 *Returns:
 * CSSM_TRUE - Addin is thread safe
 * CSSM_FALSE - AddIn is not thread safe
 *---------------------------------------------------------------------*/
BOOL CSSMAPI cssm_CheckThreadSafe (CSSM_HANDLE hAddIn,
                                              CSSM_SERVICE_MASK AddInType)
{
    CSSM_RETURN dwRtn;
    cssm_INTERNALMODULELIST_PTR tempRecord;

    if ((dwRtn = cssm_GetModuleByHandle (hAddIn, NULL, &tempRecord)) != CSSM_OK) {
        CSSM_SetError (&cssm_GUID, CSSM_INVALID_ADDIN_HANDLE);
        return(CSSM_FALSE);
    }

    return(tempRecord->ThreadSafe);
}

/*-----------------------------------------------------------------------
 *
 *Name: cssm_CheckMultiTaskMutexHandle
 *
 *Description:
 * Interface function that allows an API function to return mutex
 *
 *Parameters:
 * hAddIn(input) - AddIn handle of library to query
 *    AddinType
 *Returns:
 * CSSM_OK - Requested callback has been fetched.
 * CSSM_INVALID_AddIn_HANDLE - AddIn handle specified is invalid
 *---------------------------------------------------------------------*/
HANDLE CSSMAPI cssm_GetMultitaskMutexHandle (CSSM_HANDLE hAddIn,
                                              CSSM_SERVICE_MASK AddInType)
{
    CSSM_RETURN dwRtn;
    cssm_INTERNALMODULELIST_PTR tempRecord;

    if ((dwRtn = cssm_GetModuleByHandle (hAddIn, NULL, &tempRecord)) != CSSM_OK) {
        CSSM_SetError (&cssm_GUID, CSSM_INVALID_ADDIN_HANDLE);
        return(NULL);
    }

    return(tempRecord->MultiTaskMutex);
}


/*-----------------------------------------------------------------------
 *
 *Name: cssm_GetAddInCallbackByHandle
 *
 *Description:
 * Interface function that allows an API function to get the callback
 * into an AddIn given its handle.
 *
 *Parameters:
 * hAddIn(input) - AddIn handle of library to query
 * pAddInCallback(output) - Pointer to a function pointer that will hold
 *  the callback registered with the CSSM.
 *
 *Returns:
 * CSSM_OK - Requested callback has been fetched.
 * CSSM_INVALID_AddIn_HANDLE - AddIn handle specified is invalid
 *---------------------------------------------------------------------*/
void * CSSMAPI cssm_GetAddInCallBackByHandle (CSSM_HANDLE hAddIn,
                                              CSSM_SERVICE_MASK AddInType)
{
    cssm_INTERNALMODULELIST_PTR tempRecord;
    CSSM_REGISTRATION_INFO_PTR JTPtr;
    CSSM_MODULE_FUNCS_PTR Service;
    uint32 SubServiceID, i;

    if (cssm_GetModuleByHandle (hAddIn, &SubServiceID, &tempRecord) != CSSM_OK) {
        CSSM_SetError (&cssm_GUID, CSSM_INVALID_ADDIN_HANDLE);
        return(NULL);
    }

    JTPtr = tempRecord->AddInJT;
    Service = JTPtr->Services;
    for (i=0; i<JTPtr->NumberOfServiceTables; i++) {
        if ((uint32)Service[i].ServiceType == (uint32)AddInType &&
               Service[i].ServiceFuncs != NULL)
            return(Service[i].ServiceFuncs);

    }

    CSSM_SetError (&cssm_GUID, CSSM_FUNCTION_NOT_IMPLEMENTED);
    return(NULL);
}

/*-----------------------------------------------------------------------
 *
 *Name: cssm_GetModuleCallbackByHandle
 *
 *Description:
 * Interface function that allows an API function to get the callback
 * into an AddIn given its handle.
 *
 *Parameters:
 * hAddIn(input) - AddIn handle of library to query
 * pAddInCallback(output) - Pointer to a function pointer that will hold
 *  the callback registered with the CSSM.
 *
 *Returns:
 * CSSM_OK - Requested callback has been fetched.
 * CSSM_INVALID_AddIn_HANDLE - AddIn handle specified is invalid
 *---------------------------------------------------------------------*/
CSSM_REGISTRATION_INFO_PTR CSSMAPI cssm_GetModuleCallBackByHandle (
                                         CSSM_HANDLE hAddIn)
{
    cssm_INTERNALMODULELIST_PTR tempRecord;
    uint32 SubServiceID;

    if (cssm_GetModuleByHandle (hAddIn, &SubServiceID, &tempRecord) != CSSM_OK) {
        CSSM_SetError (&cssm_GUID, CSSM_INVALID_ADDIN_HANDLE);
        return(NULL);
    }

    return(tempRecord->AddInJT);
}

CSSM_RETURN CSSMAPI cssm_GenerateCredentialPathAndSection(char* szdllPath, char* szCredentialPath, char* szSection)
{
    char szdllName[255];
    int i;

    if( szdllPath == NULL || szCredentialPath == NULL || szSection== NULL) {
		CSSM_SetError(&cssm_GUID, CSSM_CSP_FILE_NOT_EXISTS);  
        return(CSSM_FAIL);
	}
    strcpy(szCredentialPath, szdllPath);
    i = strlen(szdllPath);

    while( (szCredentialPath[i] != '\\') && (i != 0))
        i--;
    if(szCredentialPath[i] == '\\')
        i++;
    strcpy(szdllName, &szCredentialPath[i]);
    szCredentialPath[i] = '\0';
    strcat(szCredentialPath, "META-INF\\");

    i = strlen(szdllName);
    while( (szdllName[i] != '.') && (i != 0) )
        i--;
    if(szdllName[i] == '.')
        szdllName[i] = '\0';
    strcpy(szSection, szdllName);
    strcat(szdllName, ".dsa");
    strcat(szCredentialPath, szdllName);

    return(CSSM_OK);
}
/*---------------------------------------------------------------
 *
 *Name: cssm_ModuleAttach
 *
 *Description:
 *   Generic function for attaching and add-in types
 *
 *Parameters:
 *   GUID - guid of the add-in module
 *   pVersion - version number of requested add-in
 *   MemoryFunc - application's memory functions
 *   SlotID - Logical slot ID in the add-in to which the handle referes
 *   SessionFlags - How the sessions should be handled
 *   Application - Application context nonce for use with the callback
 *   Notification - Callback used to tell the application when an
 *                  add-in event takes place.
 *   eventType - Event code passed to the add-in after attach
 *   detachEventType - Event code passed to the add-in when a load
 *                     failure occures.
 *
 *Returns:
 *  0 - unable to attach to the add-in module
 *  non 0 - handle to the add-in module
 *
 *----------------------------------------------------------------*/
CSSM_HANDLE CSSMAPI cssm_ModuleAttach (const CSSM_GUID_PTR pModuleGUID,
                                      CSSM_VERSION_PTR pVersion,
                                      const CSSM_API_MEMORY_FUNCS_PTR pMemoryFunc,
                                      uint32 SubServiceID,
                                      uint32 SubServiceFlags,
                                      uint32 Application,
                                      const CSSM_NOTIFY_CALLBACK Notification,
                                      CSSM_EVENT_TYPE eventType,
                                      CSSM_EVENT_TYPE detachEventType)
{
    CSSM_HANDLE tempHandle = 0;
    CSSM_MUTEX retMutex;
    char szCSSMPath[MAX_REG];
    char szModulePath[MAX_REG];
    cssm_INTERNALMODULELIST_PTR pTempRecord = NULL;
    CSSM_RETURN dwRtn;
    CSSM_LIB_HANDLE LibHandle;
	CSSM_MODULE_FLAGS flags=0;
	char mutexName[BUFSIZE];

	CSSM_ClearError();

    /* Check for valid paramerers */
	if (pModuleGUID == NULL ||		
		cssm_IsBadReadPtr(pModuleGUID, sizeof(CSSM_GUID)) == CSSM_TRUE) {
		CSSM_SetError(&cssm_GUID,CSSM_INVALID_GUID);
        return(0);
	}

	if (pVersion == NULL ||
		cssm_IsBadReadPtr(pVersion, sizeof(CSSM_VERSION)) == CSSM_TRUE) {
		CSSM_SetError(&cssm_GUID,CSSM_INVALID_POINTER);
        return(0);
	}

	if (pMemoryFunc == NULL ||
		cssm_IsBadReadPtr(pMemoryFunc, sizeof(CSSM_API_MEMORY_FUNCS)) == CSSM_TRUE) {
		CSSM_SetError(&cssm_GUID,CSSM_INVALID_POINTER);
        return(0);
	}

    /* Locks mutex to prevent two threads allocating at the same time */
    if(hCssmAddinMutex != NULL) {
        retMutex = cssm_LockMutex (hCssmAddinMutex, CSSM_INFINITE_WAIT);
        if(retMutex != CSSM_MUTEX_LOCKED) {
			// cssm error is set
            return(0);
        }
    } else {
        CSSM_SetError(&cssm_GUID,CSSM_INVALID_MUTEX_PTR);
        return(0);
    }

    if ((dwRtn = cssm_GetModuleRecordByGUID (pModuleGUID, &pTempRecord)) != CSSM_FAIL)
    {
        dwRtn = cssm_IncrementAddInAppMemory (pTempRecord, &tempHandle, pMemoryFunc, SubServiceID,
                                      SubServiceFlags, Application, Notification);
		if (dwRtn != CSSM_OK)
			goto exit;
    }
    else
    {
        CSSM_PROC_ADDR pfnAddInAuthenticate = NULL;

        if (CSSM_OK != cssm_RegGetLocation (pModuleGUID, szModulePath))
        {
			// error code is set correctly in the lowest level routine cssm_GetValue
            dwRtn = CSSM_FAIL;
			goto exit;		
        }

        dwRtn= cssm_RegGetLocation (&cssm_GUID, szCSSMPath);
        if (dwRtn != CSSM_OK){ 
			goto exit;
		}
        
        /* Load the library */
        if ((LibHandle = cssm_LoadLibrary (szModulePath)) == NULL) {
			// error is set by calee 
			dwRtn = CSSM_FAIL;
            goto exit;
        }

        pfnAddInAuthenticate = cssm_GetProcAddress(LibHandle, "AddInAuthenticate");
        if(pfnAddInAuthenticate != NULL)
		{
			if ((( (ADDIN_AUTH_FUNC_PTR)
					pfnAddInAuthenticate)("CSSM32", szCSSMPath)) == CSSM_FAIL)
			{
				CSSM_SetError (&cssm_GUID, CSSM_ATTACH_FAIL);
				dwRtn = CSSM_FAIL;
				goto exit;
			}
		}

        if ((dwRtn = cssm_GetModuleRecordByGUID (pModuleGUID, &pTempRecord)) != CSSM_FAIL) {
            char regKey[MAX_REG];
            char ID[MAX_REG];

            dwRtn = cssm_IncrementAddInAppMemory (pTempRecord, &tempHandle, pMemoryFunc, SubServiceID,
                                          SubServiceFlags, Application, Notification);
			if (dwRtn != CSSM_OK)	
			goto exit;

            pTempRecord->LibHandle = LibHandle;
            pTempRecord->AddinInitialized = FALSE;
            pTempRecord->MultiTaskMutex = NULL;

            /* Generate the registry Section for the add in information */
            strcpy (regKey, CSSMSECTION);
            cssm_GUIDToStr (pModuleGUID, ID);
            strcat (regKey, ID);

			// Build unique mutex name
			memset(mutexName, 0, BUFSIZE);  
			sprintf(mutexName,"%s%d","IBMADDIN", tempHandle);

			dwRtn = cssm_RegReadBinary (regKey, "Flags", &flags,sizeof (CSSM_MODULE_FLAGS));  
			if (dwRtn != CSSM_OK)  {
				/* error is set */
				goto exit;
			}
			pTempRecord->ThreadSafe =  (flags & CSSM_MODULE_THREADSAFE) ? CSSM_TRUE : CSSM_FALSE;

        } else {
			/* module not loaded */
			dwRtn = CSSM_FAIL;
            goto exit;
		}
    }/*end cssm_GetModuleRecordByGUID*/

	/* Found an entry for this GUID */
    if(!pTempRecord->ThreadSafe)
        if(pTempRecord->MultiTaskMutex == NULL)
            pTempRecord->MultiTaskMutex = cssm_CreateMutex(mutexName);	

    if (!pTempRecord->AddinInitialized) {
        /* Do the Initialzation only the first time the dll is loaded. */
        CSSM_REGISTRATION_INFO_PTR pCallBack;
        dwRtn = CSSM_FAIL;
        pCallBack  = cssm_GetModuleCallBackByHandle (tempHandle);
        if (pCallBack)
        {
            dwRtn = CSSM_OK;

			/* NOTE that here we do not need to protect against non-threadsafe */
			/* addins - since this is the first Attach and it is locked by hCssmAddinsMutex */

            if (eventType != CSSM_EVENT_INFOATTACH)
            {
                if (pCallBack->Initialize)
                {
                    dwRtn = pCallBack->Initialize (tempHandle, pVersion->Major, pVersion->Minor);
                }
                if(dwRtn == CSSM_OK) {
                    pTempRecord->AddinInitialized = TRUE;
                    if (pCallBack->EventNotify)
                        dwRtn = pCallBack->EventNotify(tempHandle,eventType,0);
                }
            }
			else if (eventType == CSSM_EVENT_INFOATTACH)	
            {
                if (pCallBack->Initialize)
                {
					uint32	Major, Minor;

					char regKey[MAX_REG];
					char ID[MAX_REG];

		            strcpy (regKey, CSSMSECTION);
				    cssm_GUIDToStr (pModuleGUID, ID);
					strcat (regKey, ID);

					dwRtn =  cssm_RegReadVersion(regKey, "Version", &Major, &Minor);

					if(dwRtn == CSSM_OK)
						dwRtn = pCallBack->Initialize (tempHandle, Major, Minor);
					else
						goto exit;	

					if(dwRtn == CSSM_OK)
					{
						if (pCallBack->EventNotify)
							dwRtn = pCallBack->EventNotify(tempHandle,eventType,0);
					}
					else
						goto exit;
				}
            }												
        } else {  
			/* bad luck */
			CSSM_SetError(&cssm_GUID, CSSM_CSP_INTERNAL_ERROR);
			goto exit;
		}

    } else {
        /* addin already initialized - notify addin of new attach */
        if (eventType != CSSM_EVENT_INFOATTACH) {
            CSSM_REGISTRATION_INFO_PTR pCallBack;

			// Fail only if an addin has event notify function and
			// the call to it fails
            dwRtn = CSSM_OK;

            pCallBack  = cssm_GetModuleCallBackByHandle (tempHandle);

            if (pCallBack) {

                if (pCallBack->EventNotify) {

					/* notice that the second parameter - addin type - is 0; for as it*/
					/* turns out neither cssm_GetMultitaskMutexHandle() nor */
					/* cssm_CheckThreadSafe() needs it - they just look at the handle */
					if( cssm_CheckThreadSafe(tempHandle, 0) == CSSM_FALSE) {
						dwRtn = cssm_LockMutex(cssm_GetMultitaskMutexHandle (tempHandle, 0),CSSM_INFINITE_WAIT);
						if(dwRtn != CSSM_MUTEX_LOCKED) {
							// cssm error is set
							goto exit;
						}
					}

                    dwRtn = pCallBack->EventNotify (tempHandle,eventType,0);

					/* notice that the second parameter - addin type - is 0; for as it*/
					/* turns out neither cssm_GetMultitaskMutexHandle() nor */
					/* cssm_CheckThreadSafe() needs it - they just look at the handle */
					if(cssm_CheckThreadSafe (tempHandle, 0) == CSSM_FALSE) {
						dwRtn = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (tempHandle,0));
						if (dwRtn != CSSM_MUTEX_UNLOCKED) {
							// cssm error is set
							goto exit;
						} else {
							dwRtn = CSSM_OK;
						}
					}

				}	/* if (pCallBack->EventNotify) */

            }	/* if (pCallBack) */

        }	/* if (eventType != CSSM_EVENT_INFOATTACH) */
    }

exit:
    /* Check result from Initialize */
    if (dwRtn != CSSM_OK)
	{
		if (tempHandle) {	

			CSSM_ERROR preserve_error, *preserve_error_ptr = NULL;

			/* preserve the error set by the CSP's Initialize function in */
			/* anticipation of cssm_AddInDetach() possibly resetting it */
			preserve_error_ptr = CSSM_GetError();
			if (preserve_error_ptr) {
				memcpy((char *)&preserve_error, (char *)preserve_error_ptr,
					sizeof(CSSM_ERROR));
			}

			cssm_AddInDetach (tempHandle, detachEventType);

			/* restore the error set by the CSP's Initialize function prior */
			/* to the above call to cssm_AddInDetach() */
			if (preserve_error_ptr) {
				CSSM_SetError(&preserve_error.guid, preserve_error.error);
			}

			tempHandle = 0;
#ifdef		_DEBUG
			OutputDebugString("Error in CSSM::ModuleAttach's Cleanup\n");
#endif
		}
    }

    if(hCssmAddinMutex != NULL) {
        if (cssm_UnlockMutex (hCssmAddinMutex) != CSSM_MUTEX_UNLOCKED) {
			// cssm error is set
			tempHandle = 0;
		}
	}
    return(tempHandle);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_DeleteModuleRecord
 *
 *Description:
 *   Deletes internal structure associated with the add-in module
 *
 *Parameters:
 *   AddInType - add-in type identifier
 *   GUID - guid of the add-in module
 *
 *Returns:
 *  CSSM_FAIL - unable to delete internal add-in record
 *  CSSM_OK - add-in record is removed
 *
 *----------------------------------------------------------------*/
CSSM_RETURN cssm_DeleteModuleRecord (CSSM_GUID_PTR GUID)
{
    cssm_INTERNALMODULELIST_PTR tempListPtr, PriorPtr;
    CSSM_RETURN dwRtn = CSSM_OK;

	uint32 ii; 

    /* Interate through the list looking for the AddIn */

    tempListPtr = ModuleListHead;
    PriorPtr = NULL;

    while (tempListPtr) {
        if (GUIDcmp (GUID, tempListPtr->GUID) == 0) {
            cssm_INTERNALMODULELIST_PTR deletePtr = tempListPtr;

            if (PriorPtr == NULL) {
                tempListPtr = tempListPtr->Next;
                if (tempListPtr == NULL) {
                    ModuleListHead = NULL;
                    ModuleListTail = NULL;
                } else
                    ModuleListHead = tempListPtr;
            } else {
                PriorPtr->Next = tempListPtr->Next;
                if (tempListPtr->Next == NULL) {
                    ModuleListTail = PriorPtr;
                }
            }


			for (ii = 0; ii < deletePtr->AddInJT->NumberOfServiceTables; ii++)
			{
				cssm_free(deletePtr->AddInJT->Services[ii].ServiceFuncs, 0);
			}

			cssm_free(deletePtr->AddInJT->Services, 0);

            cssm_free (deletePtr->AddInJT, 0);
            cssm_free (deletePtr, 0);
            return(CSSM_OK);
        } else {
            PriorPtr = tempListPtr;
            tempListPtr = tempListPtr->Next;
        }
    }

    return(CSSM_OK);
}

/*-----------------------------------------------------------------------
 *
 *Name: cssm_AddInDetach
 *
 *Description:
 * Used to implement garbage collection on the loaded AddIns. Whenever
 * the UnloadAddInByHandle function is called, it decrements the reference
 * count on the library. When the reference count is reduced to zero,
 * the library is automatically unloaded.
 *
 *Parameters:
 * record(input) - Internal tracking record pointer of the AddIn that
 *  should have the reference count decreased.
 *
 *Returns:
 * CSSM_OK - Reference incremented.
 * CSSM_NO_REFERENCES - A blank record was passed
 *---------------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_AddInDetach (CSSM_HANDLE AddInHandle,
                                      CSSM_EVENT_TYPE eventType)
{
    CSSM_RETURN dwRtn;
    cssm_INTERNALMODULELIST_PTR AddInRecord;
    cssm_INTERNALMEMORYJT_PTR HandleInfo, TempInfo = NULL;
    
    if ((dwRtn = cssm_GetModuleByHandle (AddInHandle, NULL, &AddInRecord)) != CSSM_OK) {
        CSSM_SetError (&cssm_GUID, CSSM_INVALID_ADDIN_HANDLE);
        return(dwRtn);
    }

    HandleInfo = AddInRecord->AppMemory;
    while (HandleInfo != NULL) {
        if (AddInHandle == HandleInfo->Handle) {
            CSSM_REGISTRATION_INFO_PTR CallBack = NULL;

            /* free library when no one ia attach to it */
            if (TempInfo == NULL && HandleInfo->Next == NULL) {
                dwRtn = CSSM_FAIL;
                /* callback to add-in for version check */
                CallBack  = cssm_GetModuleCallBackByHandle (AddInHandle);

                /* Make sure that function structure and
                   function pointer is valid */
                if (CallBack) {

					/* notice that the second parameter - addin type - is 0; for as it*/
					/* turns out neither cssm_GetMultitaskMutexHandle() nor */
					/* cssm_CheckThreadSafe() needs it - they just look at the handle */
					if( cssm_CheckThreadSafe(AddInHandle, 0) == CSSM_FALSE) {
						dwRtn = cssm_LockMutex(cssm_GetMultitaskMutexHandle (AddInHandle, 0),CSSM_INFINITE_WAIT);
						if(dwRtn != CSSM_MUTEX_LOCKED) {
							// cssm error is set
							return(dwRtn);
						}
					}

					if (CallBack->EventNotify)
                        dwRtn = CallBack->EventNotify(AddInHandle,eventType,0);

                    if (CallBack->Terminate)
                        dwRtn = CallBack->Terminate (AddInHandle);

 					/* notice that the second parameter - addin type - is 0; for as it*/
					/* turns out neither cssm_GetMultitaskMutexHandle() nor */
					/* cssm_CheckThreadSafe() needs it - they just look at the handle */
					if(cssm_CheckThreadSafe (AddInHandle, 0) == CSSM_FALSE) {
						dwRtn = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (AddInHandle,0));
						if (dwRtn != CSSM_MUTEX_UNLOCKED) {
							// cssm error is set
							return(dwRtn);
						} else {
							dwRtn = CSSM_OK;
						}
					}

				}	/* if (CallBack) */

                if (dwRtn == CSSM_OK) {
                    /* found handle now update list */
                    if (TempInfo == NULL)
                       AddInRecord->AppMemory = HandleInfo->Next;
                    else
                       TempInfo->Next = HandleInfo->Next;

                    /* free memory associated with handle */
                    if(HandleInfo->MemoryFunctions != NULL)
                        cssm_free(HandleInfo->MemoryFunctions,0);
                    cssm_free (HandleInfo, 0);
					if (AddInRecord->MultiTaskMutex) {
						cssm_CloseMutex(AddInRecord->MultiTaskMutex);
					}

                    cssm_FreeLibrary(AddInRecord->LibHandle);
                    cssm_DeleteModuleRecord (&AddInRecord->GUID);
                }
            } else {
                /* callback to add-in for version check */
                CallBack  = cssm_GetModuleCallBackByHandle (AddInHandle);

                /* Make sure that function structure and
                   function pointer is valid */
                if (CallBack) {

					if (CallBack->EventNotify) {

						/* notice that the second parameter - addin type - is 0; for as it*/
						/* turns out neither cssm_GetMultitaskMutexHandle() nor */
						/* cssm_CheckThreadSafe() needs it - they just look at the handle */
						if( cssm_CheckThreadSafe(AddInHandle, 0) == CSSM_FALSE) {
							dwRtn = cssm_LockMutex(cssm_GetMultitaskMutexHandle (AddInHandle, 0),CSSM_INFINITE_WAIT);
							if(dwRtn != CSSM_MUTEX_LOCKED) {
								// cssm error is set
								return(dwRtn);
							}
						}

                        CallBack->EventNotify(AddInHandle,eventType,0);

 						/* notice that the second parameter - addin type - is 0; for as it*/
						/* turns out neither cssm_GetMultitaskMutexHandle() nor */
						/* cssm_CheckThreadSafe() needs it - they just look at the handle */
						if(cssm_CheckThreadSafe (AddInHandle, 0) == CSSM_FALSE) {
							dwRtn = cssm_UnlockMutex(cssm_GetMultitaskMutexHandle (AddInHandle,0));
							if (dwRtn != CSSM_MUTEX_UNLOCKED) {
								// cssm error is set
								return(dwRtn);
							} else {
								dwRtn = CSSM_OK;
							}
						}

					}	/* if (CallBack->EventNotify) */

                }

                if (TempInfo != NULL)
                    TempInfo->Next = HandleInfo->Next;
                else
                    AddInRecord->AppMemory = HandleInfo->Next;

				cssm_free(HandleInfo->MemoryFunctions, 0);	
                cssm_free(HandleInfo, 0);

                return(CSSM_OK);
            }

            return(CSSM_OK);
        } else {
            TempInfo = HandleInfo;
            HandleInfo = HandleInfo->Next;
        }
    }

    CSSM_SetError (&cssm_GUID, CSSM_INVALID_ADDIN_HANDLE);
    return(CSSM_FAIL);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_RemoveAddInRecord
 *
 *Description:
 *   Remove the internal add-in record structure
 *
 *Parameters:
 *   GUID - guid of the add-in module
 *   AddInType - add-in type identifier
 *
 *Returns:
 *  CSSM_FAIL - CSSM unable remove add-in record
 *  CSSM_OK - add-in record is removed
 *
 *----------------------------------------------------------------*/
CSSM_RETURN CSSMAPI cssm_RemoveAddInRecord (const CSSM_GUID_PTR GUID)

{
    cssm_INTERNALMODULELIST_PTR tempListPtr;
    cssm_INTERNALMEMORYJT_PTR HandleInfo, TempInfo;
    sint32 AddInFound = 0;

    /* Interate through the list looking for the AddIn */

    tempListPtr = ModuleListHead;

    while (tempListPtr && !AddInFound) {
        if (GUIDcmp (GUID,tempListPtr->GUID) == 0) {
            AddInFound = 1;
        } else {
            tempListPtr = tempListPtr->Next;
        }
    }

    if (!AddInFound) {
        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
        return(CSSM_FAIL);
/* Add in not loaded */
    }

    /* Free the memory resources */
    HandleInfo = tempListPtr->AppMemory;
    if (HandleInfo != NULL) {
        while (HandleInfo != NULL) {
            TempInfo = HandleInfo->Next;
            cssm_free (HandleInfo, 0);
            HandleInfo = TempInfo;
        }
    }

    /* Unlink the record */
    cssm_DeleteModuleRecord (GUID);

    return(CSSM_OK);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_FindMemory
 *
 *Description:
 *   Find the meomory functions associated with the add-in handle
 *   The caller does not lock the addin list.
 *   It is called from cssm_InsertContext and error handling in CL.
 *
 *Parameters:
 *   handle - handle of add-in module
 *   AddInHead - first entry in the add-in record
 *
 *Returns:
 *  Null - CSSM unable locate the memory functions
 *  non Null - pointer to memory functions
 *
 *----------------------------------------------------------------*/
cssm_INTERNALMEMORYJT_PTR cssm_FindMemory (CSSM_HANDLE handle,
                                           cssm_INTERNALMODULELIST_PTR AddInHead)
{
    cssm_INTERNALMODULELIST_PTR TempAddIn = NULL;
    cssm_INTERNALMEMORYJT_PTR TempLst = NULL;
	CSSM_BOOL done = CSSM_FALSE;

	// it would be nice to lock
    if(hCssmAddinMutex != NULL) {
        if(cssm_LockMutex (hCssmAddinMutex, CSSM_INFINITE_WAIT) != CSSM_MUTEX_LOCKED) {
            // cssm error is set
            return(NULL);
        }
    } else {
        CSSM_SetError(&cssm_GUID,CSSM_INVALID_MUTEX_PTR);
        return(NULL);
    }

	TempAddIn = AddInHead;
    if (TempAddIn == NULL)
        goto exit;

    while (TempAddIn) {
        TempLst = TempAddIn->AppMemory;
        while (TempLst) {
            if (TempLst->Handle == handle) {
				done = CSSM_TRUE;
				break;
			}
            TempLst = TempLst->Next;
        }

		if (done == CSSM_TRUE) break;
        TempAddIn = TempAddIn->Next;
    }

exit:
	if(hCssmAddinMutex != NULL) {
		if (cssm_UnlockMutex (hCssmAddinMutex) != CSSM_MUTEX_UNLOCKED) {
			// cssm error is set
			return(NULL);
		}
	}
    return(TempLst);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_GetMemory
 *
 *Description:
 *   Locate the memory functions of a given handle
 *
 *Parameters:
 *   handle - handle of add-in module
 *
 *Returns:
 *  Null - CSSM unable locate the memory functions
 *  non Null - pointer to memory functions
 *
 *----------------------------------------------------------------*/
CSSM_API_MEMORY_FUNCS_PTR CSSMAPI cssm_GetMemory (CSSM_HANDLE handle)
{
    cssm_INTERNALMEMORYJT_PTR mem_ptr = NULL;

    /* look first at cache mem ptr */

    if (cache_mem_ptr) {
        if (!IsBadReadPtr (cache_mem_ptr, sizeof (cache_mem_ptr)))
            if (cache_mem_ptr->Handle == handle)
                return(cache_mem_ptr->MemoryFunctions);
    }

    /* look for memory functions in all the attaches */
    if ((mem_ptr = cssm_FindMemory (handle, ModuleListHead)) == NULL) {
        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
        return(NULL);
    }

    cache_mem_ptr = mem_ptr;
    return(cache_mem_ptr->MemoryFunctions);
}

/*---------------------------------------------------------------
 *
 *Name: cssm_GetHandleInfo
 *
 *Description:
 *   Locate the information about a given handle and return
 *   the proper CSSM_HANDLEINFO structure.
 *
 *Parameters:
 *   handle - handle of add-in module
 *
 *Returns:
 *  Null - CSSM unable locate the memory functions
 *  non Null - pointer to memory functions
 *
 *----------------------------------------------------------------*/
CSSM_HANDLEINFO_PTR cssm_GetHandleInfo(CSSM_HANDLE hModule) {
    CSSM_HANDLEINFO_PTR handleInfo;
    cssm_INTERNALMEMORYJT_PTR infoPtr;

        /* look for memory functions in all the attaches */

    if ((infoPtr = cssm_FindMemory (hModule, ModuleListHead)) == NULL) {
        CSSM_SetError (&cssm_GUID, CSSM_INVALID_ADDIN_HANDLE);
        return(NULL);
    }

    if ((handleInfo =
        infoPtr->MemoryFunctions->malloc_func(sizeof(CSSM_HANDLEINFO),
                                  infoPtr->MemoryFunctions->AllocRef)) == NULL) {
        CSSM_SetError(&cssm_GUID,CSSM_MEMORY_ERROR);
        return(NULL);
    }

    handleInfo->SubServiceID = infoPtr->SubServiceID;
    handleInfo->SessionFlags = infoPtr->SubServiceFlags;
    handleInfo->ApplicationContext = infoPtr->Application;
    handleInfo->Callback = infoPtr->Notification;

    return(handleInfo);
}

CSSM_SERVICE_MASK CSSMAPI cssm_GetUsageMask (CSSM_HANDLE ModuleHandle)
{
    cssm_INTERNALMODULELIST_PTR tempRecord;
    uint32 SubServiceID;

    if (cssm_GetModuleByHandle (ModuleHandle, &SubServiceID, &tempRecord) != CSSM_OK) {
        CSSM_SetError (&cssm_GUID, CSSM_INVALID_ADDIN_HANDLE);
        return(0);
    }

    return(tempRecord->ServiceSummary);
}

CSSM_GUID_PTR CSSMAPI cssm_GetGUIDFromHandle (CSSM_HANDLE ModuleHandle)
{
    cssm_INTERNALMODULELIST_PTR tempRecord;
    uint32 SubServiceID;
    CSSM_GUID_PTR Guid;
    sint16 i;

    if (cssm_GetModuleByHandle (ModuleHandle, &SubServiceID, &tempRecord) != CSSM_OK) {
        CSSM_SetError (&cssm_GUID, CSSM_INVALID_ADDIN_HANDLE);
        return(NULL);
    }

    if ((Guid = app_malloc (sizeof (CSSM_GUID), memRef)) == NULL) {
        CSSM_SetError (&cssm_GUID, CSSM_MEMORY_ERROR);
        return(NULL);
    }

    /* copy the guid to return pointer */
    Guid->Data1 = tempRecord->GUID.Data1;
    Guid->Data2 = tempRecord->GUID.Data2;
    Guid->Data3 = tempRecord->GUID.Data3;

    for (i=0; i<8; i++)
        Guid->Data4[i] = tempRecord->GUID.Data4[i];

    return(Guid);
}

void cssm_CleanUp (void)
{
	cssm_INTERNALMODULELIST_PTR tempListPtr;

	/*  free all context information */
	cssm_CleanContextTable();

    /*  Free all add-in information. No need to lock since the caller is DLLMain().
	 */
    tempListPtr = ModuleListHead;
    while (tempListPtr) {
        if (tempListPtr->AddInJT->Terminate) {
            cssm_INTERNALMEMORYJT_PTR HandleInfo = tempListPtr->AppMemory;

            if (HandleInfo != NULL) {
                /* forcing a detach as CSSM goes down */
                cssm_AddInDetach (HandleInfo->Handle, CSSM_EVENT_DETACH);
            }
        }

        tempListPtr = ModuleListHead;
    }

    return;
}
