/*++ Copyright (C) Microsoft Corporation, 1996 - 1999 Module Name: scredir Abstract: This module redirects the SCard* API calls Author: reidk 7/27/2000 --*/ #include #include #include #include #include #include #include "scredir.h" #include "scioctl.h" #include "calmsgs.h" #include "calaislb.h" #include "rdpdr.h" // // from secpkg.h // typedef NTSTATUS (NTAPI LSA_IMPERSONATE_CLIENT) (VOID); typedef LSA_IMPERSONATE_CLIENT * PLSA_IMPERSONATE_CLIENT; #define wszWinSCardRegKeyRedirector (L"Software\\Microsoft\\SmartCard\\Redirector") #define wszWinSCardRegVersion (L"Version") #define wszWinSCardRegName (L"Name") #define wszWinSCardRegNameValue (L"scredir.dll") // This is the version number of the interface. // The high word is the major version which must match exactly. // The low word is the minor version. The dll must implement // a minor version that is greater than or equal to the system // minor version. This means that if we add a new funtion to the API, // we increase the minor version and a remoting DLL can still be // backward compatible. This is just like RPC version numbers #define REDIRECTION_VERSION 0x00010000 #define ERROR_RETURN(x) lReturn = x; goto ErrorReturn; #define MAX_SCARDCONTEXT_SIZE 32 #define MAX_SCARDHANDLE_SIZE 32 typedef struct _REDIR_LOCAL_SCARDCONTEXT { REDIR_SCARDCONTEXT Context; HANDLE hHeap; } REDIR_LOCAL_SCARDCONTEXT; typedef struct _REDIR_LOCAL_SCARDHANDLE { REDIR_LOCAL_SCARDCONTEXT *pRedirContext; REDIR_SCARDHANDLE Handle; } REDIR_LOCAL_SCARDHANDLE; // // This structure is used to maintain a list of buffers that are // used for the _SendSCardIOCTL calls // #define INITIAL_BUFFER_SIZE 512 typedef struct _BUFFER_LIST_STRUCT { void *pNext; BOOL fInUse; BYTE *pbBytes; unsigned long cbBytes; unsigned long cbBytesUsed; } BUFFER_LIST_STRUCT; HMODULE g_hModule = NULL; CRITICAL_SECTION g_CreateCS; CRITICAL_SECTION g_SetStartedEventStateCS; CRITICAL_SECTION g_StartedEventCreateCS; CRITICAL_SECTION g_ProcessDetachEventCreateCS; CRITICAL_SECTION g_BufferListCS; HANDLE g_hRdpdrDeviceHandle = INVALID_HANDLE_VALUE; HANDLE g_hRedirStartedEvent = NULL; HANDLE g_hProcessDetachEvent = NULL; LONG g_lProcessDetachEventClients = 0; BOOL g_fInTheProcessOfSettingStartedEvent = FALSE; HANDLE g_hRegisteredWaitHandle = NULL; HANDLE g_hWaitEvent = NULL; IO_STATUS_BLOCK g_StartedStatusBlock; HANDLE g_hUnifiedStartedEvent = NULL; BOOL g_fInProcessDetach = FALSE; BUFFER_LIST_STRUCT *g_pBufferList = NULL; #define IOCTL_RETURN_BUFFER_SIZE 256 BYTE g_rgbIOCTLReturnBuffer[IOCTL_RETURN_BUFFER_SIZE]; unsigned long g_cbIOCTLReturnBuffer; #define _TRY_(y) __try \ { \ y; \ } \ __except(EXCEPTION_EXECUTE_HANDLER) \ { \ ERROR_RETURN(GetExceptionCode()) \ } #define _TRY_2(y) __try \ { \ y; \ } \ __except(EXCEPTION_EXECUTE_HANDLER){} // do nothing // // Forward declarations // NTSTATUS _SendSCardIOCTLWithWaitForCallback( ULONG IoControlCode, PVOID InputBuffer, ULONG InputBufferLength, WAITORTIMERCALLBACK Callback); void SafeMesHandleFree( handle_t *ph); LONG I_DecodeLongReturn( BYTE *pb, unsigned long cb); BOOL _SetStartedEventToCorrectState(void); //--------------------------------------------------------------------------------------- // // MIDL allocation routines // //--------------------------------------------------------------------------------------- void __RPC_FAR *__RPC_USER MIDL_user_allocate(size_t size) { void *pv; if (NULL == (pv = (void *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size))) { SetLastError(ERROR_OUTOFMEMORY); } return (pv); } void __RPC_USER MIDL_user_free(void __RPC_FAR *pv) { if (pv != NULL) { HeapFree(GetProcessHeap(), 0, pv); } } void * SCRedirAlloc(REDIR_LOCAL_SCARDCONTEXT *pRedirContext, size_t size) { return (HeapAlloc( (pRedirContext != NULL) ? pRedirContext->hHeap : GetProcessHeap(), HEAP_ZERO_MEMORY, size)); } LONG _MakeSCardError(NTSTATUS Status) { switch (Status) { case STATUS_DEVICE_NOT_CONNECTED: return (SCARD_E_NO_SERVICE); break; case STATUS_CANCELLED: return (SCARD_E_SYSTEM_CANCELLED); break; default: return (SCARD_E_NO_SERVICE); } } //--------------------------------------------------------------------------------------- // // DllRegisterServer // //--------------------------------------------------------------------------------------- STDAPI DllRegisterServer(void) { HRESULT hr = ERROR_SUCCESS; HKEY hKey; DWORD dwDisposition; DWORD dwVersion = REDIRECTION_VERSION; hr = RegCreateKeyExW( HKEY_LOCAL_MACHINE, wszWinSCardRegKeyRedirector, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition); if (hr == ERROR_SUCCESS) { hr = RegSetValueExW( hKey, wszWinSCardRegName, 0, REG_SZ, (BYTE *) wszWinSCardRegNameValue, (wcslen(wszWinSCardRegNameValue) + 1) * sizeof(WCHAR)); if (hr == ERROR_SUCCESS) { hr = RegSetValueExW( hKey, wszWinSCardRegVersion, 0, REG_DWORD, (BYTE *) &dwVersion, sizeof(DWORD)); } RegCloseKey(hKey); } return (hr); } //--------------------------------------------------------------------------------------- // // DllUnregisterServer // //--------------------------------------------------------------------------------------- STDAPI DllUnregisterServer(void) { HRESULT hr = ERROR_SUCCESS; HKEY hKey; DWORD dwDisposition; DWORD dwVersion = REDIRECTION_VERSION; hr = RegCreateKeyExW( HKEY_LOCAL_MACHINE, wszWinSCardRegKeyRedirector, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition); if (hr == ERROR_SUCCESS) { RegDeleteValueW(hKey, wszWinSCardRegName); RegDeleteValueW(hKey, wszWinSCardRegVersion); RegCloseKey(hKey); } return (hr); } //--------------------------------------------------------------------------------------- // // DllMain // //--------------------------------------------------------------------------------------- BOOL WINAPI DllMain(HMODULE hInstDLL, DWORD fdwReason, LPVOID lpvReserved) { DWORD dwTryCount = 0; DWORD dwCritSecsInitialized = 0; BUFFER_LIST_STRUCT *pTemp = NULL; switch (fdwReason) { case DLL_PROCESS_ATTACH: g_hModule = hInstDLL; __try { InitializeCriticalSection(&g_CreateCS); dwCritSecsInitialized++; InitializeCriticalSection(&g_SetStartedEventStateCS); dwCritSecsInitialized++; InitializeCriticalSection(&g_StartedEventCreateCS); dwCritSecsInitialized++; InitializeCriticalSection(&g_ProcessDetachEventCreateCS); dwCritSecsInitialized++; InitializeCriticalSection(&g_BufferListCS); dwCritSecsInitialized++; } __except(EXCEPTION_EXECUTE_HANDLER) { if (dwCritSecsInitialized >= 1) { DeleteCriticalSection(&g_CreateCS); } if (dwCritSecsInitialized >= 2) { DeleteCriticalSection(&g_SetStartedEventStateCS); } if (dwCritSecsInitialized >= 3) { DeleteCriticalSection(&g_StartedEventCreateCS); } if (dwCritSecsInitialized >= 4) { DeleteCriticalSection(&g_ProcessDetachEventCreateCS); } if (dwCritSecsInitialized >= 5) { DeleteCriticalSection(&g_BufferListCS); } SetLastError(GetExceptionCode()); return (FALSE); } break; case DLL_PROCESS_DETACH: g_fInProcessDetach = TRUE; // // The third parameter, lpvReserved, passed to DllMain // is NULL for FreeLibrary and non-NULL for ProcessExit. // Only clean up for FreeLibrary // //if (lpvReserved == NULL) { // // If we are currently waiting for the started event then kill // that wait // EnterCriticalSection(&g_SetStartedEventStateCS); if (g_hRegisteredWaitHandle != NULL) { UnregisterWaitEx(g_hRegisteredWaitHandle, INVALID_HANDLE_VALUE); g_hRegisteredWaitHandle = NULL; } if (g_hWaitEvent != NULL) { CloseHandle(g_hWaitEvent); g_hWaitEvent = NULL; } LeaveCriticalSection(&g_SetStartedEventStateCS); // // If there are clients waiting on IOCTLs to complete, then let them go. // if (g_hProcessDetachEvent != NULL) { SetEvent(g_hProcessDetachEvent); } if (g_hProcessDetachEvent != NULL) { // // wait for all clients until they are done with the event // while ((g_lProcessDetachEventClients > 0) && (dwTryCount < 50)) { Sleep(10); dwTryCount++; } if (dwTryCount < 50) { CloseHandle(g_hProcessDetachEvent); } } if (g_hRdpdrDeviceHandle != INVALID_HANDLE_VALUE) { CloseHandle(g_hRdpdrDeviceHandle); } if (g_hRedirStartedEvent != NULL) { CloseHandle(g_hRedirStartedEvent); } // // Free all the buffers used for the IOCTL calls // pTemp = g_pBufferList; while (pTemp != NULL) { g_pBufferList = (BUFFER_LIST_STRUCT *) pTemp->pNext; MIDL_user_free(pTemp->pbBytes); MIDL_user_free(pTemp); pTemp = g_pBufferList; } DeleteCriticalSection(&g_CreateCS); DeleteCriticalSection(&g_SetStartedEventStateCS); DeleteCriticalSection(&g_StartedEventCreateCS); DeleteCriticalSection(&g_ProcessDetachEventCreateCS); DeleteCriticalSection(&g_BufferListCS); } break; } return (TRUE); } //--------------------------------------------------------------------------------------- // // GetBuffer // //--------------------------------------------------------------------------------------- BUFFER_LIST_STRUCT * GetBuffer(void) { BUFFER_LIST_STRUCT *pTemp = NULL; BUFFER_LIST_STRUCT *p1 = NULL; BUFFER_LIST_STRUCT *p2 = NULL; EnterCriticalSection(&g_BufferListCS); // // See if there are any buffers allocated yet // if (g_pBufferList == NULL) { g_pBufferList = (BUFFER_LIST_STRUCT *) MIDL_user_allocate(sizeof(BUFFER_LIST_STRUCT)); if (g_pBufferList == NULL) { goto Return; } g_pBufferList->pbBytes = (BYTE *) MIDL_user_allocate(INITIAL_BUFFER_SIZE); if (g_pBufferList->pbBytes == NULL) { MIDL_user_free(g_pBufferList); goto Return; } g_pBufferList->pNext = NULL; g_pBufferList->fInUse = TRUE; g_pBufferList->cbBytes = INITIAL_BUFFER_SIZE; pTemp = g_pBufferList; goto Return; } // // Walk the existing list to see if a free buffer can be found // pTemp = g_pBufferList; while ((pTemp != NULL) && (pTemp->fInUse)) { pTemp = (BUFFER_LIST_STRUCT *)pTemp->pNext; } if (pTemp != NULL) { pTemp->fInUse = TRUE; // // Get rid of any buffers that exist which aren't being used // p1 = pTemp; p2 = (BUFFER_LIST_STRUCT *) pTemp->pNext; while (p2 != NULL) { if (!(p2->fInUse)) { p1->pNext = p2->pNext; MIDL_user_free(p2->pbBytes); MIDL_user_free(p2); p2 = (BUFFER_LIST_STRUCT *) p1->pNext; } else { p1 = (BUFFER_LIST_STRUCT *) p1->pNext; p2 = (BUFFER_LIST_STRUCT *) p2->pNext; } } goto Return; } // // No free buffers, so create a new one // pTemp = (BUFFER_LIST_STRUCT *) MIDL_user_allocate(sizeof(BUFFER_LIST_STRUCT)); if (pTemp == NULL) { goto Return; } pTemp->pbBytes = (BYTE *) MIDL_user_allocate(INITIAL_BUFFER_SIZE); if (pTemp->pbBytes == NULL) { MIDL_user_free(pTemp); goto Return; } pTemp->fInUse = TRUE; pTemp->cbBytes = INITIAL_BUFFER_SIZE; pTemp->pNext = g_pBufferList; g_pBufferList = pTemp; Return: LeaveCriticalSection(&g_BufferListCS); return(pTemp); } //--------------------------------------------------------------------------------------- // // FreeBuffer // //--------------------------------------------------------------------------------------- void FreeBuffer(BUFFER_LIST_STRUCT *pBuffer) { if (pBuffer != NULL) { pBuffer->fInUse = FALSE; } } //--------------------------------------------------------------------------------------- // // GrowBuffer // //--------------------------------------------------------------------------------------- BOOL GrowBuffer(BUFFER_LIST_STRUCT *pBuffer) { BYTE *pTemp; BOOL fRet = TRUE; pTemp = pBuffer->pbBytes; pBuffer->pbBytes = (BYTE *) MIDL_user_allocate(pBuffer->cbBytes * 2); if (pBuffer->pbBytes == NULL) { pBuffer->pbBytes = pTemp; fRet = FALSE; } else { MIDL_user_free(pTemp); pBuffer->cbBytes = pBuffer->cbBytes * 2; } return (fRet); } //--------------------------------------------------------------------------------------- // // _GetProcessDetachEventHandle // //--------------------------------------------------------------------------------------- HANDLE _GetProcessDetachEventHandle(void) { EnterCriticalSection(&g_ProcessDetachEventCreateCS); if (NULL == g_hProcessDetachEvent) { try { g_hProcessDetachEvent = CreateEvent( NULL, // pointer to security attributes TRUE, // flag for manual-reset event FALSE, // flag for initial state NULL); // event-object name } catch (...) { goto Return; } } LeaveCriticalSection(&g_ProcessDetachEventCreateCS); Return: if (g_hProcessDetachEvent != NULL) { InterlockedIncrement(&g_lProcessDetachEventClients); } return (g_hProcessDetachEvent); } void _ReleaseProcessDetachEventHandle(void) { InterlockedDecrement(&g_lProcessDetachEventClients); } //--------------------------------------------------------------------------------------- // // All the code below is to solve the problem of weather or not the redirect Smart // Card Subsystem is available. It is available if we are connected to the client, // and if the clients Smart Card Subsystem is running // //--------------------------------------------------------------------------------------- HANDLE _GetStartedEventHandle(void) { EnterCriticalSection(&g_StartedEventCreateCS); if (NULL == g_hRedirStartedEvent) { g_hRedirStartedEvent = CreateEvent(NULL, TRUE, FALSE, NULL); } LeaveCriticalSection(&g_StartedEventCreateCS); return (g_hRedirStartedEvent); } VOID CALLBACK AccessStartedEventIOCTLCallback( PVOID lpParameter, BOOLEAN TimerOrWaitFired) { HANDLE h = NULL; BOOL fRetry = FALSE; //OutputDebugString("SCREDIR: AccessStartedEventIOCTLCallback\n"); // // Close the handle that was used to fire this callback // EnterCriticalSection(&g_SetStartedEventStateCS); h = g_hRegisteredWaitHandle; g_hRegisteredWaitHandle = NULL; LeaveCriticalSection(&g_SetStartedEventStateCS); //OutputDebugString("SCREDIR: AccessStartedEventIOCTLCallback - through the CS\n"); if (h != NULL) { UnregisterWait(h); } // // Make sure the AccessStartedEvent IOCTL completed and wasn't timed out // if (!TimerOrWaitFired) { // // Make sure the AccessStartedEvent IOCTL completed successfully // if (g_StartedStatusBlock.Status == STATUS_SUCCESS) { //OutputDebugString("SCREDIR: AccessStartedEventIOCTLCallback - g_StartedStatusBlock.Status == STATUS_SUCCESS\n"); g_cbIOCTLReturnBuffer = (unsigned long) g_StartedStatusBlock.Information; // // Look at the value returned from the SCARD_IOCTL_ACCESSSTARTEDEVENT // call to see if we should set the local started event // if (I_DecodeLongReturn( g_rgbIOCTLReturnBuffer, g_cbIOCTLReturnBuffer) == SCARD_S_SUCCESS) { //OutputDebugString("SCREDIR: AccessStartedEventIOCTLCallback - SetEvent\n"); SetEvent(g_hRedirStartedEvent); } } else if (g_StartedStatusBlock.Status == STATUS_CANCELLED) { //OutputDebugString("SCREDIR: AccessStartedEventIOCTLCallback - Got STATUS_CANCELLED\n"); // // Retry // fRetry = TRUE; } else { char a[256]; sprintf(a, "SCREDIR: AccessStartedEventIOCTLCallback - Status = %lx\n", g_StartedStatusBlock.Status); //OutputDebugString(a); } } else { //OutputDebugString("SCREDIR: AccessStartedEventIOCTLCallback - Timed out\n"); } // // Unset the g_fInTheProcessOfSettingStartedEvent boolean // EnterCriticalSection(&g_SetStartedEventStateCS); g_fInTheProcessOfSettingStartedEvent = FALSE; LeaveCriticalSection(&g_SetStartedEventStateCS); if (fRetry) { _SetStartedEventToCorrectState(); } } VOID CALLBACK SCardOnLineIOCTLCallback( PVOID lpParameter, BOOLEAN TimerOrWaitFired) { BOOL fOperationDone = FALSE; NTSTATUS Status = STATUS_SUCCESS; BYTE rgb[4]; HANDLE h = NULL; // // Close the handle that was used to fire this callback // EnterCriticalSection(&g_SetStartedEventStateCS); h = g_hRegisteredWaitHandle; g_hRegisteredWaitHandle = NULL; LeaveCriticalSection(&g_SetStartedEventStateCS); if (h != NULL) { UnregisterWait(h); } // // Make sure the online IOCTL completed and wasn't timed out // if (TimerOrWaitFired) { // // Timed out, so just cancel operation // fOperationDone = TRUE; } else { // // Make sure the SCardOnLine IOCTL completed successfully, then try to // send the IOCTL which will wait on the clients started event // if (g_StartedStatusBlock.Status == STATUS_SUCCESS) { Status = _SendSCardIOCTLWithWaitForCallback( SCARD_IOCTL_ACCESSSTARTEDEVENT, rgb, 4, AccessStartedEventIOCTLCallback); if (Status == STATUS_SUCCESS) { //OutputDebugString("SCREDIR: SCardOnLineIOCTLCallback - _SendSCardIOCTLWithWaitForCallback(SCARD_IOCTL_ACCESSSTARTEDEVENT) - suceeded\n"); g_cbIOCTLReturnBuffer = (unsigned long) g_StartedStatusBlock.Information; // // Look at the value returned from the SCARD_IOCTL_ACCESSSTARTEDEVENT // call to see if we should set the local started event // if (I_DecodeLongReturn( g_rgbIOCTLReturnBuffer, g_cbIOCTLReturnBuffer) == SCARD_S_SUCCESS) { SetEvent(g_hRedirStartedEvent); } fOperationDone = TRUE; } else if (Status == STATUS_PENDING) { //OutputDebugString("SCREDIR: SCardOnLineIOCTLCallback - _SendSCardIOCTLWithWaitForCallback(SCARD_IOCTL_ACCESSSTARTEDEVENT) - PENDING\n"); // // This OK, since the AccessStartedEventIOCTLCallback function // will handle the return once the operation is complete // } else { fOperationDone = TRUE; } } else { fOperationDone = TRUE; } } if (fOperationDone) { EnterCriticalSection(&g_SetStartedEventStateCS); g_fInTheProcessOfSettingStartedEvent = FALSE; LeaveCriticalSection(&g_SetStartedEventStateCS); } } BOOL _SetStartedEventToCorrectState(void) { BOOL fRet = TRUE; BOOL fOperationDone = FALSE; HANDLE h = NULL; NTSTATUS Status = STATUS_SUCCESS; BYTE rgb[4]; // // Make sure the event is created // if (NULL == (h = _GetStartedEventHandle())) { fRet = FALSE; goto Return; } // // If the event is already set then just return // /*if (WAIT_OBJECT_0 == WaitForSingleObject(h, 0)) { //OutputDebugString("SCREDIR: _SetStartedEventToCorrectState - Event already set\n"); goto Return; }*/ EnterCriticalSection(&g_SetStartedEventStateCS); // // If we are already in the process of setting the started event, then just get out // if (g_fInTheProcessOfSettingStartedEvent) { //OutputDebugString("SCREDIR: _SetStartedEventToCorrectState - g_fInTheProcessOfSettingStartedEvent set\n"); LeaveCriticalSection(&g_SetStartedEventStateCS); goto Return; } g_fInTheProcessOfSettingStartedEvent = TRUE; LeaveCriticalSection(&g_SetStartedEventStateCS); ResetEvent(g_hRedirStartedEvent); // // Make the blocking call to rdpdr.sys that will only return after the // client is connected, and the scard device announce has been processed // // NOTE: If this fails, then we can't do much, // Status = _SendSCardIOCTLWithWaitForCallback( SCARD_IOCTL_SMARTCARD_ONLINE, NULL, 0, SCardOnLineIOCTLCallback); if (Status == STATUS_SUCCESS) { //OutputDebugString("SCREDIR: _SetStartedEventToCorrectState - _SendSCardIOCTLWithWaitForCallback(SCARD_IOCTL_SMARTCARD_ONLINE) - suceeded\n"); // // Since the SCARD_IOCTL_SMARTCARD_ONLINE succeeded immediately, we // can just make the SCARD_IOCTL_ACCESSSTARTEDEVENT right now. // Status = _SendSCardIOCTLWithWaitForCallback( SCARD_IOCTL_ACCESSSTARTEDEVENT, rgb, 4, AccessStartedEventIOCTLCallback); if (Status == STATUS_SUCCESS) { //OutputDebugString("SCREDIR: _SetStartedEventToCorrectState - _SendSCardIOCTLWithWaitForCallback(SCARD_IOCTL_ACCESSSTARTEDEVENT) - suceeded\n"); g_cbIOCTLReturnBuffer = (unsigned long) g_StartedStatusBlock.Information; // // Look at the value returned from the SCARD_IOCTL_ACCESSSTARTEDEVENT // call to see if we should set the local started event // if (I_DecodeLongReturn( g_rgbIOCTLReturnBuffer, g_cbIOCTLReturnBuffer) == SCARD_S_SUCCESS) { SetEvent(g_hRedirStartedEvent); } fOperationDone = TRUE; } else if (Status == STATUS_PENDING) { //OutputDebugString("SCREDIR: _SetStartedEventToCorrectState - _SendSCardIOCTLWithWaitForCallback(SCARD_IOCTL_ACCESSSTARTEDEVENT) - PENDING\n"); // // This OK, since the AccessStartedEventIOCTLCallback function // will handle the return once the operation is complete // } else { fOperationDone = TRUE; } } else if (Status == STATUS_PENDING) { //OutputDebugString("SCREDIR: _SetStartedEventToCorrectState - _SendSCardIOCTLWithWaitForCallback(SCARD_IOCTL_SMARTCARD_ONLINE) - PENDING\n"); // // This is OK, the SCardOnLineIOCTLCallback will make the next call // to _SendSCardIOCTLWithWaitForCallback with SCARD_IOCTL_ACCESSSTARTEDEVENT // } else { fOperationDone = TRUE; } if (fOperationDone) { EnterCriticalSection(&g_SetStartedEventStateCS); g_fInTheProcessOfSettingStartedEvent = FALSE; LeaveCriticalSection(&g_SetStartedEventStateCS); } // // Now check to see if the operation completed successfully // if ((Status != STATUS_PENDING) && (Status != STATUS_SUCCESS)) { fRet = FALSE; } Return: return (fRet); } //--------------------------------------------------------------------------------------- // // _CreateRdpdrDeviceHandle // //--------------------------------------------------------------------------------------- HANDLE _CreateRdpdrDeviceHandle() { WCHAR wszDeviceName[56]; swprintf(wszDeviceName, L"\\\\TSCLIENT\\%S", DR_SMARTCARD_SUBSYSTEM); return (CreateFileW( wszDeviceName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, NULL)); } //--------------------------------------------------------------------------------------- // // _CreateGlobalRdpdrHandle // //--------------------------------------------------------------------------------------- NTSTATUS _CreateGlobalRdpdrHandle() { NTSTATUS Status = STATUS_SUCCESS; EnterCriticalSection(&g_CreateCS); // // Check to see if the SCardDevice handle has been created // yet, if not, then create it // if (g_hRdpdrDeviceHandle == INVALID_HANDLE_VALUE) { g_hRdpdrDeviceHandle = _CreateRdpdrDeviceHandle(); if (g_hRdpdrDeviceHandle == INVALID_HANDLE_VALUE) { Status = STATUS_OPEN_FAILED; } } LeaveCriticalSection(&g_CreateCS); return (Status); } //--------------------------------------------------------------------------------------- // // _SendSCardIOCTLWithWaitForCallback // //--------------------------------------------------------------------------------------- NTSTATUS _SendSCardIOCTLWithWaitForCallback( ULONG IoControlCode, PVOID InputBuffer, ULONG InputBufferLength, WAITORTIMERCALLBACK Callback) { NTSTATUS Status = STATUS_SUCCESS; if (g_fInProcessDetach) { goto ErrorReturn; } Status = _CreateGlobalRdpdrHandle(); if (Status != STATUS_SUCCESS) { return (Status); } // // Create the event which is set when the function successfully completes // if (g_hWaitEvent == NULL) { g_hWaitEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (g_hWaitEvent == NULL) { goto ErrorReturn; } } else { ResetEvent(g_hWaitEvent); } Status = NtDeviceIoControlFile( g_hRdpdrDeviceHandle, g_hWaitEvent, NULL, NULL, &g_StartedStatusBlock, IoControlCode, InputBuffer, InputBufferLength, g_rgbIOCTLReturnBuffer, IOCTL_RETURN_BUFFER_SIZE); if (Status == STATUS_PENDING) { EnterCriticalSection(&g_SetStartedEventStateCS); // // The g_hWaitEvent being set by the driver will trigger this registered callback // if (!RegisterWaitForSingleObject( &g_hRegisteredWaitHandle, g_hWaitEvent, Callback, NULL, INFINITE, WT_EXECUTEONLYONCE)) { LeaveCriticalSection(&g_SetStartedEventStateCS); goto ErrorReturn; } LeaveCriticalSection(&g_SetStartedEventStateCS); } else if (Status == STATUS_SUCCESS) { g_cbIOCTLReturnBuffer = (unsigned long) g_StartedStatusBlock.Information; } else { g_cbIOCTLReturnBuffer = 0; } Return: return (Status); ErrorReturn: Status = STATUS_INSUFFICIENT_RESOURCES; goto Return; } //--------------------------------------------------------------------------------------- // // _SendSCardIOCTL // //--------------------------------------------------------------------------------------- NTSTATUS _SendSCardIOCTL( ULONG IoControlCode, PVOID InputBuffer, ULONG InputBufferLength, BUFFER_LIST_STRUCT **ppOutputBuffer) { NTSTATUS Status = STATUS_SUCCESS; IO_STATUS_BLOCK StatusBlock; HANDLE rgWaitHandles[2]; DWORD dwIndex; *ppOutputBuffer = NULL; rgWaitHandles[0] = NULL; rgWaitHandles[1] = NULL; // // Make sure the handle to the rdpdr device is created // Status = _CreateGlobalRdpdrHandle(); if (Status != STATUS_SUCCESS) { return (Status); } // // Get an output buffer for the call // *ppOutputBuffer = GetBuffer(); if (*ppOutputBuffer == NULL) { return (STATUS_NO_MEMORY); } // // Create the event that will be signaled when the IOCTL is complete // rgWaitHandles[0] = CreateEvent(NULL, TRUE, FALSE, NULL); if (rgWaitHandles[0] == NULL) { return (STATUS_INSUFFICIENT_RESOURCES); } while (1) { Status = NtDeviceIoControlFile( g_hRdpdrDeviceHandle, rgWaitHandles[0], NULL, NULL, &StatusBlock, IoControlCode, InputBuffer, InputBufferLength, (*ppOutputBuffer)->pbBytes, (*ppOutputBuffer)->cbBytes); if (Status == STATUS_PENDING) { rgWaitHandles[1] = _GetProcessDetachEventHandle(); if (rgWaitHandles[1] == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } dwIndex = WaitForMultipleObjects(2, rgWaitHandles, FALSE, INFINITE); if (dwIndex != WAIT_FAILED) { dwIndex = dwIndex - WAIT_OBJECT_0; // // The IOCTL wait event was signaled if dwIndex == 0. Otherwise the // process detach event was signaled // if (dwIndex == 0) { Status = StatusBlock.Status; } } else { Status = STATUS_UNEXPECTED_IO_ERROR; } _ReleaseProcessDetachEventHandle(); } if (Status == STATUS_BUFFER_TOO_SMALL) { if (!GrowBuffer(*ppOutputBuffer)) { Status = STATUS_NO_MEMORY; break; } ResetEvent(rgWaitHandles[0]); } else { break; } } if (Status != STATUS_SUCCESS) { // // If we got the STATUS_DEVICE_NOT_CONNECTED error, then go back to waiting // for a connect // if (Status == STATUS_DEVICE_NOT_CONNECTED) { _SetStartedEventToCorrectState(); } else if ((Status == STATUS_CANCELLED) && (g_hUnifiedStartedEvent != NULL)) { //OutputDebugString("SCREDIR: _SendSCardIOCTL: resetting g_hUnifiedStartedEvent\n"); ResetEvent(g_hUnifiedStartedEvent); _SetStartedEventToCorrectState(); } (*ppOutputBuffer)->cbBytesUsed = 0; goto Return; } (*ppOutputBuffer)->cbBytesUsed = (unsigned long) StatusBlock.Information; Return: if (rgWaitHandles[0] != NULL) { CloseHandle(rgWaitHandles[0]); } return (Status); } //--------------------------------------------------------------------------------------- // // SafeMesHandleFree // //--------------------------------------------------------------------------------------- void SafeMesHandleFree(handle_t *ph) { if (*ph != 0) { MesHandleFree(*ph); *ph = 0; } } //--------------------------------------------------------------------------------------- // // _CalculateNumBytesInMultiStringA // //--------------------------------------------------------------------------------------- DWORD _CalculateNumBytesInMultiStringA(LPCSTR psz) { DWORD dwTotal = sizeof(char); // trailing '/0' DWORD dwNumChars = 0; LPCSTR pszCurrent = psz; if (psz == NULL) { return (0); } if (pszCurrent[0] == '\0') { if (pszCurrent[1] == '\0') { return (2 * sizeof(char)); } pszCurrent++; dwTotal += sizeof(char); } while (pszCurrent[0] != '\0') { dwNumChars = strlen(pszCurrent) + 1; dwTotal += dwNumChars * sizeof(char); pszCurrent += dwNumChars; } return (dwTotal); } //--------------------------------------------------------------------------------------- // // _CalculateNumBytesInMultiStringW // //--------------------------------------------------------------------------------------- DWORD _CalculateNumBytesInMultiStringW(LPCWSTR pwsz) { DWORD dwTotal = sizeof(WCHAR); // trailing L'/0' DWORD dwNumChars = 0; LPCWSTR pwszCurrent = pwsz; if (pwsz == NULL) { return (0); } if (pwszCurrent[0] == L'\0') { if (pwszCurrent[1] == L'\0') { (2 * sizeof(WCHAR)); } pwszCurrent++; dwTotal += sizeof(WCHAR); } while (pwszCurrent[0] != L'\0') { dwNumChars = wcslen(pwszCurrent) + 1; dwTotal += dwNumChars * sizeof(WCHAR); pwszCurrent += dwNumChars; } return (dwTotal); } //--------------------------------------------------------------------------------------- // // _CalculateNumBytesInAtr // //--------------------------------------------------------------------------------------- DWORD _CalculateNumBytesInAtr(LPCBYTE pbAtr) { DWORD dwAtrLen = 0; if (ParseAtr(pbAtr, &dwAtrLen, NULL, NULL, 33)) { return (dwAtrLen); } else { return (0); } } //--------------------------------------------------------------------------------------- // // _CopyReturnToCallerBuffer // //--------------------------------------------------------------------------------------- #define BYTE_TYPE_RETURN 1 #define SZ_TYPE_RETURN 2 #define WSZ_TYPE_RETURN 3 LONG _CopyReturnToCallerBuffer( REDIR_LOCAL_SCARDCONTEXT *pRedirContext, LPBYTE pbReturn, DWORD cbReturn, LPBYTE pbUserBuffer, LPDWORD pcbUserBuffer, DWORD dwReturnType) { LPBYTE *ppBuf; BOOL fAutoAllocate = (*pcbUserBuffer == SCARD_AUTOALLOCATE); DWORD dwEnd; DWORD dwCallersBufferSize = *pcbUserBuffer; // // The number of chars or bytes, depending on the type of return. // if (dwReturnType == WSZ_TYPE_RETURN) { *pcbUserBuffer = cbReturn / sizeof(WCHAR); } else if (dwReturnType == SZ_TYPE_RETURN) { *pcbUserBuffer = cbReturn / sizeof(char); } else { *pcbUserBuffer = cbReturn; } // // If pbUserBuffer is not NULL, then the caller wants the data, // not just the size, so give it to em' // if ((pbReturn != NULL) && (pbUserBuffer != NULL)) { // // validate the data // if (dwReturnType == WSZ_TYPE_RETURN) { // // If we aren't auto allocating and the users buffer is too small then // get out. This is just extra protection to ensure that the client // isn't ill behaved. Since the client was passed the size of our // callers buffer the client should really fail if the buffer isn't // big enough, but since we can't trust the client, do this extra check. // if ((!fAutoAllocate) && (dwCallersBufferSize < (cbReturn / sizeof(WCHAR)))) { return (SCARD_E_UNEXPECTED); } dwEnd = cbReturn / sizeof(WCHAR); if ((dwEnd < 2) || // must be at least two chars (((LPWSTR) pbReturn)[dwEnd-1] != L'\0') || // last char must be '\0' (((LPWSTR) pbReturn)[dwEnd-2] != L'\0')) // second to last char must be '\0' { return (SCARD_E_UNEXPECTED); } } else if (dwReturnType == SZ_TYPE_RETURN) { // // If we aren't auto allocating and the users buffer is too small then // get out. This is just extra protection to ensure that the client // isn't ill behaved. Since the client was passed the size of our // callers buffer the client should really fail if the buffer isn't // big enough, but since we can't trust the client, do this extra check. // if ((!fAutoAllocate) && (dwCallersBufferSize < (cbReturn / sizeof(char)))) { return (SCARD_E_UNEXPECTED); } dwEnd = cbReturn / sizeof(char); if ((dwEnd < 2) || // must be at least two chars (((LPSTR) pbReturn)[dwEnd-1] != '\0') || // last char must be '\0' (((LPSTR) pbReturn)[dwEnd-2] != '\0')) // second to last char must be '\0' { return (SCARD_E_UNEXPECTED); } } else { // // If we aren't auto allocating and the users buffer is too small then // get out. This is just extra protection to ensure that the client // isn't ill behaved. Since the client was passed the size of our // callers buffer the client should really fail if the buffer isn't // big enough, but since we can't trust the client, do this extra check. // if ((!fAutoAllocate) && (dwCallersBufferSize < cbReturn)) { return (SCARD_E_UNEXPECTED); } } // // Allocate space for caller if requested, else, copy to callers // supplied buffer // if (fAutoAllocate) { ppBuf = (LPBYTE *) pbUserBuffer; *ppBuf = (LPBYTE) SCRedirAlloc(pRedirContext, cbReturn); if (*ppBuf != NULL) { memcpy(*ppBuf, pbReturn, cbReturn); } else { return (SCARD_E_NO_MEMORY); } } else { memcpy(pbUserBuffer, pbReturn, cbReturn); } } return (SCARD_S_SUCCESS); } //--------------------------------------------------------------------------------------- // // I_DecodeLongReturn // //--------------------------------------------------------------------------------------- LONG I_DecodeLongReturn( BYTE *pb, unsigned long cb) { handle_t h = 0; RPC_STATUS rpcStatus; Long_Return LongReturn; LONG lReturn; rpcStatus = MesDecodeBufferHandleCreate( (char *) pb, cb, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED); } memset(&LongReturn, 0, sizeof(LongReturn)); _TRY_(Long_Return_Decode(h, &LongReturn)) lReturn = LongReturn.ReturnCode; _TRY_2(Long_Return_Free(h, &LongReturn)) Return: SafeMesHandleFree(&h); return (lReturn); ErrorReturn: goto Return; } //--------------------------------------------------------------------------------------- // // SCardEstablishContext // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardEstablishContext( IN DWORD dwScope, IN LPCVOID pvReserved1, IN LPCVOID pvReserved2, OUT LPSCARDCONTEXT phContext) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; BOOL fFreeDecode = FALSE; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; EstablishContext_Call EstablishContextCall; EstablishContext_Return EstablishContextReturn; // // This event is the "smart card subsystem started" event that // winscard.dll and scredir.dll share. scredir will Reset this event // if it gets a STATUS_CANCELLED returned from the rdpdr driver, or if it // gets and indication that the clients scardsvr service was stopped (it // gets these indications via SCardEstablishContext returing SCARD_E_NO_SERVICE // or by SCardGetStatusChange returning SCARD_E_SYSTEM_CANCELLED). It // does this so that the event goes into the unsignalled state as soon as // possible when a disconnect or service shutdown is detected... a STATUS_CANCELLED // returned from rdpdr happens when a disconnect takes place // g_hUnifiedStartedEvent = (HANDLE) pvReserved2; // // Validate input params and initialize the out param // if (phContext == NULL) { ERROR_RETURN(SCARD_E_INVALID_PARAMETER) } else { *phContext = NULL; } if ((SCARD_SCOPE_USER != dwScope) // && (SCARD_SCOPE_TERMINAL != dwScope) // Maybe NT V5+? && (SCARD_SCOPE_SYSTEM != dwScope)) { ERROR_RETURN(SCARD_E_INVALID_VALUE) } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the EstablishContext params // EstablishContextCall.dwScope = dwScope; _TRY_(EstablishContext_Call_Encode(h, &EstablishContextCall)) // // Make the EstablishContext call to the client // Status = _SendSCardIOCTL( SCARD_IOCTL_ESTABLISHCONTEXT, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } SafeMesHandleFree(&h); // // Decode the return // rpcStatus = MesDecodeBufferHandleCreate( (char *) pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } memset(&EstablishContextReturn, 0, sizeof(EstablishContextReturn)); _TRY_(EstablishContext_Return_Decode(h, &EstablishContextReturn)) fFreeDecode = TRUE; lReturn = EstablishContextReturn.ReturnCode; if (lReturn == SCARD_S_SUCCESS) { REDIR_LOCAL_SCARDCONTEXT *pRedirLocalContext = NULL; // // The value that represents the SCARDCONTEXT on the remote client // machine is a variable size, so allocate memory for the struct // that holds the variable length context size and pointer, plus // the actual bytes for the context... but first, make sure the // context is a reasonable size // if (EstablishContextReturn.Context.cbContext > MAX_SCARDCONTEXT_SIZE) { ERROR_RETURN(SCARD_E_UNEXPECTED) } pRedirLocalContext = (REDIR_LOCAL_SCARDCONTEXT *) MIDL_user_allocate( sizeof(REDIR_LOCAL_SCARDCONTEXT) + EstablishContextReturn.Context.cbContext); if (pRedirLocalContext != NULL) { pRedirLocalContext->Context.cbContext = EstablishContextReturn.Context.cbContext; pRedirLocalContext->Context.pbContext = ((BYTE *) pRedirLocalContext) + sizeof(REDIR_LOCAL_SCARDCONTEXT); memcpy( pRedirLocalContext->Context.pbContext, EstablishContextReturn.Context.pbContext, EstablishContextReturn.Context.cbContext); pRedirLocalContext->hHeap = (HANDLE) pvReserved1; *phContext = (SCARDCONTEXT) pRedirLocalContext; } else { lReturn = SCARD_E_NO_MEMORY; } } else if ((lReturn == SCARD_E_NO_SERVICE) && (g_hUnifiedStartedEvent != NULL)) { // // This error indicates that the clients scardsvr service has been stopped, // so reset the unified started event // //OutputDebugString("SCREDIR: SCardEstablishContext: resetting g_hUnifiedStartedEvent\n"); ResetEvent(g_hUnifiedStartedEvent); _SetStartedEventToCorrectState(); } Return: if (fFreeDecode) { _TRY_2(EstablishContext_Return_Free(h, &EstablishContextReturn)) } SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: if ((phContext != NULL) && (*phContext != NULL)) { MIDL_user_free((void *) *phContext); *phContext = NULL; } goto Return; } //--------------------------------------------------------------------------------------- // // I_ContextCallWithLongReturn // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI I_ContextCallWithLongReturn( IN SCARDCONTEXT hContext, ULONG IoControlCode) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; Context_Call ContextCall; if (hContext == NULL) { return (SCARD_E_INVALID_PARAMETER); } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the ContextCall params // ContextCall.Context = ((REDIR_LOCAL_SCARDCONTEXT *) hContext)->Context; _TRY_(Context_Call_Encode(h, &ContextCall)) // // Make the IoControl call to the client // Status = _SendSCardIOCTL( IoControlCode, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } // // Decode the return // lReturn = I_DecodeLongReturn(pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed); Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } //--------------------------------------------------------------------------------------- // // SCardReleaseContext // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardReleaseContext( IN SCARDCONTEXT hContext) { LONG lReturn = SCARD_S_SUCCESS; __try { if (hContext == NULL) { return (SCARD_E_INVALID_PARAMETER); } lReturn = I_ContextCallWithLongReturn( hContext, SCARD_IOCTL_RELEASECONTEXT); MIDL_user_free((REDIR_LOCAL_SCARDCONTEXT *) hContext); } __except(EXCEPTION_EXECUTE_HANDLER) { return (SCARD_E_INVALID_PARAMETER); } return (lReturn); } //--------------------------------------------------------------------------------------- // // SCardIsValidContext // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardIsValidContext( IN SCARDCONTEXT hContext) { return (I_ContextCallWithLongReturn( hContext, SCARD_IOCTL_ISVALIDCONTEXT)); } //--------------------------------------------------------------------------------------- // // SCardListReaderGroups // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI I_SCardListReaderGroups( IN SCARDCONTEXT hContext, OUT LPBYTE mszGroups, IN OUT LPDWORD pcchGroups, IN BOOL fUnicode) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; ListReaderGroups_Call ListReaderGroupsCall; ListReaderGroups_Return ListReaderGroupsReturn; if (pcchGroups == NULL) { return (SCARD_E_INVALID_PARAMETER); } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the ListReaderGroups params // if (hContext != NULL) { ListReaderGroupsCall.Context = ((REDIR_LOCAL_SCARDCONTEXT *) hContext)->Context; } else { ListReaderGroupsCall.Context.pbContext = NULL; ListReaderGroupsCall.Context.cbContext = 0; } ListReaderGroupsCall.fmszGroupsIsNULL = (mszGroups == NULL); ListReaderGroupsCall.cchGroups = *pcchGroups; _TRY_(ListReaderGroups_Call_Encode(h, &ListReaderGroupsCall)) // // Make the ListReaderGroups call to the client // Status = _SendSCardIOCTL( fUnicode ? SCARD_IOCTL_LISTREADERGROUPSW : SCARD_IOCTL_LISTREADERGROUPSA, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } SafeMesHandleFree(&h); // // Decode the return // rpcStatus = MesDecodeBufferHandleCreate( (char *) pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } memset(&ListReaderGroupsReturn, 0, sizeof(ListReaderGroupsReturn)); _TRY_(ListReaderGroups_Return_Decode(h, &ListReaderGroupsReturn)) // // If successful, then copy the returned multi string // if (ListReaderGroupsReturn.ReturnCode == SCARD_S_SUCCESS) { lReturn = _CopyReturnToCallerBuffer( (REDIR_LOCAL_SCARDCONTEXT *) hContext, ListReaderGroupsReturn.msz, ListReaderGroupsReturn.cBytes, mszGroups, pcchGroups, fUnicode ? WSZ_TYPE_RETURN : SZ_TYPE_RETURN); } else { lReturn = ListReaderGroupsReturn.ReturnCode; } _TRY_2(ListReaderGroups_Return_Free(h, &ListReaderGroupsReturn)) Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } WINSCARDAPI LONG WINAPI SCardListReaderGroupsA( IN SCARDCONTEXT hContext, OUT LPSTR mszGroups, IN OUT LPDWORD pcchGroups) { return (I_SCardListReaderGroups( hContext, (LPBYTE) mszGroups, pcchGroups, FALSE)); } WINSCARDAPI LONG WINAPI SCardListReaderGroupsW( IN SCARDCONTEXT hContext, OUT LPWSTR mszGroups, IN OUT LPDWORD pcchGroups) { return (I_SCardListReaderGroups( hContext, (LPBYTE) mszGroups, pcchGroups, TRUE)); } //--------------------------------------------------------------------------------------- // // SCardListReaders // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI I_SCardListReaders( IN SCARDCONTEXT hContext, IN LPCBYTE mszGroups, OUT LPBYTE mszReaders, IN OUT LPDWORD pcchReaders, IN BOOL fUnicode) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; ListReaders_Call ListReadersCall; ListReaders_Return ListReadersReturn; if (pcchReaders == NULL) { return (SCARD_E_INVALID_PARAMETER); } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the ListReaders params // if (hContext != NULL) { ListReadersCall.Context = ((REDIR_LOCAL_SCARDCONTEXT *) hContext)->Context; } else { ListReadersCall.Context.pbContext = NULL; ListReadersCall.Context.cbContext = 0; } ListReadersCall.cBytes = fUnicode ? _CalculateNumBytesInMultiStringW((LPCWSTR) mszGroups) : _CalculateNumBytesInMultiStringA((LPCSTR) mszGroups); ListReadersCall.mszGroups = mszGroups; ListReadersCall.fmszReadersIsNULL = (mszReaders == NULL); ListReadersCall.cchReaders = *pcchReaders; _TRY_(ListReaders_Call_Encode(h, &ListReadersCall)) // // Make the ListReaders call to the client // Status = _SendSCardIOCTL( fUnicode ? SCARD_IOCTL_LISTREADERSW : SCARD_IOCTL_LISTREADERSA, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } SafeMesHandleFree(&h); // // Decode the return // rpcStatus = MesDecodeBufferHandleCreate( (char *) pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } memset(&ListReadersReturn, 0, sizeof(ListReadersReturn)); _TRY_(ListReaders_Return_Decode(h, &ListReadersReturn)) // // If successful, then copy the returned multi string // if (ListReadersReturn.ReturnCode == SCARD_S_SUCCESS) { lReturn = _CopyReturnToCallerBuffer( (REDIR_LOCAL_SCARDCONTEXT *) hContext, ListReadersReturn.msz, ListReadersReturn.cBytes, mszReaders, pcchReaders, fUnicode ? WSZ_TYPE_RETURN : SZ_TYPE_RETURN); } else { lReturn = ListReadersReturn.ReturnCode; } _TRY_2(ListReaders_Return_Free(h, &ListReadersReturn)) Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } WINSCARDAPI LONG WINAPI SCardListReadersA( IN SCARDCONTEXT hContext, IN LPCSTR mszGroups, OUT LPSTR mszReaders, IN OUT LPDWORD pcchReaders) { return (I_SCardListReaders( hContext, (LPCBYTE) mszGroups, (LPBYTE) mszReaders, pcchReaders, FALSE)); } WINSCARDAPI LONG WINAPI SCardListReadersW( IN SCARDCONTEXT hContext, IN LPCWSTR mszGroups, OUT LPWSTR mszReaders, IN OUT LPDWORD pcchReaders) { return (I_SCardListReaders( hContext, (LPCBYTE) mszGroups, (LPBYTE) mszReaders, pcchReaders, TRUE)); } //--------------------------------------------------------------------------------------- // // I_ContextAndStringCallWithLongReturn // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI I_ContextAndStringCallWithLongReturn( IN SCARDCONTEXT hContext, IN LPCBYTE sz, IN BOOL fUnicode, ULONG IoControlCode) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; ContextAndStringA_Call ContextAndStringCallA; ContextAndStringW_Call ContextAndStringCallW; if (hContext == NULL) { return (SCARD_E_INVALID_PARAMETER); } else if (sz == NULL) { return (SCARD_E_INVALID_VALUE); } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the ContextAndString params // ContextAndStringCallA.Context = ContextAndStringCallW.Context = ((REDIR_LOCAL_SCARDCONTEXT *) hContext)->Context; if (fUnicode) { ContextAndStringCallW.sz = (LPCWSTR) sz; _TRY_(ContextAndStringW_Call_Encode(h, &ContextAndStringCallW)) } else { ContextAndStringCallA.sz = (LPCSTR) sz; _TRY_(ContextAndStringA_Call_Encode(h, &ContextAndStringCallA)) } // // Make the call to the client // Status = _SendSCardIOCTL( IoControlCode, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } // // Decode the return // lReturn = I_DecodeLongReturn(pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed); Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } //--------------------------------------------------------------------------------------- // // SCardIntroduceReaderGroup // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardIntroduceReaderGroupA( IN SCARDCONTEXT hContext, IN LPCSTR szGroupName) { return (I_ContextAndStringCallWithLongReturn( hContext, (LPCBYTE) szGroupName, FALSE, SCARD_IOCTL_INTRODUCEREADERGROUPA)); } WINSCARDAPI LONG WINAPI SCardIntroduceReaderGroupW( IN SCARDCONTEXT hContext, IN LPCWSTR szGroupName) { return (I_ContextAndStringCallWithLongReturn( hContext, (LPCBYTE) szGroupName, TRUE, SCARD_IOCTL_INTRODUCEREADERGROUPW)); } //--------------------------------------------------------------------------------------- // // SCardForgetReaderGroup // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardForgetReaderGroupA( IN SCARDCONTEXT hContext, IN LPCSTR szGroupName) { return (I_ContextAndStringCallWithLongReturn( hContext, (LPCBYTE) szGroupName, FALSE, SCARD_IOCTL_FORGETREADERGROUPA)); } WINSCARDAPI LONG WINAPI SCardForgetReaderGroupW( IN SCARDCONTEXT hContext, IN LPCWSTR szGroupName) { return (I_ContextAndStringCallWithLongReturn( hContext, (LPCBYTE) szGroupName, TRUE, SCARD_IOCTL_FORGETREADERGROUPW)); } //--------------------------------------------------------------------------------------- // // I_ContextAndTwoStringCallWithLongReturn // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI I_ContextAndTwoStringCallWithLongReturn( IN SCARDCONTEXT hContext, IN LPCBYTE sz1, IN LPCBYTE sz2, IN BOOL fUnicode, ULONG IoControlCode) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; ContextAndTwoStringA_Call ContextAndTwoStringCallA; ContextAndTwoStringW_Call ContextAndTwoStringCallW; if (hContext == NULL) { return (SCARD_E_INVALID_PARAMETER); } else if ((sz1 == NULL) || (sz2 == NULL)) { return (SCARD_E_INVALID_VALUE); } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the ContextAndTwoString params // ContextAndTwoStringCallA.Context = ContextAndTwoStringCallW.Context = ((REDIR_LOCAL_SCARDCONTEXT *) hContext)->Context; if (fUnicode) { ContextAndTwoStringCallW.sz1 = (LPCWSTR) sz1; ContextAndTwoStringCallW.sz2 = (LPCWSTR) sz2; _TRY_(ContextAndTwoStringW_Call_Encode(h, &ContextAndTwoStringCallW)) } else { ContextAndTwoStringCallA.sz1 = (LPCSTR) sz1; ContextAndTwoStringCallA.sz2 = (LPCSTR) sz2; _TRY_(ContextAndTwoStringA_Call_Encode(h, &ContextAndTwoStringCallA)) } // // Make the call to the client // Status = _SendSCardIOCTL( IoControlCode, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { MesHandleFree(h); ERROR_RETURN(_MakeSCardError(Status)) } // // Decode the return // lReturn = I_DecodeLongReturn(pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed); Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } //--------------------------------------------------------------------------------------- // // SCardIntroduceReader // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardIntroduceReaderA( IN SCARDCONTEXT hContext, IN LPCSTR szReaderName, IN LPCSTR szDeviceName) { return (I_ContextAndTwoStringCallWithLongReturn( hContext, (LPCBYTE) szReaderName, (LPCBYTE) szDeviceName, FALSE, SCARD_IOCTL_INTRODUCEREADERA)); } WINSCARDAPI LONG WINAPI SCardIntroduceReaderW( IN SCARDCONTEXT hContext, IN LPCWSTR szReaderName, IN LPCWSTR szDeviceName) { return (I_ContextAndTwoStringCallWithLongReturn( hContext, (LPCBYTE) szReaderName, (LPCBYTE) szDeviceName, TRUE, SCARD_IOCTL_INTRODUCEREADERW)); } //--------------------------------------------------------------------------------------- // // SCardForgetReader // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardForgetReaderA( IN SCARDCONTEXT hContext, IN LPCSTR szReaderName) { return (I_ContextAndStringCallWithLongReturn( hContext, (LPCBYTE) szReaderName, FALSE, SCARD_IOCTL_FORGETREADERA)); } WINSCARDAPI LONG WINAPI SCardForgetReaderW( IN SCARDCONTEXT hContext, IN LPCWSTR szReaderName) { return (I_ContextAndStringCallWithLongReturn( hContext, (LPCBYTE) szReaderName, TRUE, SCARD_IOCTL_FORGETREADERW)); } //--------------------------------------------------------------------------------------- // // SCardAddReaderToGroup // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardAddReaderToGroupA( IN SCARDCONTEXT hContext, IN LPCSTR szReaderName, IN LPCSTR szGroupName) { return (I_ContextAndTwoStringCallWithLongReturn( hContext, (LPCBYTE) szReaderName, (LPCBYTE) szGroupName, FALSE, SCARD_IOCTL_ADDREADERTOGROUPA)); } WINSCARDAPI LONG WINAPI SCardAddReaderToGroupW( IN SCARDCONTEXT hContext, IN LPCWSTR szReaderName, IN LPCWSTR szGroupName) { return (I_ContextAndTwoStringCallWithLongReturn( hContext, (LPCBYTE) szReaderName, (LPCBYTE) szGroupName, TRUE, SCARD_IOCTL_ADDREADERTOGROUPW)); } //--------------------------------------------------------------------------------------- // // SCardRemoveReaderFromGroup // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardRemoveReaderFromGroupA( IN SCARDCONTEXT hContext, IN LPCSTR szReaderName, IN LPCSTR szGroupName) { return (I_ContextAndTwoStringCallWithLongReturn( hContext, (LPCBYTE) szReaderName, (LPCBYTE) szGroupName, FALSE, SCARD_IOCTL_REMOVEREADERFROMGROUPA)); } WINSCARDAPI LONG WINAPI SCardRemoveReaderFromGroupW( IN SCARDCONTEXT hContext, IN LPCWSTR szReaderName, IN LPCWSTR szGroupName) { return (I_ContextAndTwoStringCallWithLongReturn( hContext, (LPCBYTE) szReaderName, (LPCBYTE) szGroupName, TRUE, SCARD_IOCTL_REMOVEREADERFROMGROUPW)); } //--------------------------------------------------------------------------------------- // // _AllocAndCopyReaderState*StructsForCall and _CopyReaderState*StructsForReturn // //--------------------------------------------------------------------------------------- LONG _AllocAndCopyReaderStateAStructsForCall( DWORD cReaders, ReaderStateA **prgReaderStatesToEncodeA, LPSCARD_READERSTATE_A rgReaderStates) { DWORD i; ReaderStateA *rgAlloced; rgAlloced = (ReaderStateA *) MIDL_user_allocate(cReaders * sizeof(ReaderStateA)); if (rgAlloced == NULL) { return (SCARD_E_NO_MEMORY); } for (i=0; iContext; LocateCardsCallA.cBytes = _CalculateNumBytesInMultiStringA(mszCards); LocateCardsCallA.mszCards = (LPCBYTE) mszCards; LocateCardsCallA.cReaders = cReaders; lReturn = _AllocAndCopyReaderStateAStructsForCall( cReaders, &rgReaderStatesToEncodeA, rgReaderStates); if (lReturn != SCARD_S_SUCCESS) { ERROR_RETURN(SCARD_E_NO_MEMORY) } LocateCardsCallA.rgReaderStates = rgReaderStatesToEncodeA; _TRY_(LocateCardsA_Call_Encode(h, &LocateCardsCallA)) // // Make the LocateCards call to the client // Status = _SendSCardIOCTL( SCARD_IOCTL_LOCATECARDSA, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } SafeMesHandleFree(&h); // // Decode the return // rpcStatus = MesDecodeBufferHandleCreate( (char *) pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } memset(&LocateCardsReturn, 0 , sizeof(LocateCardsReturn)); _TRY_(LocateCards_Return_Decode(h, &LocateCardsReturn)) lReturn = LocateCardsReturn.ReturnCode; if (lReturn == SCARD_S_SUCCESS) { // // Validate return info // if (cReaders != LocateCardsReturn.cReaders) { ERROR_RETURN(SCARD_E_UNEXPECTED) } _CopyReaderStateAStructsForReturn( cReaders, rgReaderStates, LocateCardsReturn.rgReaderStates); } _TRY_2(LocateCards_Return_Free(h, &LocateCardsReturn)) Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); MIDL_user_free(rgReaderStatesToEncodeA); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } //--------------------------------------------------------------------------------------- // // SCardLocateCardsW // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardLocateCardsW( IN SCARDCONTEXT hContext, IN LPCWSTR mszCards, IN OUT LPSCARD_READERSTATE_W rgReaderStates, IN DWORD cReaders) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; LocateCardsW_Call LocateCardsCallW; LocateCards_Return LocateCardsReturn; ReaderStateW *rgReaderStatesToEncodeW = NULL; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; DWORD i; if (hContext == NULL) { return (SCARD_E_INVALID_PARAMETER); } else if (mszCards == NULL) { return (SCARD_E_INVALID_VALUE); } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the LocateCards params // LocateCardsCallW.Context = ((REDIR_LOCAL_SCARDCONTEXT *) hContext)->Context; LocateCardsCallW.cBytes = _CalculateNumBytesInMultiStringW(mszCards); LocateCardsCallW.mszCards = (LPCBYTE) mszCards; LocateCardsCallW.cReaders = cReaders; lReturn = _AllocAndCopyReaderStateWStructsForCall( cReaders, &rgReaderStatesToEncodeW, rgReaderStates); if (lReturn != SCARD_S_SUCCESS) { ERROR_RETURN(SCARD_E_NO_MEMORY) } LocateCardsCallW.rgReaderStates = rgReaderStatesToEncodeW; _TRY_(LocateCardsW_Call_Encode(h, &LocateCardsCallW)) // // Make the LocateCards call to the client // Status = _SendSCardIOCTL( SCARD_IOCTL_LOCATECARDSW, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } SafeMesHandleFree(&h); // // Decode the return // rpcStatus = MesDecodeBufferHandleCreate( (char *) pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } memset(&LocateCardsReturn, 0, sizeof(LocateCardsReturn)); _TRY_(LocateCards_Return_Decode(h, &LocateCardsReturn)) lReturn = LocateCardsReturn.ReturnCode; if (lReturn == SCARD_S_SUCCESS) { // // Validate return info // if (cReaders != LocateCardsReturn.cReaders) { ERROR_RETURN(SCARD_E_UNEXPECTED) } _CopyReaderStateWStructsForReturn( cReaders, rgReaderStates, LocateCardsReturn.rgReaderStates); } _TRY_2(LocateCards_Return_Free(h, &LocateCardsReturn)) Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); MIDL_user_free(rgReaderStatesToEncodeW); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } //--------------------------------------------------------------------------------------- // // SCardLocateCardsByATRA // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardLocateCardsByATRA( IN SCARDCONTEXT hContext, IN LPSCARD_ATRMASK rgAtrMasks, IN DWORD cAtrs, IN OUT LPSCARD_READERSTATE_A rgReaderStates, IN DWORD cReaders) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; LocateCardsByATRA_Call LocateCardsByATRA_Call; LocateCards_ATRMask *rgATRMasksToEncode = NULL; LocateCards_Return LocateCardsReturn; ReaderStateA *rgReaderStatesToEncodeA = NULL; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; DWORD i; if (hContext == NULL) { return (SCARD_E_INVALID_PARAMETER); } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the LocateCards params // LocateCardsByATRA_Call.Context = ((REDIR_LOCAL_SCARDCONTEXT *) hContext)->Context; LocateCardsByATRA_Call.cAtrs = cAtrs; LocateCardsByATRA_Call.cReaders = cReaders; lReturn = _AllocAndCopyATRMasksForCall( cAtrs, &rgATRMasksToEncode, rgAtrMasks); if (lReturn != SCARD_S_SUCCESS) { ERROR_RETURN(SCARD_E_NO_MEMORY) } LocateCardsByATRA_Call.rgAtrMasks = rgATRMasksToEncode; lReturn = _AllocAndCopyReaderStateAStructsForCall( cReaders, &rgReaderStatesToEncodeA, rgReaderStates); if (lReturn != SCARD_S_SUCCESS) { ERROR_RETURN(SCARD_E_NO_MEMORY) } LocateCardsByATRA_Call.rgReaderStates = rgReaderStatesToEncodeA; _TRY_(LocateCardsByATRA_Call_Encode(h, &LocateCardsByATRA_Call)) // // Make the LocateCards call to the client // Status = _SendSCardIOCTL( SCARD_IOCTL_LOCATECARDSBYATRA, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } SafeMesHandleFree(&h); // // Decode the return // rpcStatus = MesDecodeBufferHandleCreate( (char *) pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } memset(&LocateCardsReturn, 0 , sizeof(LocateCardsReturn)); _TRY_(LocateCards_Return_Decode(h, &LocateCardsReturn)) lReturn = LocateCardsReturn.ReturnCode; if (lReturn == SCARD_S_SUCCESS) { // // Validate return info // if (cReaders != LocateCardsReturn.cReaders) { ERROR_RETURN(SCARD_E_UNEXPECTED) } _CopyReaderStateAStructsForReturn( cReaders, rgReaderStates, LocateCardsReturn.rgReaderStates); } _TRY_2(LocateCards_Return_Free(h, &LocateCardsReturn)) Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); MIDL_user_free(rgATRMasksToEncode); MIDL_user_free(rgReaderStatesToEncodeA); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } //--------------------------------------------------------------------------------------- // // SCardLocateCardsByATRW // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardLocateCardsByATRW( IN SCARDCONTEXT hContext, IN LPSCARD_ATRMASK rgAtrMasks, IN DWORD cAtrs, IN OUT LPSCARD_READERSTATE_W rgReaderStates, IN DWORD cReaders) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; LocateCardsByATRW_Call LocateCardsByATRW_Call; LocateCards_ATRMask *rgATRMasksToEncode = NULL; LocateCards_Return LocateCardsReturn; ReaderStateW *rgReaderStatesToEncodeW = NULL; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; DWORD i; if (hContext == NULL) { return (SCARD_E_INVALID_PARAMETER); } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the LocateCards params // LocateCardsByATRW_Call.Context = ((REDIR_LOCAL_SCARDCONTEXT *) hContext)->Context; LocateCardsByATRW_Call.cAtrs = cAtrs; LocateCardsByATRW_Call.cReaders = cReaders; lReturn = _AllocAndCopyATRMasksForCall( cAtrs, &rgATRMasksToEncode, rgAtrMasks); if (lReturn != SCARD_S_SUCCESS) { ERROR_RETURN(SCARD_E_NO_MEMORY) } LocateCardsByATRW_Call.rgAtrMasks = rgATRMasksToEncode; lReturn = _AllocAndCopyReaderStateWStructsForCall( cReaders, &rgReaderStatesToEncodeW, rgReaderStates); if (lReturn != SCARD_S_SUCCESS) { ERROR_RETURN(SCARD_E_NO_MEMORY) } LocateCardsByATRW_Call.rgReaderStates = rgReaderStatesToEncodeW; _TRY_(LocateCardsByATRW_Call_Encode(h, &LocateCardsByATRW_Call)) // // Make the LocateCards call to the client // Status = _SendSCardIOCTL( SCARD_IOCTL_LOCATECARDSBYATRW, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } SafeMesHandleFree(&h); // // Decode the return // rpcStatus = MesDecodeBufferHandleCreate( (char *) pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } memset(&LocateCardsReturn, 0 , sizeof(LocateCardsReturn)); _TRY_(LocateCards_Return_Decode(h, &LocateCardsReturn)) lReturn = LocateCardsReturn.ReturnCode; if (lReturn == SCARD_S_SUCCESS) { // // Validate return info // if (cReaders != LocateCardsReturn.cReaders) { ERROR_RETURN(SCARD_E_UNEXPECTED) } _CopyReaderStateWStructsForReturn( cReaders, rgReaderStates, LocateCardsReturn.rgReaderStates); } _TRY_2(LocateCards_Return_Free(h, &LocateCardsReturn)) Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); MIDL_user_free(rgATRMasksToEncode); MIDL_user_free(rgReaderStatesToEncodeW); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } //--------------------------------------------------------------------------------------- // // SCardGetStatusChangeA // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardGetStatusChangeA( IN SCARDCONTEXT hContext, IN DWORD dwTimeout, IN OUT LPSCARD_READERSTATE_A rgReaderStates, IN DWORD cReaders) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; GetStatusChangeA_Call GetStatusChangeCallA; GetStatusChange_Return GetStatusChangeReturn; ReaderStateA *rgReaderStatesToEncodeA = NULL; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; DWORD i; if (hContext == NULL) { return (SCARD_E_INVALID_PARAMETER); } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the LocateCards params // GetStatusChangeCallA.Context = ((REDIR_LOCAL_SCARDCONTEXT *) hContext)->Context; GetStatusChangeCallA.dwTimeOut = dwTimeout; GetStatusChangeCallA.cReaders = cReaders; lReturn = _AllocAndCopyReaderStateAStructsForCall( cReaders, &rgReaderStatesToEncodeA, rgReaderStates); if (lReturn != SCARD_S_SUCCESS) { ERROR_RETURN(SCARD_E_NO_MEMORY) } GetStatusChangeCallA.rgReaderStates = rgReaderStatesToEncodeA; _TRY_(GetStatusChangeA_Call_Encode(h, &GetStatusChangeCallA)) // // Make the GetStatusChange call to the client // Status = _SendSCardIOCTL( SCARD_IOCTL_GETSTATUSCHANGEA, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } SafeMesHandleFree(&h); // // Decode the return // rpcStatus = MesDecodeBufferHandleCreate( (char *) pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } memset(&GetStatusChangeReturn, 0, sizeof(GetStatusChangeReturn)); _TRY_(GetStatusChange_Return_Decode(h, &GetStatusChangeReturn)) lReturn = GetStatusChangeReturn.ReturnCode; if (lReturn == SCARD_S_SUCCESS) { // // Validate return info // if (cReaders != GetStatusChangeReturn.cReaders) { ERROR_RETURN(SCARD_E_UNEXPECTED) } _CopyReaderStateAStructsForReturn( cReaders, rgReaderStates, GetStatusChangeReturn.rgReaderStates); } else if ((lReturn == SCARD_E_SYSTEM_CANCELLED) && (g_hUnifiedStartedEvent != NULL)) { // // This error indicates that the clients scardsvr service has been stopped, // so reset the unified started event // //OutputDebugString("SCREDIR: SCardGetStatusChangeA: resetting g_hUnifiedStartedEvent\n"); ResetEvent(g_hUnifiedStartedEvent); _SetStartedEventToCorrectState(); } _TRY_2(GetStatusChange_Return_Free(h, &GetStatusChangeReturn)) Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); MIDL_user_free(rgReaderStatesToEncodeA); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } //--------------------------------------------------------------------------------------- // // SCardGetStatusChangew // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardGetStatusChangeW( IN SCARDCONTEXT hContext, IN DWORD dwTimeout, IN OUT LPSCARD_READERSTATE_W rgReaderStates, IN DWORD cReaders) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; GetStatusChangeW_Call GetStatusChangeCallW; GetStatusChange_Return GetStatusChangeReturn; ReaderStateW *rgReaderStatesToEncodeW = NULL; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; DWORD i; if (hContext == NULL) { return (SCARD_E_INVALID_PARAMETER); } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the LocateCards params // GetStatusChangeCallW.Context = ((REDIR_LOCAL_SCARDCONTEXT *) hContext)->Context; GetStatusChangeCallW.dwTimeOut = dwTimeout; GetStatusChangeCallW.cReaders = cReaders; lReturn = _AllocAndCopyReaderStateWStructsForCall( cReaders, &rgReaderStatesToEncodeW, rgReaderStates); if (lReturn != SCARD_S_SUCCESS) { ERROR_RETURN(SCARD_E_NO_MEMORY) } GetStatusChangeCallW.rgReaderStates = rgReaderStatesToEncodeW; _TRY_(GetStatusChangeW_Call_Encode(h, &GetStatusChangeCallW)) // // Make the GetStatusChange call to the client // Status = _SendSCardIOCTL( SCARD_IOCTL_GETSTATUSCHANGEW, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } SafeMesHandleFree(&h); // // Decode the return // rpcStatus = MesDecodeBufferHandleCreate( (char *) pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } memset(&GetStatusChangeReturn, 0, sizeof(GetStatusChangeReturn)); _TRY_(GetStatusChange_Return_Decode(h, &GetStatusChangeReturn)) lReturn = GetStatusChangeReturn.ReturnCode; if (lReturn == SCARD_S_SUCCESS) { // // Validate return info // if (cReaders != GetStatusChangeReturn.cReaders) { ERROR_RETURN(SCARD_E_UNEXPECTED) } _CopyReaderStateWStructsForReturn( cReaders, rgReaderStates, GetStatusChangeReturn.rgReaderStates); } else if ((lReturn == SCARD_E_SYSTEM_CANCELLED) && (g_hUnifiedStartedEvent != NULL)) { // // This error indicates that the clients scardsvr service has been stopped, // so reset the unified started event // //OutputDebugString("SCREDIR: SCardGetStatusChangeW: resetting g_hUnifiedStartedEvent\n"); ResetEvent(g_hUnifiedStartedEvent); _SetStartedEventToCorrectState(); } _TRY_2(GetStatusChange_Return_Free(h, &GetStatusChangeReturn)) Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); MIDL_user_free(rgReaderStatesToEncodeW); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } WINSCARDAPI LONG WINAPI SCardCancel( IN SCARDCONTEXT hContext) { return (I_ContextCallWithLongReturn( hContext, SCARD_IOCTL_CANCEL)); } //--------------------------------------------------------------------------------------- // // SCardConnect // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI I_SCardConnect( IN SCARDCONTEXT hContext, IN LPCBYTE szReader, IN DWORD dwShareMode, IN DWORD dwPreferredProtocols, OUT LPSCARDHANDLE phCard, OUT LPDWORD pdwActiveProtocol, IN BOOL fUnicode) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; ConnectA_Call ConnectCallA; ConnectW_Call ConnectCallW; Connect_Return ConnectReturn; if ((hContext == NULL) || (phCard == NULL) || (pdwActiveProtocol == NULL)) { return (SCARD_E_INVALID_PARAMETER); } else if (szReader == NULL) { return (SCARD_E_INVALID_VALUE); } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the Connect params // ConnectCallA.Common.Context = ConnectCallW.Common.Context = ((REDIR_LOCAL_SCARDCONTEXT *) hContext)->Context; ConnectCallA.Common.dwShareMode = ConnectCallW.Common.dwShareMode = dwShareMode; ConnectCallA.Common.dwPreferredProtocols = ConnectCallW.Common.dwPreferredProtocols = dwPreferredProtocols; if (fUnicode) { ConnectCallW.szReader = (LPCWSTR) szReader; _TRY_(ConnectW_Call_Encode(h, &ConnectCallW)) } else { ConnectCallA.szReader = (LPCSTR) szReader; _TRY_(ConnectA_Call_Encode(h, &ConnectCallA)) } // // Make the ListInterfaces call to the client // Status = _SendSCardIOCTL( fUnicode ? SCARD_IOCTL_CONNECTW : SCARD_IOCTL_CONNECTA, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } SafeMesHandleFree(&h); // // Decode the return // rpcStatus = MesDecodeBufferHandleCreate( (char *) pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } memset(&ConnectReturn, 0, sizeof(ConnectReturn)); _TRY_(Connect_Return_Decode(h, &ConnectReturn)) lReturn = ConnectReturn.ReturnCode; if (lReturn == SCARD_S_SUCCESS) { REDIR_LOCAL_SCARDHANDLE *pRedirHandle = NULL; // // The value that represents the SCARDHANDLE on the remote client // machine is a variable size, so allocate memory to for the struct // that holds the variable length handle size and pointer, plus // the actual bytes for the handle, it also holds the context // if (ConnectReturn.hCard.cbHandle > MAX_SCARDHANDLE_SIZE) { ERROR_RETURN(SCARD_E_UNEXPECTED) } pRedirHandle = (REDIR_LOCAL_SCARDHANDLE *) MIDL_user_allocate( sizeof(REDIR_LOCAL_SCARDHANDLE) + ConnectReturn.hCard.cbHandle); if (pRedirHandle != NULL) { pRedirHandle->pRedirContext = (REDIR_LOCAL_SCARDCONTEXT *) hContext; pRedirHandle->Handle.Context = ((REDIR_LOCAL_SCARDCONTEXT *) hContext)->Context; pRedirHandle->Handle.cbHandle = ConnectReturn.hCard.cbHandle; pRedirHandle->Handle.pbHandle = ((BYTE *) pRedirHandle) + sizeof(REDIR_LOCAL_SCARDHANDLE); memcpy( pRedirHandle->Handle.pbHandle, ConnectReturn.hCard.pbHandle, ConnectReturn.hCard.cbHandle); *phCard = (SCARDHANDLE) pRedirHandle; // The original Winscard API implements this parameter as // Optional. We need to preserve that behavior. if (NULL != pdwActiveProtocol) *pdwActiveProtocol = ConnectReturn.dwActiveProtocol; } else { lReturn = SCARD_E_NO_MEMORY; } } _TRY_2(Connect_Return_Free(h, &ConnectReturn)) Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } WINSCARDAPI LONG WINAPI SCardConnectA( IN SCARDCONTEXT hContext, IN LPCSTR szReader, IN DWORD dwShareMode, IN DWORD dwPreferredProtocols, OUT LPSCARDHANDLE phCard, OUT LPDWORD pdwActiveProtocol) { return (I_SCardConnect( hContext, (LPCBYTE) szReader, dwShareMode, dwPreferredProtocols, phCard, pdwActiveProtocol, FALSE)); } WINSCARDAPI LONG WINAPI SCardConnectW( IN SCARDCONTEXT hContext, IN LPCWSTR szReader, IN DWORD dwShareMode, IN DWORD dwPreferredProtocols, OUT LPSCARDHANDLE phCard, OUT LPDWORD pdwActiveProtocol) { return (I_SCardConnect( hContext, (LPCBYTE) szReader, dwShareMode, dwPreferredProtocols, phCard, pdwActiveProtocol, TRUE)); } //--------------------------------------------------------------------------------------- // // SCardReconnect // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardReconnect( IN SCARDHANDLE hCard, IN DWORD dwShareMode, IN DWORD dwPreferredProtocols, IN DWORD dwInitialization, OUT LPDWORD pdwActiveProtocol) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; Reconnect_Call ReconnectCall; Reconnect_Return ReconnectReturn; if ((hCard == NULL) || (pdwActiveProtocol == NULL)) { return (SCARD_E_INVALID_PARAMETER); } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the Reconnect params // ReconnectCall.hCard = ((REDIR_LOCAL_SCARDHANDLE *) hCard)->Handle; ReconnectCall.dwShareMode = dwShareMode; ReconnectCall.dwPreferredProtocols = dwPreferredProtocols; ReconnectCall.dwInitialization = dwInitialization; _TRY_(Reconnect_Call_Encode(h, &ReconnectCall)) // // Make the Reconnect call to the client // Status = _SendSCardIOCTL( SCARD_IOCTL_RECONNECT, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } SafeMesHandleFree(&h); // // Decode the return // rpcStatus = MesDecodeBufferHandleCreate( (char *) pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } memset(&ReconnectReturn, 0, sizeof(ReconnectReturn)); _TRY_(Reconnect_Return_Decode(h, &ReconnectReturn)) lReturn = ReconnectReturn.ReturnCode; if (lReturn == SCARD_S_SUCCESS) { // The original Winscard API implements this parameter as // Optional. We need to preserve that behavior. if (NULL != pdwActiveProtocol) *pdwActiveProtocol = ReconnectReturn.dwActiveProtocol; } _TRY_2(Reconnect_Return_Free(h, &ReconnectReturn)) Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } //--------------------------------------------------------------------------------------- // // I_HCardAndDispositionCall // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI I_HCardAndDispositionCall( IN SCARDHANDLE hCard, IN DWORD dwDisposition, ULONG IoControlCode) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; HCardAndDisposition_Call HCardAndDispositionCall; if (hCard == NULL) { return (SCARD_E_INVALID_PARAMETER); } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the Reconnect params // HCardAndDispositionCall.hCard = ((REDIR_LOCAL_SCARDHANDLE *) hCard)->Handle; HCardAndDispositionCall.dwDisposition = dwDisposition; _TRY_(HCardAndDisposition_Call_Encode(h, &HCardAndDispositionCall)) // // Make the Reconnect call to the client // Status = _SendSCardIOCTL( IoControlCode, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } // // Decode the return // lReturn = I_DecodeLongReturn(pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed); Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } //--------------------------------------------------------------------------------------- // // SCardDisconnect // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardDisconnect( IN SCARDHANDLE hCard, IN DWORD dwDisposition) { LONG lReturn = SCARD_S_SUCCESS; lReturn = I_HCardAndDispositionCall( hCard, dwDisposition, SCARD_IOCTL_DISCONNECT); MIDL_user_free((REDIR_SCARDHANDLE *) hCard); return (lReturn); } //--------------------------------------------------------------------------------------- // // SCardBeginTransaction // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardBeginTransaction( IN SCARDHANDLE hCard) { return (I_HCardAndDispositionCall( hCard, 0, // SCardBeginTransaction doesn't use a dispostion, so just set to 0 SCARD_IOCTL_BEGINTRANSACTION)); } //--------------------------------------------------------------------------------------- // // SCardEndTransaction // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardEndTransaction( IN SCARDHANDLE hCard, IN DWORD dwDisposition) { return (I_HCardAndDispositionCall( hCard, dwDisposition, SCARD_IOCTL_ENDTRANSACTION)); } //--------------------------------------------------------------------------------------- // // SCardState // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardState( IN SCARDHANDLE hCard, OUT LPDWORD pdwState, OUT LPDWORD pdwProtocol, OUT LPBYTE pbAtr, IN OUT LPDWORD pcbAtrLen) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; State_Call StateCall; State_Return StateReturn; if (hCard == NULL) { return (SCARD_E_INVALID_PARAMETER); } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the Reconnect params // StateCall.hCard = ((REDIR_LOCAL_SCARDHANDLE *) hCard)->Handle; StateCall.fpbAtrIsNULL = (pbAtr == NULL); StateCall.cbAtrLen = *pcbAtrLen; _TRY_(State_Call_Encode(h, &StateCall)) // // Make the Reconnect call to the client // Status = _SendSCardIOCTL( SCARD_IOCTL_STATE, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } SafeMesHandleFree(&h); // // Decode the return // rpcStatus = MesDecodeBufferHandleCreate( (char *) pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } memset(&StateReturn, 0, sizeof(StateReturn)); _TRY_(State_Return_Decode(h, &StateReturn)) lReturn = StateReturn.ReturnCode; if (lReturn == SCARD_S_SUCCESS) { // // The original Winscard API implements each of these // parameters as Optional. We need to preserve that behavior. // if (NULL != pdwState) *pdwState = StateReturn.dwState; if (NULL != pdwProtocol) *pdwProtocol = StateReturn.dwProtocol; if (NULL != pcbAtrLen) { lReturn = _CopyReturnToCallerBuffer( ((REDIR_LOCAL_SCARDHANDLE *) hCard)->pRedirContext, StateReturn.rgAtr, StateReturn.cbAtrLen, pbAtr, pcbAtrLen, BYTE_TYPE_RETURN); } } _TRY_2(State_Return_Free(h, &StateReturn)) Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } //--------------------------------------------------------------------------------------- // // SCardStatus // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI I_SCardStatus( IN SCARDHANDLE hCard, OUT LPBYTE mszReaderNames, IN OUT LPDWORD pcchReaderLen, OUT LPDWORD pdwState, OUT LPDWORD pdwProtocol, OUT LPBYTE pbAtr, IN OUT LPDWORD pcbAtrLen, IN BOOL fUnicode) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; Status_Call StatusCall; Status_Return StatusReturn; if (hCard == NULL) { return (SCARD_E_INVALID_PARAMETER); } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the Reconnect params // StatusCall.hCard = ((REDIR_LOCAL_SCARDHANDLE *) hCard)->Handle; StatusCall.fmszReaderNamesIsNULL = (mszReaderNames == NULL); StatusCall.cchReaderLen = *pcchReaderLen; StatusCall.cbAtrLen = *pcbAtrLen; _TRY_(Status_Call_Encode(h, &StatusCall)) // // Make the Status call to the client // Status = _SendSCardIOCTL( fUnicode ? SCARD_IOCTL_STATUSW : SCARD_IOCTL_STATUSA, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } SafeMesHandleFree(&h); // // Decode the return // rpcStatus = MesDecodeBufferHandleCreate( (char *) pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } memset(&StatusReturn, 0, sizeof(StatusReturn)); _TRY_(Status_Return_Decode(h, &StatusReturn)) if (StatusReturn.cbAtrLen > sizeof(StatusReturn.pbAtr)) { ERROR_RETURN(SCARD_E_UNEXPECTED) } lReturn = StatusReturn.ReturnCode; if (lReturn == SCARD_S_SUCCESS) { // // The original Winscard API implements each of these // parameters as Optional. We need to preserve that behavior. // if (NULL != pcchReaderLen) { lReturn = _CopyReturnToCallerBuffer( ((REDIR_LOCAL_SCARDHANDLE *) hCard)->pRedirContext, StatusReturn.mszReaderNames, StatusReturn.cBytes, mszReaderNames, pcchReaderLen, fUnicode ? WSZ_TYPE_RETURN : SZ_TYPE_RETURN); } if (lReturn == SCARD_S_SUCCESS) { if (NULL != pdwState) *pdwState = StatusReturn.dwState; if (NULL != pdwProtocol) *pdwProtocol = StatusReturn.dwProtocol; if (NULL != pcbAtrLen) { if ((NULL != pbAtr) && (*pcbAtrLen >= StatusReturn.cbAtrLen)) { memcpy( pbAtr, StatusReturn.pbAtr, StatusReturn.cbAtrLen); } *pcbAtrLen = StatusReturn.cbAtrLen; } } } _TRY_2(Status_Return_Free(h, &StatusReturn)) Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } WINSCARDAPI LONG WINAPI SCardStatusA( IN SCARDHANDLE hCard, OUT LPSTR mszReaderNames, IN OUT LPDWORD pcchReaderLen, OUT LPDWORD pdwState, OUT LPDWORD pdwProtocol, OUT LPBYTE pbAtr, IN OUT LPDWORD pcbAtrLen) { return (I_SCardStatus( hCard, (LPBYTE) mszReaderNames, pcchReaderLen, pdwState, pdwProtocol, pbAtr, pcbAtrLen, FALSE)); } WINSCARDAPI LONG WINAPI SCardStatusW( IN SCARDHANDLE hCard, OUT LPWSTR mszReaderNames, IN OUT LPDWORD pcchReaderLen, OUT LPDWORD pdwState, OUT LPDWORD pdwProtocol, OUT LPBYTE pbAtr, IN OUT LPDWORD pcbAtrLen) { return (I_SCardStatus( hCard, (LPBYTE) mszReaderNames, pcchReaderLen, pdwState, pdwProtocol, pbAtr, pcbAtrLen, TRUE)); } //--------------------------------------------------------------------------------------- // // SCardTransmit // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardTransmit( IN SCARDHANDLE hCard, IN LPCSCARD_IO_REQUEST pioSendPci, IN LPCBYTE pbSendBuffer, IN DWORD cbSendLength, IN OUT LPSCARD_IO_REQUEST pioRecvPci, OUT LPBYTE pbRecvBuffer, IN OUT LPDWORD pcbRecvLength) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; Transmit_Call TransmitCall; Transmit_Return TransmitReturn; SCardIO_Request ioRecvPci; if (hCard == NULL) { return (SCARD_E_INVALID_PARAMETER); } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the Transmit params // TransmitCall.hCard = ((REDIR_LOCAL_SCARDHANDLE *) hCard)->Handle; TransmitCall.ioSendPci.dwProtocol = pioSendPci->dwProtocol; TransmitCall.ioSendPci.cbExtraBytes = pioSendPci->cbPciLength - sizeof(SCARD_IO_REQUEST); if (TransmitCall.ioSendPci.cbExtraBytes != 0) { TransmitCall.ioSendPci.pbExtraBytes = ((BYTE *) pioSendPci) + sizeof(SCARD_IO_REQUEST); } else { TransmitCall.ioSendPci.pbExtraBytes = NULL; } TransmitCall.cbSendLength = cbSendLength; TransmitCall.pbSendBuffer = pbSendBuffer; if (pioRecvPci != NULL) { TransmitCall.pioRecvPci = &ioRecvPci; ioRecvPci.dwProtocol = pioRecvPci->dwProtocol; ioRecvPci.cbExtraBytes = pioRecvPci->cbPciLength - sizeof(SCARD_IO_REQUEST); if (ioRecvPci.cbExtraBytes != 0) { ioRecvPci.pbExtraBytes = ((LPBYTE) pioRecvPci) + sizeof(SCARD_IO_REQUEST); } else { ioRecvPci.pbExtraBytes = NULL; } } else { TransmitCall.pioRecvPci = NULL; } TransmitCall.fpbRecvBufferIsNULL = (pbRecvBuffer == NULL); TransmitCall.cbRecvLength = *pcbRecvLength; _TRY_(Transmit_Call_Encode(h, &TransmitCall)) // // Make the Status call to the client // Status = _SendSCardIOCTL( SCARD_IOCTL_TRANSMIT, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } SafeMesHandleFree(&h); // // Decode the return // rpcStatus = MesDecodeBufferHandleCreate( (char *) pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } memset(&TransmitReturn, 0, sizeof(TransmitReturn)); _TRY_(Transmit_Return_Decode(h, &TransmitReturn)) lReturn = TransmitReturn.ReturnCode; if (lReturn == SCARD_S_SUCCESS) { if ((pioRecvPci != NULL) && (TransmitReturn.pioRecvPci != NULL)) { pioRecvPci->dwProtocol = TransmitReturn.pioRecvPci->dwProtocol; if ((TransmitReturn.pioRecvPci->cbExtraBytes != 0) && (TransmitReturn.pioRecvPci->cbExtraBytes <= (pioSendPci->cbPciLength - sizeof(SCARD_IO_REQUEST)))) { memcpy( ((LPBYTE) pioRecvPci) + sizeof(SCARD_IO_REQUEST), TransmitReturn.pioRecvPci->pbExtraBytes, TransmitReturn.pioRecvPci->cbExtraBytes); } } lReturn = _CopyReturnToCallerBuffer( ((REDIR_LOCAL_SCARDHANDLE *) hCard)->pRedirContext, TransmitReturn.pbRecvBuffer, TransmitReturn.cbRecvLength, pbRecvBuffer, pcbRecvLength, BYTE_TYPE_RETURN); } _TRY_2(Transmit_Return_Free(h, &TransmitReturn)) Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } //--------------------------------------------------------------------------------------- // // SCardControl // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardControl( IN SCARDHANDLE hCard, IN DWORD dwControlCode, IN LPCVOID pvInBuffer, IN DWORD cbInBufferSize, OUT LPVOID pvOutBuffer, IN DWORD cbOutBufferSize, OUT LPDWORD pcbBytesReturned) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; Control_Call ControlCall; Control_Return ControlReturn; if (hCard == NULL) { return (SCARD_E_INVALID_PARAMETER); } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the Control params // ControlCall.hCard = ((REDIR_LOCAL_SCARDHANDLE *) hCard)->Handle; ControlCall.dwControlCode = dwControlCode; ControlCall.cbInBufferSize = cbInBufferSize; ControlCall.pvInBuffer = (LPCBYTE) pvInBuffer; ControlCall.fpvOutBufferIsNULL = (pvOutBuffer == NULL); ControlCall.cbOutBufferSize = cbOutBufferSize; _TRY_(Control_Call_Encode(h, &ControlCall)) // // Make the Control call to the client // Status = _SendSCardIOCTL( SCARD_IOCTL_CONTROL, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } SafeMesHandleFree(&h); // // Decode the return // rpcStatus = MesDecodeBufferHandleCreate( (char *) pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } memset(&ControlReturn, 0, sizeof(ControlReturn)); _TRY_(Control_Return_Decode(h, &ControlReturn)) lReturn = ControlReturn.ReturnCode; if (lReturn == SCARD_S_SUCCESS) { *pcbBytesReturned = ControlReturn.cbOutBufferSize; lReturn = _CopyReturnToCallerBuffer( ((REDIR_LOCAL_SCARDHANDLE *) hCard)->pRedirContext, ControlReturn.pvOutBuffer, ControlReturn.cbOutBufferSize, (LPBYTE) pvOutBuffer, pcbBytesReturned, BYTE_TYPE_RETURN); } _TRY_2(Control_Return_Free(h, &ControlReturn)) Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } //--------------------------------------------------------------------------------------- // // SCardGetAttrib // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardGetAttrib( IN SCARDHANDLE hCard, IN DWORD dwAttrId, OUT LPBYTE pbAttr, IN OUT LPDWORD pcbAttrLen) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; GetAttrib_Call GetAttribCall; GetAttrib_Return GetAttribReturn; if (hCard == NULL) { return (SCARD_E_INVALID_PARAMETER); } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the GetAttrib params // GetAttribCall.hCard = ((REDIR_LOCAL_SCARDHANDLE *) hCard)->Handle; GetAttribCall.dwAttrId = dwAttrId;; GetAttribCall.fpbAttrIsNULL = (pbAttr == NULL); GetAttribCall.cbAttrLen = *pcbAttrLen; _TRY_(GetAttrib_Call_Encode(h, &GetAttribCall)) // // Make the GetAttrib call to the client // Status = _SendSCardIOCTL( SCARD_IOCTL_GETATTRIB, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } SafeMesHandleFree(&h); // // Decode the return // rpcStatus = MesDecodeBufferHandleCreate( (char *) pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } memset(&GetAttribReturn, 0, sizeof(GetAttribReturn)); _TRY_(GetAttrib_Return_Decode(h, &GetAttribReturn)) lReturn = GetAttribReturn.ReturnCode; if (lReturn == SCARD_S_SUCCESS) { lReturn = _CopyReturnToCallerBuffer( ((REDIR_LOCAL_SCARDHANDLE *) hCard)->pRedirContext, GetAttribReturn.pbAttr, GetAttribReturn.cbAttrLen, (LPBYTE) pbAttr, pcbAttrLen, BYTE_TYPE_RETURN); } _TRY_2(GetAttrib_Return_Free(h, &GetAttribReturn)) Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } //--------------------------------------------------------------------------------------- // // SCardSetAttrib // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardSetAttrib( IN SCARDHANDLE hCard, IN DWORD dwAttrId, IN LPCBYTE pbAttr, IN DWORD cbAttrLen) { LONG lReturn = SCARD_S_SUCCESS; NTSTATUS Status = STATUS_SUCCESS; RPC_STATUS rpcStatus = RPC_S_OK; char *pbEncodedBuffer = NULL; unsigned long cbEncodedBuffer = 0; handle_t h = 0; BUFFER_LIST_STRUCT *pOutputBuffer = NULL; SetAttrib_Call SetAttribCall; if (hCard == NULL) { return (SCARD_E_INVALID_PARAMETER); } // // Initialize encoding handle // rpcStatus = MesEncodeDynBufferHandleCreate( &pbEncodedBuffer, &cbEncodedBuffer, &h); if (rpcStatus != RPC_S_OK) { ERROR_RETURN(SCARD_E_UNEXPECTED) } // // Encode the SetAttrib params // SetAttribCall.hCard = ((REDIR_LOCAL_SCARDHANDLE *) hCard)->Handle; SetAttribCall.dwAttrId = dwAttrId;; SetAttribCall.pbAttr = pbAttr; SetAttribCall.cbAttrLen = cbAttrLen; _TRY_(SetAttrib_Call_Encode(h, &SetAttribCall)) // // Make the SetAttrib call to the client // Status = _SendSCardIOCTL( SCARD_IOCTL_SETATTRIB, pbEncodedBuffer, cbEncodedBuffer, &pOutputBuffer); if (Status != STATUS_SUCCESS) { ERROR_RETURN(_MakeSCardError(Status)) } // // Decode the return // lReturn = I_DecodeLongReturn(pOutputBuffer->pbBytes, pOutputBuffer->cbBytesUsed); Return: SafeMesHandleFree(&h); MIDL_user_free(pbEncodedBuffer); FreeBuffer(pOutputBuffer); return (lReturn); ErrorReturn: goto Return; } //--------------------------------------------------------------------------------------- // // SCardAccessStartedEvent // //--------------------------------------------------------------------------------------- WINSCARDAPI HANDLE WINAPI SCardAccessStartedEvent(void) { HANDLE h; h = _GetStartedEventHandle(); if ((h == NULL) || !_SetStartedEventToCorrectState()) { // // Either we couldn't create the event, or we couldn't start the thread to set // the event, so return NULL // return (NULL); } // // Check to see if the event is already set, if not, give the thread which sets // the event a chance to run and set the event before returning // if (WAIT_OBJECT_0 != WaitForSingleObject(h, 0)) { WaitForSingleObject(h, 10); } // // This API has old semantics where it just return the handle straight away // instead of duplicating it. // return (h); } //--------------------------------------------------------------------------------------- // // SCardReleaseStartedEvent // //--------------------------------------------------------------------------------------- WINSCARDAPI void WINAPI SCardReleaseStartedEvent(void) { return; } //--------------------------------------------------------------------------------------- // // SCardReleaseBadContext // //--------------------------------------------------------------------------------------- WINSCARDAPI LONG WINAPI SCardReleaseBadContext( IN SCARDCONTEXT hContext) { MIDL_user_free((REDIR_LOCAL_SCARDCONTEXT *) hContext); return (SCARD_S_SUCCESS); }