/* ***************************************************************** *
 * 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.                                                        *
 * ***************************************************************** */


#include "pkcsprivate.h"
#ifdef ISL_INCLUDED
#include "eislapi.h"
#endif

extern MSMSESSION_PTR pMsmSessionList;
extern HANDLE IbmPkcsMsmMutex;
extern int	defaultSeed[DEFAULTSEEDLEN];
#ifndef STATIC_LINK
extern HINSTANCE hPkcsModule;
#endif

CSSM_GUID CssmGuid = IBMPKCS11_GUID;
CSSM_SPI_MEMORY_FUNCS CssmMemFuncs;
extern CK_FUNCTION_LIST	FuncList;

#define		MAX_SLOT_COUNT	 20

// slots
struct
{
   CK_SLOT_ID     slotID;
   CK_SLOT_INFO   slotInfo;
} pSlotList[MAX_SLOT_COUNT];

unsigned int slotCount;

 CSSM_RETURN Get_CSSM_Functions(CSSM_MODULE Module)
{
	CSSM_RETURN retval = CSSM_FAIL;

#ifdef _DEBUG
			Message((LPCTSTR) "In Get_CSSM_Functions");
			printf("Module = %s\n", Module);
#endif
	
	do {
		CSSM_GetContext = (CSSM_GETCONTEXT) GetProcAddress(Module, "CSSM_GetContext");
		if (CSSM_GetContext == NULL) {
#ifdef _DEBUG
			Message((LPCTSTR) "Couldn't get CSSM_GetContext");
			printf("Module = %s\n", Module);
#endif
			break;
		};

		CSSM_FreeContext = (CSSM_FREECONTEXT) GetProcAddress(Module, "CSSM_FreeContext");
		if (CSSM_FreeContext == NULL) {
#ifdef _DEBUG
			Message((LPCTSTR) "Couldn't get CSSM_FreeContext");
			printf("Module = %s\n", Module);
#endif
			break;
		};
		
		CSSM_GetContextAttribute = (CSSM_GETCONTEXTATTRIBUTE) GetProcAddress(Module, "CSSM_GetContextAttribute");
		if (CSSM_GetContextAttribute == NULL) {
#ifdef _DEBUG
			Message((LPCTSTR) "Couldn't get CSSM_GetContextAttribute");
			printf("Module = %s\n", Module);
#endif
			break;
		};
		
		CSSM_RegisterServices = (CSSM_REGISTERSERVICES) GetProcAddress(Module, "CSSM_RegisterServices");
		if (CSSM_RegisterServices == NULL) {
#ifdef _DEBUG
			Message((LPCTSTR) "Couldn't get CSSM_RegisterServices");
			printf("Module = %s\n", Module);
#endif
			break;
		};
		
		CSSM_DeregisterServices = (CSSM_DEREGISTERSERVICES) GetProcAddress(Module, "CSSM_DeregisterServices");
		if (CSSM_DeregisterServices == NULL) {
#ifdef _DEBUG
			Message((LPCTSTR) "Couldn't get CSSM_DeregisterServices");
			printf("Module = %s\n", Module);
#endif
			break;
		};
		
		CSSM_SetError = (CSSM_SETERROR) GetProcAddress(Module, "CSSM_SetError");
		if (CSSM_SetError == NULL) {
#ifdef _DEBUG
			Message((LPCTSTR) "Couldn't get CSSM_SetError");
			printf("Module = %s\n", Module);
#endif
			break;
		};
		
		CSSM_ClearError = (CSSM_CLEARERROR) GetProcAddress(Module, "CSSM_ClearError");
		if (CSSM_ClearError == NULL) {
#ifdef _DEBUG
			Message((LPCTSTR) "Couldn't get CSSM_ClearError");
			printf("Module = %s\n", Module);
#endif
			break;
		};

		CSSM_GetHandleInfo = (CSSM_GETHANDLEINFO) GetProcAddress(Module, "CSSM_GetHandleInfo");
		if (CSSM_GetHandleInfo == NULL) {
#ifdef _DEBUG
			Message((LPCTSTR) "Couldn't get CSSM_GetHandleInfo");
			printf("Module = %s\n", Module);
#endif
			break;
		};
		
		retval = CSSM_OK;
	} while (0);

#ifdef _DEBUG
			Message((LPCTSTR) "Exit Get_CSSM_Functions");
#endif
	return retval;
}

