/*----------------------------------------------------------------------- * File: MAF_DLLMAIN.C * * Copyright (c) 1995-2000 Intel Corporation. All rights reserved. *----------------------------------------------------------------------- */ /* * OpenVMS History * * 24-Sep-2002 Carol Kelly * o Add VMS to Posix ifdef * 13-Sep-2002 Carol Kelly * o Merge in V3_14 changes * 02-Nov-1999 Carol Kelly * o Merge in changes from Unix code base * */ #include "maf_include.h" /* Microsoft specific headers for debug heap usage */ #if defined(_DEBUG) && defined(WIN32) #include /* This header needed to use the debug heap functions * directly to change the apparent calling location. */ #endif #ifdef VMS static int _init(); static int _fini(); #endif /* check the validity of config.h */ #ifndef ADDIN_GUID_INITIALIZER #error ADDIN_GUID_INITIALIZER not defined in maf_config.h #endif #ifndef ADDIN_NAME #error ADDIN_NAME not defined in maf_config.h #endif #ifndef ADDIN_VERSION_MAJOR #error ADDIN_VERSION_MAJOR not defined in maf_config.h #endif #ifndef ADDIN_VERSION_MINOR #error ADDIN_VERSION_MAJOR not defined in maf_config.h #endif #ifndef ADDIN_THREAD_SAFE #error ADDIN_THREAD_SAFE not defined in maf_config.h #endif #ifndef ADDIN_NEED_LOAD_WRITER_LOCK #error ADDIN_NEED_LOAD_WRITER_LOCK not defined in maf_config.h #endif #ifndef ADDIN_NEED_ATTACH_WRITER_LOCK #error ADDIN_NEED_ATTACH_WRITER_LOCK not defined in maf_config.h #endif #ifndef ADDIN_NEED_ADDIN_LOAD_STRUCT #error ADDIN_NEED_ADDIN_LOAD_STRUCT not defined in maf_config.h #endif #ifndef ADDIN_NEED_ADDIN_ATTACH_STRUCT #error ADDIN_NEED_ADDIN_ATTACH_STRUCT not defined in maf_config.h #endif #ifndef ADDIN_IS_VALID_SUBSERVICE #error ADDIN_IS_VALID_SUBSERVICE not defined in maf_config.h #endif /************************************************************************* ************************************************************************* ***** Global constants for MAF and SP implementation ******************** ************************************************************************* *************************************************************************/ const CSSM_GUID ADDIN_GUID = ADDIN_GUID_INITIALIZER; /************************************************************************* ************************************************************************* ***** Addin Memory Functions ******************************************** ************************************************************************* *************************************************************************/ /* Addin's local memory allocation functions. These functions match the * prototypes required to build a CSSM_API_MEMORY_FUNCS structure for * attaching to other modules. */ void* CSSMAPI _Addin_malloc( uint32 size, void *AllocRef #ifdef CSSM_MEMTRACK_ON , const char *szFilename, uint32 u32LineNumber #endif ) { #if defined(_DEBUG) && defined(CSSM_MEMTRACK_ON) && defined(WIN32) return _malloc_dbg( size, _NORMAL_BLOCK, szFilename, u32LineNumber ); #else return malloc( size ); #endif } void* CSSMAPI _Addin_realloc( void *Ptr, uint32 size, void *AllocRef #ifdef CSSM_MEMTRACK_ON , const char *szFilename, uint32 u32LineNumber #endif ) { #if defined(_DEBUG) && defined(CSSM_MEMTRACK_ON) && defined(WIN32) return _realloc_dbg( Ptr, size, _NORMAL_BLOCK, szFilename, u32LineNumber ); #else return realloc( Ptr, size ); #endif } void CSSMAPI _Addin_free( void *Ptr, void *AllocRef #ifdef CSSM_MEMTRACK_ON , const char *szFilename, uint32 u32LineNumber #endif ) { #if defined(_DEBUG) && defined(CSSM_MEMTRACK_ON) && defined(WIN32) _free_dbg( Ptr, _NORMAL_BLOCK ); #else free( Ptr ); #endif } void* CSSMAPI _Addin_calloc( uint32 size, uint32 count, void* AllocRef #ifdef CSSM_MEMTRACK_ON , const char *szFilename, uint32 u32LineNumber #endif ) { #if defined(_DEBUG) && defined(CSSM_MEMTRACK_ON) && defined(WIN32) return _calloc_dbg( size, count, _NORMAL_BLOCK, szFilename, u32LineNumber ); #else return calloc( size, count ); #endif } /* "Global" table of memory functions to be used by an addin to attach to * other service providers. */ const CSSM_API_MEMORY_FUNCS Addin_APIMemFuncs = { _Addin_malloc, _Addin_free, _Addin_realloc, _Addin_calloc, 0 }; /* Application's memory allocation functions */ void* CSSMAPI _App_Malloc( CSSM_MODULE_HANDLE AddinHandle, uint32 size #ifdef CSSM_MEMTRACK_ON , const char *szFilename, uint32 u32LineNumber #endif ) { const MAF_MODULE_ATTACH_TRACKER *pTracker = Addin_GetAttachTracker(); if ( pTracker == NULL ) { /* Did someone forget to call Addin_SPIBegin? */ return NULL; } return pTracker->AppUpcalls.malloc_func( AddinHandle, size #ifdef CSSM_MEMTRACK_ON , szFilename, u32LineNumber #endif ); } void* CSSMAPI _App_Realloc( CSSM_MODULE_HANDLE AddinHandle, void *Ptr, uint32 size #ifdef CSSM_MEMTRACK_ON , const char * szFilename, uint32 u32LineNumber #endif ) { const MAF_MODULE_ATTACH_TRACKER *pTracker = Addin_GetAttachTracker(); if ( pTracker == NULL ) { /* Did someone forget to call Addin_SPIBegin? */ return NULL; } return pTracker->AppUpcalls.realloc_func( AddinHandle, Ptr, size #ifdef CSSM_MEMTRACK_ON , szFilename, u32LineNumber #endif ); } void CSSMAPI _App_Free( CSSM_MODULE_HANDLE AddinHandle, void *Ptr #ifdef CSSM_MEMTRACK_ON , const char *szFilename, uint32 u32LineNumber #endif ) { const MAF_MODULE_ATTACH_TRACKER *pTracker = Addin_GetAttachTracker(); if ( pTracker == NULL ) { /* Did someone forget to call Addin_SPIBegin? */ return; } pTracker->AppUpcalls.free_func( AddinHandle, Ptr #ifdef CSSM_MEMTRACK_ON , szFilename, u32LineNumber #endif ); } void* CSSMAPI _App_Calloc( CSSM_MODULE_HANDLE AddinHandle, uint32 size, uint32 count #ifdef CSSM_MEMTRACK_ON , const char * szFilename, uint32 u32LineNumber #endif ) { const MAF_MODULE_ATTACH_TRACKER *pTracker = Addin_GetAttachTracker(); if ( pTracker == NULL ) { /* Did someone forget to call Addin_SPIBegin? */ return NULL; } return pTracker->AppUpcalls.calloc_func( AddinHandle, size, count #ifdef CSSM_MEMTRACK_ON , szFilename, u32LineNumber #endif ); } /************************************************************************* ************************************************************************* ***** state tracking definitions and declarations *********************** ************************************************************************* *************************************************************************/ /* Mutex used to protect service provider resource initialization and * destruction. This mutex is locked BEFORE checking to see if the SP is * initialized (indicated by s_bInitialized). If not, the lock is held * throughout the load process. Otherwise, the lock is only held until the * the proper level of use protection can be aquired on the SWMR lock * s_hUseLock. */ #if defined (POSIX) || defined (VMS) #ifdef PORT_STATIC_MUTEX_INITIALIZER #undef PORT_STATIC_MUTEX_INITIALIZER #endif static pthread_mutex_t s_hLoadMutex = PTHREAD_MUTEX_INITIALIZER; #define PORT_STATIC_MUTEX_INITIALIZER (&s_hLoadMutex) #endif /* POSIX */ static PORT_MUTEX_HANDLE s_hLoadLock = NULL; #if defined (POSIX) || defined (VMS) static pthread_mutex_t s_LoadMutex; #endif /* Indicates whether library initialization has taken place. */ static CSSM_BOOL s_bInitialized = CSSM_FALSE; /* Macro to abstract initialization indicator */ #define addin_IsInitialized() s_bInitialized /* Thread local storage index value for keeping track of the operating * context of the SPI call (which CSSM called it). */ static PORT_TLS_INDEX s_hThreadContext = PORT_INVALID_TLS_INDEX; /* Single-writer/multiple-reader lock used to enforce initialization order * on public interfaces and to insure that the module unload does not take * place before all SPI calls are done servicing. */ static cssm_SWMRLock s_hUseLock = PORT_SWMR_LOCK_INITIALIZER; /* List for maintaining a record of the CSSMs that have loaded this module. */ static MAF_LIST_COLLECTION s_lcLoadList; /* List for maintaining a record of the attaches that have been made to * this module by all CSSMs. */ static MAF_LIST_COLLECTION s_lcAttachList; /************************************************************************* ************************************************************************* ***** Begin internal function declarations ****************************** ************************************************************************* *************************************************************************/ static int MLC_FASTCALL addin_FindLoadByGUID( const MAF_MODULE_LOAD_TRACKER *pLoadTracker, /* void *pItem */ const CSSM_GUID *pGuid /* void *pKey */ ); static int MLC_FASTCALL addin_FindAttachByHandle( const MAF_MODULE_ATTACH_TRACKER *pAttachTracker, /* void *pItem */ const CSSM_MODULE_HANDLE *pHandle /* void *pKey */ ); /* Validates the identity of a MAF_MODULE_ATTACH_TRACKER structure */ #ifdef _DEBUG /* Debug version */ #define ATTACH_TRACKER_MAGIC_NUMBER( pTracker ) (~((unsigned long)(pTracker))) static void ATTACH_TRACKER_ASSERT_VALID( const MAF_MODULE_ATTACH_TRACKER *pTracker ) { assert( !port_IsBadReadPtr( pTracker, sizeof(MAF_MODULE_ATTACH_TRACKER) ) ); assert( pTracker->debug_MagicNumber == ATTACH_TRACKER_MAGIC_NUMBER( pTracker ) ); } #else /* Release version */ #define ATTACH_TRACKER_MAGIC_NUMBER( pTracker ) #define ATTACH_TRACKER_ASSERT_VALID( pTracker ) #endif /* Validates the identity of a MAF_MODULE_LOAD_TRACKER structure */ #ifdef _DEBUG /* Debug version */ #define LOAD_TRACKER_MAGIC_NUMBER( pTracker ) ((unsigned long)(pTracker) - 5123) static void LOAD_TRACKER_ASSERT_VALID( const MAF_MODULE_LOAD_TRACKER *pTracker ) { assert( !port_IsBadReadPtr( pTracker, sizeof(MAF_MODULE_LOAD_TRACKER) ) ); assert( pTracker->debug_MagicNumber == LOAD_TRACKER_MAGIC_NUMBER( pTracker ) ); } #else /* Release Version */ #define LOAD_TRACKER_ASSERT_VALID( pTracker ) #define LOAD_TRACKER_MAGIC_NUMBER( pTracker ) #endif /* Sets the current operating context of the running thread */ #ifdef _DEBUG void addin_SetCurrentAttach( MAF_MODULE_ATTACH_TRACKER *pAttachTracker ) { ATTACH_TRACKER_ASSERT_VALID( pAttachTracker ); port_SetTlsValue( s_hThreadContext, (void *)pAttachTracker ); } #else #define addin_SetCurrentAttach( pAttachTracker ) \ port_SetTlsValue( s_hThreadContext, (void *)pAttachTracker ) #endif /* Clears the current operating context of the running thread */ #define addin_ClearCurrentAttach() \ port_SetTlsValue( s_hThreadContext, NULL ); /* Validate that the operating context is well known... none */ #define ASSERT_NO_CURRENT_ATTACH() \ { \ void *TempTlsValue = NULL; \ port_GetTlsValue( s_hThreadContext, &TempTlsValue ); \ assert( TempTlsValue == NULL ); \ } /* Abstracts the operation of synchronizing access to the service provider. * Must be called when entering and SPI. Returns a CSSM_OBJECT value defined * in cssmport.h. */ #if (ADDIN_THREAD_SAFE) #define ADDIN_LOCK_FOR_SPI() \ cssm_SWMRLockWaitToRead( &s_hUseLock, CSSM_INFINITE_WAIT ) #else #define ADDIN_LOCK_FOR_SPI() \ cssm_SWMRLockWaitToWrite( &s_hUseLock, CSSM_INFINITE_WAIT ) #endif /* Abstracts the operation of synchronizing access to the service provider. * Must be called when leaving an SPI. Does not return a value. */ #if (ADDIN_THREAD_SAFE) #define ADDIN_UNLOCK_FROM_SPI() \ cssm_SWMRLockDoneReading( &s_hUseLock ) #else #define ADDIN_UNLOCK_FROM_SPI() \ cssm_SWMRLockDoneWriting( &s_hUseLock ) #endif /************************************************************************* ************************************************************************* ***** Exported Functions ************************************************ ************************************************************************* *************************************************************************/ /* Lock type constants for SPI handlers */ #if (ADDIN_NEED_LOAD_WRITER_LOCK) #define _MAF_LOAD_LOCK_TYPE MLC_WRITE_LOCK #else #define _MAF_LOAD_LOCK_TYPE MLC_READ_LOCK #endif #if (ADDIN_NEED_ATTACH_WRITER_LOCK) #define _MAF_ATTACH_LOCK_TYPE MLC_WRITE_LOCK #else #define _MAF_ATTACH_LOCK_TYPE MLC_READ_LOCK #endif /*----------------------------------------------------------------------------- * Name: Addin_SPIBegin * * Description: * Function that is called at the begining of every protected interface, finds * the context (which CSSM are we talking to) and stores information in thread * local storage * * Note: SPIBegin/End operate in a multi-CSSM environment. It follows these basic steps. * * 1) Lock the module for reading to prevent the final unload * from happening while the SPI is being serviced. * 2) Find the tracking record for the given handle. This gives * the proper set of callbacks into the calling CSSM as well * as enabling strong validation of all SPI calls. * A) Get a read lock on the tracking record to prevent a * detach in another thread from taking place while the * call is being serviced. * B) Get a write lock on the tracking record fs the SPI * needs to information in the record. * 3) Get a tracking record for the CSSM that the addin handle belongs to * 4) Verify that the return address belongs to the same module * that originally attached to the addin. This prevents * another module from masquerading as the original. * 5) Perform the SPI functions. * 6) Release the locks on the tracking record and the library. * * Parameters: * AddinHandle (input) : Handle of the addin * ReturnAddress (input) : Address of the caller * * Return Code: * NULL if the function failed, otherwise a lock reference that is returned to * Addin_SPIEnd *-------------------------------------------------------------*/ CSSM_RETURN Addin_SPIBegin( CSSM_MODULE_HANDLE AddinHandle, CSSM_PROC_ADDR RetAddr, MLC_LOCK_REF *pLockRef ) { CSSM_RETURN rv = CSSM_OK; MAF_MODULE_ATTACH_TRACKER * pAttachTracker = NULL; MAF_MODULE_LOAD_TRACKER * pLoadTracker = NULL; MLC_LOCK_REF LockRef = NULL; if ( !addin_IsInitialized() ) { ERR( rv = CSSMERR_CSSM_INTERNAL_ERROR ); } else { ASSERT_NO_CURRENT_ATTACH(); /* Get a lock on the library */ if ( ADDIN_LOCK_FOR_SPI() != CSSM_OK ) { ERR( rv = CSSMERR_CSSM_INTERNAL_ERROR ); } else { /* Find the tracker for this attach */ if ( MLC_FindItem( &s_lcAttachList, (MLC_FIND_FUNC)addin_FindAttachByHandle, (void*)&AddinHandle, _MAF_ATTACH_LOCK_TYPE, &LockRef, (void**)&pAttachTracker ) != CSSM_OK ) { /* Doesn't exist. What is the CSSM thinking? */ ADDIN_UNLOCK_FROM_SPI(); ERR( rv = CSSMERR_CSSM_INVALID_ADDIN_HANDLE ); } else { ATTACH_TRACKER_ASSERT_VALID( pAttachTracker ); /* reaquire the proper lock on the load record */ if ( MLC_RelockItem( _MAF_LOAD_LOCK_TYPE, pAttachTracker->LoadLockRef, (void**)&pLoadTracker ) != CSSM_OK ) { /* Doesn't exist. What is the CSSM thinking? */ MLC_ReleaseItem( _MAF_ATTACH_LOCK_TYPE, LockRef ); pAttachTracker = NULL; ADDIN_UNLOCK_FROM_SPI(); ERR( rv = CSSMERR_CSSM_INTERNAL_ERROR ); } else { LOAD_TRACKER_ASSERT_VALID( pLoadTracker ); /* Is this the proper module manager calling us? */ if ( ( rv = Addin_CheckAddressInModule( pAttachTracker->hModuleManager, RetAddr ) ) != CSSM_OK ) { /* Someone is trying to spoof us! */ MLC_ReleaseItem( _MAF_LOAD_LOCK_TYPE, pAttachTracker->LoadLockRef ); pLoadTracker = NULL; MLC_ReleaseItem( _MAF_ATTACH_LOCK_TYPE, LockRef ); pAttachTracker = NULL; ADDIN_UNLOCK_FROM_SPI(); } else { /* Set the execution context for the thread so that we call the correct * API/SPI functions. */ addin_SetCurrentAttach( pAttachTracker ); } /* if return address check fails */ } /* if pLoadTracker == NULL */ } /* if pAttachTracker == NULL */ } /* ADDIN_LOCK_FOR_SPI != CSSM_OBJECT_LOCKED */ } /* if !s_bInitialized */ /* Set the attach lock reference for later. Clear it if there was and * error. */ if ( rv == CSSM_OK ) { *pLockRef = LockRef; } else { *pLockRef = NULL; } return rv; } /*----------------------------------------------------------------------------- * Name: Addin_SPIEnd * * Description: * Function that is called at the end of every protected interface. This function * cleans up state created by Addin_SPIBegin * * Parameters: * pLockRef (input) : lock reference returned by SPIBegin * * Return Code: * None *---------------------------------------------------------------------------*/ void Addin_SPIEnd( MLC_LOCK_REF LockRef ) { /* Done servicing the SPI. Release the library and the tracker. */ const MAF_MODULE_ATTACH_TRACKER *pTracker = Addin_GetAttachTracker(); addin_ClearCurrentAttach(); MLC_ReleaseItem( _MAF_LOAD_LOCK_TYPE, pTracker->LoadLockRef ); MLC_ReleaseItem( _MAF_ATTACH_LOCK_TYPE, LockRef ); ADDIN_UNLOCK_FROM_SPI(); } /*----------------------------------------------------------------------------- * Name: Addin_GetAttachContext * * Description: * Returns a reference, locked as specified, to the attach information * associated with AttachHandle. Use the MLC_ReleaseItem function to unlock * the context when finished. Use the Addin_GetAttachTrackerFromLock or * Addin_GetAttachDataFromLock function to access the attach context data. * * Parameters: * AttachHandle (input) : Attach handle used to lookup information. * ltLockType (input) : How to lock the context before it is returned. * pLockRef (ouput) : Pointer to a void* that will receive the value of a * lock reference. The reference is to the node containing * the requested attah information. * * Return Code: * CSSM_OK : Attach context found * CSSMERR_CSSM_INVALID_ADDIN_HANDLE : AttachHandle does not contain a valid attach * handle value. *---------------------------------------------------------------------------*/ CSSM_RETURN Addin_GetAttachContext( CSSM_HANDLE AttachHandle, MLC_LOCK_TYPE ltLockType, MLC_LOCK_REF *pLockRef ) { CSSM_RETURN rv = CSSM_OK; MAF_MODULE_ATTACH_TRACKER * pAttachTracker = NULL; /* Find the tracker for this attach */ if ( MLC_FindItem( &s_lcAttachList, (MLC_FIND_FUNC)addin_FindAttachByHandle, (void*)&AttachHandle, ltLockType, pLockRef, (void**)pAttachTracker ) != CSSM_OK ) { ERR( rv = CSSMERR_CSSM_INVALID_ADDIN_HANDLE ); } else { ATTACH_TRACKER_ASSERT_VALID( pAttachTracker ); } return rv; } #if ADDIN_NEED_ADDIN_LOAD_STRUCT /*----------------------------------------------------------------------------- * Name: Addin_GetLoadData * * Description: * Function that returns the ADDIN_LOAD_DATA structure inside the load * tracker for the current thread. Addin must call Addin_SPIBegin before calling * this function. This data should not be modified unless ADDIN_NEED_LOAD_WRITER_LOCK * is true. * * Parameters: * None. * * Return Code: * On success, a pointer to a ADDIN_LOAD_DATA, otherwise NULL *---------------------------------------------------------------------------*/ #if (ADDIN_NEED_LOAD_WRITER_LOCK == 0) const #endif ADDIN_LOAD_DATA* Addin_GetLoadData() { MAF_MODULE_LOAD_TRACKER *pTracker = (MAF_MODULE_LOAD_TRACKER *)Addin_GetLoadTracker(); if ( pTracker == NULL ) { return NULL; } return &pTracker->AddinLoadData; } #endif #if ADDIN_NEED_ADDIN_ATTACH_STRUCT /*----------------------------------------------------------------------------- * Name: Addin_GetAttachData * * Description: * Function that returns the ADDIN_ATTACH_DATA structure inside the attach * tracker for the current thread. Addin must call Addin_SPIBegin before calling * this function. This data should not be modified unless ADDIN_NEED_ATTACH_WRITER_LOCK * is true. * * Parameters: * None. * * Return Code: * On success, a pointer to a ADDIN_ATTACH_DATA, otherwise NULL *---------------------------------------------------------------------------*/ #if (ADDIN_NEED_ATTACH_WRITER_LOCK == 0) const #endif ADDIN_ATTACH_DATA* Addin_GetAttachData() { MAF_MODULE_ATTACH_TRACKER *pTracker = (MAF_MODULE_ATTACH_TRACKER *)Addin_GetAttachTracker(); if ( pTracker == NULL ) { return NULL; } return &pTracker->AddinAttachData; } /*----------------------------------------------------------------------------- * Name: Addin_GetAttachTrackerFromLock * * Description: * Returns the MAF_MODULE_ATTACH_TRACKER structure from a lock reference. * Caller must insure that the lock reference is appropriately locked. * * Parameters: * LockRef (input) : Lock reference to query. * ppAttachTracker (ouput) : Pointer that will receive the address of the * attach tracker record. * * Return Code: * CSSM_OK : Attach tracker returned. * CSSMERR_CSSM_INVALID_ADDIN_HANDLE : LockRef does not protect an attach tracker record. *---------------------------------------------------------------------------*/ CSSM_RETURN Addin_GetAttachTrackerFromLock( MLC_LOCK_REF LockRef, const MAF_MODULE_ATTACH_TRACKER **ppAttachTracker ) { CSSM_RETURN rv = CSSM_OK; const MAF_MODULE_ATTACH_TRACKER *pAttachTracker = NULL; assert( ppAttachTracker != NULL ); /* "relock" the reference with a "no lock" to get the item from the lock */ if ( MLC_RelockItem( MLC_NO_LOCK, LockRef, (void**)pAttachTracker ) != CSSM_OK ) { *ppAttachTracker = NULL; ERR( rv = CSSMERR_CSSM_INVALID_ADDIN_HANDLE ); } else { ATTACH_TRACKER_ASSERT_VALID( pAttachTracker ); /* Return the item */ *ppAttachTracker = pAttachTracker; } return rv; } /*----------------------------------------------------------------------------- * Name: Addin_GetAttachDataFromLock * * Description: * Returns the ADDIN_ATTACH_DATA structure from a lock reference. Caller must * insure that the lock reference is appropriately locked. * * Parameters: * LockRef (input) : Lock reference to query. * ppAttachData (ouput) : Pointer that will receive the address of the * attach data record. * * Return Code: * CSSM_OK : Attach tracker returned. * CSSMERR_CSSM_INVALID_ADDIN_HANDLE : LockRef does not protect an attach tracker record. *---------------------------------------------------------------------------*/ CSSM_RETURN Addin_GetAttachDataFromLock( MLC_LOCK_REF LockRef, ADDIN_ATTACH_DATA **ppAttachData ) { CSSM_RETURN rv = CSSM_OK; MAF_MODULE_ATTACH_TRACKER *pAttachTracker = NULL; assert( ppAttachData != NULL ); /* "relock" the reference with a "no lock" to get the item from the lock */ if ( MLC_RelockItem( MLC_NO_LOCK, LockRef, (void**)&pAttachTracker ) != CSSM_OK ) { *ppAttachData = NULL; ERR( rv = CSSMERR_CSSM_INVALID_ADDIN_HANDLE ); } else { ATTACH_TRACKER_ASSERT_VALID( pAttachTracker ); /* Return the item */ *ppAttachData = &pAttachTracker->AddinAttachData; } return rv; } #endif /*----------------------------------------------------------------------------- * Name: Addin_GetLoadTracker * * Description: * Function that returns the MAF_MODULE_LOAD_TRACKER structure for the current * thread. Addin must call Addin_SPIBegin before calling this function. The * structure returned should not be modified. * * Parameters: * None. * * Return Code: * On success, a pointer to a MAF_MODULE_LOAD_TRACKER, otherwise NULL *---------------------------------------------------------------------------*/ const MAF_MODULE_LOAD_TRACKER* Addin_GetLoadTracker() { const MAF_MODULE_ATTACH_TRACKER * pAttachTracker = NULL; const MAF_MODULE_LOAD_TRACKER * pLoadTracker = NULL; port_GetTlsValue( s_hThreadContext, (void**)&pAttachTracker ); if ( pAttachTracker == NULL ) { return NULL; } ATTACH_TRACKER_ASSERT_VALID( pAttachTracker ); MLC_RelockItem( MLC_NO_LOCK, pAttachTracker->LoadLockRef, (void**)&pLoadTracker ); LOAD_TRACKER_ASSERT_VALID( pLoadTracker ); return pLoadTracker; } /*----------------------------------------------------------------------------- * Name: Addin_GetAttachTracker * * Description: * Function that returns the MAF_MODULE_ATTACH_TRACKER structure for the current * thread. Addin must call Addin_SPIBegin before calling this function. The * structure returned should not be modified. * * Parameters: * None. * * Return Code: * On success, a pointer to a MAF_MODULE_ATTACH_TRACKER, otherwise NULL *---------------------------------------------------------------------------*/ const MAF_MODULE_ATTACH_TRACKER * Addin_GetAttachTracker() { const MAF_MODULE_ATTACH_TRACKER * pAttachTracker; port_GetTlsValue( s_hThreadContext, (void**)&pAttachTracker ); if ( pAttachTracker != NULL ) { ATTACH_TRACKER_ASSERT_VALID( pAttachTracker ); return pAttachTracker; } else { return NULL; } } /* Internal structure type used by the __Addin_SendEvent and * Addin_SendModuleEvent functions to pass data to the MLC_ForEach iterator. */ typedef struct _addin_send_event { CSSM_GUID ModuleGuid; uint32 uSubserviceId; CSSM_SERVICE_TYPE stServiceType; CSSM_MODULE_EVENT meEvent; } __ADDIN_SEND_EVENT; /*----------------------------------------------------------------------------- * Name: __Addin_SendEvent * * Description: * Helper function used with the MLC_ForEach interator to send the message to * all CSSMs in the list. * * Parameters: * pItem (input) - Void pointer that will be cast to a load tracker record. * pParam (input) - Void pointer that will be cast to an __ADDIN_SEND_EVENT * structure. * * Return value: * non-zero if the function succedes and the ForEach iterator should continue, * zero otherwise. *----------------------------------------------------------------------------*/ static int MLC_FASTCALL __Addin_SendEvent( const MAF_MODULE_LOAD_TRACKER *pTracker, /* void *pItem */ const __ADDIN_SEND_EVENT *pEventRec /* void *pParam */ ) { if ( !port_IsBadCodePtr( (CSSM_PROC_ADDR)pTracker->ModuleEventHandler ) ) { pTracker->ModuleEventHandler( &pEventRec->ModuleGuid, (void*)pTracker->ModuleEventHandlerCtx, pEventRec->uSubserviceId, pEventRec->stServiceType, pEventRec->meEvent ); } return 1; } /*----------------------------------------------------------------------------- * Name: Addin_SendModuleEvent * * Description: * Iterates through the load list and sends the specified message to all of * the CSSMs being tracked. * * Parameters: * uSubserviceId (input) - Subservice ID to from which the event originated. * stServiceType (input) - Service mask of the represented subservice. * meEvent (input) - Event code to send. * * Return value: * ~(CSSM_OK), if the message could not be sent * CSSM_OK, if the message was sent successfully *----------------------------------------------------------------------------*/ CSSM_RETURN Addin_SendModuleEvent( uint32 uSubserviceId, CSSM_SERVICE_TYPE stServiceType, CSSM_MODULE_EVENT meEvent ) { CSSM_RETURN rv = CSSM_OK; __ADDIN_SEND_EVENT EventStruct; /* Fill in the event structure */ EventStruct.ModuleGuid = ADDIN_GUID; EventStruct.uSubserviceId = uSubserviceId; EventStruct.stServiceType = stServiceType; EventStruct.meEvent = meEvent; rv = MLC_ForEach( &s_lcLoadList, (MLC_ITEM_ITERATOR_FUNC)__Addin_SendEvent, (void*)&EventStruct, MLC_READ_LOCK ); return rv; } CSSM_RETURN CSSMAPI Addin_CcToHandle( CSSM_CC_HANDLE Cc, CSSM_MODULE_HANDLE *pHandle ) { const MAF_MODULE_ATTACH_TRACKER *pTracker = Addin_GetAttachTracker(); ATTACH_TRACKER_ASSERT_VALID( pTracker ); return pTracker->AppUpcalls.CcToHandle_func( Cc, pHandle ); } /************************************************************************* ************************************************************************* ***** Begin attach tracker functions ************************************ ************************************************************************* *************************************************************************/ /*----------------------------------------------------------------------------- * Name: addin_AttachTrackerNew * * Description: * Creates a new MAF_MODULE_ATTACH_TRACKER instanace * * Parameters: * FuntionName (input) - Name of function to be imported * ppFunction (output) - Pointer to function retrieved * hCssm (input) - Handle to CSSM used to extract functions from * * Return value: * CSSM_FAIL, if the function pointer could not be retrieved * CSSM_OK, if the funtion pointer was retrieved successfully *----------------------------------------------------------------------------*/ static CSSM_RETURN addin_AttachTrackerNew( uint32 SubServiceID, CSSM_SERVICE_TYPE SubServiceType, CSSM_MODULE_HANDLE ModuleHandle, CSSM_KEY_HIERARCHY KeyHierarchy, const CSSM_UPCALLS *pAppUpcalls, MLC_LOCK_REF LoadLockRef, ADDIN_MODULE_HANDLE hCssm, ADDIN_MODULE_HANDLE hModuleManager, ADDIN_MODULE_HANDLE hCaller, MAF_MODULE_ATTACH_TRACKER **ppNewTracker ) { CSSM_RETURN rv = CSSM_OK; MAF_MODULE_ATTACH_TRACKER *pTracker = NULL; assert( ModuleHandle ); assert( pAppUpcalls ); assert( LoadLockRef ); pTracker = (MAF_MODULE_ATTACH_TRACKER*)Addin_malloc( sizeof(MAF_MODULE_ATTACH_TRACKER), NULL ); if ( pTracker == NULL ) { ERR( rv = CSSMERR_CSSM_MEMORY_ERROR ); } else { /* Wipe the structure */ memset( pTracker, 0, sizeof(MAF_MODULE_ATTACH_TRACKER) ); #ifdef _DEBUG /* Magic Number that is used to verify the integrity of the structure */ pTracker->debug_MagicNumber = ATTACH_TRACKER_MAGIC_NUMBER( pTracker ); #endif /* Parameter values passed by CSSM during attach */ pTracker->SubServiceID = SubServiceID; pTracker->SubServiceType = SubServiceType; pTracker->ModuleHandle = ModuleHandle; pTracker->KeyHierarchy = KeyHierarchy; pTracker->AppUpcalls = *pAppUpcalls; pTracker->LoadLockRef = LoadLockRef; pTracker->hCssm = hCssm; pTracker->hModuleManager = hModuleManager; pTracker->hCaller = hCaller; #if ADDIN_NEED_ADDIN_ATTACH_STRUCT addin_SetCurrentAttach( pTracker ); if ( ( rv = Addin_callout_AttachDataConstruct( &pTracker->AddinAttachData) ) != CSSM_OK ) { memset( pTracker, 0, sizeof(MAF_MODULE_ATTACH_TRACKER) ); Addin_free( pTracker, NULL ); pTracker = NULL; } addin_ClearCurrentAttach(); #endif } /* Set the return parameter(s) */ *ppNewTracker = pTracker; return rv; } static CSSM_RETURN addin_AttachTrackerDelete( MAF_MODULE_ATTACH_TRACKER *pTracker ) { CSSM_RETURN rv = CSSM_OK; ATTACH_TRACKER_ASSERT_VALID( pTracker ); #if ADDIN_NEED_ADDIN_ATTACH_STRUCT addin_SetCurrentAttach( pTracker ); Addin_callout_AttachDataDestroy( &pTracker->AddinAttachData ); addin_ClearCurrentAttach(); #endif memset( pTracker, 0, sizeof(MAF_MODULE_ATTACH_TRACKER) ); Addin_free( pTracker, NULL ); return rv; } /************************************************************************* ************************************************************************* ***** Begin load tracker functions ************************************** ************************************************************************* *************************************************************************/ static CSSM_RETURN addin_LoadTrackerNew( const CSSM_GUID *pGuidCSSM, CSSM_SPI_ModuleEventHandler CSSMModuleEventHandler, const void *CSSMModuleEventHandlerCtx, ADDIN_MODULE_HANDLE hCssm, MAF_MODULE_LOAD_TRACKER **ppNewTracker ) { CSSM_RETURN rv = CSSM_OK; MAF_MODULE_LOAD_TRACKER * pTracker; assert( pGuidCSSM ); pTracker = (MAF_MODULE_LOAD_TRACKER*)Addin_malloc( sizeof(MAF_MODULE_LOAD_TRACKER), NULL ); if ( pTracker == NULL ) { ERR( rv = CSSMERR_CSSM_MEMORY_ERROR ); } else { /* Wipe the load tracker structure */ memset( pTracker, 0, sizeof(MAF_MODULE_LOAD_TRACKER) ); #ifdef _DEBUG /* Magic Number that is used to verify the integrity of the structure */ pTracker->debug_MagicNumber = LOAD_TRACKER_MAGIC_NUMBER(pTracker); #endif pTracker->CssmGuid = *pGuidCSSM; pTracker->ModuleEventHandler = CSSMModuleEventHandler; pTracker->ModuleEventHandlerCtx = CSSMModuleEventHandlerCtx; pTracker->NumLoads = 1; pTracker->hCssm = hCssm; #if ADDIN_NEED_ADDIN_LOAD_STRUCT ASSERT_NO_CURRENT_ATTACH(); addin_ClearCurrentAttach(); if ( ( rv = Addin_callout_LoadDataConstruct( hCssm, &pTracker->AddinLoadData) ) != CSSM_OK ) { /* Wipe and deallocate the tracker structure */ memset( pTracker, 0, sizeof(MAF_MODULE_LOAD_TRACKER) ); Addin_free( pTracker, NULL ); pTracker = NULL; } #endif } /* Set the return parameter(s) */ *ppNewTracker = pTracker; return rv; } static CSSM_RETURN addin_LoadTrackerDelete( MAF_MODULE_LOAD_TRACKER *pTracker ) { LOAD_TRACKER_ASSERT_VALID( pTracker ); #if ADDIN_NEED_ADDIN_LOAD_STRUCT ASSERT_NO_CURRENT_ATTACH(); addin_ClearCurrentAttach(); Addin_callout_LoadDataDestroy( &pTracker->AddinLoadData ); #endif /* Wipe and deallocate the tracker structure */ memset( pTracker, 0, sizeof(MAF_MODULE_LOAD_TRACKER) ); Addin_free( pTracker, NULL ); return CSSM_OK; } /************************************************************************* ************************************************************************* ***** Begin list searching functions ************************************ ************************************************************************* *************************************************************************/ static int MLC_FASTCALL addin_FindLoadByGUID( const MAF_MODULE_LOAD_TRACKER *pLoadTracker, /* void *pItem */ const CSSM_GUID *pGuid /* void *pKey */ ) { assert( pGuid ); LOAD_TRACKER_ASSERT_VALID( pLoadTracker ); return memcmp( &pLoadTracker->CssmGuid, pGuid, sizeof(CSSM_GUID) ); } static int MLC_FASTCALL addin_FindAttachByHandle( const MAF_MODULE_ATTACH_TRACKER *pAttachTracker, /* void *pItem */ const CSSM_MODULE_HANDLE *pHandle /* void *pKey */ ) { assert( pHandle ); ATTACH_TRACKER_ASSERT_VALID( pAttachTracker ); return ( pAttachTracker->ModuleHandle - (*pHandle) ); } /* Search function that matches everything */ int MLC_FASTCALL addin_FindFirst( void *pItem, void *pKey ) { return 0; } int MLC_FASTCALL addin_FindSelf( void *pItem, void *pKey ) { if ( pItem == pKey ) { return 0; } return 1; } /************************************************************************* ************************************************************************* ***** High Level Integrity Wrapper ************************************** ************************************************************************* *************************************************************************/ static CSSM_RETURN addin_DoBilatChecks( CSSM_PROC_ADDR RetAddr, const CSSM_GUID *ModuleGuid, const CSSM_GUID *CssmGuid, const CSSM_GUID *ModuleManagerGuid, const CSSM_GUID *CallerGuid, CSSM_KEY_HIERARCHY KeyKierarchy, ADDIN_MODULE_HANDLE *phCssm, ADDIN_MODULE_HANDLE *phEmm, ADDIN_MODULE_HANDLE *phCaller ) { CSSM_RETURN rv = CSSM_OK; assert( ModuleGuid && CssmGuid && ModuleManagerGuid ); assert( phCssm && phEmm && phCaller ); /* We don't do anthing with the caller guid, so always set caller * handle to NULL. */ *phCaller = NULL; /* Bilat the CSSM */ if ( ( rv = Addin_AuthenticateModule( CssmGuid, CSSM_KEY_HIERARCHY_INTEG, MAF_INTEG_MT_CSSM, RetAddr, phCssm ) ) == CSSM_OK ) { /* Only check the EMM GUID if it is different than the CSSM */ if ( !MAF_CompareGuids( (*CssmGuid), (*ModuleManagerGuid) ) ) { rv = Addin_AuthenticateModule( ModuleManagerGuid, CSSM_KEY_HIERARCHY_INTEG, MAF_INTEG_MT_EMM, NULL, phEmm ); } else { *phEmm = *phCssm; } } return rv; } /************************************************************************* ************************************************************************* ***** Begin SPI helper functions **************************************** ************************************************************************* *************************************************************************/ CSSM_RETURN addin_LockServiceProvider( CSSM_BOOL bWriter ) { CSSM_RETURN rv = CSSM_OK; if ( bWriter ) { if ( cssm_SWMRLockWaitToWrite( &s_hUseLock, CSSM_INFINITE_WAIT ) != CSSM_OK ) { ERR( rv = CSSMERR_CSSM_INTERNAL_ERROR ); } } else { if ( cssm_SWMRLockWaitToRead( &s_hUseLock, CSSM_INFINITE_WAIT ) != CSSM_OK ) { ERR( rv = CSSMERR_CSSM_INTERNAL_ERROR ); } } return rv; } CSSM_RETURN addin_UnlockServiceProvider( CSSM_BOOL bWriter ) { if ( bWriter ) { cssm_SWMRLockDoneWriting( &s_hUseLock ); } else { cssm_SWMRLockDoneReading( &s_hUseLock ); } return CSSM_OK; } CSSM_BOOL addin_IsLastUnload() { CSSM_BOOL rv = CSSM_FALSE; const MAF_MODULE_LOAD_TRACKER *pTracker = NULL; MLC_LOCK_REF LockRef = NULL; /* This is the last unload if there is only one load record, and that * record has a reference count of 1. */ /* Is the list longer than 1? */ if ( MLC_Size( s_lcLoadList ) > 1 ) { rv = CSSM_FALSE; } else { /* Is there only one reference to that load? */ if ( MLC_FindItem( &s_lcLoadList, addin_FindFirst, (void*)1, /* Prevent assert */ MLC_READ_LOCK, &LockRef, (void**)&pTracker ) != CSSM_OK ) { assert( 0 ); /* Something bad happened in the call sequence */ rv = CSSM_FALSE; } else { if ( pTracker->NumLoads == 1 ) { rv = CSSM_TRUE; } MLC_ReleaseItem( MLC_READ_LOCK, LockRef ); } } return rv; } /************************************************************************* ************************************************************************* ***** Begin resource initialization and destruction ********************* ************************************************************************* *************************************************************************/ static void MLC_FASTCALL addin_TeardownLoad( MAF_MODULE_LOAD_TRACKER *pTracker /* void *pItem */ ) { addin_LoadTrackerDelete( pTracker ); } static void MLC_FASTCALL addin_TeardownAttach( MAF_MODULE_ATTACH_TRACKER *pTracker /* void *pItem */ ) { addin_AttachTrackerDelete( pTracker ); } static CSSM_RETURN addin_InitResources() { CSSM_RETURN rv = CSSM_OK; /* Catch improper locking situations */ assert( !addin_IsInitialized() ); /* Initialize the integrity sub-system. This will fail because of a * resource failure or a failed self-check. */ if ( ( rv = Addin_IntegrityInit() ) == CSSM_OK ) { /* Initialize the thread-local storage index for storing the * current operating context. */ if ( ( rv = port_AllocateTlsIndex( &s_hThreadContext, NULL ) ) != CSSM_OK ) { ERR( rv = CSSMERR_CSSM_INTERNAL_ERROR ); } else { /* Initialize the load tracker list */ if ( MLC_Init( &s_lcLoadList, (MLC_ITEM_TEARDOWN_FUNC)addin_TeardownLoad ) != CSSM_OK ) { ERR( rv = CSSMERR_CSSM_INTERNAL_ERROR ); } else { /* Initialize the attach tracker list */ if ( MLC_Init( &s_lcAttachList, (MLC_ITEM_TEARDOWN_FUNC)addin_TeardownAttach ) != CSSM_OK ) { ERR( rv = CSSMERR_CSSM_INTERNAL_ERROR ); } else { /* Call the SP specific initialization */ if ( ( rv = Addin_callout_Initialize() ) == CSSM_OK ) { /* Everything is initialized, set the indicator */ s_bInitialized = CSSM_TRUE; } else { /* Custom init failed, terminate the attach list */ MLC_Term( &s_lcAttachList ); } } /* If something failed, terminate the load list */ if ( rv != CSSM_OK ) { MLC_Term( &s_lcLoadList ); } } /* If something failed, terminate the thread context index */ if ( rv != CSSM_OK ) { port_DeleteTlsIndex( s_hThreadContext ); s_hThreadContext = PORT_INVALID_TLS_INDEX; } } /* If something failed, terminate the integrity sub-system */ if ( rv != CSSM_OK ) { Addin_IntegrityTerm(); } } return rv; } static CSSM_RETURN addin_TermResources() { CSSM_RETURN rv = CSSM_OK; /* Perform custom termination */ Addin_callout_Terminate(); /* Reset the initialization indicator */ s_bInitialized = CSSM_FALSE; /* Terminate the attach tracker list */ MLC_Term( &s_lcAttachList ); /* Terminate the load tracker list */ MLC_Term( &s_lcLoadList ); /* Terminate the thread context index */ port_DeleteTlsIndex( s_hThreadContext ); /* Terminate the integrity sub-system */ Addin_IntegrityTerm(); return rv; } /************************************************************************* ************************************************************************* ***** Begin main load/unload functionality ****************************** ************************************************************************* *************************************************************************/ static CSSM_RETURN addin_PerformModuleLoad( const CSSM_GUID *CssmGuid, const CSSM_GUID *ModuleGuid, CSSM_SPI_ModuleEventHandler CssmNotifyCallback, const void* CssmNotifyCallbackCtx, const ADDIN_MODULE_HANDLE hCssm ) { CSSM_RETURN rv = CSSM_OK; MAF_MODULE_LOAD_TRACKER_PTR pLoadTracker = NULL; MAF_MODULE_LOAD_TRACKER_PTR pLoadTracker2 = NULL; MLC_LOCK_REF LockRef = MLC_NULL_LOCK_REF; /* Make sure that we have called ourselves correctly */ assert( CssmGuid && ModuleGuid && CssmNotifyCallback ); /* Find this load tracker if it already exists and lock it for * writing. */ if ( ( rv = MLC_FindItem( &s_lcLoadList, (MLC_FIND_FUNC)addin_FindLoadByGUID, (void*)CssmGuid, MLC_WRITE_LOCK, &LockRef, (void**)&pLoadTracker ) ) == CSSM_OK ) { LOAD_TRACKER_ASSERT_VALID( pLoadTracker ); /* This module has been loaded by this CSSM before */ pLoadTracker->NumLoads++; } else if ( rv == MLC_ERR_NOT_FOUND ) { /* First time being loaded by this CSSM. Insert a tracking record * into the internal list. */ if ( ( rv = addin_LoadTrackerNew( CssmGuid, CssmNotifyCallback, CssmNotifyCallbackCtx, hCssm, &pLoadTracker ) ) == CSSM_OK ) { LOAD_TRACKER_ASSERT_VALID( pLoadTracker ); /* Add the new item to the tracking list */ if ( MLC_AddItem( &s_lcLoadList, (void *)pLoadTracker, MLC_WRITE_LOCK, &LockRef ) != CSSM_OK ) { /* Couldn't add the item to the list */ ERR( rv = CSSMERR_CSSM_INTERNAL_ERROR ); addin_LoadTrackerDelete( pLoadTracker ); } } /* if addin_LoadTrackerNew succeeded */ } else { ERR( rv = CSSMERR_CSSM_INTERNAL_ERROR ); } /* If rv==CSSM_OK at this point, then pLoadTracker is a valid item that * has been inserted into the load list, and there is a write lock on * the record. The lock reference for the record is in LockRef. */ /* Are we successful so far? */ if ( rv == CSSM_OK ) { ASSERT_NO_CURRENT_ATTACH(); addin_ClearCurrentAttach(); rv = Addin_callout_ModuleLoad( pLoadTracker, CssmNotifyCallback, CssmNotifyCallbackCtx ); /* Delete the new item if initialization failed */ if ( rv != CSSM_OK ) { /* Remove the load record if this was the first load from this CSSM */ if ( pLoadTracker->NumLoads == 1 ) { /* Drop the writer lock on the new item */ MLC_ReleaseItem( MLC_WRITE_LOCK, LockRef ); /* Remove the new item from the list */ MLC_DeleteItem( &s_lcLoadList, addin_FindSelf, (void*)pLoadTracker, (void**)pLoadTracker2 ); assert( pLoadTracker == pLoadTracker2 ); addin_LoadTrackerDelete( pLoadTracker ); pLoadTracker = NULL; } else { /* Decrement the load count to the previous value */ pLoadTracker->NumLoads--; /* Drop the writer lock on the new item */ MLC_ReleaseItem( MLC_WRITE_LOCK, LockRef ); } } else { MLC_ReleaseItem( MLC_WRITE_LOCK, LockRef ); } } return rv; } static CSSM_RETURN addin_PerformModuleUnload( const CSSM_GUID *CssmGuid, const CSSM_GUID *ModuleGuid, CSSM_SPI_ModuleEventHandler CssmNotifyCallback, const void* CssmNotifyCallbackCtx, const CSSM_PROC_ADDR RetAddr ) { CSSM_RETURN rv = CSSM_OK; MAF_MODULE_LOAD_TRACKER_PTR pLoadTracker = NULL; void *pLockRef = NULL; CSSM_BOOL bLastUsage = CSSM_FALSE; /* Find the tracker for this load */ if ( MLC_FindItem( &s_lcLoadList, (MLC_FIND_FUNC)addin_FindLoadByGUID, (void*)CssmGuid, MLC_WRITE_LOCK, &pLockRef, (void**)&pLoadTracker ) != CSSM_OK ) { ERR( rv = CSSM_ERRCODE_FUNCTION_FAILED ); } else { LOAD_TRACKER_ASSERT_VALID( pLoadTracker ); /* Only allow the CSSM that loaded us to unload */ if ( ( rv = Addin_CheckAddressInModule( pLoadTracker->hCssm, RetAddr ) ) == CSSM_OK ) { /* Decrement the load count and check for a final unload situation */ assert( pLoadTracker->NumLoads != 0 ); pLoadTracker->NumLoads--; if ( pLoadTracker->NumLoads == 0 ) { bLastUsage = CSSM_TRUE; } ASSERT_NO_CURRENT_ATTACH(); addin_ClearCurrentAttach(); rv = Addin_callout_ModuleUnload( pLoadTracker, CssmNotifyCallback, CssmNotifyCallbackCtx ); /* Drop the writer lock on the tracker record */ MLC_ReleaseItem( MLC_WRITE_LOCK, pLockRef ); pLoadTracker = NULL; /* If the record is no longer needed, delete it */ if ( bLastUsage ) { /* Delete the list linkage */ if ( MLC_DeleteItem( &s_lcLoadList, (MLC_FIND_FUNC)addin_FindLoadByGUID, (void*)CssmGuid, (void**)&pLoadTracker ) != CSSM_OK ) { /* We just had this record, something went wrong */ ERR( rv = CSSMERR_CSSM_INTERNAL_ERROR ); } else { LOAD_TRACKER_ASSERT_VALID( pLoadTracker ); /* Free the memory for the record */ addin_LoadTrackerDelete( pLoadTracker ); } } } else { MLC_ReleaseItem( MLC_WRITE_LOCK, pLockRef ); } } return rv; } /************************************************************************* ************************************************************************* ***** Begin standard SPI interface ************************************** ************************************************************************* *************************************************************************/ CSSM_RETURN CSSMAPI CSSM_SPI_ModuleLoad( const CSSM_GUID * CssmGuid, const CSSM_GUID * ModuleGuid, CSSM_SPI_ModuleEventHandler CssmNotifyCallback, void* CssmNotifyCallbackCtx ) { CSSM_RETURN rv = CSSM_OK; CSSM_BOOL bFirstLoad = CSSM_FALSE; CSSM_PROC_ADDR RetAddr = NULL; ADDIN_MODULE_HANDLE hCssm = NULL; /* Fetch the return address of the caller */ Addin_GetReturnAddress( RetAddr ); #ifdef VMS if( s_hLoadLock == NULL ){ rv = _init(); } #endif /* Are the parameters valid pointers? */ if ( port_IsBadReadPtr( CssmGuid, sizeof(CSSM_GUID) ) || port_IsBadReadPtr( ModuleGuid, sizeof(CSSM_GUID) ) || port_IsBadCodePtr( (CSSM_PROC_ADDR)CssmNotifyCallback ) ) { ERR( rv = CSSMERR_CSSM_INVALID_POINTER ); } /* Is this the correct module being requested? */ else if ( memcmp( ModuleGuid, &ADDIN_GUID, sizeof(CSSM_GUID) ) ) { ERR( rv = CSSMERR_CSSM_INVALID_GUID ); } /* Lock the load/unload process so we can determine our current state */ else if ( port_LockMutex( s_hLoadLock, CSSM_INFINITE_WAIT ) != CSSM_OK ) { ERR( rv = CSSMERR_CSSM_INTERNAL_ERROR ); } else { /* Determine whether or not resources have been initialized */ if ( !addin_IsInitialized() ) { bFirstLoad = CSSM_TRUE; rv = addin_InitResources(); } if ( rv == CSSM_OK ) { /* Make sure something hasn't gone wrong. If this assert triggers, then * we have probably detected a deadlock situation because of a * circular reference among modules. */ ASSERT_NO_CURRENT_ATTACH(); /* Obtain the appropriate lock on the library. */ if ( ( rv = addin_LockServiceProvider( bFirstLoad ) ) == CSSM_OK ) { /* Unlock the resource init/destruct lock if this isn't the * first load. Allow additional load/unload operations to * progress in parallel. */ if ( !bFirstLoad ) { port_UnlockMutex( s_hLoadLock ); } /* Lock states: * if ( bFirstLoad ) * { * This is the first time an SPI has been called in the * SP. s_hLoadLock (mutex) is locked to protect any initial * resource creation and initialization. s_hUseLock (SWMR) * is locked for writing (via addin_LockServiceProvider). * * No SPI functions are executing, or are able to begin * executing. Resource creation may proceed without * worrying about multiple threads. * } * else * { * s_hLoadLock is unlocked to allow other load/unload * operations to run in parallel. s_hUseLock is locked for * reading (via addin_LockServiceProvider). SPI functions * may be executing or invoked in parallel. All resources * are guaranteed to exist until all existing SPIs have * completed (including this one). * } */ /* Perform a cross check of the CSSM using the integrity * key hierarchy. */ if ( ( rv = Addin_AuthenticateModule( CssmGuid, CSSM_KEY_HIERARCHY_INTEG, MAF_INTEG_MT_CSSM, RetAddr, &hCssm ) ) == CSSM_OK ) { /* Perform SP defined behavior */ rv = addin_PerformModuleLoad( CssmGuid, ModuleGuid, CssmNotifyCallback, CssmNotifyCallbackCtx, hCssm ); } /* Drop the service provider lock on the internals */ addin_UnlockServiceProvider( bFirstLoad ); } /* Drop the load/unload lock */ if ( bFirstLoad ) { port_UnlockMutex( s_hLoadLock ); /* Destroy resources if the module load failed since this * is the first load. */ if ( rv != CSSM_OK ) { addin_TermResources(); } } } /* all resources initialized and valid */ else { /* SP resource creation failed. so we can't go any further, * but we still hold the library lock. */ port_UnlockMutex( s_hLoadLock ); } } /* parameters are valid and lib is locked for load */ return rv; } CSSM_RETURN CSSMAPI CSSM_SPI_ModuleUnload ( const CSSM_GUID * CssmGuid, const CSSM_GUID * ModuleGuid, CSSM_SPI_ModuleEventHandler CssmNotifyCallback, void* CssmNotifyCallbackCtx ) { CSSM_RETURN rv = CSSM_OK; CSSM_BOOL bLastLoad = CSSM_FALSE; CSSM_PROC_ADDR RetAddr = NULL; /* Fetch the return address of the caller */ Addin_GetReturnAddress( RetAddr ); /* Check pointer validity */ if ( port_IsBadReadPtr( CssmGuid, sizeof(CSSM_GUID) ) || port_IsBadReadPtr( ModuleGuid, sizeof(CSSM_GUID)) ) { ERR( rv = CSSMERR_CSSM_INVALID_POINTER ); } /* Is this the correct module being requested? */ else if ( memcmp( ModuleGuid, &ADDIN_GUID, sizeof(ADDIN_GUID) ) ) { ERR( rv = CSSMERR_CSSM_INVALID_GUID ); } /* Get a lock on the load/unload */ else if ( port_LockMutex( s_hLoadLock, CSSM_INFINITE_WAIT ) != CSSM_OK ) { ERR( rv = CSSMERR_CSSM_INTERNAL_ERROR ); } else if ( !addin_IsInitialized() ) { /* Unlock the load/unload mutex */ port_UnlockMutex( s_hLoadLock ); ERR( rv = CSSMERR_CSSM_NOT_INITIALIZED ); } else { /* Make sure something hasn't gone wrong. If this assert triggers, then * we have probably detected a deadlock situation because of a * circular reference among modules. */ ASSERT_NO_CURRENT_ATTACH(); addin_ClearCurrentAttach(); /* Determine if this is the last load */ bLastLoad = addin_IsLastUnload(); /* Get a reader lock on the module. */ if ( addin_LockServiceProvider( bLastLoad ) != CSSM_OK ) { ERR( rv = CSSMERR_CSSM_INTERNAL_ERROR ); } else { /* Unload the load/unload mutex if this is not the last unload */ if ( !bLastLoad ) { port_UnlockMutex( s_hLoadLock ); } /* Lock states: * if ( bLastLoad ) * { * This is the last time an SPI will be called in the * SP. s_hLoadLock (mutex) is locked to protect any final * resource destruction. s_hUseLock (SWMR) is locked for * writing (via addin_LockServiceProvider). * * No SPI functions are executing, or are able to begin * executing. Resource destruction may proceed without * worrying about multiple threads. * } * else * { * s_hLoadLock is unlocked to allow other load/unload * operations to run in parallel. s_hUseLock is locked for * reading (via addin_LockServiceProvider). SPI functions * may be executing or invoked in parallel. All resources * are guaranteed to exist until all existing SPIs have * completed (including this one). * } */ /* Perform SP defined behavior */ rv = addin_PerformModuleUnload( CssmGuid, ModuleGuid, CssmNotifyCallback, CssmNotifyCallbackCtx, RetAddr ); /* If this is the last unload operation, prepare the SP to * be unloaded by destroying all of the resources. */ if ( bLastLoad ) { addin_TermResources(); } /* Drop the service provider lock */ addin_UnlockServiceProvider( bLastLoad ); } /* Unlock the load/unload mutex if this is the last unload */ if ( bLastLoad ) { port_UnlockMutex( s_hLoadLock ); } } return rv; } CSSM_RETURN CSSMAPI CSSM_SPI_ModuleAttach( const CSSM_GUID *ModuleGuid, const CSSM_VERSION *Version, uint32 SubServiceId, CSSM_SERVICE_TYPE SubServiceType, CSSM_ATTACH_FLAGS AttachFlags, CSSM_MODULE_HANDLE ModuleHandle, CSSM_KEY_HIERARCHY KeyHierarchy, const CSSM_GUID *CssmGuid, const CSSM_GUID *ModuleManagerGuid, const CSSM_GUID *CallerGuid, const CSSM_UPCALLS *Upcalls, CSSM_MODULE_FUNCS_PTR *FuncTbl ) { CSSM_RETURN rv = CSSM_OK; MAF_MODULE_ATTACH_TRACKER_PTR pAttachTracker = NULL; MLC_LOCK_REF AttachLockRef = MLC_NULL_LOCK_REF; MAF_MODULE_LOAD_TRACKER_PTR pLoadTracker = NULL; MLC_LOCK_REF LoadLockRef = MLC_NULL_LOCK_REF; ADDIN_MODULE_HANDLE hCssm = NULL; ADDIN_MODULE_HANDLE hModuleManager = NULL; ADDIN_MODULE_HANDLE hCaller = NULL; CSSM_PROC_ADDR RetAddr = NULL; /* Get the caller return address */ Addin_GetReturnAddress( RetAddr ); /* Make sure the system is initialized */ if ( !addin_IsInitialized() ) { ERR( rv = CSSMERR_CSSM_NOT_INITIALIZED ); } /* Perform basic parameter pointer checks */ else if ( port_IsBadReadPtr( ModuleGuid, sizeof(CSSM_GUID) ) || port_IsBadReadPtr( CssmGuid, sizeof(CSSM_GUID) ) || port_IsBadReadPtr( ModuleManagerGuid, sizeof(CSSM_GUID) ) || port_IsBadReadPtr( Version, sizeof(CSSM_VERSION) ) || port_IsBadReadPtr( Upcalls, sizeof(CSSM_UPCALLS) ) || port_IsBadWritePtr( FuncTbl, sizeof(CSSM_MODULE_FUNCS_PTR) ) ) { ERR( rv = CSSMERR_CSSM_INVALID_POINTER ); } /* Check for a valid module handle */ else if ( ModuleHandle == CSSM_INVALID_HANDLE ) { ERR( rv = CSSMERR_CSSM_INVALID_ADDIN_HANDLE ); } /* Check the upcall table pointers */ else if ( port_IsBadCodePtr( (CSSM_PROC_ADDR)Upcalls->malloc_func ) || port_IsBadCodePtr( (CSSM_PROC_ADDR)Upcalls->free_func ) || port_IsBadCodePtr( (CSSM_PROC_ADDR)Upcalls->realloc_func ) || port_IsBadCodePtr( (CSSM_PROC_ADDR)Upcalls->calloc_func ) ) { ERR( rv = CSSMERR_CSSM_INVALID_POINTER ); } /* Is this the correct module being requested? */ else if ( memcmp( ModuleGuid, &ADDIN_GUID, sizeof(CSSM_GUID) ) ) { ERR( rv = CSSMERR_CSSM_INVALID_GUID ); } /* Check that this is a compatible version */ else if ( ( Version->Major != ADDIN_VERSION_MAJOR ) || ( Version->Minor != ADDIN_VERSION_MINOR ) ) { ERR( rv = CSSMERR_CSSM_INCOMPATIBLE_VERSION ); } /* Check to see that the subservice and service type are supported */ else if ( !ADDIN_IS_VALID_SUBSERVICE(SubServiceId, SubServiceType) ) { ERR( rv = CSSMERR_CSSM_INVALID_SUBSERVICEID ); } else { /* Make sure something hasn't gone wrong. If this assert triggers, then * we have probably detected a deadlock situation because of a * circular reference among modules. */ ASSERT_NO_CURRENT_ATTACH(); addin_ClearCurrentAttach(); /* Get a reader lock on the library */ if ( addin_LockServiceProvider( CSSM_FALSE ) != CSSM_OK ) { ERR( rv = CSSMERR_CSSM_INTERNAL_ERROR ); } else { /* Perform complete bilat */ if ( ( rv = addin_DoBilatChecks( RetAddr, ModuleGuid, CssmGuid, ModuleManagerGuid, CallerGuid, KeyHierarchy, &hCssm, &hModuleManager, &hCaller ) ) == CSSM_OK ) { /* Make sure the CSSM has called load */ if ( MLC_FindItem( &s_lcLoadList, (MLC_FIND_FUNC)addin_FindLoadByGUID, (void*)CssmGuid, MLC_READ_LOCK, &LoadLockRef, (void**)&pLoadTracker ) != CSSM_OK ) { /* This cssm has never called load */ ERR( rv = CSSM_ERRCODE_FUNCTION_FAILED ); } else { /* Allocate a new attach tracker record */ if ( ( rv = addin_AttachTrackerNew( SubServiceId, SubServiceType, ModuleHandle, KeyHierarchy, Upcalls, LoadLockRef, hCssm, hModuleManager, hCaller, &pAttachTracker ) ) == CSSM_OK ) { /* Call custom functionality */ addin_SetCurrentAttach( pAttachTracker ); rv = Addin_callout_ModuleAttach( pLoadTracker, pAttachTracker, FuncTbl ); addin_ClearCurrentAttach(); if ( rv == CSSM_OK ) { /* Add the new record to the tracker list */ if ( ( rv = MLC_AddItem( &s_lcAttachList, (void *)pAttachTracker, MLC_NO_LOCK, &AttachLockRef ) ) != CSSM_OK ) { /* Couldn't add the item to the list */ ERR( rv = CSSMERR_CSSM_INTERNAL_ERROR ); } } /* Custom attach stuff done */ /* Clean-up attach tracker in the event of an error */ if ( rv != CSSM_OK ) { addin_AttachTrackerDelete( pAttachTracker ); } /* Indicate that we are done with the attach tracker */ pAttachTracker = NULL; } /* New tracker created */ } /* Load record found */ MLC_ReleaseItem( MLC_READ_LOCK, LoadLockRef ); pLoadTracker = NULL; } /* bilat succeeds */ /* Drop the reader lock to signal that we are finished */ addin_UnlockServiceProvider( CSSM_FALSE ); } /* Service provider locked for attach */ } /* Parameters are valid */ return rv; } /*--------------------------------------------------------------- * *Name: CSSM_SPI_ModuleDetach * *Description: * Public entry point used by CSSMs to detach a single attach. * Default behavior is to find the attach tracking record for * the attach and verify that the same module that made the * original attach is making the detach call. It then tears * down the tracking record and frees the resources. * *Parameters: * Handle (input) - CSSM specified handle representing the * attach session. * *Returns: * CSSM_FAIL - Internal error, unknown handle, or bad caller. * CSSM_OK - The detach succeded. * *-------------------------------------------------------------*/ CSSM_RETURN CSSMAPI CSSM_SPI_ModuleDetach(CSSM_MODULE_HANDLE Handle) { CSSM_RETURN rv = CSSM_OK; MAF_MODULE_ATTACH_TRACKER_PTR pAttachTracker = NULL; MLC_LOCK_REF LockRef = NULL; CSSM_PROC_ADDR RetAddr = NULL; /* Fetch the return address */ Addin_GetReturnAddress( RetAddr ); /* Check to see that the SP has been initialized */ if ( !addin_IsInitialized() ) { ERR( rv = CSSMERR_CSSM_NOT_INITIALIZED ); } /* Check for a presumably valid handle */ else if ( Handle == CSSM_INVALID_HANDLE ) { ERR( rv = CSSMERR_CSSM_INVALID_ADDIN_HANDLE ); } else { ASSERT_NO_CURRENT_ATTACH(); addin_ClearCurrentAttach(); /* Get a reader lock on the library */ if ( addin_LockServiceProvider( CSSM_FALSE ) != CSSM_OK ) { ERR( rv = CSSMERR_CSSM_INTERNAL_ERROR ); } else { /* Find the tracker for this attach */ if ( MLC_FindItem( &s_lcAttachList, (MLC_FIND_FUNC)addin_FindAttachByHandle, (void*)&Handle, MLC_READ_LOCK, &LockRef, (void**)&pAttachTracker ) != CSSM_OK ) { /* Doesn't exist. What is the CSSM thinking? */ ERR( rv = CSSMERR_CSSM_INVALID_ADDIN_HANDLE ); } else { ATTACH_TRACKER_ASSERT_VALID(pAttachTracker); /* Is this the same module that attached us? */ if ( ( rv = Addin_CheckAddressInModule( pAttachTracker->hCssm, RetAddr ) ) == CSSM_OK ) { /* Release the read lock so we can delete the record */ MLC_ReleaseItem( MLC_READ_LOCK, LockRef ); pAttachTracker = NULL; /* Unlink the tracker for this attach */ if ( MLC_DeleteItem( &s_lcAttachList, (MLC_FIND_FUNC)addin_FindAttachByHandle, (void*)&Handle, (void**)&pAttachTracker ) != CSSM_OK ) { /* Something went wrong here */ ERR( rv = CSSMERR_CSSM_INTERNAL_ERROR ); } else { /* Teardown the attach record */ ATTACH_TRACKER_ASSERT_VALID( pAttachTracker ); addin_AttachTrackerDelete( pAttachTracker ); } /* Item was removed from the list */ } /* Secure linkage passed */ else { /* Release the read lock because secure linkage failed */ MLC_ReleaseItem( MLC_READ_LOCK, LockRef ); pAttachTracker = NULL; } } /* Attach record found */ /* Drop the reader lock to signal that we are finished */ addin_UnlockServiceProvider( CSSM_FALSE ); } /* Service provider locked */ } /* Parameter validation passed */ return rv; } #ifdef LINUX static int _init() __attribute__ ((constructor)); static int _fini() __attribute__ ((destructor)); #endif int _init() { CSSM_BOOL rv = CSSM_TRUE; /* Initialize a tracing functionality */ if ( port_InitMemoryTracking() == CSSM_OK ) { /* Initialize the library load and initialization mutex */ #if defined (POSIX) || defined (VMS) s_hLoadLock = &s_LoadMutex; #endif if ( port_CreateMutex( NULL, &s_hLoadLock ) == CSSM_OK ) { if ( cssm_SWMRLockCreate( &s_hUseLock, NULL ) != CSSM_OK ) { port_CloseMutex( s_hLoadLock ); rv = CSSM_FALSE; } else { /* * Indicate the the service provider resources have not * been allocated. */ s_bInitialized = CSSM_FALSE; } } else { rv = CSSM_FALSE; } } else { rv = CSSM_FALSE; } return rv; #ifdef VMS return(0); #endif } int _fini() { /* Dump heap leaks when we are unloaded */ port_DumpMemoryLeaks( ADDIN_NAME ); /* * Here's why we moved the deletion of s_hUseLock from * addin_TermResources() to _fini(): CSSM_SPI_ModuleUnload() * needs to lock s_hUseLock while calling addin_TermResources(), * but s_hUseLock can't always be deleted while it's locked. * It can on WIN32, but it can't on UNIX where it's implemented * with POSIX rw locks. * * Since we moved the deletion, we also moved the creation from * addin_InitResources() to _init(). */ if ( cssm_SWMRLockDelete( &s_hUseLock ) != CSSM_OK ) { assert( 0 ); } /* Destroy the load mutex */ if ( port_CloseMutex( s_hLoadLock ) != CSSM_OK ) { assert( 0 ); } return CSSM_OK; } #if 0 /*--------------------------------------------------------------- * *Name: _init * *Description: * Entry point for the DLL in non-Win32 environments. This * function matches the conventions of the Solaris DDI * interface as well as the AIX standard interface. This * function should only be used initialization that must be * done atomically in an environment where there is a guarantee * that only a single thread can be running this code. The CSSM * maintains an exclusive lock on its internal tracking * structure for this library when this function is called. * NOTE: Activity in this function should be kept to a minimum * for performance reasons. It should be limited to clearing * data values and creating resource locks only! * *Parameters: * None. * *Returns: * FALSE - Initialization failed. Loading fails. * TRUE - DLL is initialized for use. * *-------------------------------------------------------------*/ int _init() { /* * Open the MDS Object and CDSA directory. */ if (maf_open_mds_directory (&hDLDBObject, &hDLDBCdsa, &pMDSFunctions) != CSSM_OK) return FALSE; if ( Addin_SelfCheck() != CSSM_OK ) { maf_close_mds_directory (hDLDBObject, hDLDBCdsa); return FALSE; } /* Initialize the thread local storage for the module */ s_hThreadContext = TLS_NewIndex(); if ( s_hThreadContext == TLS_BAD_INDEX ) { maf_close_mds_directory (hDLDBObject, hDLDBCdsa); return FALSE; } /* Create the SWMR lock to gaurd the library resources */ if ( cssm_SWMRLockCreate( &s_swmrInit, NULL, NULL, NULL ) != CSSM_TRUE ) { maf_close_mds_directory (hDLDBObject, hDLDBCdsa); TLS_DeleteIndex( s_hThreadContext ); return FALSE; } /* Create the load/unload lock */ if ( ( s_hLoadLock = cssm_CreateMutex( NULL ) ) == NULL ) { cssm_SWMRLockDelete( &s_swmrInit ); maf_close_mds_directory (hDLDBObject, hDLDBCdsa); TLS_DeleteIndex( s_hThreadContext ); return FALSE; } /* Initialize the locking on the load and attach tracking lists */ if ( !CLC_Init( &s_lcLoadList, NULL ) ) { cssm_SWMRLockDelete( &s_swmrInit ); maf_close_mds_directory (hDLDBObject, hDLDBCdsa); cssm_SWMRLockDelete( &s_swmrInit ); TLS_DeleteIndex( s_hThreadContext ); return FALSE; } else { if ( !CLC_Init( &s_lcAttachList, NULL ) ) { cssm_SWMRLockDelete( &s_swmrInit ); maf_close_mds_directory (hDLDBObject, hDLDBCdsa); CLC_Term( &s_lcLoadList ); cssm_SWMRLockDelete( &s_swmrInit ); TLS_DeleteIndex( s_hThreadContext ); return FALSE; } } ASSERT_NO_CURRENT_ATTACH(); if (CSSM_OK != Addin_callout_Initialize()) { cssm_SWMRLockDelete( &s_swmrInit ); maf_close_mds_directory (hDLDBObject, hDLDBCdsa); CLC_Term( &s_lcAttachList ); CLC_Term( &s_lcLoadList ); cssm_SWMRLockDelete( &s_swmrInit ); TLS_DeleteIndex( s_hThreadContext ); return FALSE; } s_fInitialized = CSSM_TRUE; return TRUE; } /*--------------------------------------------------------------- * *Name: _fini * *Description: * Entry point for the DLL in non-Win32 environments. This * function matches the conventions of the Solaris DDI * interface as well as the AIX standard interface. This * function should only be used for emergency clean-up for * unexpected shutdowns or uninitialization that must be done * in an environment where there is a guarantee that only a * single thread can be running this code. The CSSM maintains * an exclusive lock on its internal tracking structure for * this library when this function is called. * *Parameters: * None. * *Returns: * FALSE - whoops. * TRUE - DLL is uninitialized for unloading * *-------------------------------------------------------------*/ int _fini() { int retCode = TRUE; s_fInitialized = CSSM_FALSE; if (CSSM_OK != Addin_callout_Terminate()) retCode = FALSE; ASSERT_NO_CURRENT_ATTACH(); addin_ClearCurrentAttach(); /* Destroy the SWMR lock gaurding the library resources */ if (!CLC_CleanList(&s_lcAttachList, (CSSM_COLLECTION_ITEM_TEARDOWN_FUNC)addin_AttachTrackerDelete)) retCode = FALSE; if (!CLC_CleanList(&s_lcLoadList, (CSSM_COLLECTION_ITEM_TEARDOWN_FUNC)addin_LoadTrackerDelete)) retCode = FALSE; CLC_Term( &s_lcAttachList ); CLC_Term( &s_lcLoadList ); cssm_SWMRLockDelete( &s_swmrInit ); cssm_CloseMutex( s_hLoadLock ); /* Deallocate the thread local storage index */ TLS_DeleteIndex( s_hThreadContext ); /* * Close the mds directory. */ maf_close_mds_directory (hDLDBObject, hDLDBCdsa); /* Always succedes */ return retCode; } #endif /* 0 */ #ifdef WIN32 /**--------------------------------------------------------------- ** DllMain ** ** Description: ** Entry point for the DLL in Win32. This function is responsible for ** initializing and destroying the s_LoadLock mutex and insuring that the ** s_bInitialized variable is set to the known state CSSM_FALSE. Memory ** heap tracking is also initialized and terminated. ** ** Parameters: ** hInstance (input) - Instance handle of calling process ** dwReason (input) - Reasons for receiving this call ** lpReserved (input) - Reserved field ** ** Returns: ** FALSE - unable to initialize DLL. This will cause the LoadLibrary ** call to fail. ** TRUE - DLL is initialize and ready to be called **------------------------------------------------------------------------ **/ BOOL WINAPI DllMain( HANDLE hInstance, DWORD dwReason, LPVOID lpReserved ) { BOOL rv = TRUE; switch ( dwReason ) { case DLL_PROCESS_ATTACH: { rv = _init(); break; } /* DLL_PROCESS_ATTACH */ case DLL_THREAD_ATTACH: { break; } /* DLL_THREAD_ATTACH */ case DLL_THREAD_DETACH: { break; } /* DLL_THREAD_DETACH */ case DLL_PROCESS_DETACH: { _fini(); break; } /* DLL_PROCESS_DETACH */ } return rv; } #endif /* ifdef WIN32 */