You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4877 lines
136 KiB
4877 lines
136 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
|
|
Module Name:
|
|
|
|
scredir
|
|
|
|
Abstract:
|
|
|
|
This module redirects the SCard* API calls
|
|
|
|
Author:
|
|
|
|
reidk 7/27/2000
|
|
|
|
|
|
--*/
|
|
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <winscard.h>
|
|
#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; i<cReaders; i++)
|
|
{
|
|
rgAlloced[i].Common.dwCurrentState =
|
|
rgReaderStates[i].dwCurrentState;
|
|
rgAlloced[i].Common.dwEventState =
|
|
rgReaderStates[i].dwEventState;
|
|
rgAlloced[i].Common.cbAtr =
|
|
rgReaderStates[i].cbAtr;
|
|
memcpy(
|
|
rgAlloced[i].Common.rgbAtr,
|
|
rgReaderStates[i].rgbAtr,
|
|
36);
|
|
rgAlloced[i].szReader =
|
|
rgReaderStates[i].szReader;
|
|
}
|
|
|
|
*prgReaderStatesToEncodeA = rgAlloced;
|
|
|
|
return (SCARD_S_SUCCESS);
|
|
}
|
|
|
|
LONG
|
|
_AllocAndCopyReaderStateWStructsForCall(
|
|
DWORD cReaders,
|
|
ReaderStateW **prgReaderStatesToEncodeW,
|
|
LPSCARD_READERSTATE_W rgReaderStates)
|
|
{
|
|
DWORD i;
|
|
ReaderStateW *rgAlloced;
|
|
|
|
rgAlloced = (ReaderStateW *)
|
|
MIDL_user_allocate(cReaders * sizeof(ReaderStateW));
|
|
|
|
if (rgAlloced == NULL)
|
|
{
|
|
return (SCARD_E_NO_MEMORY);
|
|
}
|
|
|
|
for (i=0; i<cReaders; i++)
|
|
{
|
|
rgAlloced[i].Common.dwCurrentState =
|
|
rgReaderStates[i].dwCurrentState;
|
|
rgAlloced[i].Common.dwEventState =
|
|
rgReaderStates[i].dwEventState;
|
|
rgAlloced[i].Common.cbAtr =
|
|
rgReaderStates[i].cbAtr;
|
|
memcpy(
|
|
rgAlloced[i].Common.rgbAtr,
|
|
rgReaderStates[i].rgbAtr,
|
|
36);
|
|
rgAlloced[i].szReader =
|
|
rgReaderStates[i].szReader;
|
|
}
|
|
|
|
*prgReaderStatesToEncodeW = rgAlloced;
|
|
|
|
return (SCARD_S_SUCCESS);
|
|
}
|
|
|
|
void
|
|
_CopyReaderStateAStructsForReturn(
|
|
DWORD cReaders,
|
|
LPSCARD_READERSTATE_A rgReaderStates,
|
|
ReaderState_Return *rgReaderStatesReturned)
|
|
{
|
|
DWORD i;
|
|
|
|
for (i=0; i<cReaders; i++)
|
|
{
|
|
rgReaderStates[i].dwCurrentState =
|
|
rgReaderStatesReturned[i].dwCurrentState;
|
|
rgReaderStates[i].dwEventState =
|
|
rgReaderStatesReturned[i].dwEventState;
|
|
rgReaderStates[i].cbAtr =
|
|
rgReaderStatesReturned[i].cbAtr;
|
|
memcpy(
|
|
rgReaderStates[i].rgbAtr,
|
|
rgReaderStatesReturned[i].rgbAtr,
|
|
36);
|
|
}
|
|
}
|
|
|
|
void
|
|
_CopyReaderStateWStructsForReturn(
|
|
DWORD cReaders,
|
|
LPSCARD_READERSTATE_W rgReaderStates,
|
|
ReaderState_Return *rgReaderStatesReturned)
|
|
{
|
|
DWORD i;
|
|
|
|
for (i=0; i<cReaders; i++)
|
|
{
|
|
rgReaderStates[i].dwCurrentState =
|
|
rgReaderStatesReturned[i].dwCurrentState;
|
|
rgReaderStates[i].dwEventState =
|
|
rgReaderStatesReturned[i].dwEventState;
|
|
rgReaderStates[i].cbAtr =
|
|
rgReaderStatesReturned[i].cbAtr;
|
|
memcpy(
|
|
rgReaderStates[i].rgbAtr,
|
|
rgReaderStatesReturned[i].rgbAtr,
|
|
36);
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------------------
|
|
//
|
|
// _AllocAndCopyATRMasksForCall
|
|
//
|
|
//---------------------------------------------------------------------------------------
|
|
LONG
|
|
_AllocAndCopyATRMasksForCall(
|
|
DWORD cAtrs,
|
|
LocateCards_ATRMask **prgATRMasksToEncode,
|
|
LPSCARD_ATRMASK rgAtrMasks)
|
|
{
|
|
DWORD i;
|
|
LocateCards_ATRMask *rgAlloced;
|
|
|
|
rgAlloced = (LocateCards_ATRMask *)
|
|
MIDL_user_allocate(cAtrs * sizeof(LocateCards_ATRMask));
|
|
|
|
if (rgAlloced == NULL)
|
|
{
|
|
return (SCARD_E_NO_MEMORY);
|
|
}
|
|
|
|
for (i=0; i<cAtrs; i++)
|
|
{
|
|
rgAlloced[i].cbAtr = rgAtrMasks[i].cbAtr;
|
|
memcpy(
|
|
rgAlloced[i].rgbAtr,
|
|
rgAtrMasks[i].rgbAtr,
|
|
36);
|
|
memcpy(
|
|
rgAlloced[i].rgbMask,
|
|
rgAtrMasks[i].rgbMask,
|
|
36);
|
|
}
|
|
|
|
*prgATRMasksToEncode = rgAlloced;
|
|
|
|
return (SCARD_S_SUCCESS);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------
|
|
//
|
|
// SCardLocateCardsA
|
|
//
|
|
//---------------------------------------------------------------------------------------
|
|
WINSCARDAPI LONG WINAPI
|
|
SCardLocateCardsA(
|
|
IN SCARDCONTEXT hContext,
|
|
IN LPCSTR mszCards,
|
|
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;
|
|
LocateCardsA_Call LocateCardsCallA;
|
|
LocateCards_Return LocateCardsReturn;
|
|
ReaderStateA *rgReaderStatesToEncodeA = 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
|
|
//
|
|
LocateCardsCallA.Context = ((REDIR_LOCAL_SCARDCONTEXT *) hContext)->Context;
|
|
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);
|
|
}
|
|
|
|
|
|
|