__declspec(dllexport) CSSM_RETURN AddInAuthenticate(char* cssmCredentialPath, char* cssmSection)
{
	// used to register services
	CSSM_REGISTRATION_INFO	CssmRegInfo;
	CSSM_MODULE_FUNCS		CssmModuleFuncs[NUMBEROFSERVICES];
	CSSM_SPI_CSP_FUNCS		CssmCSPFuncs;
	CSSM_SPI_DL_FUNCS		CssmDLFuncs;

	CSSM_RETURN retval = CSSM_FAIL;

	CSSM_MODULE cssmHandle;

#ifdef _DEBUG
			Message((LPCTSTR) "In Addinauthenticate");
			printf("cssmSection = %s\n", cssmSection);
#endif
	cssmHandle = cssm_LoadLibrary(cssmSection);
	if (cssmHandle == NULL) {
		retval = CSSM_FAIL;
#ifdef _DEBUG
		Message((LPCTSTR) "bad cssmHandle");
#endif
	} else {
		retval = Get_CSSM_Functions(cssmHandle);
	}
#ifdef WIN32
	cssm_FreeLibrary(cssmHandle);
#endif

	if (retval == CSSM_FAIL) {
		return retval;
		#ifdef _DEBUG
			Message((LPCTSTR) "Get_CSSM_Functions produced bad retval");
		#endif
	}

	// Now register services
	memset(&CssmRegInfo, 0, sizeof(CssmRegInfo));
	memset(&CssmCSPFuncs, 0, sizeof(CssmCSPFuncs));
	memset(&CssmDLFuncs, 0, sizeof(CssmDLFuncs));

	CssmRegInfo.Initialize = Initialize;
	CssmRegInfo.Terminate = Terminate;
	CssmRegInfo.EventNotify = EventNotify;
	CssmRegInfo.GetModuleInfo = GetMsmInfo;
	
	CssmRegInfo.ThreadSafe = CSSM_TRUE;
	CssmRegInfo.ServiceSummary = CSSM_SERVICE_CSP | CSSM_SERVICE_DL;
	CssmRegInfo.NumberOfServiceTables = NUMBEROFSERVICES; 
	CssmRegInfo.Services = CssmModuleFuncs;

	CssmModuleFuncs[0].ServiceType = CSSM_SERVICE_CSP;
	CssmModuleFuncs[0].CspFuncs = &CssmCSPFuncs;
	CssmModuleFuncs[1].ServiceType = CSSM_SERVICE_DL;
	CssmModuleFuncs[1].DlFuncs = &CssmDLFuncs;


	//
	// Set up CSP Function Table
	//

	CssmCSPFuncs.DecryptData				= DecryptData;
	CssmCSPFuncs.DecryptDataInit			= DecryptDataInitSymmetric;
	CssmCSPFuncs.DecryptDataUpdate			= DecryptDataUpdateSymmetric;
	CssmCSPFuncs.DecryptDataFinal			= DecryptDataFinalSymmetric;

	CssmCSPFuncs.DigestData					= DigestData;
	CssmCSPFuncs.DigestDataInit				= DigestDataInit;
	CssmCSPFuncs.DigestDataUpdate			= DigestDataUpdate;
	CssmCSPFuncs.DigestDataFinal			= DigestDataFinal;

	CssmCSPFuncs.EncryptData				= EncryptData;
	CssmCSPFuncs.EncryptDataInit			= EncryptDataInitSymmetric;
	CssmCSPFuncs.EncryptDataUpdate			= EncryptDataUpdateSymmetric;
	CssmCSPFuncs.EncryptDataFinal			= EncryptDataFinalSymmetric;

	CssmCSPFuncs.GenerateAlgorithmParams	= NULL;

	CssmCSPFuncs.GenerateKey				= GenerateKey;
	CssmCSPFuncs.GenerateKeyPair			= GenerateKeyPair;
	CssmCSPFuncs.GenerateRandom				= GenerateRandom;

	CssmCSPFuncs.GenerateMac				= GenerateMac;
	CssmCSPFuncs.GenerateMacInit			= GenerateMacInit;
	CssmCSPFuncs.GenerateMacUpdate			= GenerateMacUpdate;
	CssmCSPFuncs.GenerateMacFinal			= GenerateMacFinal;

	CssmCSPFuncs.Login						= Login;
	CssmCSPFuncs.Logout						= Logout;
 	CssmCSPFuncs.ChangeLoginPassword		= ChangeLoginPassword;

	CssmCSPFuncs.SignData					= SignData;
#ifdef PKCS11_V20
	CssmCSPFuncs.SignDataInit				= SignDataInit;
	CssmCSPFuncs.SignDataUpdate				= SignDataUpdate;
	CssmCSPFuncs.SignDataFinal				= SignDataFinal;
#endif

	CssmCSPFuncs.VerifyData					= VerifyData;
#ifdef PKCS11_V20
	CssmCSPFuncs.VerifyDataInit				= VerifyDataInit;
	CssmCSPFuncs.VerifyDataUpdate			= VerifyDataUpdate;
	CssmCSPFuncs.VerifyDataFinal			= VerifyDataFinal;
#endif
	CssmCSPFuncs.VerifyMac					= VerifyMac;
	CssmCSPFuncs.VerifyMacInit				= VerifyMacInit;
	CssmCSPFuncs.VerifyMacUpdate			= VerifyMacUpdate;
	CssmCSPFuncs.VerifyMacFinal				= VerifyMacFinal;
	
	CssmCSPFuncs.WrapKey					= WrapKey;
	CssmCSPFuncs.UnwrapKey					= UnwrapKey;
	CssmCSPFuncs.QueryKeySizeInBits			= QueryKeySizeInBits;
	CssmCSPFuncs.PassThrough				= PassThrough;


	//
	// Set up DL Function Table
	//

	CssmDLFuncs.DbOpen						= DbOpen;
	CssmDLFuncs.DbClose						= DbClose;

	CssmDLFuncs.DataInsert					= DataInsert;
	CssmDLFuncs.DataDelete					= DataDelete;
	
	CssmDLFuncs.DataGetFirst				= DataGetFirst;
	CssmDLFuncs.DataGetNext					= DataGetNext;
#ifdef PKCS11_V20
	CssmDLFuncs.DataAbortQuery				= DataAbortQuery;
#endif			

	//
	// Register Services
	//

	if (CSSM_RegisterServices (&CssmGuid, &CssmRegInfo, &CssmMemFuncs, NULL) != CSSM_OK) {
#ifdef _DEBUG
		Message((LPCTSTR) "RC from CSS_RegisterServices failed");
#endif
		return CSSM_FAIL;
	}

#ifdef _DEBUG
			Message((LPCTSTR) "Exit Addinauthenticate");
#endif
	return CSSM_OK;
}


#ifdef _WIN32

/*****************************************************************************
 * Function: DllMain - DLL main entry point.
 *
 * Input:
 *	hModule				- Module handle	
 *	dwReason			- Type of call to DllMain
 *   
 * Output:
 *	None
 *   
 * Returns:
 *  TRUE				- Successful			
 *	FALSE				- Failed
 *
 */

BOOL WINAPI DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
	//CK_RV				PkcsRc;
	
	switch (dwReason)
	{
		case DLL_PROCESS_ATTACH:
			
		{
#ifdef ADDIN_SELFCHECK
            ISL_VERIFIED_MODULE_PTR VerifiedCSPModulePtr = NULL;
#endif
			
			if ((IbmPkcsMsmMutex = cssm_CreateMutex(IBMPKCSMSMMUTEX)) == NULL)
				return FALSE;

#ifdef _DEBUG
			Message((LPCTSTR) "DLL_PROCESS_ATTACH");
#endif

#ifdef ADDIN_SELFCHECK
#ifdef _DEBUG
			Message((LPCTSTR) "ADDIN_SELFCHECK");
#endif
            VerifiedCSPModulePtr = ISL_SelfCheck();
            if(VerifiedCSPModulePtr == NULL)
            {
#ifdef _DEBUG
                Message((LPCTSTR) "PKCSMSM::ISL_SelfCheck() Failed");
#endif // _DEBUG
                return FALSE;
            }
            ISL_RecycleVerifiedModuleCredentials(VerifiedCSPModulePtr);
#endif // ADDIN_SELFCHECK

#ifdef _DEBUG
			Message((LPCTSTR) "About to do RNG_Initialize");
#endif

			break;
		}

		case DLL_THREAD_ATTACH:
#ifdef _DEBUG
			Message((LPCTSTR) "DLL_THREAD_ATTACH");
#endif
			break;


		case DLL_THREAD_DETACH:
#ifdef _DEBUG
			Message((LPCTSTR) "DLL_THREAD_DETACH");
#endif
			break;


		case DLL_PROCESS_DETACH:
#ifdef _DEBUG
			Message((LPCTSTR) "DLL_PROCESS_DETACH");
#endif
			if (CSSM_DeregisterServices != NULL) 
			{
				if (CSSM_DeregisterServices(&CssmGuid) != CSSM_OK)
					return FALSE;
			}
			cssm_CloseMutex(IbmPkcsMsmMutex);
#ifdef _DEBUG
			Message((LPCTSTR) "Exit DLL_PROCESS_DETACH");
#endif

			break;
  }
#ifdef _DEBUG
			Message((LPCTSTR) "Returning True for this operation");
#endif
		return TRUE;
}

#endif



