Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1227 lines
25 KiB

/*++
Copyright (C) Microsoft Corporation, 2000
Module Name:
scuisupp
Abstract:
Support for smart card certificate selection UI
Author:
Klaus Schutz
--*/
#include "stdafx.h"
#include <wincrypt.h>
#include <winscard.h>
#include <winwlx.h>
#include <string.h>
#include "calaislb.h"
#include "scuisupp.h"
#include "StatMon.h" // smart card reader status monitor
#include "scevents.h"
#include <mmsystem.h>
typedef struct _READER_DATA
{
CERT_ENUM CertEnum;
LPTSTR pszReaderName;
LPTSTR pszCardName;
LPTSTR pszCSPName;
} READER_DATA, *PREADER_DATA;
typedef struct _THREAD_DATA
{
// handle to heap of this thread
HANDLE hHeap;
// the smart card context we use
SCARDCONTEXT hSCardContext;
// the window we send messages to
HWND hWindow;
// event to signal that the monitor thread can terminate
HANDLE hClose;
// thread handle for the monitor thread
HANDLE hThread;
// number of readers detected
DWORD dwNumReaders;
// messages to be sent to parent
UINT msgReaderArrival;
UINT msgReaderRemoval;
UINT msgSmartCardInsertion;
UINT msgSmartCardRemoval;
UINT msgSmartCardStatus;
UINT msgSmartCardCertAvail;
// reader state array
PSCARD_READERSTATE rgReaders;
// number of removed readers
DWORD dwRemovedReaders;
// pointer array of removed reader data
PREADER_DATA *ppRemovedReaderData;
} THREAD_DATA, *PTHREAD_DATA;
#ifndef TEST
#define SC_DEBUG(a)
#else
#define SC_DEBUG(a) _DebugPrint a
#undef PostMessage
#define PostMessage(a,b,c,d) _PostMessage(a, b, c, d)
#undef RegisterWindowMessage
#define RegisterWindowMessage(a) _RegisterWindowMessage(a)
void
__cdecl
_DebugPrint(
LPCTSTR szFormat,
...
)
{
TCHAR szBuffer[1024];
va_list ap;
va_start(ap, szFormat);
_vstprintf(szBuffer, szFormat, ap);
OutputDebugString(szBuffer);
_tprintf(szBuffer);
}
#define MAX_MESSAGES 10
static struct {
UINT dwMessage;
LPCTSTR lpMessage;
} Messages[MAX_MESSAGES];
UINT
_RegisterWindowMessage(
LPCTSTR lpString
)
{
for (DWORD dwIndex = 0; dwIndex < MAX_MESSAGES; dwIndex += 1) {
if (Messages[dwIndex].lpMessage == NULL) {
break;
}
if (_tcscmp(lpString, Messages[dwIndex].lpMessage) == 0) {
return Messages[dwIndex].dwMessage;
}
}
Messages[dwIndex].lpMessage = lpString;
Messages[dwIndex].dwMessage = dwIndex;
return dwIndex;
}
LPCTSTR
_GetWindowMessageString(
UINT dwMessage
)
{
for (DWORD dwIndex = 0; dwIndex < MAX_MESSAGES; dwIndex += 1) {
if (Messages[dwIndex].lpMessage == NULL) {
return TEXT("(NOT DEFINED)");
}
if (dwMessage == Messages[dwIndex].dwMessage) {
return Messages[dwIndex].lpMessage;
}
}
return TEXT("(INTERNAL ERROR)");
}
LRESULT
_PostMessage(
HWND hWindow,
UINT Msg,
WPARAM wParam,
LPARAM lParam
)
{
SC_DEBUG((TEXT("Received message %s\n"), _GetWindowMessageString(Msg)));
return 0;
}
#endif
static
LPCTSTR
FirstString(
IN LPCTSTR szMultiString
)
/*++
FirstString:
This routine returns a pointer to the first string in a multistring, or NULL
if there aren't any.
Arguments:
szMultiString - This supplies the address of the current position within a
Multi-string structure.
Return Value:
The address of the first null-terminated string in the structure, or NULL if
there are no strings.
Author:
Doug Barlow (dbarlow) 11/25/1996
--*/
{
LPCTSTR szFirst = NULL;
try
{
if (0 != *szMultiString)
szFirst = szMultiString;
}
catch (...) {}
return szFirst;
}
static
LPCTSTR
NextString(
IN LPCTSTR szMultiString)
/*++
NextString:
In some cases, the Smartcard API returns multiple strings, separated by Null
characters, and terminated by two null characters in a row. This routine
simplifies access to such structures. Given the current string in a
multi-string structure, it returns the next string, or NULL if no other
strings follow the current string.
Arguments:
szMultiString - This supplies the address of the current position within a
Multi-string structure.
Return Value:
The address of the next Null-terminated string in the structure, or NULL if
no more strings follow.
Author:
Doug Barlow (dbarlow) 8/12/1996
--*/
{
LPCTSTR szNext;
try
{
DWORD cchLen = lstrlen(szMultiString);
if (0 == cchLen)
szNext = NULL;
else
{
szNext = szMultiString + cchLen + 1;
if (0 == *szNext)
szNext = NULL;
}
}
catch (...)
{
szNext = NULL;
}
return szNext;
}
static
void
FreeReaderData(
PTHREAD_DATA pThreadData,
PREADER_DATA pReaderData
)
{
if (pThreadData->hSCardContext && pReaderData->pszCardName) {
SCardFreeMemory(pThreadData->hSCardContext, pReaderData->pszCardName);
pReaderData->pszCardName = NULL;
pReaderData->CertEnum.pszCardName = NULL;
}
if (pThreadData->hSCardContext && pReaderData->pszCSPName) {
SCardFreeMemory(pThreadData->hSCardContext, pReaderData->pszCSPName);
pReaderData->pszCSPName = NULL;
}
if (pReaderData->CertEnum.pCertContext) {
CertFreeCertificateContext(pReaderData->CertEnum.pCertContext);
pReaderData->CertEnum.pCertContext = NULL;
}
pReaderData->CertEnum.dwStatus = 0;
}
static
void
UpdateCertificates(
PTHREAD_DATA pThreadData,
PSCARD_READERSTATE pReaderState
)
{
PREADER_DATA pReaderData = (PREADER_DATA) pReaderState->pvUserData;
FreeReaderData(pThreadData, pReaderData);
SC_DEBUG((TEXT("Enumerating certificates on %s...\n"), pReaderState->szReader));
LPTSTR pszContainerName = NULL;
LPTSTR pszDefaultContainerName = NULL;
PBYTE pbCert = NULL;
HCRYPTKEY hKey = NULL;
HCRYPTPROV hCryptProv = NULL;
__try {
pReaderData->CertEnum.dwStatus = SCARD_F_UNKNOWN_ERROR;
// Get the name of the card
DWORD dwAutoAllocate = SCARD_AUTOALLOCATE;
LONG lReturn = SCardListCards(
pThreadData->hSCardContext,
pReaderState->rgbAtr,
NULL,
0,
(LPTSTR)&pReaderData->pszCardName,
&dwAutoAllocate
);
if (lReturn != SCARD_S_SUCCESS) {
SC_DEBUG((TEXT("Failed to get card name for card in %s\n"), pReaderState->szReader));
pReaderData->CertEnum.dwStatus = lReturn;
__leave;
}
pReaderData->CertEnum.pszCardName = pReaderData->pszCardName;
dwAutoAllocate = SCARD_AUTOALLOCATE;
lReturn = SCardGetCardTypeProviderName(
pThreadData->hSCardContext,
pReaderData->pszCardName,
SCARD_PROVIDER_CSP,
(LPTSTR)&pReaderData->pszCSPName,
&dwAutoAllocate
);
if (lReturn != SCARD_S_SUCCESS) {
SC_DEBUG((TEXT("Failed to get CSP name from %s\n"), pReaderState->szReader));
pReaderData->CertEnum.dwStatus = SCARD_E_UNKNOWN_CARD;
__leave;
}
pszContainerName = (LPTSTR) HeapAlloc(
pThreadData->hHeap,
HEAP_ZERO_MEMORY,
(_tcslen(pReaderState->szReader) + 10) * sizeof(TCHAR)
);
if (pszContainerName == NULL) {
pReaderData->CertEnum.dwStatus = SCARD_E_NO_MEMORY;
__leave;
}
_stprintf(
pszContainerName,
TEXT("\\\\.\\%s\\"),
pReaderState->szReader);
BOOL fSuccess = CryptAcquireContext(
&hCryptProv,
pszContainerName,
pReaderData->pszCSPName,
PROV_RSA_FULL,
CRYPT_SILENT
);
if (fSuccess == FALSE) {
SC_DEBUG((
TEXT("Failed to acquire context on %s (%lx)\n"),
pReaderState->szReader, GetLastError()
));
pReaderData->CertEnum.dwStatus = GetLastError();
__leave;
}
// Get the default container name, so we can use it
DWORD cbDefaultContainerName;
fSuccess = CryptGetProvParam(
hCryptProv,
PP_CONTAINER,
NULL,
&cbDefaultContainerName,
0
);
if (!fSuccess) {
SC_DEBUG((TEXT("Failed to get default container name from %s\n"), pReaderState->szReader));
pReaderData->CertEnum.dwStatus = GetLastError();
__leave;
}
pszDefaultContainerName =
(LPTSTR) HeapAlloc(pThreadData->hHeap, HEAP_ZERO_MEMORY, cbDefaultContainerName * sizeof(TCHAR));
if (NULL == pszContainerName) {
pReaderData->CertEnum.dwStatus = SCARD_E_NO_MEMORY;
__leave;
}
fSuccess = CryptGetProvParam(
hCryptProv,
PP_CONTAINER,
(PBYTE)pszDefaultContainerName,
&cbDefaultContainerName,
0
);
if (!fSuccess) {
pReaderData->CertEnum.dwStatus = GetLastError();
__leave;
}
fSuccess = CryptGetUserKey(
hCryptProv,
AT_KEYEXCHANGE,
&hKey
);
if (fSuccess == FALSE) {
SC_DEBUG((TEXT("Failed to get key from %s\n"), pReaderState->szReader));
pReaderData->CertEnum.dwStatus = GetLastError();
__leave;
}
// get length of certificate
DWORD cbCertLen = 0;
fSuccess = CryptGetKeyParam(
hKey,
KP_CERTIFICATE,
NULL,
&cbCertLen,
0
);
DWORD dwError = GetLastError();
if (fSuccess == FALSE && dwError != ERROR_MORE_DATA) {
SC_DEBUG((TEXT("Failed to get certificate from %s\n"), pReaderState->szReader));
pReaderData->CertEnum.dwStatus = GetLastError();
__leave;
}
pbCert = (LPBYTE) HeapAlloc(pThreadData->hHeap, HEAP_ZERO_MEMORY, cbCertLen);
if (pbCert == NULL)
{
pReaderData->CertEnum.dwStatus = SCARD_E_NO_MEMORY;
__leave;
}
// read the certificate off the card
fSuccess = CryptGetKeyParam(
hKey,
KP_CERTIFICATE,
pbCert,
&cbCertLen,
0
);
if (fSuccess == FALSE) {
SC_DEBUG((TEXT("Failed to get certificate from %s\n"), pReaderState->szReader));
pReaderData->CertEnum.dwStatus = GetLastError();
__leave;
}
PCERT_CONTEXT pCertContext = (PCERT_CONTEXT) CertCreateCertificateContext(
X509_ASN_ENCODING,
pbCert,
cbCertLen
);
if (pCertContext == NULL) {
__leave;
}
pReaderData->CertEnum.dwStatus = SCARD_S_SUCCESS;
pReaderData->CertEnum.pCertContext = pCertContext;
SC_DEBUG((TEXT("Found new certificate on %s\n"), pReaderState->szReader));
PostMessage(
pThreadData->hWindow,
pThreadData->msgSmartCardCertAvail,
(WPARAM) &pReaderData->CertEnum,
0
);
}
__finally {
//
// free all allocated memory
//
if (NULL != pszContainerName)
{
HeapFree(pThreadData->hHeap, 0, pszContainerName);
}
if (NULL != pszDefaultContainerName)
{
HeapFree(pThreadData->hHeap, 0, pszDefaultContainerName);
}
if (NULL != pbCert)
{
HeapFree(pThreadData->hHeap, 0, pbCert);
}
if (NULL != hKey)
{
CryptDestroyKey(hKey);
}
if (NULL != hCryptProv)
{
CryptReleaseContext(hCryptProv, 0);
}
}
}
static
void
StopMonitorReaders(
PTHREAD_DATA pThreadData
)
{
_ASSERT(pThreadData != NULL);
SetEvent(pThreadData->hClose);
if (pThreadData->hSCardContext) {
SCardCancel(pThreadData->hSCardContext);
}
}
static
void
RemoveCard(
PTHREAD_DATA pThreadData,
PREADER_DATA pReaderData
)
{
SC_DEBUG((TEXT("Smart Card removed from %s\n"), pReaderData->CertEnum.pszReaderName));
PostMessage(
pThreadData->hWindow,
pThreadData->msgSmartCardRemoval,
(WPARAM) &pReaderData->CertEnum,
0
);
}
static
BOOL
AddReader(
PTHREAD_DATA pThreadData,
LPCTSTR pszNewReader
)
{
PSCARD_READERSTATE pScardReaderState =
(PSCARD_READERSTATE) HeapReAlloc(
pThreadData->hHeap,
HEAP_ZERO_MEMORY,
pThreadData->rgReaders,
(pThreadData->dwNumReaders + 1) * (sizeof(SCARD_READERSTATE))
);
if (pScardReaderState == NULL) {
return FALSE;
}
pThreadData->rgReaders = pScardReaderState;
PREADER_DATA pReaderData =
(PREADER_DATA) HeapAlloc(
pThreadData->hHeap,
HEAP_ZERO_MEMORY,
sizeof(READER_DATA)
);
if (pReaderData == NULL) {
return FALSE;
}
pThreadData->rgReaders[pThreadData->dwNumReaders].pvUserData =
pReaderData;
LPTSTR pszReaderName =
(LPTSTR) HeapAlloc(
pThreadData->hHeap,
HEAP_ZERO_MEMORY,
(_tcslen(pszNewReader) + 1) * sizeof(TCHAR)
);
if (pszReaderName == NULL) {
return FALSE;
}
_tcscpy(pszReaderName, pszNewReader);
pReaderData->pszReaderName = pszReaderName;
pThreadData->rgReaders[pThreadData->dwNumReaders].szReader =
pszReaderName;
pThreadData->rgReaders[pThreadData->dwNumReaders].dwCurrentState =
SCARD_STATE_EMPTY;
pReaderData->CertEnum.pszReaderName = (LPTSTR) pszReaderName;
pThreadData->dwNumReaders++;
PostMessage(
pThreadData->hWindow,
pThreadData->msgReaderArrival,
(WPARAM) &pReaderData->CertEnum,
0
);
return TRUE;
}
static
BOOL
RemoveReader(
PTHREAD_DATA pThreadData,
PSCARD_READERSTATE pReaderState
)
{
PREADER_DATA pReaderData =
(PREADER_DATA) pReaderState->pvUserData;
if (pReaderState->dwCurrentState & SCARD_STATE_PRESENT) {
RemoveCard(
pThreadData,
pReaderData
);
}
SC_DEBUG((TEXT("Reader %s removed\n"), pReaderData->CertEnum.pszReaderName));
PostMessage(
pThreadData->hWindow,
pThreadData->msgReaderRemoval,
(WPARAM) &pReaderData->CertEnum,
0
);
// build an array of reader data that needs to be deleted on exit
PREADER_DATA *ppRemovedReaderData = NULL;
if (pThreadData->dwRemovedReaders == 0) {
ppRemovedReaderData = (PREADER_DATA *) HeapAlloc(
pThreadData->hHeap,
HEAP_ZERO_MEMORY,
sizeof(PREADER_DATA)
);
} else {
ppRemovedReaderData = (PREADER_DATA *) HeapReAlloc(
pThreadData->hHeap,
HEAP_ZERO_MEMORY,
pThreadData->ppRemovedReaderData,
(pThreadData->dwRemovedReaders + 1) * sizeof(PREADER_DATA)
);
}
if (ppRemovedReaderData == NULL) {
return FALSE;
}
// add the reader data to the list of stuff that needs to be freed on exit
pThreadData->ppRemovedReaderData = ppRemovedReaderData;
pThreadData->ppRemovedReaderData[pThreadData->dwRemovedReaders] = pReaderData;
for (DWORD dwIndex = 1; dwIndex < pThreadData->dwNumReaders; dwIndex += 1) {
if (pReaderState == &pThreadData->rgReaders[dwIndex]) {
// check if the reader we remove is not the last or the only one.
if (pThreadData->dwNumReaders > 1 && dwIndex != pThreadData->dwNumReaders - 1) {
// put the reader from the end of the list into this available slot
pThreadData->rgReaders[dwIndex] =
pThreadData->rgReaders[pThreadData->dwNumReaders - 1];
}
// shrink the reader state array
PSCARD_READERSTATE pReaders = (PSCARD_READERSTATE) HeapReAlloc(
pThreadData->hHeap,
0,
pThreadData->rgReaders,
(pThreadData->dwNumReaders - 1) * sizeof(SCARD_READERSTATE)
);
if (pReaders == NULL) {
return FALSE;
}
pThreadData->rgReaders = pReaders;
break;
}
}
pThreadData->dwNumReaders -= 1;
pThreadData->dwRemovedReaders += 1;
return TRUE;
}
static
BOOL
RemoveAllReaders(
PTHREAD_DATA pThreadData
)
{
if (pThreadData->rgReaders == NULL) {
return TRUE;
}
// This loop will destroy all the readers starting with the first one
// dwIndex doesn't have to be incremented. pThreadData->dwNumReaders is
// decremented in RemoveReader
for (DWORD dwIndex = 1; dwIndex < pThreadData->dwNumReaders; ) {
if (RemoveReader(
pThreadData,
&pThreadData->rgReaders[dwIndex]
) == FALSE) {
return FALSE;
}
}
// Remove the PnP pseudo reader
HeapFree(
pThreadData->hHeap,
0,
pThreadData->rgReaders
);
pThreadData->rgReaders = NULL;
return TRUE;
}
static
DWORD
StartMonitorReaders(
LPVOID pData
)
{
PTHREAD_DATA pThreadData = (PTHREAD_DATA) pData;
LPCTSTR szReaderNameList = NULL;
//
// We use this outer loop to restart in case the
// resource manager was stopped
//
__try {
pThreadData->rgReaders =
(PSCARD_READERSTATE) HeapAlloc(
pThreadData->hHeap,
HEAP_ZERO_MEMORY,
sizeof(SCARD_READERSTATE)
);
if (pThreadData->rgReaders == NULL) {
__leave;
}
pThreadData->rgReaders[0].szReader = SCPNP_NOTIFICATION;
pThreadData->rgReaders[0].dwCurrentState = 0;
pThreadData->dwNumReaders = 1;
while (WaitForSingleObject(pThreadData->hClose, 0) == WAIT_TIMEOUT) {
// Acquire context with resource manager
LONG lReturn = SCardEstablishContext(
SCARD_SCOPE_USER,
NULL,
NULL,
&pThreadData->hSCardContext
);
if (SCARD_S_SUCCESS != lReturn) {
// The prev. call should never fail
// It's better to terminate this thread.
__leave;
}
szReaderNameList = NULL;
DWORD dwAutoAllocate = SCARD_AUTOALLOCATE;
// now list the available readers
lReturn = SCardListReaders(
pThreadData->hSCardContext,
SCARD_DEFAULT_READERS,
(LPTSTR)&szReaderNameList,
&dwAutoAllocate
);
if (SCARD_S_SUCCESS == lReturn)
{
// bugbug - this pointer should not be modified
for (LPCTSTR szReader = FirstString( szReaderNameList );
szReader != NULL;
szReader = NextString(szReader)) {
BOOL fFound = FALSE;
// now check if this reader is already in the reader array
for (DWORD dwIndex = 1; dwIndex < pThreadData->dwNumReaders; dwIndex++) {
if (lstrcmp(
szReader,
pThreadData->rgReaders[dwIndex].szReader
) == 0) {
fFound = TRUE;
break;
}
}
if (fFound == FALSE) {
if (AddReader(pThreadData, szReader) == FALSE) {
__leave;
}
}
}
}
BOOL fNewReader = FALSE;
// analyze newly inserted cards
while (WaitForSingleObject(pThreadData->hClose, 0) == WAIT_TIMEOUT &&
fNewReader == FALSE) {
lReturn = SCardGetStatusChange(
pThreadData->hSCardContext,
INFINITE,
pThreadData->rgReaders,
pThreadData->dwNumReaders
);
if (SCARD_E_SYSTEM_CANCELLED == lReturn) {
// the smart card system has been stopped
// send notification that all readers are gone
if (RemoveAllReaders(pThreadData) == FALSE) {
__leave;
}
// Wait until it restarted
HANDLE hCalaisStarted = CalaisAccessStartedEvent();
if (hCalaisStarted == NULL) {
// no way to recover. stop cert prop
StopMonitorReaders(pThreadData);
break;
}
HANDLE lHandles[2] = { hCalaisStarted, pThreadData->hClose };
lReturn = WaitForMultipleObjectsEx(
2,
lHandles,
FALSE,
INFINITE,
FALSE
);
if (lReturn != WAIT_OBJECT_0) {
// We stop if an error occured
StopMonitorReaders(pThreadData);
break;
}
// Otherwise the resource manager has been restarted
break;
}
if (SCARD_S_SUCCESS != lReturn)
{
StopMonitorReaders(pThreadData);
break;
}
// Enumerate the readers and for every card change send a message
for (DWORD dwIndex = 1; dwIndex < pThreadData->dwNumReaders; dwIndex++)
{
// Check if the reader has been removed
if ((pThreadData->rgReaders[dwIndex].dwEventState & SCARD_STATE_UNAVAILABLE)) {
if (RemoveReader(
pThreadData,
&pThreadData->rgReaders[dwIndex]
) == FALSE) {
__leave;
}
// Continue the loop with the same index
dwIndex--;
continue;
}
// check if this is a card insertion
if ((pThreadData->rgReaders[dwIndex].dwCurrentState & SCARD_STATE_EMPTY) &&
(pThreadData->rgReaders[dwIndex].dwEventState & SCARD_STATE_PRESENT)) {
PREADER_DATA pReaderData =
(PREADER_DATA) pThreadData->rgReaders[dwIndex].pvUserData;
SC_DEBUG((TEXT("Smart Card inserted into %s\n"), pThreadData->rgReaders[dwIndex].szReader));
PostMessage(
pThreadData->hWindow,
pThreadData->msgSmartCardInsertion,
(WPARAM) &pReaderData->CertEnum,
0
);
// read in all certificates
UpdateCertificates(
pThreadData,
&pThreadData->rgReaders[dwIndex]
);
PostMessage(
pThreadData->hWindow,
pThreadData->msgSmartCardStatus,
(WPARAM) &pReaderData->CertEnum,
0
);
}
// check if this is a card removal
if ((pThreadData->rgReaders[dwIndex].dwCurrentState & SCARD_STATE_PRESENT) &&
(pThreadData->rgReaders[dwIndex].dwEventState & SCARD_STATE_EMPTY)) {
PREADER_DATA pReaderData = (PREADER_DATA) pThreadData->rgReaders[dwIndex].pvUserData;
RemoveCard(pThreadData, pReaderData);
// we can't update the certificates because it would delete
// some memory data that the caller could reference.
}
// Update the "current state" of this reader
pThreadData->rgReaders[dwIndex].dwCurrentState =
pThreadData->rgReaders[dwIndex].dwEventState;
}
// check if a new reader showed up
if ((pThreadData->dwNumReaders == 1 ||
pThreadData->rgReaders[0].dwCurrentState != 0) &&
pThreadData->rgReaders[0].dwEventState & SCARD_STATE_CHANGED) {
fNewReader = TRUE;
}
pThreadData->rgReaders[0].dwCurrentState =
pThreadData->rgReaders[0].dwEventState;
}
// Clean up
if (NULL != szReaderNameList)
{
SCardFreeMemory(pThreadData->hSCardContext, (PVOID) szReaderNameList);
szReaderNameList = NULL;
}
if (NULL != pThreadData->hSCardContext)
{
SCardReleaseContext(pThreadData->hSCardContext);
pThreadData->hSCardContext = NULL;
}
}
}
__finally {
if (NULL != szReaderNameList)
{
SCardFreeMemory(pThreadData->hSCardContext, (PVOID) szReaderNameList);
}
if (NULL != pThreadData->hSCardContext)
{
SCardReleaseContext(pThreadData->hSCardContext);
pThreadData->hSCardContext = NULL;
}
RemoveAllReaders(pThreadData);
SC_DEBUG((TEXT("Terminating monitor thread\n")));
}
return TRUE;
}
HSCARDUI
WINAPI
SCardUIInit(
HWND hWindow
)
{
PTHREAD_DATA pThreadData =
(PTHREAD_DATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(THREAD_DATA));
BOOL fSuccess = FALSE;
__try {
if (pThreadData == NULL) {
__leave;
}
pThreadData->hHeap = GetProcessHeap();
pThreadData->hWindow = hWindow;
pThreadData->msgReaderArrival =
RegisterWindowMessage(TEXT(SCARDUI_READER_ARRIVAL));
pThreadData->msgReaderRemoval =
RegisterWindowMessage(TEXT(SCARDUI_READER_REMOVAL));
pThreadData->msgSmartCardInsertion =
RegisterWindowMessage(TEXT(SCARDUI_SMART_CARD_INSERTION));
pThreadData->msgSmartCardRemoval =
RegisterWindowMessage(TEXT(SCARDUI_SMART_CARD_REMOVAL));
pThreadData->msgSmartCardStatus =
RegisterWindowMessage(TEXT(SCARDUI_SMART_CARD_STATUS));
pThreadData->msgSmartCardCertAvail =
RegisterWindowMessage(TEXT(SCARDUI_SMART_CARD_CERT_AVAIL));
pThreadData->hClose = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
);
if (pThreadData->hClose == NULL) {
__leave;
}
pThreadData->hThread = CreateThread(
NULL,
0,
StartMonitorReaders,
(LPVOID) pThreadData,
CREATE_SUSPENDED,
NULL
);
if (pThreadData->hThread == NULL) {
__leave;
}
ResumeThread(pThreadData->hThread);
fSuccess = TRUE;
}
__finally {
if (fSuccess == FALSE) {
if (pThreadData && pThreadData->hClose) {
CloseHandle(pThreadData->hClose);
}
if (pThreadData) {
HeapFree(pThreadData->hHeap, 0, pThreadData);
pThreadData = NULL;
}
}
}
return (HSCARDUI) pThreadData;
}
DWORD
WINAPI
SCardUIExit(
HSCARDUI hSCardUI
)
/*++
Routine Description:
Stops cert. propagation when the user logs out.
Arguments:
lpvParam - Winlogon notification info.
--*/
{
PTHREAD_DATA pThreadData = (PTHREAD_DATA) hSCardUI;
if(NULL != pThreadData->hThread)
{
DWORD dwStatus;
StopMonitorReaders(pThreadData);
dwStatus = WaitForSingleObject(
pThreadData->hThread,
INFINITE
);
_ASSERT(dwStatus == WAIT_OBJECT_0);
CloseHandle(pThreadData->hClose);
// now free all data
for (DWORD dwIndex = 0; dwIndex < pThreadData->dwRemovedReaders; dwIndex++) {
FreeReaderData(
pThreadData,
pThreadData->ppRemovedReaderData[dwIndex]
);
HeapFree(
pThreadData->hHeap,
0,
pThreadData->ppRemovedReaderData[dwIndex]->pszReaderName
);
HeapFree(
pThreadData->hHeap,
0,
pThreadData->ppRemovedReaderData[dwIndex]
);
}
HeapFree(pThreadData->hHeap, 0, pThreadData);
}
return ERROR_SUCCESS;
}
#ifdef TEST
#include <conio.h>
__cdecl
main(
int argc,
char ** argv
)
{
HSCARDUI hScardUi;
hScardUi = SCardUIInit(NULL);
while (TRUE) {
_sleep(1000);
if (_kbhit()) {
_getch();
SCardUIExit(hScardUi);
break;
}
}
hScardUi = SCardUIInit(NULL);
while (TRUE) {
_sleep(1000);
if (_kbhit()) {
SCardUIExit(hScardUi);
return 0;
}
}
}
#endif