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.
3012 lines
79 KiB
3012 lines
79 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
|
|
Module Name:
|
|
|
|
WinSCard
|
|
|
|
Abstract:
|
|
|
|
This module supplies the API for the Calais Smartcard Service Manager.
|
|
|
|
The Calais Service Manager does the work of coordinating the protocols,
|
|
readers, drivers, and smartcards on behalf of the application. The
|
|
following services are provided as part of a library to simplify access to
|
|
the Service Manager. These routines are the documented, exposed APIs.
|
|
These routines merely package the requests and forward them to the Calais
|
|
Service Manager, allowing the actual implementation of Calais to vary over
|
|
time.
|
|
|
|
At no time does the API library make security decisions. All
|
|
security-related functions must be performed by the Service Manager, running
|
|
in its own address space, or in the operating system kernel. However, some
|
|
utility routines may be implemented in the API library for speed, as long as
|
|
they do not involve security decisions.
|
|
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/23/1996
|
|
|
|
Environment:
|
|
|
|
Win32, C++ w/ Exceptions
|
|
|
|
Notes:
|
|
|
|
?Notes?
|
|
|
|
--*/
|
|
|
|
#define __SUBROUTINE__
|
|
#ifndef WIN32_LEAN_AND_MEAN
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#endif
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <winbase.h>
|
|
#include <wtsapi32.h>
|
|
#include "client.h"
|
|
#include "redirect.h"
|
|
#include "winsta.h"
|
|
|
|
const SCARD_IO_REQUEST
|
|
g_rgSCardT0Pci = { SCARD_PROTOCOL_T0, sizeof(SCARD_IO_REQUEST) },
|
|
g_rgSCardT1Pci = { SCARD_PROTOCOL_T1, sizeof(SCARD_IO_REQUEST) },
|
|
g_rgSCardRawPci = { SCARD_PROTOCOL_RAW, sizeof(SCARD_IO_REQUEST) };
|
|
CHandleList
|
|
* g_phlContexts = NULL,
|
|
* g_phlReaders = NULL;
|
|
const WCHAR g_wszBlank[] = L"\000";
|
|
|
|
HINSTANCE g_hInst;
|
|
HANDLE g_hSessionChangeEvent = NULL;
|
|
HANDLE g_hSessionChangeCallbackHandle = NULL;
|
|
ULONG_PTR g_SessionChangeID = 0;
|
|
CRITICAL_SECTION g_RegisterForSessionChangeNoticationsCS;
|
|
BOOL g_fRegisteredForSessionChangeNotications = FALSE;
|
|
DWORD g_dwTimerCallbacksMade = 0;
|
|
DWORD g_dwClientCount = 0;
|
|
HANDLE g_hTimerEvent = NULL;
|
|
HANDLE g_hWaitTimerEventCallbackHandle = NULL;
|
|
|
|
CRITICAL_SECTION g_SafeCreateHandleCS;
|
|
CRITICAL_SECTION g_SetStartedEventCS;
|
|
CRITICAL_SECTION g_RegisterForStoppedEventCS;
|
|
CRITICAL_SECTION g_DllMainCS;
|
|
HANDLE g_hWaitForStartedCallbackHandle = NULL;
|
|
HANDLE g_hUnifiedStartedEvent = NULL;
|
|
HANDLE g_hWaitForStoppedCallbackHandle = NULL;
|
|
|
|
CRITICAL_SECTION g_TermSrvEnabledCS;
|
|
BOOL g_fTermSrvEnableChecked = FALSE;
|
|
BOOL g_bTermSrvEnabled = FALSE;
|
|
BOOL g_fInClientRundown = FALSE;
|
|
BOOL g_fInDllMain = FALSE;
|
|
|
|
|
|
BOOL SetStartedEventWhenSCardSubsytemIsStarted(BOOL fUseLocal);
|
|
|
|
|
|
void
|
|
PrintDebugString(LPSTR szString, DWORD dwValue)
|
|
{
|
|
char szOutString[256];
|
|
|
|
sprintf(szOutString,
|
|
"%d.%d> WINSCARD: %s - %lx\n",
|
|
GetCurrentProcessId(),
|
|
GetCurrentThreadId(),
|
|
szString,
|
|
dwValue);
|
|
|
|
//OutputDebugStringA(szOutString);
|
|
}
|
|
|
|
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Mark all current held contexts bad
|
|
//
|
|
WINSCARDAPI void WINAPI
|
|
MarkContextsAsBad(BOOL fCancel)
|
|
{
|
|
try {
|
|
g_phlContexts->MarkContentAsBad(fCancel);
|
|
g_phlReaders->MarkContentAsBad(FALSE);
|
|
}
|
|
catch (...)
|
|
{
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DllMain
|
|
//
|
|
BOOL WINAPI
|
|
DllMain(
|
|
HMODULE hInstDLL,
|
|
DWORD fdwReason,
|
|
LPVOID lpvReserved)
|
|
{
|
|
DWORD dw;
|
|
BOOL f;
|
|
|
|
g_fInDllMain = TRUE;
|
|
|
|
switch (fdwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
|
|
g_hInst = hInstDLL;
|
|
|
|
try
|
|
{
|
|
dw = 0;;
|
|
InitializeCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
|
|
dw++;
|
|
InitializeCriticalSection(&g_SafeCreateHandleCS);
|
|
dw++;
|
|
InitializeCriticalSection(&g_SetStartedEventCS);
|
|
dw++;
|
|
InitializeCriticalSection(&g_TermSrvEnabledCS);
|
|
dw++;
|
|
InitializeCriticalSection(&g_RegisterForStoppedEventCS);
|
|
dw++;
|
|
InitializeCriticalSection(&g_DllMainCS);
|
|
}
|
|
catch(...)
|
|
{
|
|
if (dw >= 1)
|
|
{
|
|
DeleteCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
|
|
}
|
|
if (dw >= 2)
|
|
{
|
|
DeleteCriticalSection(&g_SafeCreateHandleCS);
|
|
}
|
|
if (dw >= 3)
|
|
{
|
|
DeleteCriticalSection(&g_SetStartedEventCS);
|
|
}
|
|
if (dw >= 4)
|
|
{
|
|
DeleteCriticalSection(&g_TermSrvEnabledCS);
|
|
}
|
|
if (dw >= 5)
|
|
{
|
|
DeleteCriticalSection(&g_RegisterForStoppedEventCS);
|
|
}
|
|
|
|
g_fInDllMain = FALSE;
|
|
return FALSE;
|
|
}
|
|
|
|
g_phlContexts = new CHandleList(CONTEXT_HANDLE_ID);
|
|
g_phlReaders = new CHandleList(READER_HANDLE_ID);
|
|
|
|
if ((NULL == g_phlContexts) ||
|
|
(NULL == g_phlReaders) ||
|
|
g_phlContexts->InitFailed() ||
|
|
g_phlReaders->InitFailed())
|
|
{
|
|
if (g_phlContexts)
|
|
{
|
|
delete g_phlContexts;
|
|
g_phlContexts = NULL;
|
|
}
|
|
|
|
if (g_phlReaders)
|
|
{
|
|
delete g_phlReaders;
|
|
g_phlReaders = NULL;
|
|
}
|
|
|
|
DeleteCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
|
|
DeleteCriticalSection(&g_SafeCreateHandleCS);
|
|
DeleteCriticalSection(&g_SetStartedEventCS);
|
|
DeleteCriticalSection(&g_TermSrvEnabledCS);
|
|
DeleteCriticalSection(&g_RegisterForStoppedEventCS);
|
|
DeleteCriticalSection(&g_DllMainCS);
|
|
|
|
g_fInDllMain = FALSE;
|
|
return FALSE;
|
|
}
|
|
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
|
|
//
|
|
// Clean up the registered waits if they are still outstanding
|
|
//
|
|
HANDLE hCallbackToUnregister;
|
|
|
|
EnterCriticalSection(&g_DllMainCS);
|
|
g_fInDllMain = TRUE;
|
|
LeaveCriticalSection(&g_DllMainCS);
|
|
|
|
hCallbackToUnregister = InterlockedExchangePointer(
|
|
&g_hWaitTimerEventCallbackHandle,
|
|
NULL);
|
|
|
|
if (hCallbackToUnregister != NULL)
|
|
{
|
|
UnregisterWaitEx(hCallbackToUnregister, INVALID_HANDLE_VALUE);
|
|
}
|
|
|
|
hCallbackToUnregister = InterlockedExchangePointer(
|
|
&g_hSessionChangeCallbackHandle,
|
|
NULL);
|
|
|
|
if (hCallbackToUnregister != NULL)
|
|
{
|
|
UnregisterWaitEx(hCallbackToUnregister, INVALID_HANDLE_VALUE);
|
|
}
|
|
|
|
hCallbackToUnregister = InterlockedExchangePointer(
|
|
&g_hWaitForStoppedCallbackHandle,
|
|
NULL);
|
|
|
|
if (hCallbackToUnregister != NULL)
|
|
{
|
|
UnregisterWaitEx(hCallbackToUnregister, INVALID_HANDLE_VALUE);
|
|
}
|
|
|
|
hCallbackToUnregister = InterlockedExchangePointer(
|
|
&g_hWaitForStartedCallbackHandle,
|
|
NULL);
|
|
|
|
if (hCallbackToUnregister != NULL)
|
|
{
|
|
UnregisterWaitEx(hCallbackToUnregister, INVALID_HANDLE_VALUE);
|
|
}
|
|
|
|
//
|
|
// 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 (g_hSessionChangeEvent != NULL)
|
|
{
|
|
CloseHandle(g_hSessionChangeEvent);
|
|
}
|
|
|
|
if (g_hTimerEvent != NULL)
|
|
{
|
|
CloseHandle(g_hTimerEvent);
|
|
}
|
|
|
|
//
|
|
// Cleanup CritSecs.
|
|
//
|
|
DeleteCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
|
|
DeleteCriticalSection(&g_SafeCreateHandleCS);
|
|
DeleteCriticalSection(&g_SetStartedEventCS);
|
|
DeleteCriticalSection(&g_TermSrvEnabledCS);
|
|
DeleteCriticalSection(&g_RegisterForStoppedEventCS);
|
|
DeleteCriticalSection(&g_DllMainCS);
|
|
|
|
try {
|
|
if (g_phlReaders)
|
|
{
|
|
g_fInClientRundown = TRUE;
|
|
|
|
CHandle * pReader = g_phlReaders->GetFirst();
|
|
|
|
while (pReader != NULL)
|
|
{
|
|
try
|
|
{
|
|
((CReaderContext *) pReader)->EndTransaction(SCARD_LEAVE_CARD_FORCE);
|
|
}
|
|
catch (...){}
|
|
|
|
pReader = g_phlReaders->GetNext(pReader);
|
|
}
|
|
|
|
delete g_phlReaders;
|
|
g_phlReaders = NULL;
|
|
}
|
|
|
|
if (g_phlContexts)
|
|
{
|
|
delete g_phlContexts;
|
|
g_phlContexts = NULL;
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
}
|
|
|
|
ReleaseStartedEvent();
|
|
ReleaseStoppedEvent();
|
|
|
|
if (g_hUnifiedStartedEvent != NULL)
|
|
{
|
|
CloseHandle(g_hUnifiedStartedEvent);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
f = RedirDllMain(hInstDLL, fdwReason, lpvReserved);
|
|
|
|
g_fInDllMain = FALSE;
|
|
|
|
return(f);
|
|
}
|
|
|
|
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SessionChangeCallback
|
|
//
|
|
VOID CALLBACK
|
|
SessionChangeCallback(
|
|
PVOID lpParameter,
|
|
BOOLEAN TimerOrWaitFired)
|
|
{
|
|
WTS_CONNECTSTATE_CLASS *pConnectState = NULL;
|
|
BOOL fConnected = FALSE;
|
|
DWORD dw;
|
|
HANDLE hCallbackToUnregister;
|
|
|
|
EnterCriticalSection(&g_DllMainCS);
|
|
|
|
if (g_fInDllMain)
|
|
{
|
|
LeaveCriticalSection(&g_DllMainCS);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// If we are registered for local smart card stopped callbacks then
|
|
// unregister
|
|
//
|
|
hCallbackToUnregister = InterlockedExchangePointer(
|
|
&g_hWaitForStoppedCallbackHandle,
|
|
NULL);
|
|
|
|
if (hCallbackToUnregister != NULL)
|
|
{
|
|
UnregisterWait(hCallbackToUnregister);
|
|
}
|
|
|
|
//
|
|
// Detect whether we are in a connected state or not
|
|
//
|
|
if (!WTSQuerySessionInformation(
|
|
WTS_CURRENT_SERVER_HANDLE,
|
|
WTS_CURRENT_SESSION,
|
|
WTSConnectState,
|
|
(LPTSTR *) &pConnectState,
|
|
&dw))
|
|
{
|
|
//OutputDebugString("WINSCARD: SessionChangeCallback: WTSQuerySessionInformation failed!\n");
|
|
LeaveCriticalSection(&g_DllMainCS);
|
|
return;
|
|
}
|
|
|
|
fConnected = ( (*pConnectState == WTSActive) ||
|
|
(*pConnectState == WTSConnected));
|
|
|
|
WTSFreeMemory(pConnectState);
|
|
|
|
//
|
|
// If there is an outstanding wait, it may be waiting on the wrong event,
|
|
// so cancel the wait here. When there is a connect event the
|
|
// SetStartedEventWhenSCardSubsytemIsStarted() API will be called again
|
|
// to wait on the correct event
|
|
//
|
|
hCallbackToUnregister = InterlockedExchangePointer(
|
|
&g_hWaitForStartedCallbackHandle,
|
|
NULL);
|
|
|
|
if (hCallbackToUnregister != NULL)
|
|
{
|
|
UnregisterWait(hCallbackToUnregister);
|
|
}
|
|
|
|
if (!fConnected)
|
|
{
|
|
//
|
|
// Make sure the unified started event isn't set since we
|
|
// are now in a disconnected state
|
|
//
|
|
//OutputDebugString("WINSCARD: SessionChangeCallback: Disconnect\n");
|
|
ResetEvent(g_hUnifiedStartedEvent);
|
|
|
|
//
|
|
// Only mark the contexts bad if we're not in a service, because we
|
|
// know we're not redirecting if we're in a service.
|
|
//
|
|
if (FALSE == InAService())
|
|
MarkContextsAsBad(TRUE);
|
|
}
|
|
else
|
|
{
|
|
//OutputDebugString("WINSCARD: SessionChangeCallback: Reconnect\n");
|
|
SetRedirectDisabledValue();
|
|
SetStartedEventWhenSCardSubsytemIsStarted(FALSE);
|
|
}
|
|
|
|
LeaveCriticalSection(&g_DllMainCS);
|
|
}
|
|
|
|
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// TimerCallback
|
|
//
|
|
VOID CALLBACK
|
|
TimerCallback(
|
|
PVOID lpParameter,
|
|
BOOLEAN TimerOrWaitFired
|
|
)
|
|
{
|
|
HANDLE h = NULL;
|
|
BOOL fUnregister = TRUE;
|
|
|
|
__try
|
|
{
|
|
EnterCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (g_dwClientCount == 0)
|
|
{
|
|
LeaveCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// The check for !g_fInDllMain is only to reduce the window in which a deadlock
|
|
// can occur. The deadlock condition is as follows:
|
|
//
|
|
// 1) A thread enters winscard's DllMain (the thread in DllMain is of course holding the loader lock)
|
|
// 2) TimerCallback gets called
|
|
// 3) winscard's DllMain calls UnregisterWaitEx(INVALID_HANDLE_VALUE) for TimerCallback, which will
|
|
// block until the TimerCallback callback completes.
|
|
// 4) TimerCallback makes the WinStationRegisterNotificationEvent call which may try to load or unload
|
|
// a DLL, which of course requires the loader lock.
|
|
// 5) WHAMO!!!
|
|
//
|
|
if (!g_fInDllMain)
|
|
{
|
|
if (!g_fRegisteredForSessionChangeNotications)
|
|
{
|
|
if (WinStationRegisterNotificationEvent(
|
|
g_hSessionChangeEvent,
|
|
&g_SessionChangeID,
|
|
NOTIFY_FOR_THIS_SESSION,
|
|
WTS_CONSOLE_CONNECT_MASK |
|
|
WTS_CONSOLE_DISCONNECT_MASK |
|
|
WTS_REMOTE_CONNECT_MASK |
|
|
WTS_REMOTE_DISCONNECT_MASK))
|
|
{
|
|
g_fRegisteredForSessionChangeNotications = TRUE;
|
|
}
|
|
else if (++g_dwTimerCallbacksMade < 60) // 60 attemps at 10 seconds each will be ten minutes
|
|
{
|
|
//
|
|
// We still haven't succusfully registered for session change notifications and we haven't
|
|
// exausted our max retries, so don't unregister the callback yet.
|
|
//
|
|
fUnregister = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fUnregister = FALSE;
|
|
}
|
|
|
|
if (fUnregister)
|
|
{
|
|
h = InterlockedExchangePointer(&g_hWaitTimerEventCallbackHandle, NULL);
|
|
if (h != NULL)
|
|
{
|
|
UnregisterWait(h);
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
|
|
}
|
|
|
|
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// RegisterForSessionChangeNotifications
|
|
//
|
|
BOOL
|
|
RegisterForSessionChangeNotifications()
|
|
{
|
|
BOOL fRet = TRUE;
|
|
|
|
//
|
|
// Make sure we only register for session change notifications once
|
|
//
|
|
__try
|
|
{
|
|
EnterCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
g_dwClientCount++;
|
|
|
|
//
|
|
// If the global session change event and callback aren't setup then do that
|
|
//
|
|
if (g_hSessionChangeEvent == NULL)
|
|
{
|
|
g_hSessionChangeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
if (g_hSessionChangeEvent == NULL)
|
|
{
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (!RegisterWaitForSingleObject(
|
|
&g_hSessionChangeCallbackHandle,
|
|
g_hSessionChangeEvent,
|
|
SessionChangeCallback,
|
|
0,
|
|
INFINITE,
|
|
WT_EXECUTEDEFAULT))
|
|
{
|
|
CloseHandle(g_hSessionChangeEvent);
|
|
g_hSessionChangeEvent = NULL;
|
|
goto ErrorReturn;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Register with the WTS subsystem for change notifications
|
|
//
|
|
if (!g_fRegisteredForSessionChangeNotications)
|
|
{
|
|
if (WinStationRegisterNotificationEvent(
|
|
g_hSessionChangeEvent,
|
|
&g_SessionChangeID,
|
|
NOTIFY_FOR_THIS_SESSION,
|
|
WTS_CONSOLE_CONNECT_MASK |
|
|
WTS_CONSOLE_DISCONNECT_MASK |
|
|
WTS_REMOTE_CONNECT_MASK |
|
|
WTS_REMOTE_DISCONNECT_MASK))
|
|
{
|
|
g_fRegisteredForSessionChangeNotications = TRUE;
|
|
}
|
|
else if (g_hWaitTimerEventCallbackHandle == NULL)
|
|
{
|
|
//OutputDebugString("WINSCARD: RegisterForSessionChangeNotifications - WinStationRegisterNotificationEvent failed!!\n");
|
|
|
|
//
|
|
// Since the WinStationRegisterNotificationEvent call failed, TermSrv probably
|
|
// isn't ready, so just register for a callback and try to register again later
|
|
//
|
|
|
|
g_dwTimerCallbacksMade = 0;
|
|
|
|
if (g_hTimerEvent == NULL)
|
|
{
|
|
g_hTimerEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
}
|
|
|
|
if (!RegisterWaitForSingleObject(
|
|
&g_hWaitTimerEventCallbackHandle,
|
|
g_hTimerEvent,
|
|
TimerCallback,
|
|
0,
|
|
10000,
|
|
WT_EXECUTEDEFAULT))
|
|
{
|
|
goto ErrorReturn;
|
|
}
|
|
}
|
|
}
|
|
|
|
Return:
|
|
|
|
LeaveCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
|
|
g_dwClientCount--;
|
|
fRet = FALSE;
|
|
goto Return;
|
|
}
|
|
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UnRegisterForSessionChangeNotifications
|
|
//
|
|
BOOL
|
|
UnRegisterForSessionChangeNotifications()
|
|
{
|
|
BOOL fRet = TRUE;
|
|
HANDLE h;
|
|
|
|
//
|
|
// Make sure we only unregister if there are no more clients
|
|
//
|
|
__try
|
|
{
|
|
EnterCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (g_dwClientCount == 0)
|
|
{
|
|
fRet = FALSE;
|
|
goto Return;
|
|
}
|
|
else if (g_dwClientCount == 1)
|
|
{
|
|
g_dwClientCount = 0;
|
|
|
|
//
|
|
// If the timer callback is going then kill it
|
|
//
|
|
h = InterlockedExchangePointer(&g_hWaitTimerEventCallbackHandle, NULL);
|
|
if (h != NULL)
|
|
{
|
|
UnregisterWait(h);
|
|
}
|
|
|
|
//
|
|
// If we are registered then unregister
|
|
//
|
|
if (g_fRegisteredForSessionChangeNotications)
|
|
{
|
|
WinStationUnRegisterNotificationEvent(g_SessionChangeID);
|
|
g_SessionChangeID = 0;
|
|
}
|
|
|
|
g_fRegisteredForSessionChangeNotications = FALSE;
|
|
}
|
|
else
|
|
{
|
|
g_dwClientCount--;
|
|
}
|
|
|
|
Return:
|
|
|
|
LeaveCriticalSection(&g_RegisterForSessionChangeNoticationsCS);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SetStartedEventAfterTestingConnectedState
|
|
//
|
|
BOOL
|
|
SetStartedEventAfterTestingConnectedState()
|
|
{
|
|
BOOL fRet = TRUE;
|
|
WTS_CONNECTSTATE_CLASS *pConnectState = NULL;
|
|
BOOL fConnected = FALSE;
|
|
DWORD dw;
|
|
BOOL fUnregister = FALSE;
|
|
|
|
//
|
|
// Register for connect/disconnect notifications from the WTS subsystem
|
|
//
|
|
if (!RegisterForSessionChangeNotifications())
|
|
{
|
|
//OutputDebugString("WINSCARD: SetStartedEventAfterTestingConnectedState - RegisterForSessionChangeNotifications failed!!\n");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
fUnregister = TRUE;
|
|
|
|
//
|
|
// Detect whether we are in a connected state or not
|
|
//
|
|
if (!WTSQuerySessionInformation(
|
|
WTS_CURRENT_SERVER_HANDLE,
|
|
WTS_CURRENT_SESSION,
|
|
WTSConnectState,
|
|
(LPTSTR *) &pConnectState,
|
|
&dw))
|
|
{
|
|
//OutputDebugString("WINSCARD: SetStartedEventAfterTestingConnectedState - WTSQuerySessionInformation failed!!\n");
|
|
|
|
//
|
|
// Since that failed, TermSrv is probably not started, so just go local
|
|
//
|
|
if (!SetStartedEventWhenSCardSubsytemIsStarted(TRUE))
|
|
{
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
goto Return;
|
|
}
|
|
|
|
fConnected = ( (*pConnectState == WTSActive) ||
|
|
(*pConnectState == WTSConnected));
|
|
|
|
WTSFreeMemory(pConnectState);
|
|
|
|
//
|
|
// If we are connected, then call SetStartedEventWhenSCardSubsytemIsStarted
|
|
// which will detect whether we are in local or redirect mode and subsequently
|
|
// wait on the appropriate smart card subsystem (the local or the remote).
|
|
// Otherwise, we are not connected, so do nothing since
|
|
// SetStartedEventWhenSCardSubsytemIsStarted will be called once when we get
|
|
// a connnected notification from the WTS subsystem
|
|
//
|
|
if (fConnected)
|
|
{
|
|
//OutputDebugString("WINSCARD: SetStartedEventAfterTestingConnectedState - Connected!!\n");
|
|
if (!SetStartedEventWhenSCardSubsytemIsStarted(FALSE))
|
|
{
|
|
goto ErrorReturn;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//OutputDebugString("WINSCARD: SetStartedEventAfterTestingConnectedState - NOT Connected!!\n");
|
|
}
|
|
|
|
Return:
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
|
|
if (fUnregister)
|
|
{
|
|
UnRegisterForSessionChangeNotifications();
|
|
}
|
|
|
|
fRet = FALSE;
|
|
goto Return;
|
|
}
|
|
|
|
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// TermSrvEnabled
|
|
//
|
|
BOOL
|
|
TermSrvEnabled()
|
|
{
|
|
BOOL fRet = TRUE;
|
|
SC_HANDLE schSCM = NULL;
|
|
SC_HANDLE schService = NULL;
|
|
LPQUERY_SERVICE_CONFIG pServiceConfig = NULL;
|
|
DWORD cbServiceConfig = 0;
|
|
|
|
//
|
|
// Make sure we only do this once
|
|
//
|
|
__try
|
|
{
|
|
EnterCriticalSection(&g_TermSrvEnabledCS);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (g_fTermSrvEnableChecked)
|
|
{
|
|
goto Return;
|
|
}
|
|
|
|
//
|
|
// Open the service control manager
|
|
//
|
|
schSCM = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
|
|
if(schSCM == NULL)
|
|
{
|
|
//OutputDebugString("WINSCARD: TermSrvEnabled - OpenSCManagerW failed!!\n");
|
|
goto Return;
|
|
}
|
|
|
|
//
|
|
// open the "Terminal Services" service so we can query it's configuration
|
|
//
|
|
schService = OpenServiceW(schSCM, L"TermService", SERVICE_QUERY_CONFIG);
|
|
|
|
if (schService == NULL)
|
|
{
|
|
//OutputDebugString("WINSCARD: TermSrvEnabled - OpenServiceW failed!!\n");
|
|
goto Return;
|
|
}
|
|
|
|
//
|
|
// Get and check the services configuration
|
|
//
|
|
QueryServiceConfig(schService, NULL, 0, &cbServiceConfig);
|
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
pServiceConfig = (LPQUERY_SERVICE_CONFIG) HeapAlloc(
|
|
GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
cbServiceConfig);
|
|
if (pServiceConfig == NULL)
|
|
{
|
|
goto Return;
|
|
}
|
|
|
|
if (QueryServiceConfig(schService, pServiceConfig, cbServiceConfig, &cbServiceConfig))
|
|
{
|
|
if(pServiceConfig->dwStartType == SERVICE_DISABLED)
|
|
{
|
|
g_fTermSrvEnableChecked = TRUE;
|
|
goto Return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//OutputDebugString("WINSCARD: TermSrvEnabled - QueryServiceConfig failed - 2!!\n");
|
|
goto Return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//OutputDebugString("WINSCARD: TermSrvEnabled - QueryServiceConfig failed!!\n");
|
|
goto Return;
|
|
}
|
|
|
|
g_fTermSrvEnableChecked = TRUE;
|
|
g_bTermSrvEnabled = TRUE;
|
|
|
|
Return:
|
|
|
|
LeaveCriticalSection(&g_TermSrvEnabledCS);
|
|
|
|
if (pServiceConfig != NULL)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, pServiceConfig);
|
|
}
|
|
|
|
if (schService != NULL)
|
|
{
|
|
CloseServiceHandle(schService);
|
|
}
|
|
|
|
if (schSCM != NULL)
|
|
{
|
|
CloseServiceHandle(schSCM);
|
|
}
|
|
|
|
return g_bTermSrvEnabled;
|
|
}
|
|
|
|
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SafeCreateEvent
|
|
//
|
|
BOOL
|
|
SafeCreateEvent(
|
|
HANDLE *phEvent)
|
|
{
|
|
BOOL fRet = TRUE;
|
|
|
|
__try
|
|
{
|
|
EnterCriticalSection(&g_SafeCreateHandleCS);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
if (*phEvent != NULL)
|
|
{
|
|
goto Return;
|
|
}
|
|
|
|
*phEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
if (*phEvent == NULL)
|
|
{
|
|
fRet = FALSE;
|
|
}
|
|
|
|
Return:
|
|
LeaveCriticalSection(&g_SafeCreateHandleCS);
|
|
return (fRet);
|
|
}
|
|
|
|
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SmartCardSubsystemStoppedCallback and RegisterForStoppedCallback
|
|
//
|
|
VOID CALLBACK SmartCardSubsystemStoppedCallback(
|
|
PVOID lpParameter,
|
|
BOOLEAN TimerOrWaitFired
|
|
)
|
|
{
|
|
HANDLE hCallbackToUnregister;
|
|
|
|
EnterCriticalSection(&g_DllMainCS);
|
|
|
|
if (g_fInDllMain)
|
|
{
|
|
LeaveCriticalSection(&g_DllMainCS);
|
|
return;
|
|
}
|
|
|
|
//OutputDebugString("WINSCARD: SmartCardSubsystemStoppedCallback - resetting event \n");
|
|
ResetEvent(g_hUnifiedStartedEvent);
|
|
|
|
SetStartedEventWhenSCardSubsytemIsStarted(TRUE);
|
|
|
|
hCallbackToUnregister = InterlockedExchangePointer(
|
|
&g_hWaitForStoppedCallbackHandle,
|
|
NULL);
|
|
|
|
if (hCallbackToUnregister != NULL)
|
|
{
|
|
UnregisterWait(hCallbackToUnregister);
|
|
}
|
|
|
|
LeaveCriticalSection(&g_DllMainCS);
|
|
}
|
|
|
|
BOOL
|
|
RegisterForStoppedCallback()
|
|
{
|
|
BOOL fRet = TRUE;
|
|
BOOL fEnteredCS = FALSE;
|
|
HANDLE h = NULL;
|
|
|
|
h = AccessStoppedEvent();
|
|
if (h == NULL)
|
|
{
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
__try
|
|
{
|
|
EnterCriticalSection(&g_RegisterForStoppedEventCS);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
fEnteredCS = TRUE;
|
|
|
|
if (g_hWaitForStoppedCallbackHandle != NULL)
|
|
{
|
|
goto Return;
|
|
}
|
|
|
|
if (!RegisterWaitForSingleObject(
|
|
&g_hWaitForStoppedCallbackHandle,
|
|
h,
|
|
SmartCardSubsystemStoppedCallback,
|
|
0,
|
|
INFINITE,
|
|
WT_EXECUTEONLYONCE))
|
|
{
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
Return:
|
|
|
|
if (fEnteredCS)
|
|
{
|
|
LeaveCriticalSection(&g_RegisterForStoppedEventCS);
|
|
}
|
|
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto Return;
|
|
}
|
|
|
|
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SmartCardSubsystemStartedCallback
|
|
//
|
|
// This callback is fired when the smart card subsystem sets its started event.
|
|
// NOTE: Both local and remote scard subsystems being started will fire this
|
|
// same callback
|
|
//
|
|
VOID CALLBACK SmartCardSubsystemStartedCallback(
|
|
PVOID lpParameter,
|
|
BOOLEAN TimerOrWaitFired
|
|
)
|
|
{
|
|
BOOL fLocal = (lpParameter == (PVOID) 1);
|
|
HANDLE hCallbackToUnregister;
|
|
|
|
EnterCriticalSection(&g_DllMainCS);
|
|
|
|
if (g_fInDllMain)
|
|
{
|
|
LeaveCriticalSection(&g_DllMainCS);
|
|
return;
|
|
}
|
|
|
|
//OutputDebugString("WINSCARD: SmartCardSubsystemStartedCallback - setting event \n");
|
|
SetEvent(g_hUnifiedStartedEvent);
|
|
|
|
if (fLocal)
|
|
{
|
|
RegisterForStoppedCallback();
|
|
}
|
|
|
|
hCallbackToUnregister = InterlockedExchangePointer(
|
|
&g_hWaitForStartedCallbackHandle,
|
|
NULL);
|
|
|
|
if (hCallbackToUnregister != NULL)
|
|
{
|
|
UnregisterWait(hCallbackToUnregister);
|
|
}
|
|
|
|
LeaveCriticalSection(&g_DllMainCS);
|
|
}
|
|
|
|
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SetStartedEventWhenSCardSubsytemIsStarted
|
|
//
|
|
BOOL
|
|
SetStartedEventWhenSCardSubsytemIsStarted(
|
|
BOOL fUseLocal)
|
|
{
|
|
HANDLE h = NULL;
|
|
BOOL fRet = TRUE;
|
|
BOOL fEnteredCritSec = FALSE;
|
|
BOOL fLocal = FALSE;
|
|
|
|
//
|
|
// If termsrv is enabled and we are in redirect mode then get the
|
|
// started event that corresponds to the remoted scard subsystem being
|
|
// available, otherwise, get the started event of the local scard
|
|
// resource manager
|
|
//
|
|
if (!fUseLocal && TermSrvEnabled() && InTSRedirectMode())
|
|
{
|
|
//OutputDebugString("WINSCARD: SetStartedEventWhenSCardSubsytemIsStarted REDIRECT\n");
|
|
//
|
|
// if redirect is disabled, then just get out
|
|
//
|
|
if (TS_REDIRECT_DISABLED)
|
|
{
|
|
goto Return;
|
|
}
|
|
|
|
if (TS_REDIRECT_READY)
|
|
{
|
|
h = pfnSCardAccessStartedEvent();
|
|
}
|
|
else
|
|
{
|
|
goto ErrorReturn;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//OutputDebugString("WINSCARD: SetStartedEventWhenSCardSubsytemIsStarted LOCAL\n");
|
|
h = AccessStartedEvent();
|
|
fLocal = TRUE;
|
|
}
|
|
|
|
if (h == NULL)
|
|
{
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
//
|
|
// If the event is already set, then just set the event returned
|
|
// to the caller and return
|
|
//
|
|
if (WAIT_OBJECT_0 == WaitForSingleObject(h, 0))
|
|
{
|
|
//OutputDebugString("WINSCARD: SetStartedEventWhenSCardSubsytemIsStarted SETTING EVENT\n");
|
|
SetEvent(g_hUnifiedStartedEvent);
|
|
|
|
if (fLocal)
|
|
{
|
|
RegisterForStoppedCallback();
|
|
}
|
|
|
|
goto Return;
|
|
}
|
|
|
|
//
|
|
// The event wasn't set so we need to register a callback which
|
|
// fires when the scard subsystem is started.
|
|
//
|
|
// Make sure only one callback is registered.
|
|
//
|
|
__try
|
|
{
|
|
EnterCriticalSection(&g_SetStartedEventCS);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
fEnteredCritSec = TRUE;
|
|
|
|
//
|
|
// There is already a callback registered, so just get out
|
|
//
|
|
if (g_hWaitForStartedCallbackHandle != NULL)
|
|
{
|
|
goto Return;
|
|
}
|
|
|
|
//
|
|
// Register for the callback. The callback is fired when the smart
|
|
// card resource manager event is set (either the remote or the local
|
|
// subsystem event, based on whether this is a redirected session or not).
|
|
//
|
|
if (!RegisterWaitForSingleObject(
|
|
&g_hWaitForStartedCallbackHandle,
|
|
h,
|
|
SmartCardSubsystemStartedCallback,
|
|
(fLocal ? ((PVOID) 1) : ((PVOID) 0)), // tell the callback whether this is local or not
|
|
INFINITE,
|
|
WT_EXECUTEONLYONCE))
|
|
{
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
Return:
|
|
if (fEnteredCritSec)
|
|
{
|
|
LeaveCriticalSection(&g_SetStartedEventCS);
|
|
}
|
|
|
|
return (fRet);
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto Return;
|
|
}
|
|
|
|
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Service Manager Access Services
|
|
//
|
|
// The following services are used to manage user and terminal contexts for
|
|
// smartcards.
|
|
//
|
|
|
|
/*++
|
|
|
|
SCardEstablishContext:
|
|
|
|
This service establishes a context within which communication to the Service
|
|
Manager is performed.
|
|
|
|
Arguments:
|
|
|
|
dwScope supplies the scope under which this context acts. Possible values
|
|
are:
|
|
|
|
SCARD_SCOPE_USER - The context is a user context, and any database
|
|
operations are performed within the domain of the user.
|
|
|
|
SCARD_SCOPE_TERMINAL - The context is that of the current terminal, and
|
|
any database operations are performed within the domain of that
|
|
terminal. (The calling application must have appropriate access
|
|
permissions for any database actions.)
|
|
|
|
SCARD_SCOPE_SYSTEM - The context is the system context, and any database
|
|
operations are performed within the domain of the system. (The
|
|
calling application must have appropriate access permissions for any
|
|
database actions.)
|
|
|
|
pvReserved1 is reserved for future use, and must be NULL. [Reserved to
|
|
allow a suitably privileged management application to act on behalf of
|
|
another user.]
|
|
|
|
PvReserved2 is reserved for future use, and must be NULL. [Reserved to
|
|
allow a suitably privileged management application to act on behalf of
|
|
another terminal.]
|
|
|
|
phContext receives a handle to the established context, to be supplied to
|
|
other routines attempting to do work within the context.
|
|
|
|
Return Value:
|
|
|
|
A 32-bit value indicating whether or not the service completed successfully.
|
|
SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
|
|
represents an error condition.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/23/1996
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("SCardEstablishContext")
|
|
|
|
WINSCARDAPI LONG WINAPI
|
|
SCardEstablishContext(
|
|
IN DWORD dwScope,
|
|
IN LPCVOID pvReserved1,
|
|
IN LPCVOID pvReserved2,
|
|
OUT LPSCARDCONTEXT phContext)
|
|
{
|
|
LONG nReturn = SCARD_S_SUCCESS;
|
|
CSCardUserContext *pCtx = NULL;
|
|
|
|
try
|
|
{
|
|
if (NULL != pvReserved1)
|
|
throw (DWORD)SCARD_E_INVALID_VALUE;
|
|
if (NULL != pvReserved2)
|
|
throw (DWORD)SCARD_E_INVALID_VALUE;
|
|
if ((SCARD_SCOPE_USER != dwScope)
|
|
// && (SCARD_SCOPE_TERMINAL != dwScope) // Maybe NT V5+?
|
|
&& (SCARD_SCOPE_SYSTEM != dwScope))
|
|
throw (DWORD)SCARD_E_INVALID_VALUE;
|
|
*phContext = 0; // Make sure it's valid.
|
|
|
|
pCtx = new CSCardUserContext(dwScope);
|
|
if (NULL == pCtx)
|
|
{
|
|
CalaisWarning(
|
|
__SUBROUTINE__,
|
|
DBGT("Client can't allocate a new context"));
|
|
throw (DWORD)SCARD_E_NO_MEMORY;
|
|
}
|
|
if (pCtx->InitFailed())
|
|
{
|
|
delete pCtx;
|
|
pCtx = NULL;
|
|
return SCARD_E_NO_MEMORY;
|
|
}
|
|
|
|
if (!SafeCreateEvent(&g_hUnifiedStartedEvent))
|
|
{
|
|
throw GetLastError();
|
|
}
|
|
|
|
//
|
|
// If TermSrv is enabled then register for session change notifications.
|
|
// Don't fail if we can't do this, since it may not be fatal
|
|
//
|
|
if (TermSrvEnabled() && RegisterForSessionChangeNotifications())
|
|
{
|
|
pCtx->fCallUnregister = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pCtx->fCallUnregister = FALSE;
|
|
}
|
|
|
|
if (InTSRedirectMode())
|
|
{
|
|
HANDLE hHeap;
|
|
SCARDCONTEXT hContext = NULL;
|
|
HANDLE hEvent = NULL;
|
|
|
|
//
|
|
// if redirect is disabled, then just get out
|
|
//
|
|
if (TS_REDIRECT_DISABLED)
|
|
{
|
|
throw (DWORD)SCARD_E_NO_SERVICE;
|
|
}
|
|
|
|
hEvent = g_hUnifiedStartedEvent;
|
|
|
|
pCtx->AllocateMemory(0);
|
|
hHeap = pCtx->HeapHandle();
|
|
if (NULL == hHeap)
|
|
throw GetLastError();
|
|
|
|
if (!TS_REDIRECT_READY)
|
|
{
|
|
throw GetLastError();
|
|
}
|
|
|
|
nReturn = pfnSCardEstablishContext(dwScope, (LPCVOID)hHeap, (LPCVOID) hEvent, &hContext);
|
|
|
|
//
|
|
// See if there is an indication that the client's scardsvr service was shutdown
|
|
//
|
|
if (SCARD_E_NO_SERVICE == nReturn)
|
|
{
|
|
SetStartedEventAfterTestingConnectedState();
|
|
//OutputDebugString("WINSCARD: SCardEstablishContext: got E_NO_SERVICE!\n");
|
|
}
|
|
|
|
if (SCARD_S_SUCCESS != nReturn)
|
|
throw (DWORD)nReturn;
|
|
|
|
pCtx->SetRedirContext(hContext);
|
|
}
|
|
else
|
|
{
|
|
pCtx->EstablishContext();
|
|
}
|
|
|
|
*phContext = g_phlContexts->Add(pCtx);
|
|
}
|
|
|
|
catch (DWORD dwStatus)
|
|
{
|
|
if (NULL != pCtx)
|
|
delete pCtx;
|
|
nReturn = (LONG)dwStatus;
|
|
}
|
|
|
|
catch (...)
|
|
{
|
|
if (NULL != pCtx)
|
|
delete pCtx;
|
|
nReturn = SCARD_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
SCardIsValidContext:
|
|
|
|
This routine verifies that the context to the Service Manager is intact.
|
|
It is possible that if someone stops the Resource Manager Service, that
|
|
existing handles can be rendered useless, resulting in an
|
|
SCARD_E_SERVICE_STOPPED error. This routine simply tests to see if the
|
|
context is valid by pinging the server. It's used internally to validate
|
|
handles, and appears useful for external tools.
|
|
|
|
Arguments:
|
|
|
|
hContext supplies the handle to the context previously established via the
|
|
SCardEstablishContext service.
|
|
|
|
Return Value:
|
|
|
|
A 32-bit value indicating whether or not the service completed successfully.
|
|
SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
|
|
represents an error condition. Specific interesting error codes are:
|
|
|
|
SCARD_E_SERVICE_STOPPED - The Resource Manager Service has been ended.
|
|
|
|
SCARD_E_INVALID_HANDLE - The supplied handle isn't valid.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 11/2/1998
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("SCardIsValidContext")
|
|
|
|
WINSCARDAPI LONG WINAPI
|
|
SCardIsValidContext(
|
|
IN SCARDCONTEXT hContext)
|
|
{
|
|
LONG nReturn = SCARD_S_SUCCESS;
|
|
|
|
try
|
|
{
|
|
CSCardUserContext *pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]);
|
|
SCARDCONTEXT hRedirContext = pCtx->GetRedirContext();
|
|
|
|
if (pCtx->IsBad())
|
|
{
|
|
throw (DWORD)SCARD_E_SERVICE_STOPPED;
|
|
}
|
|
|
|
if (NULL != hRedirContext) {
|
|
nReturn = pfnSCardIsValidContext(hRedirContext);
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
if (!pCtx->IsValidContext())
|
|
throw (DWORD)SCARD_E_SERVICE_STOPPED;
|
|
}
|
|
catch (...)
|
|
{
|
|
SCardReleaseContext(hContext);
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
catch (DWORD dwStatus)
|
|
{
|
|
nReturn = (LONG)dwStatus;
|
|
}
|
|
|
|
catch (...)
|
|
{
|
|
nReturn = SCARD_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IsSafeToUnregisterForSessionChangeNotifications
|
|
//
|
|
BOOL IsSafeToUnregisterForSessionChangeNotifications(
|
|
IN SCARDCONTEXT hContext)
|
|
{
|
|
//
|
|
// Check if the loader lock is held by the caller (in which case
|
|
// we may be in the caller's DllMain right now). If the lock is held,
|
|
// it's not safe to make the Unregister RPC call, since that could cause
|
|
// deadlock.
|
|
//
|
|
|
|
// IsSafe is TRUE if the current Thread is Not Equal to the lock's owning
|
|
// thread.
|
|
//
|
|
// Note, we tried using RtlIsThreadWithinLoaderCallout here, but that only
|
|
// tells us if we're in PROCESS_ATTACH. It doesn't tell us if we're in
|
|
// any other loader callbacks so it's not sufficient.
|
|
|
|
return ( NtCurrentTeb()->ClientId.UniqueThread ) !=
|
|
( ((PRTL_CRITICAL_SECTION)(NtCurrentPeb()->LoaderLock))->OwningThread );
|
|
}
|
|
|
|
/*++
|
|
|
|
SCardReleaseContext:
|
|
|
|
This routine closes an established context to the Service Manager, and frees
|
|
any resources allocated under that context.
|
|
|
|
Arguments:
|
|
|
|
hContext supplies the handle to the context previously established via the
|
|
SCardEstablishContext service.
|
|
|
|
Return Value:
|
|
|
|
A 32-bit value indicating whether or not the service completed successfully.
|
|
SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
|
|
represents an error condition.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/23/1996
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("SCardReleaseContext")
|
|
|
|
WINSCARDAPI LONG WINAPI
|
|
SCardReleaseContext(
|
|
IN SCARDCONTEXT hContext)
|
|
{
|
|
LONG nReturn = SCARD_S_SUCCESS;
|
|
CSCardUserContext *pCtx = NULL;
|
|
|
|
try
|
|
{
|
|
pCtx = (CSCardUserContext *)g_phlContexts->Close(hContext);
|
|
SCARDCONTEXT hRedirContext = pCtx->GetRedirContext();
|
|
|
|
if (pCtx->fCallUnregister)
|
|
{
|
|
if (IsSafeToUnregisterForSessionChangeNotifications(hContext))
|
|
{
|
|
UnRegisterForSessionChangeNotifications();
|
|
}
|
|
}
|
|
|
|
if (NULL != hRedirContext)
|
|
{
|
|
if (pCtx->IsBad())
|
|
{
|
|
nReturn = pfnSCardReleaseBadContext(hRedirContext);
|
|
}
|
|
else
|
|
{
|
|
nReturn = pfnSCardReleaseContext(hRedirContext);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
pCtx->Cancel();
|
|
pCtx->ReleaseContext();
|
|
}
|
|
catch (...) {}
|
|
}
|
|
delete pCtx;
|
|
pCtx = NULL;
|
|
}
|
|
|
|
catch (DWORD dwStatus)
|
|
{
|
|
nReturn = (LONG)dwStatus;
|
|
}
|
|
|
|
catch (...)
|
|
{
|
|
nReturn = SCARD_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Service Manager Support Routines
|
|
//
|
|
// The following services are supplied to simplify the use of the Service
|
|
// Manager API.
|
|
//
|
|
|
|
/*++
|
|
|
|
SCardFreeMemory:
|
|
|
|
This routine releases memory that has been returned from the Service Manager
|
|
API via the use of the SCARD_AUTOALLOCATE length designator.
|
|
|
|
Arguments:
|
|
|
|
hContext - This is the reference value returned from the
|
|
SCardEstablishContext service.
|
|
|
|
pvMem - This supplies the memory block to be released.
|
|
|
|
Return Value:
|
|
|
|
A 32-bit value indicating whether or not the service completed successfully.
|
|
SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
|
|
represents an error condition.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/23/1996
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("SCardFreeMemory")
|
|
|
|
WINSCARDAPI LONG WINAPI
|
|
SCardFreeMemory(
|
|
IN SCARDCONTEXT hContext,
|
|
IN LPCVOID pvMem)
|
|
{
|
|
LONG nReturn = SCARD_S_SUCCESS;
|
|
|
|
try
|
|
{
|
|
if ((NULL != pvMem) && ((LPVOID)g_wszBlank != pvMem))
|
|
{
|
|
if (NULL == hContext)
|
|
HeapFree(GetProcessHeap(), 0, (LPVOID)pvMem);
|
|
else
|
|
{
|
|
CSCardUserContext *pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]);
|
|
nReturn = (LONG)pCtx->FreeMemory(pvMem);
|
|
}
|
|
}
|
|
}
|
|
|
|
catch (DWORD dwStatus)
|
|
{
|
|
nReturn = (LONG)dwStatus;
|
|
}
|
|
|
|
catch (...)
|
|
{
|
|
nReturn = SCARD_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Reader Services
|
|
//
|
|
// The following services supply means for tracking cards within readers.
|
|
//
|
|
|
|
/*++
|
|
|
|
SCardCancel:
|
|
|
|
This service is used to terminate any and all outstanding actions within the
|
|
context. The caller supplies the context handle under which outstanding
|
|
requests will be canceled. Not all requests are cancelable; only those
|
|
which require waiting for external action by the smartcard or user. Any
|
|
such outstanding action requests will terminate with a status indication
|
|
that the action was canceled. This is especially useful to force
|
|
outstanding SCardGetStatusChange calls to terminate.
|
|
|
|
Arguments:
|
|
|
|
hContext supplies the handle identifying the Service Manager Context
|
|
established previously via the SCardEstablishContext() service.
|
|
|
|
Return Value:
|
|
|
|
A 32-bit value indicating whether or not the service completed successfully.
|
|
SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
|
|
represents an error condition.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/23/1996
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("SCardCancel")
|
|
|
|
WINSCARDAPI LONG WINAPI
|
|
SCardCancel(
|
|
IN SCARDCONTEXT hContext)
|
|
{
|
|
LONG nReturn = SCARD_S_SUCCESS;
|
|
|
|
try
|
|
{
|
|
CSCardUserContext *pCtx = (CSCardUserContext *)((*g_phlContexts)[hContext]);
|
|
SCARDCONTEXT hRedirContext = pCtx->GetRedirContext();
|
|
|
|
if (pCtx->IsBad())
|
|
{
|
|
throw (DWORD)SCARD_E_SERVICE_STOPPED;
|
|
}
|
|
|
|
if (NULL != hRedirContext) {
|
|
return pfnSCardCancel(hRedirContext);
|
|
}
|
|
else
|
|
pCtx->Cancel();
|
|
}
|
|
|
|
catch (DWORD dwStatus)
|
|
{
|
|
nReturn = (LONG)dwStatus;
|
|
}
|
|
|
|
catch (...)
|
|
{
|
|
nReturn = SCARD_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Card/Reader Access Services
|
|
//
|
|
// The following services provide means for establishing communication with
|
|
// the card.
|
|
//
|
|
|
|
/*++
|
|
|
|
SCardReconnect:
|
|
|
|
This service re-establishes an existing connection from the calling
|
|
application to the smartcard. This service is used to move a card handle
|
|
from direct access to general access (see Section 4), or to acknowledge and
|
|
clear an error condition that is preventing further access to the card.
|
|
|
|
Arguments:
|
|
|
|
hCard - This supplies the reference value obtained from a previous call to
|
|
the SCardConnect or SCardOpenReader service.
|
|
|
|
DwShareMode supplies a flag indicating whether or not other applications may
|
|
form connections to this card. Possible values are:
|
|
|
|
SCARD_SHARE_SHARED - This application is willing to share this card with
|
|
other applications.
|
|
|
|
SCARD_SHARE_EXCLUSIVE - This application is not willing to share this
|
|
card with other applications.
|
|
|
|
DwPreferredProtocols supplies a bit mask of acceptable protocols for this
|
|
connection. Possible values, which may be combined via the OR
|
|
operation, are:
|
|
|
|
SCARD_PROTOCOL_T0 - T=0 is an acceptable protocol.
|
|
|
|
SCARD_PROTOCOL_T1 - T=1 is an acceptable protocol.
|
|
|
|
DwInitialization supplies an indication as to the form of initialization
|
|
that should be performed on the card. Possible values are:
|
|
|
|
SCARD_LEAVE_CARD - Don't do anything special on reconnect
|
|
|
|
SCARD_RESET_CARD - Reset the card (Warm Reset)
|
|
|
|
SCARD_UNPOWER_CARD - Power down the card and reset it (Cold Reset)
|
|
|
|
pdwActiveProtocol receives a flag indicating the established active
|
|
protocol. Possible values are:
|
|
|
|
SCARD_PROTOCOL_T0 - T=0 is the active protocol.
|
|
|
|
SCARD_PROTOCOL_T1 - T=1 is the active protocol.
|
|
|
|
Return Value:
|
|
|
|
A 32-bit value indicating whether or not the service completed successfully.
|
|
SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
|
|
represents an error condition.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/23/1996
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("SCardReconnect")
|
|
|
|
WINSCARDAPI LONG WINAPI
|
|
SCardReconnect(
|
|
IN SCARDHANDLE hCard,
|
|
IN DWORD dwShareMode,
|
|
IN DWORD dwPreferredProtocols,
|
|
IN DWORD dwInitialization,
|
|
OUT LPDWORD pdwActiveProtocol)
|
|
{
|
|
LONG nReturn = SCARD_S_SUCCESS;
|
|
|
|
try
|
|
{
|
|
CReaderContext *pRdr = (CReaderContext *)((*g_phlReaders)[hCard]);
|
|
|
|
if (pRdr->IsBad())
|
|
{
|
|
throw (DWORD)SCARD_E_SERVICE_STOPPED;
|
|
}
|
|
|
|
if (NULL != pRdr->GetRedirCard()) {
|
|
nReturn = pfnSCardReconnect(pRdr->GetRedirCard(), dwShareMode, dwPreferredProtocols, dwInitialization, pdwActiveProtocol);
|
|
}
|
|
else
|
|
{
|
|
pRdr->Reconnect(
|
|
dwShareMode,
|
|
dwPreferredProtocols,
|
|
dwInitialization);
|
|
if (NULL != pdwActiveProtocol)
|
|
*pdwActiveProtocol = pRdr->Protocol();
|
|
}
|
|
}
|
|
|
|
catch (DWORD dwStatus)
|
|
{
|
|
nReturn = (LONG)dwStatus;
|
|
}
|
|
|
|
catch (...)
|
|
{
|
|
nReturn = SCARD_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
SCardDisconnect:
|
|
|
|
This service terminates a previously opened connection between the calling
|
|
application and the smartcard in the target reader.
|
|
|
|
Arguments:
|
|
|
|
hCard - This supplies the reference value obtained from a previous call to
|
|
the SCardConnect or SCardOpenReader service.
|
|
|
|
dwDisposition - Supplies an indication of what should be done with the card
|
|
in the connected reader. Possible values are:
|
|
|
|
SCARD_LEAVE_CARD - Don't do anything special on close
|
|
|
|
SCARD_RESET_CARD - Reset the card on close
|
|
|
|
SCARD_UNPOWER_CARD - Power down the card on close
|
|
|
|
SCARD_EJECT_CARD - Eject the card on close
|
|
|
|
Return Value:
|
|
|
|
A 32-bit value indicating whether or not the service completed successfully.
|
|
SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
|
|
represents a warning condition. The connection is terminated regardless of
|
|
the return code.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/23/1996
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("SCardDisconnect")
|
|
|
|
WINSCARDAPI LONG WINAPI
|
|
SCardDisconnect(
|
|
IN SCARDHANDLE hCard,
|
|
IN DWORD dwDisposition)
|
|
{
|
|
CReaderContext *pRdr = NULL;
|
|
LONG nReturn = SCARD_S_SUCCESS;
|
|
|
|
try
|
|
{
|
|
pRdr = (CReaderContext *)g_phlReaders->Close(hCard);
|
|
|
|
if (NULL != pRdr->GetRedirCard()) {
|
|
nReturn = pfnSCardDisconnect(pRdr->GetRedirCard(), dwDisposition);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(pRdr->Context()->m_hReaderHandle == hCard);
|
|
pRdr->Context()->m_hReaderHandle = NULL;
|
|
nReturn = pRdr->Disconnect(dwDisposition);
|
|
}
|
|
|
|
delete pRdr;
|
|
}
|
|
|
|
catch (DWORD dwStatus)
|
|
{
|
|
if (NULL != pRdr)
|
|
delete pRdr;
|
|
nReturn = (LONG)dwStatus;
|
|
}
|
|
|
|
catch (...)
|
|
{
|
|
if (NULL != pRdr)
|
|
delete pRdr;
|
|
nReturn = SCARD_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
SCardBeginTransaction:
|
|
|
|
This service temporarily blocks other applications from accessing the
|
|
smartcard, in order for this application to perform an operation that
|
|
requires multiple interactions.
|
|
|
|
Arguments:
|
|
|
|
hCard - This supplies the reference value obtained from a previous call to
|
|
the SCardConnect or SCardOpenReader service.
|
|
|
|
Return Value:
|
|
|
|
A 32-bit value indicating whether or not the service completed successfully.
|
|
SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
|
|
represents an error condition.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/23/1996
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("SCardBeginTransaction")
|
|
|
|
WINSCARDAPI LONG WINAPI
|
|
SCardBeginTransaction(
|
|
IN SCARDHANDLE hCard)
|
|
{
|
|
LONG nReturn = SCARD_S_SUCCESS;
|
|
|
|
try
|
|
{
|
|
CReaderContext *pRdr = (CReaderContext *)((*g_phlReaders)[hCard]);
|
|
if (pRdr->IsBad())
|
|
{
|
|
throw (DWORD)SCARD_E_SERVICE_STOPPED;
|
|
}
|
|
if (NULL != pRdr->GetRedirCard()) {
|
|
nReturn = pfnSCardBeginTransaction(pRdr->GetRedirCard());
|
|
}
|
|
else
|
|
pRdr->BeginTransaction();
|
|
}
|
|
|
|
catch (DWORD dwStatus)
|
|
{
|
|
nReturn = (LONG)dwStatus;
|
|
}
|
|
|
|
catch (...)
|
|
{
|
|
nReturn = SCARD_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
SCardEndTransaction:
|
|
|
|
This service completes a previously declared transaction, allowing other
|
|
applications to resume interactions with the card.
|
|
|
|
Arguments:
|
|
|
|
hCard - This supplies the reference value obtained from a previous call to
|
|
the SCardConnect or SCardOpenReader service.
|
|
|
|
dwDisposition - Supplies an indication of what should be done with the card
|
|
in the connected reader. Possible values are:
|
|
|
|
SCARD_LEAVE_CARD - Don't do anything special on close
|
|
|
|
SCARD_RESET_CARD - Reset the card on close
|
|
|
|
SCARD_UNPOWER_CARD - Power down the card on close
|
|
|
|
SCARD_EJECT_CARD - Eject the card on close
|
|
|
|
Return Value:
|
|
|
|
A 32-bit value indicating whether or not the service completed successfully.
|
|
SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
|
|
represents an error condition.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/23/1996
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("SCardEndTransaction")
|
|
|
|
WINSCARDAPI LONG WINAPI
|
|
SCardEndTransaction(
|
|
IN SCARDHANDLE hCard,
|
|
IN DWORD dwDisposition)
|
|
{
|
|
LONG nReturn = SCARD_S_SUCCESS;
|
|
|
|
try
|
|
{
|
|
CReaderContext *pRdr = (CReaderContext *)((*g_phlReaders)[hCard]);
|
|
if (pRdr->IsBad())
|
|
{
|
|
throw (DWORD)SCARD_E_SERVICE_STOPPED;
|
|
}
|
|
if (NULL != pRdr->GetRedirCard()) {
|
|
nReturn = pfnSCardEndTransaction(pRdr->GetRedirCard(), dwDisposition);
|
|
}
|
|
else
|
|
pRdr->EndTransaction(dwDisposition);
|
|
}
|
|
|
|
catch (DWORD dwStatus)
|
|
{
|
|
nReturn = (LONG)dwStatus;
|
|
}
|
|
|
|
catch (...)
|
|
{
|
|
nReturn = SCARD_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
SCardState:
|
|
|
|
This routine provides the current state of the reader. It may be used at
|
|
any time following a successful call to SCardConnect or SCardOpenReader, and
|
|
prior to a successful call to SCardDisconnect. It does not effect the state
|
|
of the reader or driver.
|
|
|
|
Arguments:
|
|
|
|
hCard - This is the reference value returned from the SCardConnect or
|
|
SCardOpenReader service.
|
|
|
|
pdwState - This receives the current state of the reader. Upon success, it
|
|
receives one of the following state indicators:
|
|
|
|
SCARD_ABSENT - This value implies there is no card in the reader.
|
|
|
|
SCARD_PRESENT - This value implies there is a card is present in the
|
|
reader, but that it has not been moved into position for use.
|
|
|
|
SCARD_SWALLOWED - This value implies there is a card in the reader in
|
|
position for use. The card is not powered.
|
|
|
|
SCARD_POWERED - This value implies there is power is being provided to
|
|
the card, but the Reader Driver is unaware of the mode of the card.
|
|
|
|
SCARD_NEGOTIABLEMODE - This value implies the card has been reset and is
|
|
awaiting PTS negotiation.
|
|
|
|
SCARD_SPECIFICMODE - This value implies the card has been reset and
|
|
specific communication protocols have been established.
|
|
|
|
pdwProtocol - This receives the current protocol, if any. Possible returned
|
|
values are listed below. Other values may be added in the future. The
|
|
returned value is only meaningful if the returned state is
|
|
SCARD_SPECIFICMODE.
|
|
|
|
SCARD_PROTOCOL_RAW - The Raw Transfer Protocol is in use.
|
|
|
|
SCARD_PROTOCOL_T0 - The ISO 7816/3 T=0 Protocol is in use.
|
|
|
|
SCARD_PROTOCOL_T1 - The ISO 7816/3 T=1 Protocol is in use.
|
|
|
|
pbAtr - This parameter points to a 32-byte buffer which receives the ATR
|
|
string from the currently inserted card, if available.
|
|
|
|
pbcAtrLen - This points to a DWORD which supplies the length of the pbAtr
|
|
buffer, and receives the actual number of bytes in the ATR string.
|
|
|
|
Return Value:
|
|
|
|
A 32-bit value indicating whether or not the service completed successfully.
|
|
SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
|
|
represents an error condition.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/23/1996
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("SCardState")
|
|
|
|
WINSCARDAPI LONG WINAPI
|
|
SCardState(
|
|
IN SCARDHANDLE hCard,
|
|
OUT LPDWORD pdwState,
|
|
OUT LPDWORD pdwProtocol,
|
|
OUT LPBYTE pbAtr,
|
|
IN OUT LPDWORD pcbAtrLen)
|
|
{
|
|
LONG nReturn = SCARD_S_SUCCESS;
|
|
|
|
try
|
|
{
|
|
CReaderContext *pRdr = (CReaderContext *)((*g_phlReaders)[hCard]);
|
|
if (pRdr->IsBad())
|
|
{
|
|
throw (DWORD)SCARD_E_SERVICE_STOPPED;
|
|
}
|
|
if (NULL != pRdr->GetRedirCard()) {
|
|
nReturn = pfnSCardState(pRdr->GetRedirCard(), pdwState, pdwProtocol, pbAtr, pcbAtrLen);
|
|
}
|
|
else
|
|
{
|
|
CBuffer bfAtr, bfRdr;
|
|
DWORD dwLocalState, dwLocalProtocol;
|
|
|
|
pRdr->Status(&dwLocalState, &dwLocalProtocol, bfAtr, bfRdr);
|
|
if (NULL != pdwState)
|
|
*pdwState = dwLocalState;
|
|
if (NULL != pdwProtocol)
|
|
*pdwProtocol = dwLocalProtocol;
|
|
if (NULL != pcbAtrLen)
|
|
PlaceResult(pRdr->Context()->Parent(), bfAtr, pbAtr, pcbAtrLen);
|
|
}
|
|
}
|
|
|
|
catch (DWORD dwStatus)
|
|
{
|
|
nReturn = (LONG)dwStatus;
|
|
}
|
|
|
|
catch (...)
|
|
{
|
|
nReturn = SCARD_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
SCardTransmit:
|
|
|
|
This routine sends a service request to the smartcard, and expects to
|
|
receive data back from the card.
|
|
|
|
Arguments:
|
|
|
|
hCard - This is the reference value returned from the SCardConnect service.
|
|
|
|
pioSendPci - This supplies the protocol header structure for the
|
|
instruction. This buffer is in the format of a SCARD_IO_REQUEST
|
|
structure, followed by the specific protocol control information.
|
|
|
|
pbSendBuffer - This supplies the actual data to be written to the card in
|
|
conjunction with the command.
|
|
|
|
cbSendLength - This supplies the length of the pbSendBuffer parameter, in
|
|
bytes.
|
|
|
|
pioRecvPci - This supplies the protocol header structure for the
|
|
instruction, followed by a buffer in which to receive any returned
|
|
protocol control information specific to the protocol in use. This
|
|
parameter may be NULL if no returned PCI is desired.
|
|
|
|
pbRecvBuffer - This receives any data returned from the card in conjunction
|
|
with the command.
|
|
|
|
pcbRecvLength - This supplies the length of the pbRecvBuffer parameter, in
|
|
bytes, and receives the actual number of bytes received from the
|
|
smartcard. If the buffer length is specified as SCARD_AUTOALLOCATE,
|
|
then pbAttrBuffer is converted to a pointer to a byte pointer, and
|
|
receives the address of a block of memory containing the returned data.
|
|
This block of memory must be deallocated via the SCardFreeMemory()
|
|
service.
|
|
|
|
Return Value:
|
|
|
|
A 32-bit value indicating whether or not the service completed successfully.
|
|
SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
|
|
represents an error condition.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 2/6/1997
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("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 nReturn = SCARD_S_SUCCESS;
|
|
|
|
try
|
|
{
|
|
CReaderContext *pRdr = (CReaderContext *)((*g_phlReaders)[hCard]);
|
|
if (pRdr->IsBad())
|
|
{
|
|
throw (DWORD)SCARD_E_SERVICE_STOPPED;
|
|
}
|
|
if (NULL != pRdr->GetRedirCard()) {
|
|
nReturn = pfnSCardTransmit(pRdr->GetRedirCard(), pioSendPci, pbSendBuffer, cbSendLength, pioRecvPci, pbRecvBuffer, pcbRecvLength);
|
|
}
|
|
else
|
|
{
|
|
CBuffer bfData(*pcbRecvLength);
|
|
DWORD dwLen = 0;
|
|
|
|
if (NULL != pcbRecvLength)
|
|
{
|
|
if (SCARD_AUTOALLOCATE != *pcbRecvLength)
|
|
dwLen = *pcbRecvLength;
|
|
}
|
|
|
|
pRdr->Transmit(
|
|
pioSendPci,
|
|
pbSendBuffer,
|
|
cbSendLength,
|
|
pioRecvPci,
|
|
bfData,
|
|
dwLen);
|
|
PlaceResult(
|
|
pRdr->Context()->Parent(),
|
|
bfData,
|
|
pbRecvBuffer,
|
|
pcbRecvLength);
|
|
}
|
|
}
|
|
|
|
catch (DWORD dwStatus)
|
|
{
|
|
nReturn = (LONG)dwStatus;
|
|
}
|
|
|
|
catch (...)
|
|
{
|
|
nReturn = SCARD_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Reader Control Routines
|
|
//
|
|
// The following services provide for direct, low-level manipulation of the
|
|
// reader by the calling application allowing it control over the
|
|
// attributes of the communications with the card.
|
|
//
|
|
|
|
/*++
|
|
|
|
SCardControl:
|
|
|
|
This routine provides for direct application control of the reader, should
|
|
it be necessary. It may be used at any time following a successful call to
|
|
SCardConnect or SCardOpenReader, and prior to a successful call to
|
|
SCardDisconnect. The effect on the state of the reader is dependent on the
|
|
control code.
|
|
|
|
Arguments:
|
|
|
|
hCard - This is the reference value returned from the SCardConnect or
|
|
SCardOpenReader service.
|
|
|
|
dwControlCode - This supplies the control code for the operation. This value
|
|
identifies the specific operation to be performed.
|
|
|
|
pvInBuffer - This supplies a pointer to a buffer that contains the data
|
|
required to perform the operation. This parameter can be NULL if the
|
|
dwControlCode parameter specifies an operation that does not require
|
|
input data.
|
|
|
|
cbInBufferSize - This supplies the size, in bytes, of the buffer pointed to
|
|
by pvInBuffer.
|
|
|
|
pvOutBuffer - This buffer receives the operation's output data. This
|
|
parameter can be NULL if the dwControlCode parameter specifies an
|
|
operation that does not produce output data.
|
|
|
|
cbOutBufferSize - This supplies the size, in bytes, of the buffer pointed to
|
|
by pvOutBuffer.
|
|
|
|
pcbBytesReturned - This receives the size, in bytes, of the data stored into
|
|
the buffer pointed to by pvOutBuffer.
|
|
|
|
Return Value:
|
|
|
|
A 32-bit value indicating whether or not the service completed successfully.
|
|
SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
|
|
represents an error condition.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/23/1996
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("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 nReturn = SCARD_S_SUCCESS;
|
|
|
|
try
|
|
{
|
|
CReaderContext *pRdr = (CReaderContext *)((*g_phlReaders)[hCard]);
|
|
if (pRdr->IsBad())
|
|
{
|
|
throw (DWORD)SCARD_E_SERVICE_STOPPED;
|
|
}
|
|
if (NULL != pRdr->GetRedirCard()) {
|
|
nReturn = pfnSCardControl(pRdr->GetRedirCard(), dwControlCode, pvInBuffer, cbInBufferSize, pvOutBuffer, cbOutBufferSize, pcbBytesReturned);
|
|
}
|
|
else
|
|
{
|
|
CBuffer bfResponse(cbOutBufferSize);
|
|
*pcbBytesReturned = cbOutBufferSize;
|
|
pRdr->Control(dwControlCode, pvInBuffer, cbInBufferSize, bfResponse);
|
|
PlaceResult(
|
|
pRdr->Context()->Parent(),
|
|
bfResponse,
|
|
(LPBYTE)pvOutBuffer,
|
|
pcbBytesReturned);
|
|
}
|
|
}
|
|
|
|
catch (DWORD dwStatus)
|
|
{
|
|
nReturn = (LONG)dwStatus;
|
|
}
|
|
|
|
catch (...)
|
|
{
|
|
nReturn = SCARD_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
SCardGetAttrib:
|
|
|
|
This routine gets the current communications attributes for the given
|
|
handle. It does not effect the state of the reader, driver, or card.
|
|
|
|
Arguments:
|
|
|
|
hCard - This is the reference value returned from the SCardConnect or
|
|
SCardOpenReader service.
|
|
|
|
dwAttrId - This supplies the identifier for the attribute to get.
|
|
|
|
pbAttr - This buffer receives the attribute corresponding to the attribute
|
|
id supplied in the dwAttrId parameter. If this value is NULL, the
|
|
supplied buffer length in pcbAttrLength is ignored, the length of the
|
|
buffer that would have been returned had this parameter not been null is
|
|
written to pcbAttrLength, and a success code is returned.
|
|
|
|
pcbAttrLength - This supplies the length of the pbAttr buffer in bytes, and
|
|
receives the actual length of the received attribute. If the buffer
|
|
length is specified as SCARD_AUTOALLOCATE, then pbAttrBuffer is
|
|
converted to a pointer to a byte pointer, and receives the address of a
|
|
block of memory containing the attribute. This block of memory must be
|
|
deallocated via the SCardFreeMemory() service.
|
|
|
|
Return Value:
|
|
|
|
A 32-bit value indicating whether or not the service completed successfully.
|
|
SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
|
|
represents an error condition.
|
|
|
|
Note that strings are always returned as ANSI characters, per PC/SC
|
|
standards.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/23/1996
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("SCardGetAttrib")
|
|
|
|
WINSCARDAPI LONG WINAPI
|
|
SCardGetAttrib(
|
|
IN SCARDHANDLE hCard,
|
|
IN DWORD dwAttrId,
|
|
OUT LPBYTE pbAttr,
|
|
IN OUT LPDWORD pcbAttrLen)
|
|
{
|
|
LONG nReturn = SCARD_S_SUCCESS;
|
|
|
|
try
|
|
{
|
|
CReaderContext *pRdr = (CReaderContext *)((*g_phlReaders)[hCard]);
|
|
if (pRdr->IsBad())
|
|
{
|
|
throw (DWORD)SCARD_E_SERVICE_STOPPED;
|
|
}
|
|
if (NULL != pRdr->GetRedirCard()) {
|
|
nReturn = pfnSCardGetAttrib(pRdr->GetRedirCard(), dwAttrId, pbAttr, pcbAttrLen);
|
|
}
|
|
else
|
|
{
|
|
CBuffer bfAttrib;
|
|
DWORD dwLen = 0;
|
|
|
|
if (NULL != pcbAttrLen)
|
|
{
|
|
if (SCARD_AUTOALLOCATE != *pcbAttrLen)
|
|
dwLen = *pcbAttrLen;
|
|
}
|
|
|
|
switch (dwAttrId)
|
|
{
|
|
case SCARD_ATTR_DEVICE_FRIENDLY_NAME_A:
|
|
{
|
|
CBuffer bfSysName, bfNames;
|
|
CTextMultistring mtzNames;
|
|
pRdr->GetAttrib(SCARD_ATTR_DEVICE_SYSTEM_NAME, bfSysName, MAX_PATH);
|
|
ListReaderNames(
|
|
pRdr->Context()->Scope(),
|
|
bfSysName,
|
|
bfNames);
|
|
mtzNames = (LPCTSTR)bfNames.Access();
|
|
bfAttrib.Set(
|
|
(LPCBYTE)((LPCSTR)mtzNames),
|
|
(mtzNames.Length()) * sizeof(CHAR));
|
|
break;
|
|
}
|
|
case SCARD_ATTR_DEVICE_FRIENDLY_NAME_W:
|
|
{
|
|
CBuffer bfSysName, bfNames;
|
|
CTextMultistring mtzNames;
|
|
pRdr->GetAttrib(SCARD_ATTR_DEVICE_SYSTEM_NAME, bfSysName, MAX_PATH);
|
|
ListReaderNames(
|
|
pRdr->Context()->Scope(),
|
|
bfSysName,
|
|
bfNames);
|
|
mtzNames = (LPCTSTR)bfNames.Access();
|
|
bfAttrib.Set(
|
|
(LPCBYTE)((LPCWSTR)mtzNames),
|
|
(mtzNames.Length()) * sizeof(WCHAR));
|
|
break;
|
|
}
|
|
case SCARD_ATTR_DEVICE_SYSTEM_NAME_A:
|
|
{
|
|
CBuffer bfSysName;
|
|
CTextString szSysName;
|
|
pRdr->GetAttrib(SCARD_ATTR_DEVICE_SYSTEM_NAME, bfSysName, dwLen);
|
|
szSysName = (LPCTSTR)bfSysName.Access();
|
|
bfAttrib.Set(
|
|
(LPCBYTE)((LPCSTR)szSysName),
|
|
(szSysName.Length() + 1) * sizeof(CHAR));
|
|
break;
|
|
}
|
|
case SCARD_ATTR_DEVICE_SYSTEM_NAME_W:
|
|
{
|
|
CBuffer bfSysName;
|
|
CTextString szSysName;
|
|
pRdr->GetAttrib(SCARD_ATTR_DEVICE_SYSTEM_NAME, bfSysName, dwLen);
|
|
szSysName = (LPCTSTR)bfSysName.Access();
|
|
bfAttrib.Set(
|
|
(LPCBYTE)((LPCWSTR)szSysName),
|
|
(szSysName.Length() + 1) * sizeof(WCHAR));
|
|
break;
|
|
}
|
|
default:
|
|
pRdr->GetAttrib(dwAttrId, bfAttrib, dwLen);
|
|
}
|
|
PlaceResult(pRdr->Context()->Parent(), bfAttrib, pbAttr, pcbAttrLen);
|
|
}
|
|
}
|
|
|
|
catch (DWORD dwStatus)
|
|
{
|
|
nReturn = (LONG)dwStatus;
|
|
}
|
|
|
|
catch (...)
|
|
{
|
|
nReturn = SCARD_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
SCardSetAttrib:
|
|
|
|
This routine sets the current communications attributes for the given
|
|
handle. It does not effect the state of the reader, driver, or card. Not
|
|
all attributes are settable at all times, as many of the attributes are
|
|
directly under control of the transport protocol. These attributes are
|
|
offered only as a suggestion to the reader -- the reader may ignore any
|
|
attributes it feels are inappropriate.
|
|
|
|
Arguments:
|
|
|
|
hCard - This is the reference value returned from the SCardOpenReader
|
|
service.
|
|
|
|
dwAttrId - This supplies the identifier for the attribute to get.
|
|
|
|
pbAttr - This buffer supplies the attribute corresponding to the attribute
|
|
id supplied in the dwAttrId parameter.
|
|
|
|
cbAttrLength - This supplies the length of the attribute value in pbAttr
|
|
buffer in bytes.
|
|
|
|
Return Value:
|
|
|
|
A 32-bit value indicating whether or not the service completed successfully.
|
|
SCARD_S_SUCCESS is returned on successful completion. Otherwise, the value
|
|
represents an error condition.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/23/1996
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("SCardSetAttrib")
|
|
|
|
WINSCARDAPI LONG WINAPI
|
|
SCardSetAttrib(
|
|
IN SCARDHANDLE hCard,
|
|
IN DWORD dwAttrId,
|
|
IN LPCBYTE pbAttr,
|
|
IN DWORD cbAttrLen)
|
|
{
|
|
LONG nReturn = SCARD_S_SUCCESS;
|
|
|
|
try
|
|
{
|
|
CReaderContext *pRdr = (CReaderContext *)((*g_phlReaders)[hCard]);
|
|
if (pRdr->IsBad())
|
|
{
|
|
throw (DWORD)SCARD_E_SERVICE_STOPPED;
|
|
}
|
|
if (NULL != pRdr->GetRedirCard()) {
|
|
nReturn = pfnSCardSetAttrib(pRdr->GetRedirCard(), dwAttrId, pbAttr, cbAttrLen);
|
|
}
|
|
else
|
|
pRdr->SetAttrib(dwAttrId, pbAttr, cbAttrLen);
|
|
}
|
|
|
|
catch (DWORD dwStatus)
|
|
{
|
|
nReturn = (LONG)dwStatus;
|
|
}
|
|
|
|
catch (...)
|
|
{
|
|
nReturn = SCARD_E_INVALID_PARAMETER;
|
|
}
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SCard Service Information
|
|
//
|
|
// The following services are used to manage the Calais Service itself.
|
|
// These routines are not documented to users, and are not guaranteed
|
|
// to exist in future releases.
|
|
//
|
|
|
|
/*++
|
|
|
|
SCardAccessStartedEvent:
|
|
|
|
This function obtains a local handle to the Calais Resource Manager Start
|
|
event. The handle must be released via the SCardReleaseStartedEvent
|
|
service.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
The Handle, or NULL if an error occurs.
|
|
|
|
Throws:
|
|
|
|
None
|
|
|
|
Remarks:
|
|
|
|
Programs other than the resource manager should only wait on these flags.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 7/1/1998
|
|
|
|
--*/
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("SCardAccessStartedEvent")
|
|
|
|
WINSCARDAPI HANDLE WINAPI
|
|
SCardAccessStartedEvent(
|
|
void)
|
|
{
|
|
HANDLE hRet = NULL;
|
|
|
|
//
|
|
// Create the event that is passed back to the caller...
|
|
// if it hasn't already been created
|
|
//
|
|
if (SafeCreateEvent(&g_hUnifiedStartedEvent))
|
|
{
|
|
hRet = g_hUnifiedStartedEvent;
|
|
}
|
|
else
|
|
{
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (TermSrvEnabled())
|
|
{
|
|
//
|
|
//
|
|
//
|
|
if (!SetStartedEventAfterTestingConnectedState())
|
|
{
|
|
goto ErrorReturn;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// TermSrv is disabled, so go ahead and call the
|
|
// SetStartedEventWhenSCardSubsytemIsStarted function which will make sure
|
|
// the event which is returned to the caller will be set when the LOCAL
|
|
// smart card subsystem becomes available.
|
|
//
|
|
if (!SetStartedEventWhenSCardSubsytemIsStarted(TRUE))
|
|
{
|
|
goto ErrorReturn;
|
|
}
|
|
}
|
|
|
|
Return:
|
|
return (hRet);
|
|
|
|
ErrorReturn:
|
|
hRet = NULL;
|
|
goto Return;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
SCardAccessNewReaderEvent:
|
|
|
|
This function obtains a local handle to the Calais Resource Manager's New
|
|
Reader event. The handle must be released via the
|
|
SCardReleaseNewReaderEvent service.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
The Handle, or NULL if an error occurs.
|
|
|
|
Throws:
|
|
|
|
None
|
|
|
|
Remarks:
|
|
|
|
Programs other than the resource manager should only wait on these flags.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 7/1/1998
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("SCardAccessNewReaderEvent")
|
|
|
|
WINSCARDAPI HANDLE WINAPI
|
|
SCardAccessNewReaderEvent(
|
|
void)
|
|
{
|
|
return AccessNewReaderEvent();
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
SCardReleaseStartedEvent:
|
|
|
|
This function releases a previously accessed handle to the Calais
|
|
Resource Manager Start event. The handle must be obtained via the
|
|
SCardAccessStartedEvent service.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Throws:
|
|
|
|
None
|
|
|
|
Remarks:
|
|
|
|
Programs other than the resource manager should only wait on these flags.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 7/1/1998
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("SCardReleaseStartedEvent")
|
|
|
|
WINSCARDAPI void WINAPI
|
|
SCardReleaseStartedEvent(
|
|
void)
|
|
{
|
|
if (TermSrvEnabled())
|
|
{
|
|
UnRegisterForSessionChangeNotifications();
|
|
}
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
SCardReleaseNewReaderEvent:
|
|
|
|
This function releases a previously accessed handle to the Calais
|
|
Resource Manager New Reader event. The handle must be obtained via the
|
|
SCardAccessNewReaderEvent service.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Throws:
|
|
|
|
None
|
|
|
|
Remarks:
|
|
|
|
Programs other than the resource manager should only wait on these flags.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 7/1/1998
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("SCardReleaseNewReaderEvent")
|
|
|
|
WINSCARDAPI void WINAPI
|
|
SCardReleaseNewReaderEvent(
|
|
void)
|
|
{
|
|
ReleaseNewReaderEvent();
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
SCardReleaseAllEvents:
|
|
|
|
This is a catch-all routine that releases all known special event handles.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Throws:
|
|
|
|
None
|
|
|
|
Remarks:
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 7/6/1998
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("SCardReleaseAllEvents")
|
|
|
|
WINSCARDAPI void WINAPI
|
|
SCardReleaseAllEvents(
|
|
void)
|
|
{
|
|
ReleaseAllEvents();
|
|
}
|
|
|
|
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Utility Routines
|
|
//
|
|
|
|
/*++
|
|
|
|
PlaceResult:
|
|
|
|
This set of routines places the result of an operation into the user's
|
|
output buffer, supporting SCARD_AUTO_ALLOCATE, invalid buffer sizes, etc.
|
|
|
|
Arguments:
|
|
|
|
pCtx supplies the context under which this operation is being performed.
|
|
|
|
bfResult supplies the result to be returned to the user.
|
|
|
|
pbOutput receives the result for the user, as a byte stream.
|
|
|
|
szOutput receives the result as an ANSI or UNICODE string.
|
|
|
|
pcbLength supplies the length of the user's output buffer in bytes, and
|
|
receives how much of it was used.
|
|
|
|
pcchLength supplies the length of the user's output buffer in characters,
|
|
and receives how much of it was used.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Throws:
|
|
|
|
Error conditions are thrown as DWORD status codes.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 12/7/1996
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("PlaceResult")
|
|
|
|
void
|
|
PlaceResult(
|
|
CSCardUserContext *pCtx,
|
|
CBuffer &bfResult,
|
|
LPBYTE pbOutput,
|
|
LPDWORD pcbLength)
|
|
{
|
|
LPBYTE pbForUser = NULL;
|
|
LPBYTE pbOutBuff = pbOutput;
|
|
|
|
try
|
|
{
|
|
if (NULL == pbOutput)
|
|
*pcbLength = 0;
|
|
switch (*pcbLength)
|
|
{
|
|
case 0: // They just want the length.
|
|
*pcbLength = bfResult.Length();
|
|
break;
|
|
|
|
case SCARD_AUTOALLOCATE:
|
|
if (0 < bfResult.Length())
|
|
{
|
|
if (NULL == pCtx)
|
|
{
|
|
pbForUser = (LPBYTE)HeapAlloc(
|
|
GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
bfResult.Length());
|
|
}
|
|
else
|
|
pbForUser = (LPBYTE)pCtx->AllocateMemory(bfResult.Length());
|
|
|
|
if (NULL == pbForUser)
|
|
{
|
|
CalaisWarning(
|
|
__SUBROUTINE__,
|
|
DBGT("Client can't get return memory"));
|
|
throw (DWORD)SCARD_E_NO_MEMORY;
|
|
}
|
|
|
|
*(LPBYTE *)pbOutput = pbForUser;
|
|
pbOutBuff = pbForUser;
|
|
// Fall through intentionally
|
|
}
|
|
else
|
|
{
|
|
*pcbLength = 0;
|
|
*(LPBYTE *)pbOutput = (LPBYTE)g_wszBlank;
|
|
break; // Do terminate the case now.
|
|
}
|
|
|
|
default:
|
|
if (*pcbLength < bfResult.Length())
|
|
{
|
|
*pcbLength = bfResult.Length();
|
|
throw (DWORD)SCARD_E_INSUFFICIENT_BUFFER;
|
|
}
|
|
CopyMemory(pbOutBuff, bfResult.Access(), bfResult.Length());
|
|
*pcbLength = bfResult.Length();
|
|
break;
|
|
}
|
|
}
|
|
|
|
catch (...)
|
|
{
|
|
if (NULL != pbForUser)
|
|
{
|
|
if (NULL == pCtx)
|
|
HeapFree(GetProcessHeap(), 0, pbForUser);
|
|
else
|
|
pCtx->FreeMemory(pbForUser);
|
|
}
|
|
throw;
|
|
}
|
|
}
|
|
|
|
#include <setupapi.h>
|
|
|
|
//
|
|
// On a system that installs a smart card reader for the very first time
|
|
// the smart card subsystem must be started manually, but only this first time.
|
|
// After that, it is started automatically whenever the system boots
|
|
//
|
|
DWORD
|
|
APIENTRY
|
|
ClassInstall32(
|
|
IN DI_FUNCTION dif,
|
|
IN HDEVINFO hdi,
|
|
IN PSP_DEVINFO_DATA pdevData) OPTIONAL
|
|
{
|
|
if (dif == DIF_INSTALLDEVICE)
|
|
{
|
|
StartCalaisService();
|
|
}
|
|
return ERROR_DI_DO_DEFAULT;
|
|
}
|