/*****************************************************************************
 * Function: Initialize - Initialize module.
 *
 * Input:
 *	CssmHandle			- Initial module handle	
 *	CssmVerMajor		- Major version of module attached by application
 *	CssmVerMinor		- Minor version of module attached by application
 *   
 * Output:
 *	None
 *   
 * Returns:
 *  CSSM_OK				- Successful			
 *	CSSM_FAIL			- Failed
 *
 */

CSSM_BOOL bInitDone = CSSM_FALSE;

CSSM_RETURN CSSMAPI Initialize(
	CSSM_MODULE_HANDLE CssmHandle,
	uint32 CssmVerMajor,
    uint32 CssmVerMinor)
{
	CSSM_RETURN		CssmRc = CSSM_OK;
	
	CK_RV			PkcsRc = CKR_OK;

	int				randomSeed[DEFAULTSEEDLEN];				
	int				ii;										

#ifdef _DEBUG
			Message((LPCTSTR) "In Initialize");
#endif

	if ((CssmVerMajor != IBMPKCS11_MAJOR_VERSION) || (CssmVerMinor != IBMPKCS11_MINOR_VERSION))
		return CSSM_FAIL;


	if (bInitDone == CSSM_FALSE)
	{

#ifndef STATIC_LINK
		if ((CssmRc = SetupFuncList("pkcs11.dll")) == CSSM_OK)
		{
#endif
			if ((PkcsRc = C_Initialize(NULL)) == CKR_OK)
			{
				// Initialize defaultSeed						

				for(ii = 0; ii < DEFAULTSEEDLEN; ii++)
				{
					randomSeed[ii] ^= time(NULL);
					srand(randomSeed[ii]);
					defaultSeed[ii] = (rand() << 16) | rand();
					srand(defaultSeed[ii]);
					defaultSeed[ii] = (rand() << 16) | rand();
				}						
				
				bInitDone = CSSM_TRUE;
			}

#ifndef STATIC_LINK
		}
#endif

	}


#ifdef _DEBUG
			Message((LPCTSTR) "Exit Initialize");
#endif

	if (PkcsRc != CKR_OK) {
#ifdef _DEBUG
		Message((LPCTSTR) "Bad PkcsRc");
#endif
		return SetErr(PkcsRc);
	} else
		return CssmRc;
}



/*****************************************************************************
 * Function: Terminate  - Terminate module.
 *
 * Input:
 *	CssmHandle			- Last module handle	
 *   
 * Output:
 *	None
 *   
 * Returns:
 *  CSSM_OK				- Successful			
 *	CSSM_FAIL			- Failed
 *
 */

CSSM_RETURN CSSMAPI Terminate(CSSM_MODULE_HANDLE CssmHandle)
{
	CK_RV				PkcsRc;

#ifdef _DEBUG
			Message((LPCTSTR) "Terminate");
#endif

#ifndef STATIC_LINK
	FreeLibrary(hPkcsModule);
#endif

	return CSSM_OK;
}



/*****************************************************************************
 * Function: PkcsNotify - Handle notification from PKCS11 tokens.
 *
 * Input:
 *	hPkcsSession		- PKCS11 session handle	
 *  PkcsEvent			- Event type
 *  pPkcsApplication	- Application specific info which is the same as
 *						  pMsmSession->CssmHandleInfo.ApplicationContext.
 *   
 * Output:
 *	None
 *   
 * Returns:
 *  CKR_OK				- Successful			
 *	CKR_CANCEL			- Application has canceled current operation
 *
 */

CK_RV CK_ENTRY PkcsNotify(
	CK_SESSION_HANDLE hPkcsSession,
	CK_NOTIFICATION PkcsEvent,
	CK_VOID_PTR pPkcsApplication)		
{
	MSMSESSION_PTR		pMsmSession;
	uint32				CssmReason;
#ifdef _DEBUG
			Message((LPCTSTR) "Enter PKCSNotify");
#endif

	if ((pMsmSession = FindMsmSession2(hPkcsSession)) != NULL)
	{
		switch (PkcsEvent)
		{
			case CKN_SURRENDER:
				CssmReason = CSSM_NOTIFY_SURRENDER;
				break;

			case CKN_COMPLETE:
				CssmReason = CSSM_NOTIFY_COMPLETE;
				break;

			case CKN_DEVICE_REMOVED:
				CssmReason = CSSM_NOTIFY_DEVICE_REMOVED;
				break;

#ifdef PKCS11_V20
			case CKN_TOKEN_INSERTION:
				CssmReason = CSSM_NOTIFY_DEVICE_INSERTED;
				break;
#endif

			default:
				return CKR_OK;
		}

		if ((pMsmSession->CssmHandleInfo.Callback != NULL) &&
			(pMsmSession->CssmHandleInfo.Callback(pMsmSession->CssmModuleHandle,
			 									  pMsmSession->CssmHandleInfo.ApplicationContext,
												  CssmReason,
												  0) == CSSM_CSP_CANCEL))
			return CKR_CANCEL;
	}
	
#ifdef _DEBUG
			Message((LPCTSTR) "Exit PKCSNotify");
#endif
	return CKR_OK;
}


/********************************************************
*
* SelectSlot
*
********************************************************/
CK_SLOT_ID SelectSlot()
{  
   CK_SLOT_ID  selectedSlot = 1;
	unsigned int uLoop;

#ifdef _DEBUG
			Message((LPCTSTR) "Enter SelectSlot");
#endif

   // Verify that a slot is available
   if(slotCount > 0)
   {
      // Verify condition where there is only one slot
      if(slotCount == 1)
      {
         selectedSlot = pSlotList[0].slotID;
      }
      else // More than one slot available, select one
      {
         printf("Slots available:");
         for(uLoop=0; uLoop<slotCount; ++uLoop)
         {
            printf("\n\tslot#%d - ",pSlotList[uLoop].slotID);
            printf("%s ",pSlotList[uLoop].slotInfo.slotDescription);
         }
         
         printf("\nSelect a slot: ");
		 scanf("%d",&selectedSlot);
      }
   }
   
#ifdef _DEBUG
			printf("Exit SelectSlot, slotid = %x\n", selectedSlot);
#endif
   return selectedSlot;
}


CK_RV InitializeSlots(char *pLastFunction)
{  
   CK_ULONG           usCount,
                      usCheckCount,
                      usLoop;
   CK_SLOT_ID         slotList[MAX_SLOT_COUNT];
   CK_RV              usStatus;

#ifdef _DEBUG
			Message((LPCTSTR) "Enter InitializeSlots");
#endif

   // Get number of slots
   strcpy(pLastFunction, "C_GetSlotList");
   usStatus = C_GetSlotList(FALSE, NULL, &usCount);
   if( usStatus == CKR_OK )
   {
      if(usCount > MAX_SLOT_COUNT)
      {       
         return usStatus;
      }
   }
   
   // Get slot list
   if( usStatus == CKR_OK )
   {
      strcpy(pLastFunction, "C_GetSlotList");
      usStatus = C_GetSlotList(FALSE, slotList, &usCheckCount);
   }

   // Verify that new count does not exceed allocated number of slots
   if( usStatus == CKR_OK )
   {
      if( usCheckCount > MAX_SLOT_COUNT )
      {
         return usStatus;
      }
   }
      
   // Get info for each slot
   slotCount = 0;
   strcpy(pLastFunction, "C_GetSlotInfo");
   for(usLoop=0; usLoop<usCheckCount && usStatus==CKR_OK; ++usLoop)
   {
      usStatus = C_GetSlotInfo(slotList[usLoop], &(pSlotList[usLoop].slotInfo));
      if( usStatus == CKR_OK )
      {
         pSlotList[slotCount].slotID = slotList[slotCount];
         slotCount++;
      }
   }

#ifdef _DEBUG
			Message((LPCTSTR) "Exit InitializeSlots");
#endif
   return usStatus;
}



/*****************************************************************************
 * Function: EventNotify - Handler for framework event notifications.
 *
 * Input:
 *	CssmModuleHandle	- Module/session handle	
 *  CssmEvent			- Event type
 *  CssmParam			- Event specific info
 *   
 * Output:
 *	None
 *   
 * Returns:
 *  CKR_OK				- Successful			
 *	CKR_CANCEL			- Application has canceled current operation
 *
 */

CSSM_RETURN CSSMAPI EventNotify(
	CSSM_MODULE_HANDLE CssmModuleHandle,
    const CSSM_EVENT_TYPE CssmEvent,
    const uint32 CssmParam)
{
	MSMSESSION_PTR		pMsmSession;
	CSSM_HANDLEINFO_PTR pCssmHandleInfo;
	CK_RV				PkcsRc;

#ifdef _DEBUG
			Message((LPCTSTR) "Enter EventNotify");
#endif

	switch (CssmEvent)
	{
		case CSSM_EVENT_ATTACH:
			if ((pMsmSession = NewMsmSession(CssmModuleHandle)) != NULL)
			{
				if ((pCssmHandleInfo = CSSM_GetHandleInfo(CssmModuleHandle)) != NULL)
				{
					pMsmSession->CssmHandleInfo.SubServiceID = pCssmHandleInfo->SubServiceID;
					pMsmSession->CssmHandleInfo.SessionFlags = pCssmHandleInfo->SessionFlags;
					pMsmSession->CssmHandleInfo.Callback = pCssmHandleInfo->Callback;
					pMsmSession->CssmHandleInfo.ApplicationContext = pCssmHandleInfo->ApplicationContext;
					
					//CssmMemFuncs.free_func(CssmModuleHandle, pCssmHandleInfo); 
					InitializeSlots("Unknown Function");
					if ((PkcsRc = C_OpenSession(SelectSlot(),//pMsmSession->CssmHandleInfo.SubServiceID,
												pMsmSession->CssmHandleInfo.SessionFlags,
												"application",//(CK_VOID_PTR)pMsmSession->CssmHandleInfo.ApplicationContext,
												0,//PkcsNotify,
												&pMsmSession->PkcsSessionHandle )) == CKR_OK)
					{
						return InsertMsmSession(pMsmSession);
					}
					else
					{
						DeleteMsmSession(pMsmSession);
						return SetErr(PkcsRc);
					}
				}
				else
				{
					DeleteMsmSession(pMsmSession);
					return SetErr(CSSM_CSP_INVALID_MODULE_HANDLE);
				}
			}
			else
			{
				return CSSM_FAIL;
			}


		case CSSM_EVENT_DETACH:
			if ((pMsmSession = FindMsmSession(CssmModuleHandle)) != NULL)
			{
				if ((PkcsRc = C_CloseSession(pMsmSession->PkcsSessionHandle)) == CKR_OK)
					return Destruct(pMsmSession);
				else
					return ErrDestruct(pMsmSession, PkcsRc);
			}
			else
			{
				return SetErr(CSSM_CSP_INVALID_CSP_HANDLE);
			}
			
		default:	
#ifdef _DEBUG
			Message((LPCTSTR) "Exit EventNotify");
#endif
			return CSSM_OK;
	}
}



/*****************************************************************************
 * Function: Login - Login to token.
 *
 * Input:
 *	CssmCSPHandle		- Module/session handle	
 *  pCssmPassword		- Password to login with
 *  pCssmReserved		- Reserved
 *   
 * Output:
 *	None
 *   
 * Returns:
 *  CKR_OK				- Successful			
 *	CKR_CANCEL			- Application has canceled current operation
 *
 */

CSSM_RETURN CSSMAPI Login(
	CSSM_CSP_HANDLE CssmCSPHandle,
    const CSSM_CRYPTO_DATA_PTR pCssmPassword,
    const CSSM_DATA_PTR pCssmReserved)
{
	MSMSESSION_PTR		pMsmSession;
	CSSM_DATA_PTR		pCssmPwd;
	CK_RV				PkcsRc;

#ifdef _DEBUG
			Message((LPCTSTR) "Enter Login");
#endif

	if (pCssmPassword == NULL)
		return SetErr(CSSM_CSP_INVALID_POINTER);

	if ((pMsmSession = FindMsmSession(CssmCSPHandle)) != NULL)
	{
		if (pCssmPassword->Callback != NULL)
			pCssmPwd = pCssmPassword->Callback(NULL, 0);	
		else
			pCssmPwd = pCssmPassword->Param;

		if (pMsmSession->bLogined == CSSM_FALSE)
		{
#ifdef PKCS11_V20
			if ((PkcsRc = C_Login(pMsmSession->PkcsSessionHandle,
								  CKU_USER,
								  pCssmPwd->Data,
								  (CK_ULONG) pCssmPwd->Length)) == CKR_OK)
#else
			if ((PkcsRc = C_Login(pMsmSession->PkcsSessionHandle,
								  CKU_USER,
								  pCssmPwd->Data,
								  (CK_USHORT) pCssmPwd->Length)) == CKR_OK)
#endif
			{
				pMsmSession->bLogined = CSSM_TRUE;
#ifdef _DEBUG
				Message((LPCTSTR) "Exit Login");
#endif

				return CSSM_OK;
			}
			else
			{
				return SetErr(PkcsRc);
			}
		}
		else
		{
#ifdef _DEBUG
			Message((LPCTSTR) "Exit Login");
#endif
			return CSSM_OK;
		}
	}
	else
	{
		return SetErr(CSSM_CSP_INVALID_CSP_HANDLE);
	}
}



/*****************************************************************************
 * Function: Logout - Logout of token.
 *
 * Input:
 *	CssmCSPHandle		- Module/session handle	
 *   
 * Output:
 *	None
 *   
 * Returns:
 *  CKR_OK				- Successful			
 *	CKR_CANCEL			- Application has canceled current operation
 *
 */

CSSM_RETURN CSSMAPI Logout(
	CSSM_CSP_HANDLE CssmCSPHandle)
{
	MSMSESSION_PTR		pMsmSession;
	CK_RV				PkcsRc;

#ifdef _DEBUG
			Message((LPCTSTR) "Enter Logout");
#endif

	if ((pMsmSession = FindMsmSession(CssmCSPHandle)) != NULL)
	{
		if (pMsmSession->bLogined == CSSM_TRUE)
		{
			if ((PkcsRc = C_Logout(pMsmSession->PkcsSessionHandle)) == CKR_OK)
			{
				pMsmSession->bLogined = CSSM_FALSE;
#ifdef _DEBUG
				Message((LPCTSTR) "Exit Logout");
#endif
				return CSSM_OK;
			}
			else
			{
				return SetErr(PkcsRc);
			}
		}
		else
		{
#ifdef _DEBUG
			Message((LPCTSTR) "Exit Logout");
#endif
			return CSSM_OK;
		}
	}
	else
	{
		return SetErr(CSSM_CSP_INVALID_CSP_HANDLE);
	}
}



/*****************************************************************************
 * Function: ChangeLoginPassword 
 * 
 * Change user's password.
 *
 * Input:
 *	CssmCSPHandle		- Module/session handle	
 *	pCssmOldPassword	- Old password
 *	pCssmNewPassword	- New password
 *   
 * Output:
 *	None
 *   
 * Returns:
 *  CKR_OK				- Successful			
 *	CKR_CANCEL			- Application has canceled current operation
 *
 */
    
CSSM_RETURN CSSMAPI ChangeLoginPassword(
	CSSM_CSP_HANDLE CssmCSPHandle,
    const CSSM_CRYPTO_DATA_PTR pCssmOldPassword,
    const CSSM_CRYPTO_DATA_PTR pCssmNewPassword)
{
	MSMSESSION_PTR		pMsmSession;
	CSSM_DATA_PTR		pCssmOldPwd;
	CSSM_DATA_PTR		pCssmNewPwd;
	CK_RV				PkcsRc;


#ifdef _DEBUG
				Message((LPCTSTR) "Enter ChangeLoginPassword");
#endif

	if (pCssmOldPassword == NULL)
		return SetErr(CSSM_CSP_INVALID_POINTER);

	if (pCssmNewPassword == NULL)
		return SetErr(CSSM_CSP_INVALID_POINTER);

	if ((pMsmSession = FindMsmSession(CssmCSPHandle)) != NULL)
	{
		if (pCssmOldPassword->Callback != NULL)
			pCssmOldPwd = pCssmOldPassword->Callback(NULL, 0);
		else
			pCssmOldPwd = pCssmOldPassword->Param;
		
		if (pCssmNewPassword->Callback != NULL)
			pCssmNewPwd = pCssmNewPassword->Callback(NULL, 0);
		else
			pCssmNewPwd = pCssmNewPassword->Param;

#ifdef PKCS11_V20
		if ((PkcsRc = C_SetPIN(pMsmSession->PkcsSessionHandle,
							   pCssmOldPwd->Data,
							   (CK_ULONG) pCssmOldPwd->Length,
							   pCssmNewPwd->Data,
							   (CK_ULONG) pCssmNewPwd->Length)) == CKR_OK)
#else
		if ((PkcsRc = C_SetPIN(pMsmSession->PkcsSessionHandle,
							   pCssmOldPwd->Data,
							   (CK_USHORT) pCssmOldPwd->Length,
							   pCssmNewPwd->Data,
							   (CK_USHORT) pCssmNewPwd->Length)) == CKR_OK)
#endif
		{
#ifdef _DEBUG
			Message((LPCTSTR) "Exit ChangeLoginPassword");
#endif
		   return CSSM_OK;
		} else
			return SetErr(PkcsRc);
	}
	else
	{
		return SetErr(CSSM_CSP_INVALID_CSP_HANDLE);
	}
}



#define	C_INITIALIZE					1
#define	C_FINALIZE						2
#define	C_GETINFO						3
#define	C_GETFUNCTION_LIST				4
#define	C_GETSLOT_LIST					5
#define	C_GETSLOT_INFO					6
#define	C_GETTOKEN_INFO					7
#define	C_GETMECHANISM_LIST				8
#define	C_GETMECHANISM_INFO				9
#define	C_INIT_TOKEN					10
#define	C_INIT_PIN						11
#define	C_SET_PIN						12
#define	C_OPEN_SESSION					13
#define	C_CLOSE_SESSION					14
#define	C_CLOSE_ALL_SESSIONS			15
#define	C_GET_SESSION_INFO				16
#define	C_GET_OPERATION_STATE			17
#define	C_SET_OPERATION_STATE			18
#define	C_LOGIN							19
#define	C_LOGOUT						20
#define	C_CREATE_OBJECT					21
#define	C_COPY_OBJECT					22
#define	C_DESTROY_OBJECT				23
#define	C_GET_OBJECT_SIZE				24
#define	C_GET_ATTRIBUTE_VALUE			25
#define	C_SET_ATTRIBUTE_VALUE			26
#define	C_FIND_OBJECTS_INIT				27
#define	C_FIND_OBJECTS					28
#define	C_FIND_OBJECTS_FINAL			29
#define	C_ENCRYPT_INIT					30
#define	C_ENCRYPT						31
#define	C_ENCRYPT_UPDATE				32
#define	C_ENCRYPT_FINAL					33
#define	C_DECRYPT_INIT					34
#define	C_DECRYPT						35
#define	C_DECRYPT_UPDATE				36
#define	C_DECRYPT_FINAL					37
#define	C_DIGEST_INIT					38
#define	C_DIGEST						39
#define	C_DIGEST_UPDATE					40
#define	C_DIGEST_KEY					41
#define	C_DIGEST_FINAL					42
#define	C_SIGN_INIT						43
#define	C_SIGN							44
#define	C_SIGN_UPDATE					45
#define	C_SIGN_FINAL					46
#define	C_SIGN_RECOVER_INIT				47
#define	C_SIGN_RECOVER					48
#define	C_VERIFY_INIT					49
#define	C_VERIFY						50
#define	C_VERIFY_UPDATE					51
#define	C_VERIFY_FINAL					52
#define	C_VERIFY_RECOVER_INIT			53
#define	C_VERIFY_RECOVER				54
#define C_DIGEST_ENCRYPT_UPDATE			55
#define C_DECRYPT_DIGEST_UPDATE			56
#define C_SIGN_ENCRYPT_UPDATE			57
#define C_DECRYPT_VERIFY_UPDATE			58
#define C_GENERATE_KEY					59
#define C_GENERATE_KEY_PAIR				60
#define C_WRAP_KEY						61
#define C_UNWRAP_KEY					62
#define C_DERIVE_KEY					63
#define C_SEED_RANDOM					64
#define C_GENERATE_RANDOM				65
#define C_GET_FUNCTION_STATUS			66
#define C_CANCEL_FUNCTION				67
#define C_NOTIFY						68

typedef struct
{
	void	*param0;
	void	*param1;
	void	*param2;
	void	*param3;
	void	*param4;
	void	*param5;
	void	*param6;
	void	*param7;
	void	*param8;
	void	*param9;
} PASS_DATA;


/*****************************************************************************
 * Function: PassThrough - PassThrough function.
 *
 * Input:
 *	CssmCSPHandle		- Module/session handle	
 *	CssmCCHandle		- Context handle
 *	pCssmContext		- Pointer to context 
 *  CssmPassThroughId	- PassThrough ID
 *	pCssmInData			- Input data
 *   
 * Output:
 *	None
 *   
 * Returns:
 *  The return code for PassThrough 
 */

void* CSSMAPI PassThrough(
	CSSM_CSP_HANDLE CssmCSPHandle, 
    CSSM_CC_HANDLE CssmCCHandle,
    const CSSM_CONTEXT_PTR pCssmContext,
    uint32 CssmPassThroughId,
    const void* pCssmInData)
{
	PASS_DATA	*PassData;

#ifdef _DEBUG
				Message((LPCTSTR) "Enter PassThrough");
#endif

	PassData = (PASS_DATA *)pCssmInData;
	switch (CssmPassThroughId)
	{

		case C_INITIALIZE:
			C_Initialize((void *)pCssmInData);
			break;

		case C_GETINFO:
			C_GetInfo((CK_INFO_PTR)pCssmInData);
			break;

		case C_FINALIZE:
			C_Finalize((void *)pCssmInData);
			break;

		case C_GETSLOT_LIST:
			C_GetSlotList(*(CK_BBOOL *)PassData->param0,
						  (CK_SLOT_ID_PTR)PassData->param1,
						  (CK_ULONG_PTR)PassData->param2
						 );
			break;

		case C_GETSLOT_INFO:
			C_GetSlotInfo(*(CK_SLOT_ID*)PassData->param0,
						  (CK_SLOT_INFO_PTR)PassData->param1
						 );
			break;

		case C_GETTOKEN_INFO:
			C_GetTokenInfo(*(CK_SLOT_ID *)PassData->param0,
						   (CK_TOKEN_INFO_PTR)PassData->param1
						  );
			break;

		case C_GETMECHANISM_LIST:
			C_GetMechanismList(*(CK_SLOT_ID *)PassData->param0,
								(CK_MECHANISM_TYPE_PTR)PassData->param1,
								(CK_ULONG_PTR)PassData->param2
							  );
			break;

		case C_GETMECHANISM_INFO:
			C_GetMechanismInfo(*(CK_SLOT_ID *)PassData->param0,
							   *(CK_MECHANISM_TYPE *)PassData->param1,
								(CK_MECHANISM_INFO_PTR)PassData->param2
							  );

			break;

		case C_INIT_TOKEN	:
			C_InitToken(*(CK_SLOT_ID *)PassData->param0,
						(CK_CHAR_PTR)PassData->param1,
						*(CK_ULONG *)PassData->param2,
						(CK_CHAR_PTR)PassData->param3
					   );
			break;

		case C_INIT_PIN		:
			C_InitPIN(*(CK_SESSION_HANDLE *)PassData->param0,
					  (CK_CHAR_PTR)PassData->param1,
					  *(CK_ULONG *)PassData->param2
					 );
			break;

		case C_SET_PIN		:
			C_SetPIN(*(CK_SESSION_HANDLE *)PassData->param0,
					 (CK_CHAR_PTR)PassData->param1,
					 *(CK_ULONG *)PassData->param2,
					 (CK_CHAR_PTR)PassData->param3,
					 *(CK_ULONG *)PassData->param4
					);
			break;

		case C_OPEN_SESSION	:
			C_OpenSession(*(CK_SLOT_ID *)PassData->param0,
						  *(CK_FLAGS *)PassData->param1,
						  (CK_VOID_PTR)PassData->param2,
						  *(CK_NOTIFY *)PassData->param3,
						  (CK_SESSION_HANDLE_PTR)PassData->param4
						 );
			break;

		case C_CLOSE_SESSION	:
			C_CloseSession(*(CK_SESSION_HANDLE *)PassData->param0);
			break;

		case C_CLOSE_ALL_SESSIONS:
			C_CloseAllSessions(*(CK_SLOT_ID *)PassData->param0);
			break;

		case C_GET_SESSION_INFO:
			C_GetSessionInfo(*(CK_SESSION_HANDLE *)PassData->param0,
							 (CK_SESSION_INFO_PTR)PassData->param1
							);
			break;

		case C_GET_OPERATION_STATE:
			C_GetOperationState(*(CK_SESSION_HANDLE *)PassData->param0,
								(CK_BYTE_PTR)PassData->param1,
								(CK_ULONG_PTR)PassData->param2
							   );
			break;

		case C_SET_OPERATION_STATE:
			C_SetOperationState(*(CK_SESSION_HANDLE *)PassData->param0,
								(CK_BYTE_PTR)PassData->param1,
								*(CK_ULONG *)PassData->param2,
								*(CK_OBJECT_HANDLE *)PassData->param3,
								*(CK_OBJECT_HANDLE *)PassData->param4
							   );
			break;

		case C_LOGIN			:
			C_Login(*(CK_SESSION_HANDLE *)PassData->param0,
					*(CK_USER_TYPE *)PassData->param1,
					(CK_CHAR_PTR)PassData->param2,
					*(CK_ULONG *)PassData->param3
				   );
			break;

		case C_LOGOUT		:
			C_Logout(*(CK_SESSION_HANDLE *)PassData->param0);
			break;

		case C_CREATE_OBJECT	:
			C_CreateObject(*(CK_SESSION_HANDLE *)PassData->param0,
						   (CK_ATTRIBUTE_PTR)PassData->param1,
						   *(CK_ULONG *)PassData->param2,
						   (CK_OBJECT_HANDLE_PTR)PassData->param3
						  );
			break;

		case C_COPY_OBJECT	:
			C_CopyObject(*(CK_SESSION_HANDLE *)PassData->param0,
						 *(CK_OBJECT_HANDLE *)PassData->param1,
						 (CK_ATTRIBUTE_PTR)PassData->param2,
						 *(CK_ULONG *)PassData->param3,
						 (CK_OBJECT_HANDLE_PTR)PassData->param4
						);
			break;

		case C_DESTROY_OBJECT:
			C_DestroyObject(*(CK_SESSION_HANDLE *)PassData->param0,
						    *(CK_OBJECT_HANDLE *)PassData->param1
						   );
			break;

		case C_GET_OBJECT_SIZE:
			C_GetObjectSize(*(CK_SESSION_HANDLE *)PassData->param0,
						    *(CK_OBJECT_HANDLE *)PassData->param1,
						    (CK_ULONG_PTR)PassData->param2
						   );
			break;

		case C_GET_ATTRIBUTE_VALUE:
			C_GetAttributeValue(*(CK_SESSION_HANDLE *)PassData->param0,
						   		*(CK_OBJECT_HANDLE *)PassData->param1,
						   		(CK_ATTRIBUTE_PTR)PassData->param2,
						   		*(CK_ULONG *)PassData->param3
						  	   );
			break;

		case C_SET_ATTRIBUTE_VALUE:
			C_SetAttributeValue(*(CK_SESSION_HANDLE *)PassData->param0,
						   		*(CK_OBJECT_HANDLE *)PassData->param1,
						   		(CK_ATTRIBUTE_PTR)PassData->param2,
						   		*(CK_ULONG *)PassData->param3
						  	   );
			break;

		case C_FIND_OBJECTS_INIT:
			C_FindObjectsInit(*(CK_SESSION_HANDLE *)PassData->param0,
						   	  (CK_ATTRIBUTE_PTR)PassData->param1,
						   	  *(CK_ULONG *)PassData->param2
						  	 );
			break;

		case C_FIND_OBJECTS	:
			C_FindObjects(*(CK_SESSION_HANDLE *)PassData->param0,
						  (CK_OBJECT_HANDLE_PTR)PassData->param1,
						  *(CK_ULONG *)PassData->param2,
						  (CK_ULONG_PTR)PassData->param3
					 	 );
			break;

		case C_FIND_OBJECTS_FINAL:
			C_FindObjectsFinal(*(CK_SESSION_HANDLE *)PassData->param0);
			break;

		case C_ENCRYPT_INIT	:
			C_EncryptInit(*(CK_SESSION_HANDLE *)PassData->param0,
					  	  (CK_MECHANISM_PTR)PassData->param1,
					  	  *(CK_OBJECT_HANDLE *)PassData->param2
					 );
			break;

		case C_ENCRYPT		:
			C_Encrypt(*(CK_SESSION_HANDLE *)PassData->param0,
					  (CK_BYTE_PTR)PassData->param1,
					  *(CK_ULONG *)PassData->param2,
					  (CK_BYTE_PTR)PassData->param3,
					  (CK_ULONG_PTR)PassData->param4
					 );
			break;

		case C_ENCRYPT_UPDATE:
			C_EncryptUpdate(*(CK_SESSION_HANDLE *)PassData->param0,
					  (CK_BYTE_PTR)PassData->param1,
					  *(CK_ULONG *)PassData->param2,
					  (CK_BYTE_PTR)PassData->param3,
					  (CK_ULONG_PTR)PassData->param4
							);
			break;

		case C_ENCRYPT_FINAL	:
			C_EncryptFinal(*(CK_SESSION_HANDLE *)PassData->param0,
					  	   (CK_BYTE_PTR)PassData->param1,
					  	   (CK_ULONG_PTR)PassData->param2
						  );
			break;

		case C_DECRYPT_INIT	:
			C_DecryptInit(*(CK_SESSION_HANDLE *)PassData->param0,
					  	  (CK_MECHANISM_PTR)PassData->param1,
					  	  *(CK_OBJECT_HANDLE *)PassData->param2
					 );
			break;

		case C_DECRYPT		:
			C_Decrypt(*(CK_SESSION_HANDLE *)PassData->param0,
					  (CK_BYTE_PTR)PassData->param1,
					  *(CK_ULONG *)PassData->param2,
					  (CK_BYTE_PTR)PassData->param3,
					  (CK_ULONG_PTR)PassData->param4
					 );
			break;

		case C_DECRYPT_UPDATE:
			C_DecryptUpdate(*(CK_SESSION_HANDLE *)PassData->param0,
					  (CK_BYTE_PTR)PassData->param1,
					  *(CK_ULONG *)PassData->param2,
					  (CK_BYTE_PTR)PassData->param3,
					  (CK_ULONG_PTR)PassData->param4
							);
			break;

		case C_DECRYPT_FINAL	:
			C_DecryptFinal(*(CK_SESSION_HANDLE *)PassData->param0,
					  	   (CK_BYTE_PTR)PassData->param1,
					  	   (CK_ULONG_PTR)PassData->param2
						  );
			break;

		case C_DIGEST_INIT	:
			C_DigestInit(*(CK_SESSION_HANDLE *)PassData->param0,
					  	 (CK_MECHANISM_PTR)PassData->param1
						 );
			break;

		case C_DIGEST		:
			C_Digest(*(CK_SESSION_HANDLE *)PassData->param0,
					 (CK_BYTE_PTR)PassData->param1,
					 *(CK_ULONG *)PassData->param2,
					 (CK_BYTE_PTR)PassData->param3,
					 (CK_ULONG_PTR)PassData->param4
					 );
			break;

		case C_DIGEST_UPDATE	:
			C_DigestUpdate(*(CK_SESSION_HANDLE *)PassData->param0,
					       (CK_BYTE_PTR)PassData->param1,
					       *(CK_ULONG *)PassData->param2
						   );
			break;

		case C_DIGEST_KEY	:
			C_DigestKey(*(CK_SESSION_HANDLE *)PassData->param0,
					    *(CK_OBJECT_HANDLE *)PassData->param1
					   );
			break;

		case C_DIGEST_FINAL	:
			C_DigestFinal(*(CK_SESSION_HANDLE *)PassData->param0,
					  	   (CK_BYTE_PTR)PassData->param1,
					  	   (CK_ULONG_PTR)PassData->param2
						  );
			break;

		case C_SIGN_INIT		:
			C_SignInit(*(CK_SESSION_HANDLE *)PassData->param0,
					  (CK_MECHANISM_PTR)PassData->param1,
					  *(CK_OBJECT_HANDLE *)PassData->param2
					  );
			break;

		case C_SIGN			:
			C_Sign(*(CK_SESSION_HANDLE *)PassData->param0,
				   (CK_BYTE_PTR)PassData->param1,
				   *(CK_ULONG *)PassData->param2,
				   (CK_BYTE_PTR)PassData->param3,
				   (CK_ULONG_PTR)PassData->param4
				   );
			break;

		case C_SIGN_UPDATE	:
			C_SignUpdate(*(CK_SESSION_HANDLE *)PassData->param0,
					     (CK_BYTE_PTR)PassData->param1,
					     *(CK_ULONG *)PassData->param2
					     );
			break;

		case C_SIGN_FINAL	:
			C_SignFinal(*(CK_SESSION_HANDLE *)PassData->param0,
					  	(CK_BYTE_PTR)PassData->param1,
					  	(CK_ULONG_PTR)PassData->param2
					   );
			break;

		case C_SIGN_RECOVER_INIT:
			C_SignRecoverInit(*(CK_SESSION_HANDLE *)PassData->param0,
							  (CK_MECHANISM_PTR)PassData->param1,
							  *(CK_OBJECT_HANDLE *)PassData->param2
							 );
			break;

		case C_SIGN_RECOVER	:
			C_SignRecover(*(CK_SESSION_HANDLE *)PassData->param0,
						  (CK_BYTE_PTR)PassData->param1,
						  *(CK_ULONG *)PassData->param2,
						  (CK_BYTE_PTR)PassData->param3,
						  (CK_ULONG_PTR)PassData->param4
						  );
			break;

		case C_VERIFY_INIT	:
			C_VerifyInit(*(CK_SESSION_HANDLE *)PassData->param0,
					  	  (CK_MECHANISM_PTR)PassData->param1,
					  	  *(CK_OBJECT_HANDLE *)PassData->param2
					     );
			break;

		case C_VERIFY		:
			C_Verify(*(CK_SESSION_HANDLE *)PassData->param0,
					 (CK_BYTE_PTR)PassData->param1,
					 *(CK_ULONG *)PassData->param2,
					 (CK_BYTE_PTR)PassData->param3,
					 *(CK_ULONG *)PassData->param4
					 );
			break;

		case C_VERIFY_UPDATE	:
			C_VerifyUpdate(*(CK_SESSION_HANDLE *)PassData->param0,
					       (CK_BYTE_PTR)PassData->param1,
					       *(CK_ULONG *)PassData->param2
						  );
			break;

		case C_VERIFY_FINAL	:
			C_VerifyFinal(*(CK_SESSION_HANDLE *)PassData->param0,
					  	  (CK_BYTE_PTR)PassData->param1,
					  	  *(CK_ULONG *)PassData->param2
						  );
			break;

		case C_VERIFY_RECOVER_INIT:
			C_VerifyRecoverInit(*(CK_SESSION_HANDLE *)PassData->param0,
							    (CK_MECHANISM_PTR)PassData->param1,
							    *(CK_OBJECT_HANDLE *)PassData->param2
							   );
			break;

		case C_VERIFY_RECOVER:
			C_VerifyRecover(*(CK_SESSION_HANDLE *)PassData->param0,
						    (CK_BYTE_PTR)PassData->param1,
						    *(CK_ULONG *)PassData->param2,
						    (CK_BYTE_PTR)PassData->param3,
						    (CK_ULONG_PTR)PassData->param4
						    );
			break;

		case C_DIGEST_ENCRYPT_UPDATE:
			C_DigestEncryptUpdate(*(CK_SESSION_HANDLE *)PassData->param0,
								  (CK_BYTE_PTR)PassData->param1,
								  *(CK_ULONG *)PassData->param2,
								  (CK_BYTE_PTR)PassData->param3,
								  (CK_ULONG_PTR)PassData->param4
								 );
			break;

		case C_DECRYPT_DIGEST_UPDATE:
			C_DecryptDigestUpdate(*(CK_SESSION_HANDLE *)PassData->param0,
								  (CK_BYTE_PTR)PassData->param1,
								  *(CK_ULONG *)PassData->param2,
								  (CK_BYTE_PTR)PassData->param3,
								  (CK_ULONG_PTR)PassData->param4
								 );
			break;

		case C_SIGN_ENCRYPT_UPDATE:
			C_SignEncryptUpdate(*(CK_SESSION_HANDLE *)PassData->param0,
								  (CK_BYTE_PTR)PassData->param1,
								  *(CK_ULONG *)PassData->param2,
								  (CK_BYTE_PTR)PassData->param3,
								  (CK_ULONG_PTR)PassData->param4
								 );
			break;

		case C_DECRYPT_VERIFY_UPDATE:
			C_DecryptVerifyUpdate(*(CK_SESSION_HANDLE *)PassData->param0,
								  (CK_BYTE_PTR)PassData->param1,
								  *(CK_ULONG *)PassData->param2,
								  (CK_BYTE_PTR)PassData->param3,
								  (CK_ULONG_PTR)PassData->param4
								 );
			break;

		case C_GENERATE_KEY	:
			C_GenerateKey(*(CK_SESSION_HANDLE *)PassData->param0,
						  (CK_MECHANISM_PTR)PassData->param1,
						  (CK_ATTRIBUTE_PTR)PassData->param2,
						  *(CK_ULONG *)PassData->param3,
						  (CK_OBJECT_HANDLE_PTR)PassData->param4
						 );
			break;

		case C_GENERATE_KEY_PAIR:
			C_GenerateKeyPair(*(CK_SESSION_HANDLE *)PassData->param0,
							  (CK_MECHANISM_PTR)PassData->param1,
							  (CK_ATTRIBUTE_PTR)PassData->param2,
							  *(CK_ULONG *)PassData->param3,
							  (CK_ATTRIBUTE_PTR)PassData->param4,
							  *(CK_ULONG *)PassData->param5,
							  (CK_OBJECT_HANDLE_PTR)PassData->param6,
							  (CK_OBJECT_HANDLE_PTR)PassData->param7
							 );
			break;

		case C_WRAP_KEY		:
			C_WrapKey(*(CK_SESSION_HANDLE *)PassData->param0,
					  (CK_MECHANISM_PTR)PassData->param1,
					  *(CK_OBJECT_HANDLE *)PassData->param2,
					  *(CK_OBJECT_HANDLE *)PassData->param3,
					  (CK_BYTE_PTR)PassData->param4,
					  (CK_ULONG_PTR)PassData->param5
					 );
			break;

		case C_UNWRAP_KEY	:
			C_UnwrapKey(*(CK_SESSION_HANDLE *)PassData->param0,
					    (CK_MECHANISM_PTR)PassData->param1,
					    *(CK_OBJECT_HANDLE *)PassData->param2,
					    (CK_BYTE_PTR)PassData->param3,
						*(CK_ULONG *)PassData->param4,
						(CK_ATTRIBUTE_PTR)PassData->param5,
						*(CK_ULONG *)PassData->param6,
						(CK_OBJECT_HANDLE_PTR)PassData->param7
					   );
			break;

		case C_DERIVE_KEY	:
			C_DeriveKey(*(CK_SESSION_HANDLE *)PassData->param0,
						(CK_MECHANISM_PTR)PassData->param1,
						*(CK_OBJECT_HANDLE *)PassData->param2,
						(CK_ATTRIBUTE_PTR)PassData->param3,
						*(CK_ULONG *)PassData->param4,
						(CK_OBJECT_HANDLE_PTR)PassData->param5
						);
			break;

		case C_SEED_RANDOM	:
			C_SeedRandom(*(CK_SESSION_HANDLE *)PassData->param0,
						 (CK_BYTE_PTR)PassData->param1,
						 *(CK_ULONG *)PassData->param2
						);
			break;

		case C_GENERATE_RANDOM:
			C_GenerateRandom(*(CK_SESSION_HANDLE *)PassData->param0,
							 (CK_BYTE_PTR)PassData->param1,
							 *(CK_ULONG *)PassData->param2
							);
			break;

		case C_GET_FUNCTION_STATUS:
			C_GetFunctionStatus(*(CK_SESSION_HANDLE *)PassData->param0);
			break;

		case C_CANCEL_FUNCTION:
			C_CancelFunction(*(CK_SESSION_HANDLE *)PassData->param0);
			break;

		default:

			break;
	}
#ifdef _DEBUG
				Message((LPCTSTR) "Exit PassThrough");
#endif

	return (void *)(&FuncList);
}
