|
|
/*++
Copyright (C) Microsoft Corporation, 1996 - 1999
Module Name:
SCardSvr
Abstract:
This module provides the startup logic to make the Calais Resource Manager act as a server application under Windows NT.
Author:
Doug Barlow (dbarlow) 1/16/1997
Environment:
Win32
Notes:
This file detects which operating system it's running on, and acts accordingly.
--*/
#if defined(_DEBUG)
#define DEBUG_SERVICE
#endif
#define __SUBROUTINE__
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <nt.h>
#include <ntdef.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
#include <aclapi.h>
#include <dbt.h>
#include <CalServe.h>
#include "resource.h" // Pick up resource string Ids.
// Keep one global copy of the structure which contains common initialized
// sids. This way we can control the creation and cleanup of the pointer
// and allow the service worker threads to safely access it.
static PSERVICE_THREAD_SECURITY_INFO g_pServiceThreadSecurityInfo = NULL;
static const DWORD l_dwWaitHint = CALAIS_THREAD_TIMEOUT; static const GUID l_guidSmartcards = { // 50DD5230-BA8A-11D1-BF5D-0000F805F530
0x50DD5230, 0xBA8A, 0x11D1, { 0xBF, 0x5D, 0x00, 0x00, 0xF8, 0x05, 0xF5, 0x30}}; static const DWORD l_dwInteractiveAccess = READ_CONTROL // | SYNCHRONIZE
| SERVICE_QUERY_CONFIG // | SERVICE_CHANGE_CONFIG
| SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_START // | SERVICE_STOP
// | SERVICE_PAUSE_CONTINUE
| SERVICE_INTERROGATE | SERVICE_USER_DEFINED_CONTROL | 0;
static const DWORD l_dwSystemAccess = READ_CONTROL | SERVICE_USER_DEFINED_CONTROL | SERVICE_START | SERVICE_STOP | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS | 0;
static CCriticalSectionObject *l_pcsStatusLock = NULL; static SERVICE_STATUS l_srvStatus, l_srvNonPnP; static SERVICE_STATUS_HANDLE l_hService = NULL, l_hNonPnP = NULL; static HANDLE l_hShutdownEvent = NULL;
#ifdef DEBUG_SERVICE
static SERVICE_STATUS l_srvDebug; static SERVICE_STATUS_HANDLE l_hDebug = NULL; static HANDLE l_hDebugDoneEvent = NULL; static void WINAPI DebugMain( IN DWORD dwArgc, IN LPTSTR *pszArgv); static void WINAPI DebugHandler( IN DWORD dwOpCode); #endif
static void WINAPI CalaisMain( IN DWORD dwArgc, IN LPTSTR *pszArgv); static DWORD WINAPI CalaisHandlerEx( IN DWORD dwControl, IN DWORD dwEventType, IN PVOID EventData, IN PVOID pData);
//
// Retrieve the global pointer to the service thread security info
// structure.
//
PSERVICE_THREAD_SECURITY_INFO GetServiceThreadSecurityInfo(void) { return g_pServiceThreadSecurityInfo; }
//
// Frees the SIDs contained in the passed struct, then frees
// the struct itself. The service must ensure that all service threads
// are shutdown and no longer referencing this structure before
// calling this routine.
//
DWORD FreeServiceThreadSecurityInfo( PSERVICE_THREAD_SECURITY_INFO *ppInfo) { PSERVICE_THREAD_SECURITY_INFO pLocal = *ppInfo;
if (pLocal->pServiceSid) { FreeSid(pLocal->pServiceSid); pLocal->pServiceSid = NULL; } if (pLocal->pSystemSid) { FreeSid(pLocal->pSystemSid); pLocal->pSystemSid = NULL; }
HeapFree(GetProcessHeap(), 0, pLocal);
*ppInfo = NULL;
return SCARD_S_SUCCESS; }
//
// Builds the SIDs contained in the structure allocated by this function.
//
DWORD InitializeServiceThreadSecurityInfo( PSERVICE_THREAD_SECURITY_INFO *ppInfo) { DWORD dwSts = SCARD_S_SUCCESS; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; PSERVICE_THREAD_SECURITY_INFO pLocal = NULL;
*ppInfo = NULL;
pLocal = (PSERVICE_THREAD_SECURITY_INFO) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SERVICE_THREAD_SECURITY_INFO));
if (NULL == pLocal) return SCARD_E_NO_MEMORY;
if (! AllocateAndInitializeSid( &NtAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pLocal->pSystemSid)) { dwSts = GetLastError(); goto Ret; }
if (! AllocateAndInitializeSid( &NtAuthority, 1, SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0, &pLocal->pServiceSid)) { dwSts = GetLastError(); goto Ret; }
*ppInfo = pLocal; pLocal = NULL;
Ret: if (pLocal) FreeServiceThreadSecurityInfo(&pLocal);
return dwSts; }
/*++
Main:
This routine is the entry point for the Resource Manager.
Arguments:
Per standard Windows applications
Return Value:
Per standard Windows applications
Throws:
None
Author:
Doug Barlow (dbarlow) 1/16/1997
--*/ #undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("main")
extern "C" int __cdecl main( int nArgCount, LPCTSTR *rgszArgs) { NEW_THREAD; SERVICE_TABLE_ENTRY rgsteDispatchTable[3]; DWORD dwI = 0; DWORD dwSts = ERROR_SUCCESS;
//
// Command line options are no longer supported.
//
if (1 < nArgCount) { dwSts = ERROR_INVALID_PARAMETER; goto ErrorExit; }
CalaisInfo( __SUBROUTINE__, DBGT("Initiating Smart Card Services Process")); try { #ifdef DEBUG_SERVICE
rgsteDispatchTable[dwI].lpServiceName = (LPTSTR)CalaisString(CALSTR_DEBUGSERVICE); rgsteDispatchTable[dwI].lpServiceProc = DebugMain; dwI += 1; #endif
rgsteDispatchTable[dwI].lpServiceName = (LPTSTR)CalaisString(CALSTR_PRIMARYSERVICE); rgsteDispatchTable[dwI].lpServiceProc = CalaisMain; dwI += 1;
rgsteDispatchTable[dwI].lpServiceName = NULL; rgsteDispatchTable[dwI].lpServiceProc = NULL;
if (!StartServiceCtrlDispatcher(rgsteDispatchTable)) { dwSts = GetLastError(); CalaisError(__SUBROUTINE__, 505, dwSts); goto ServiceExit; } } catch (DWORD dwErr) { CalaisWarning( __SUBROUTINE__, DBGT("Service Main Routine unhandled error: %1"), dwErr); } catch (...) { CalaisWarning( __SUBROUTINE__, DBGT("Service Main Routine received unexpected exception.")); dwSts = SCARD_F_UNKNOWN_ERROR; }
ServiceExit: CalaisInfo( __SUBROUTINE__, DBGT("Terminating Smart Card Services Process: %1"), dwSts); return dwSts;
ErrorExit: if (ERROR_SUCCESS != dwSts) { LPCTSTR szErr = NULL; try { szErr = ErrorString(dwSts); } catch(...) { // Not enough memory to build the error message
// Nothing else to do
}
if (NULL == szErr) _tprintf(_T("0x%08x"), dwSts); // Same form as in ErrorString
// if message can't be found
else _putts(szErr); } return dwSts; }
#ifdef _DEBUG
/*++
RunNow:
This routine kicks off the resource manager running as an application process. That makes the internals easier to debug.
Arguments:
None
Return Value:
S_OK
Throws:
None
Remarks:
For private debugging only.
Author:
Doug Barlow (dbarlow) 2/19/1999
--*/ #undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("RunNow")
static HRESULT RunNow( void) { DWORD dwStatus;
CalaisInfo( __SUBROUTINE__, DBGT("Initiating Smart Card Services Application"));
l_pcsStatusLock = new CCriticalSectionObject(CSID_SERVICE_STATUS); if (NULL == l_pcsStatusLock) { CalaisError(__SUBROUTINE__, 501); goto FinalExit; } if (l_pcsStatusLock->InitFailed()) { delete l_pcsStatusLock; l_pcsStatusLock = NULL; return SCARD_E_NO_MEMORY; } CalaisMessageInit(TEXT("Calais Application"));
try { l_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (NULL == l_hShutdownEvent) { CalaisError(__SUBROUTINE__, 504, GetLastError()); goto FinalExit; }
//
// Start the Calais Service.
//
dwStatus = CalaisStart(); if (SCARD_S_SUCCESS != dwStatus) goto ServiceExit;
//
// Tell interested parties that we've started.
//
ResetEvent(AccessStoppedEvent()); SetEvent(AccessStartedEvent());
//
// Now just hang around until we're supposed to stop.
//
dwStatus = WaitForSingleObject(l_hShutdownEvent, INFINITE); switch (dwStatus) { case WAIT_FAILED: CalaisWarning( __SUBROUTINE__, DBGT("Smart Card Resource Manager cannot wait for shutdown: %1"), GetLastError()); break; case WAIT_ABANDONED: CalaisWarning( __SUBROUTINE__, DBGT("Smart Card Resource Manager received shutdown wait abandoned")); // Fall through intentionally
case WAIT_OBJECT_0: break; case WAIT_TIMEOUT: CalaisWarning( __SUBROUTINE__, DBGT("Smart Card Resource Manager received shutdown wait time out")); break; default: CalaisWarning( __SUBROUTINE__, DBGT("Smart Card Resource Manager received invalid wait return code")); }
ResetEvent(AccessStartedEvent()); SetEvent(AccessStoppedEvent()); CalaisStop(); ServiceExit: ResetEvent(AccessStartedEvent()); SetEvent(AccessStoppedEvent()); CalaisInfo(__SUBROUTINE__, DBGT("Calais Stopping"));
FinalExit: ResetEvent(AccessStartedEvent()); SetEvent(AccessStoppedEvent()); if (NULL != l_hShutdownEvent) { if (!CloseHandle(l_hShutdownEvent)) CalaisWarning( __SUBROUTINE__, DBGT("Failed to close Calais Shutdown Event: %1"), GetLastError()); l_hShutdownEvent = NULL; } } catch (DWORD dwErr) { CalaisWarning( __SUBROUTINE__, DBGT("Calais RunNow Routine unhandled error: %1"), dwErr); } catch (...) { CalaisWarning( __SUBROUTINE__, DBGT("Calais RunNow Routine received unexpected exception.")); } CalaisMessageClose(); return S_OK; } #endif
#ifdef DEBUG_SERVICE
/*++
DebugMain:
This helper function supplies a simple debuggable process so that the resource manager can be debugged as a service.
Arguments:
dwArgc supplies the number of command line arguments
pszArgv supplies pointers to each of the arguments.
Return Value:
None
Throws:
None
Author:
Doug Barlow (dbarlow) 8/25/1998
--*/ #undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("DebugMain")
static void WINAPI DebugMain( IN DWORD dwArgc, IN LPTSTR *pszArgv) { NEW_THREAD; BOOL fSts;
CalaisInfo( __SUBROUTINE__, DBGT("Debug service Start")); try { l_hDebugDoneEvent = CreateEvent(NULL, TRUE, FALSE, NULL); ASSERT(NULL != l_hDebugDoneEvent);
l_srvDebug.dwServiceType = SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_SHARE_PROCESS; l_srvStatus.dwCurrentState = SERVICE_START_PENDING; l_srvDebug.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; l_srvDebug.dwWin32ExitCode = NO_ERROR; l_srvDebug.dwServiceSpecificExitCode = 0; l_srvDebug.dwCheckPoint = 0; l_srvDebug.dwWaitHint = 0; l_hDebug = RegisterServiceCtrlHandler( CalaisString(CALSTR_DEBUGSERVICE), DebugHandler); ASSERT(l_hDebug != NULL);
l_srvDebug.dwCurrentState = SERVICE_RUNNING; fSts = SetServiceStatus(l_hDebug, &l_srvDebug); ASSERT(fSts == TRUE);
CalaisInfo( __SUBROUTINE__, DBGT("Ready for debugging")); WaitForSingleObject(l_hDebugDoneEvent, INFINITE);
CalaisInfo( __SUBROUTINE__, DBGT("Debugger service Stopping")); l_srvDebug.dwCurrentState = SERVICE_STOPPED; fSts = SetServiceStatus(l_hDebug, &l_srvDebug); } catch (DWORD dwErr) { CalaisWarning( __SUBROUTINE__, DBGT("Debug Main Routine unhandled error: %1"), dwErr); } catch (...) { CalaisWarning( __SUBROUTINE__, DBGT("Debug Main Routine received unexpected exception.")); }
if (NULL != l_hDebugDoneEvent) { fSts = CloseHandle(l_hDebugDoneEvent); l_hDebugDoneEvent = NULL; if (!fSts) { CalaisWarning( __SUBROUTINE__, DBGT("Failed to close Debug Service Handle: %1"), GetLastError()); } } CalaisInfo(__SUBROUTINE__, DBGT("Debug service Complete")); }
/*++
DebugHandler:
This routine services Debug requests.
Arguments:
dwOpCode supplies the service request.
Return Value:
None
Throws:
None
Remarks:
Standard Service processing routine. In theory, this will never get called, but just in case...
Author:
Doug Barlow (dbarlow) 8/25/1998
--*/ #undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("DebugHandler")
static void WINAPI DebugHandler( IN DWORD dwOpCode) { NEW_THREAD; DWORD nRetVal = NO_ERROR;
//
// Process the command.
//
CalaisInfo(__SUBROUTINE__, DBGT("Debug Handler Entered")); try { switch (dwOpCode) { case SERVICE_CONTROL_PAUSE: l_srvDebug.dwCurrentState = SERVICE_PAUSED; break;
case SERVICE_CONTROL_CONTINUE: l_srvDebug.dwCurrentState = SERVICE_RUNNING; break;
case SERVICE_CONTROL_INTERROGATE: break;
case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: l_srvDebug.dwCurrentState = SERVICE_STOP_PENDING; l_srvDebug.dwCheckPoint = 0; l_srvDebug.dwWaitHint = 0; SetEvent(l_hDebugDoneEvent); break;
default: // No action
break; }
l_srvDebug.dwWin32ExitCode = nRetVal; if (!SetServiceStatus(l_hDebug, &l_srvDebug)) CalaisWarning( __SUBROUTINE__, DBGT("Failed to register Debug service status: %1"), GetLastError()); } catch (DWORD dwErr) { CalaisWarning( __SUBROUTINE__, DBGT("Debug Handler Routine unhandled error: %1"), dwErr); } catch (...) { CalaisWarning( __SUBROUTINE__, DBGT("Debug Handler Routine received unexpected exception.")); } CalaisInfo(__SUBROUTINE__, DBGT("Debug Handler Returned")); } #endif
//
// Permanently removes unneeded privileges from the service.
//
DWORD DisableUnnecessaryPrivileges(void) { DWORD dwSts = ERROR_SUCCESS; HANDLE hToken = NULL; PTOKEN_PRIVILEGES pTokenPrivileges = NULL; DWORD cbTokenPrivileges = 0; LUID_AND_ATTRIBUTES rgAttributes [] = { { RtlConvertUlongToLuid(SE_SECURITY_PRIVILEGE), SE_PRIVILEGE_REMOVED }, { RtlConvertUlongToLuid(SE_CREATE_TOKEN_PRIVILEGE), SE_PRIVILEGE_REMOVED }, { RtlConvertUlongToLuid(SE_TAKE_OWNERSHIP_PRIVILEGE), SE_PRIVILEGE_REMOVED }, { RtlConvertUlongToLuid(SE_CREATE_PAGEFILE_PRIVILEGE), SE_PRIVILEGE_REMOVED }, { RtlConvertUlongToLuid(SE_LOCK_MEMORY_PRIVILEGE), SE_PRIVILEGE_REMOVED }, { RtlConvertUlongToLuid(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE), SE_PRIVILEGE_REMOVED }, { RtlConvertUlongToLuid(SE_INCREASE_QUOTA_PRIVILEGE), SE_PRIVILEGE_REMOVED }, { RtlConvertUlongToLuid(SE_INC_BASE_PRIORITY_PRIVILEGE), SE_PRIVILEGE_REMOVED }, { RtlConvertUlongToLuid(SE_CREATE_PERMANENT_PRIVILEGE), SE_PRIVILEGE_REMOVED }, { RtlConvertUlongToLuid(SE_DEBUG_PRIVILEGE), SE_PRIVILEGE_REMOVED }, { RtlConvertUlongToLuid(SE_AUDIT_PRIVILEGE), SE_PRIVILEGE_REMOVED }, { RtlConvertUlongToLuid(SE_SYSTEM_ENVIRONMENT_PRIVILEGE), SE_PRIVILEGE_REMOVED }, { RtlConvertUlongToLuid(SE_BACKUP_PRIVILEGE), SE_PRIVILEGE_REMOVED }, { RtlConvertUlongToLuid(SE_RESTORE_PRIVILEGE), SE_PRIVILEGE_REMOVED }, { RtlConvertUlongToLuid(SE_SHUTDOWN_PRIVILEGE), SE_PRIVILEGE_REMOVED }, { RtlConvertUlongToLuid(SE_PROF_SINGLE_PROCESS_PRIVILEGE), SE_PRIVILEGE_REMOVED }, { RtlConvertUlongToLuid(SE_SYSTEMTIME_PRIVILEGE), SE_PRIVILEGE_REMOVED }, { RtlConvertUlongToLuid(SE_UNDOCK_PRIVILEGE), SE_PRIVILEGE_REMOVED } };
// PTOKEN_PRIVILEGES is one ULONG count followed by the privileges
// array.
cbTokenPrivileges = sizeof(rgAttributes) + sizeof(ULONG);
pTokenPrivileges = (PTOKEN_PRIVILEGES) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, cbTokenPrivileges);
if (NULL == pTokenPrivileges) return ERROR_NOT_ENOUGH_MEMORY;
pTokenPrivileges->PrivilegeCount = sizeof(rgAttributes) / sizeof(rgAttributes[0]);
// Taking the hit of copying the array after it's been set up. This method
// seems to generate a lot less code than setting up each array item
// one by one, but not sure which way is faster.
memcpy( pTokenPrivileges->Privileges, rgAttributes, sizeof(rgAttributes));
// Get our token.
if (! OpenThreadToken( GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, TRUE, &hToken)) { if (! OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) { dwSts = GetLastError(); goto Ret; } }
// Permenantly remove this set of privileges for this process.
if (! AdjustTokenPrivileges( hToken, FALSE, pTokenPrivileges, cbTokenPrivileges, NULL, NULL)) { dwSts = GetLastError(); goto Ret; }
Ret: if (hToken) CloseHandle(hToken); if (pTokenPrivileges) HeapFree(GetProcessHeap(), 0, pTokenPrivileges);
return dwSts; }
/*++
CalaisMain:
This is the ServiceMain service entry point. It is only called under the NT operating system, and makes that assumption.
Arguments:
argc supplies the number of command line arguments
argv supplies pointers to each of the arguments.
Return Value:
None
Throws:
None
Author:
Doug Barlow (dbarlow) 1/16/1997
--*/ #undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CalaisMain")
static void WINAPI CalaisMain( IN DWORD dwArgc, IN LPTSTR *pszArgv) { NEW_THREAD; CalaisMessageInit(CalaisString(CALSTR_PRIMARYSERVICE), NULL, TRUE); CalaisInfo(__SUBROUTINE__, DBGT("CalaisMain Entered"));
l_pcsStatusLock = new CCriticalSectionObject(CSID_SERVICE_STATUS); if (NULL == l_pcsStatusLock) { CalaisError(__SUBROUTINE__, 507); return; } if (l_pcsStatusLock->InitFailed()) { CalaisError(__SUBROUTINE__, 502); delete l_pcsStatusLock; l_pcsStatusLock = NULL; return; }
try { DWORD dwStatus; BOOL fSts;
l_srvStatus.dwServiceType = #ifdef DBG
SERVICE_INTERACTIVE_PROCESS | #endif
SERVICE_WIN32_SHARE_PROCESS; l_srvStatus.dwCurrentState = SERVICE_START_PENDING; l_srvStatus.dwControlsAccepted = #ifdef SERVICE_ACCEPT_POWER_EVENTS
SERVICE_ACCEPT_POWER_EVENTS | #endif
#ifdef SERVICE_ACCEPT_DEVICE_EVENTS
SERVICE_ACCEPT_DEVICE_EVENTS | #endif
SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; l_srvStatus.dwWin32ExitCode = NO_ERROR; l_srvStatus.dwServiceSpecificExitCode = 0; l_srvStatus.dwCheckPoint = 0; l_srvStatus.dwWaitHint = 0;
l_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (NULL == l_hShutdownEvent) { CalaisError(__SUBROUTINE__, 504, GetLastError()); goto FinalExit; }
//
// Initialize the service and the internal data structures.
//
l_hService = RegisterServiceCtrlHandlerEx( CalaisString(CALSTR_PRIMARYSERVICE), CalaisHandlerEx, NULL); if (NULL == l_hService) { CalaisError(__SUBROUTINE__, 506, GetLastError()); goto FinalExit; }
//
// Tell the Service Manager that we're trying to start.
//
{ LockSection(l_pcsStatusLock, DBGT("Service Start Pending")); l_srvStatus.dwCurrentState = SERVICE_START_PENDING; l_srvStatus.dwCheckPoint = 0; l_srvStatus.dwWaitHint = l_dwWaitHint;
fSts = SetServiceStatus(l_hService, &l_srvStatus); dwStatus = fSts ? ERROR_SUCCESS : GetLastError(); }
if (ERROR_SUCCESS != dwStatus) { CalaisWarning( __SUBROUTINE__, DBGT("Failed to update Service Manager status: %1"), dwStatus); }
//
// Register for future Plug 'n Play events.
//
try { AppInitializeDeviceRegistration( l_hService, DEVICE_NOTIFY_SERVICE_HANDLE); } catch (...) { CalaisWarning( __SUBROUTINE__, DBGT("Smart Card Resource Manager failed to register PnP events")); }
//
// Setup the shared security data used by the service threads.
//
dwStatus = InitializeServiceThreadSecurityInfo( &g_pServiceThreadSecurityInfo);
if (SCARD_S_SUCCESS != dwStatus) goto ServiceExit;
dwStatus = DisableUnnecessaryPrivileges();
if (ERROR_SUCCESS != dwStatus) goto ServiceExit;
//
// Start the Calais Service.
//
dwStatus = CalaisStart(); if (SCARD_S_SUCCESS != dwStatus) goto ServiceExit; else { LockSection(l_pcsStatusLock, DBGT("Declare Service Running")); l_srvStatus.dwCurrentState = SERVICE_RUNNING; l_srvStatus.dwCheckPoint = 0; l_srvStatus.dwWaitHint = 0; fSts = SetServiceStatus(l_hService, &l_srvStatus); dwStatus = fSts ? ERROR_SUCCESS : GetLastError(); } if (ERROR_SUCCESS != dwStatus) CalaisWarning( __SUBROUTINE__, DBGT("Failed to update Service Manager status: %1"), dwStatus);
//
// Tell interested parties that we've started.
//
ResetEvent(AccessStoppedEvent()); SetEvent(AccessStartedEvent()); //
// Now just hang around until we're supposed to stop.
//
dwStatus = WaitForSingleObject(l_hShutdownEvent, INFINITE); switch (dwStatus) { case WAIT_FAILED: CalaisWarning( __SUBROUTINE__, DBGT("Smart Card Resource Manager cannot wait for shutdown: %1"), GetLastError()); break; case WAIT_ABANDONED: CalaisWarning( __SUBROUTINE__, DBGT("Smart Card Resource Manager received shutdown wait abandoned")); // Fall through intentionally
case WAIT_OBJECT_0: break; case WAIT_TIMEOUT: CalaisWarning( __SUBROUTINE__, DBGT("Smart Card Resource Manager received shutdown wait time out")); break; default: CalaisWarning( __SUBROUTINE__, DBGT("Smart Card Resource Manager received invalid wait return code")); }
ResetEvent(AccessStartedEvent()); SetEvent(AccessStoppedEvent()); CalaisStop(); ServiceExit: ResetEvent(AccessStartedEvent()); SetEvent(AccessStoppedEvent()); CalaisInfo(__SUBROUTINE__, DBGT("Calais Main Stopping")); AppTerminateDeviceRegistration(); { LockSection(l_pcsStatusLock, DBGT("Declare service stopped")); l_srvStatus.dwCurrentState = SERVICE_STOPPED; l_srvStatus.dwWin32ExitCode = dwStatus; l_srvStatus.dwCheckPoint = 0; l_srvStatus.dwWaitHint = 0; fSts = SetServiceStatus(l_hService, &l_srvStatus); dwStatus = fSts ? ERROR_SUCCESS : GetLastError(); } if (ERROR_SUCCESS != dwStatus) CalaisWarning( __SUBROUTINE__, DBGT("Failed to update Service Manager status: %1"), dwStatus);
FinalExit: ResetEvent(AccessStartedEvent()); SetEvent(AccessStoppedEvent()); if (NULL != l_hShutdownEvent) { fSts = CloseHandle(l_hShutdownEvent); l_hShutdownEvent = NULL; if (!fSts) CalaisWarning( __SUBROUTINE__, DBGT("Failed to close Calais Shutdown Event: %1"), GetLastError()); } ReleaseAllEvents();
if (NULL != g_pServiceThreadSecurityInfo) FreeServiceThreadSecurityInfo( &g_pServiceThreadSecurityInfo); } catch (DWORD dwErr) { CalaisWarning( __SUBROUTINE__, DBGT("Calais Main Routine unhandled error: %1"), dwErr); } catch (...) { CalaisWarning( __SUBROUTINE__, DBGT("Calais Main Routine received unexpected exception.")); } CalaisInfo(__SUBROUTINE__, DBGT("CalaisMain Ended")); CalaisMessageClose(); if (NULL != l_pcsStatusLock) { delete l_pcsStatusLock; l_pcsStatusLock = NULL; } }
/*++
CalaisHandlerEx:
The handler service function for Calais on NT5. This version gets PnP and Power Management notifications, too.
Arguments:
dwOpCode supplies the operation to perform.
Return Value:
None
Throws:
None
Author:
Doug Barlow (dbarlow) 1/16/1997
--*/ #undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CalaisHandlerEx")
static DWORD WINAPI CalaisHandlerEx( IN DWORD dwControl, IN DWORD dwEventType, IN PVOID EventData, IN PVOID pData) { NEW_THREAD; DWORD nRetVal = NO_ERROR; LockSection(l_pcsStatusLock, DBGT("Responding to service event"));
CalaisDebug((DBGT("SCARDSVR!CalaisHandlerEx: Enter\n"))); try {
//
// Process the command.
//
switch (dwControl) { case SERVICE_CONTROL_PAUSE: // ?noSupport?
l_srvStatus.dwCurrentState = SERVICE_PAUSED; break;
case SERVICE_CONTROL_CONTINUE: l_srvStatus.dwCurrentState = SERVICE_RUNNING; // ?noSupport?
break;
case SERVICE_CONTROL_INTERROGATE: break;
case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: l_srvStatus.dwCurrentState = SERVICE_STOP_PENDING; l_srvStatus.dwCheckPoint = 0; l_srvStatus.dwWaitHint = l_dwWaitHint; if (!SetEvent(l_hShutdownEvent)) CalaisError(__SUBROUTINE__, 516, GetLastError()); break;
case SERVICE_CONTROL_DEVICEEVENT: { DWORD dwSts; CTextString tzReader; LPCTSTR szReader = NULL; DEV_BROADCAST_HDR *pDevHdr = (DEV_BROADCAST_HDR *)EventData;
CalaisInfo( __SUBROUTINE__, DBGT("Processing Device Event")); switch (dwEventType) { //
// A device has been inserted and is now available.
case DBT_DEVICEARRIVAL: { DEV_BROADCAST_DEVICEINTERFACE *pDev = (DEV_BROADCAST_DEVICEINTERFACE *)EventData;
try { CalaisInfo( __SUBROUTINE__, DBGT("Processing Device Arrival Event")); if (DBT_DEVTYP_DEVICEINTERFACE == pDev->dbcc_devicetype) { ASSERT(sizeof(DEV_BROADCAST_DEVICEINTERFACE) < pDev->dbcc_size); ASSERT(0 == memcmp( &pDev->dbcc_classguid, &l_guidSmartcards, sizeof(GUID))); ASSERT(0 != pDev->dbcc_name[0]);
if (0 == pDev->dbcc_name[1]) tzReader = (LPCWSTR)pDev->dbcc_name; else tzReader = (LPCTSTR)pDev->dbcc_name; szReader = tzReader; dwSts = CalaisAddReader(szReader, RDRFLAG_PNPMONITOR); if (ERROR_SUCCESS != dwSts) throw dwSts; CalaisWarning( __SUBROUTINE__, DBGT("New device '%1' added."), szReader); } else CalaisWarning( __SUBROUTINE__, DBGT("Spurious device arrival event.")); } catch (DWORD dwError) { CalaisError(__SUBROUTINE__, 514, dwError, szReader); } catch (...) { CalaisError(__SUBROUTINE__, 517, szReader); } break; }
//
// Permission to remove a device is requested. Any application can
// deny this request and cancel the removal.
case DBT_DEVICEQUERYREMOVE: { DEV_BROADCAST_HANDLE *pDev = (DEV_BROADCAST_HANDLE *)EventData;
try { CalaisInfo( __SUBROUTINE__, DBGT("Processing Device Query Remove Event")); if (DBT_DEVTYP_HANDLE == pDev->dbch_devicetype) { ASSERT(FIELD_OFFSET( DEV_BROADCAST_HANDLE, dbch_eventguid) <= pDev->dbch_size); ASSERT(NULL != pDev->dbch_handle); ASSERT(NULL != pDev->dbch_hdevnotify);
if (NULL != pDev->dbch_handle) { if (!CalaisQueryReader(pDev->dbch_handle)) { CalaisError( __SUBROUTINE__, 520, TEXT("DBT_DEVICEQUERYREMOVE/dbch_handle")); nRetVal = ERROR_DEVICE_IN_USE; // BROADCAST_QUERY_DENY
} else { szReader = CalaisDisableReader( (LPVOID)pDev->dbch_handle); CalaisWarning( __SUBROUTINE__, DBGT("Device '%1' removal pending."), szReader); } } else { CalaisError( __SUBROUTINE__, 523, TEXT("DBT_DEVICEQUERYREMOVE/dbch_handle")); nRetVal = ERROR_DEVICE_IN_USE; // BROADCAST_QUERY_DENY
} } else { CalaisWarning( __SUBROUTINE__, DBGT("Spurious device removal query event.")); nRetVal = TRUE; } } catch (DWORD dwError) { CalaisWarning( __SUBROUTINE__, DBGT("Error querying device busy state on reader %2: %1"), dwError, szReader); nRetVal = ERROR_DEVICE_IN_USE; // BROADCAST_QUERY_DENY
} catch (...) { CalaisWarning( __SUBROUTINE__, DBGT("Exception querying device busy state on reader %1"), szReader); CalaisError( __SUBROUTINE__, 522, TEXT("DBT_DEVICEQUERYREMOVE")); nRetVal = ERROR_DEVICE_IN_USE; // BROADCAST_QUERY_DENY
} break; }
//
// Request to remove a device has been canceled.
case DBT_DEVICEQUERYREMOVEFAILED: { CBuffer bfDevice; DEV_BROADCAST_HANDLE *pDev = (DEV_BROADCAST_HANDLE *)EventData;
try { CalaisInfo( __SUBROUTINE__, DBGT("Processing Device Query Remove Failed Event")); if (DBT_DEVTYP_HANDLE == pDev->dbch_devicetype) { ASSERT(FIELD_OFFSET( DEV_BROADCAST_HANDLE, dbch_eventguid) <= pDev->dbch_size); ASSERT(NULL != pDev->dbch_handle); ASSERT(NULL != pDev->dbch_hdevnotify);
if (NULL != pDev->dbch_handle) { szReader = CalaisConfirmClosingReader( pDev->dbch_handle); if (NULL != szReader) { bfDevice.Set( (LPBYTE)szReader, (lstrlen(szReader) + 1) * sizeof(TCHAR)); szReader = (LPCTSTR)bfDevice.Access(); CalaisWarning( __SUBROUTINE__, DBGT("Smart Card Resource Manager asked to cancel release of reader %1"), szReader); if (NULL != pDev->dbch_hdevnotify) { CalaisRemoveReader( (LPVOID)pDev->dbch_hdevnotify); if (NULL != szReader) dwSts = CalaisAddReader( szReader, RDRFLAG_PNPMONITOR); } } else CalaisWarning( __SUBROUTINE__, DBGT("Smart Card Resource Manager asked to cancel release on unreleased reader")); } else CalaisError( __SUBROUTINE__, 521, TEXT("DBT_DEVICEQUERYREMOVEFAILED/dbch_handle")); } else { CalaisWarning( __SUBROUTINE__, DBGT("Spurious device removal query failure event.")); } } catch (DWORD dwError) { CalaisWarning( __SUBROUTINE__, DBGT("Error cancelling removal on reader %2: %1"), dwError, szReader); } catch (...) { CalaisWarning( __SUBROUTINE__, DBGT("Exception cancelling removal on reader %1"), szReader); CalaisError( __SUBROUTINE__, 513, TEXT("DBT_DEVICEQUERYREMOVEFAILED")); } break; }
//
// Device is about to be removed. Cannot be denied.
case DBT_DEVICEREMOVEPENDING: { DEV_BROADCAST_HANDLE *pDev = (DEV_BROADCAST_HANDLE *)EventData;
try { CalaisInfo( __SUBROUTINE__, DBGT("Processing Device Remove Pending Event")); if (DBT_DEVTYP_HANDLE == pDev->dbch_devicetype) { ASSERT(FIELD_OFFSET( DEV_BROADCAST_HANDLE, dbch_eventguid) <= pDev->dbch_size); ASSERT(NULL != pDev->dbch_handle); ASSERT(NULL != pDev->dbch_hdevnotify);
if (NULL != pDev->dbch_handle) { szReader = CalaisDisableReader(pDev->dbch_handle); CalaisWarning( __SUBROUTINE__, DBGT("Device '%1' being removed."), szReader); } else CalaisError( __SUBROUTINE__, 512, TEXT("DBT_DEVICEREMOVEPENDING/dbch_handle")); } else { CalaisWarning( __SUBROUTINE__, DBGT("Spurious device removal pending event.")); } } catch (DWORD dwError) { CalaisWarning( __SUBROUTINE__, DBGT("Error removing reader %2: %1"), dwError, szReader); } catch (...) { CalaisWarning( __SUBROUTINE__, DBGT("Exception removing reader %1"), szReader); CalaisError( __SUBROUTINE__, 511, TEXT("DBT_DEVICEREMOVEPENDING")); } break; }
//
// Device has been removed.
case DBT_DEVICEREMOVECOMPLETE: { try { switch (pDevHdr->dbch_devicetype) { case DBT_DEVTYP_HANDLE: { DEV_BROADCAST_HANDLE *pDev = (DEV_BROADCAST_HANDLE *)EventData; try { CalaisInfo( __SUBROUTINE__, DBGT("Processing Device Remove Complete by handle Event")); ASSERT(FIELD_OFFSET( DEV_BROADCAST_HANDLE, dbch_eventguid) <= pDev->dbch_size); ASSERT(DBT_DEVTYP_HANDLE == pDev->dbch_devicetype); ASSERT(NULL != pDev->dbch_handle); ASSERT(NULL != pDev->dbch_hdevnotify);
if ((NULL != pDev->dbch_handle) && (NULL != pDev->dbch_hdevnotify)) { szReader = CalaisDisableReader( pDev->dbch_handle); CalaisRemoveReader( (LPVOID)pDev->dbch_hdevnotify); if (NULL != szReader) CalaisWarning( __SUBROUTINE__, DBGT("Device '%1' removed."), szReader); } else { if (NULL == pDev->dbch_handle) CalaisError( __SUBROUTINE__, 510, TEXT("DBT_DEVICEREMOVECOMPLETE/DBT_DEVTYP_HANDLE/dbch_handle")); if (NULL == pDev->dbch_hdevnotify) CalaisError( __SUBROUTINE__, 519, TEXT("DBT_DEVICEREMOVECOMPLETE/DBT_DEVTYP_HANDLE/dbch_hdevnotify")); } } catch (DWORD dwError) { CalaisWarning( __SUBROUTINE__, DBGT("Error completing removal of reader %2: %1"), dwError, szReader); } catch (...) { CalaisWarning( __SUBROUTINE__, DBGT("Exception completing removal of reader %1"), szReader); CalaisError( __SUBROUTINE__, 509, TEXT("DBT_DEVICEREMOVECOMPLETE/DBT_DEVTYP_HANDLE")); } break; } case DBT_DEVTYP_DEVICEINTERFACE: { DEV_BROADCAST_DEVICEINTERFACE *pDev = (DEV_BROADCAST_DEVICEINTERFACE *)EventData;
try { CalaisInfo( __SUBROUTINE__, DBGT("Processing Device Remove Complete by interface Event")); ASSERT(sizeof(DEV_BROADCAST_DEVICEINTERFACE) < pDev->dbcc_size); ASSERT(DBT_DEVTYP_DEVICEINTERFACE == pDev->dbcc_devicetype); ASSERT(0 == memcmp( &pDev->dbcc_classguid, &l_guidSmartcards, sizeof(GUID))); ASSERT(0 != pDev->dbcc_name[0]);
if (0 == pDev->dbcc_name[1]) tzReader = (LPCWSTR)pDev->dbcc_name; else tzReader = (LPCTSTR)pDev->dbcc_name; szReader = tzReader; dwSts = CalaisRemoveDevice(szReader); if (ERROR_SUCCESS == dwSts) CalaisWarning( __SUBROUTINE__, DBGT("Device '%1' Removed."), szReader); else CalaisWarning( __SUBROUTINE__, DBGT("Error removing device '%2': %1"), dwSts, szReader); } catch (DWORD dwError) { CalaisWarning( __SUBROUTINE__, DBGT("Error completing removal of reader %2: %1"), dwError, szReader); } catch (...) { CalaisWarning( __SUBROUTINE__, DBGT("Exception completing removal of reader %1"), szReader); CalaisError( __SUBROUTINE__, 508, TEXT("DBT_DEVICEREMOVECOMPLETE/DBT_DEVTYP_DEVICEINTERFACE")); } break; } default: CalaisWarning( __SUBROUTINE__, DBGT("Unrecognized PnP Device Removal Type")); break; } } catch (...) { CalaisError( __SUBROUTINE__, 518, TEXT("DBT_DEVICEREMOVECOMPLETE")); } break; }
default: CalaisWarning( __SUBROUTINE__, DBGT("Unrecognized PnP Event")); break; } break; }
case SERVICE_CONTROL_POWEREVENT: CalaisWarning( __SUBROUTINE__, DBGT("Smart Card Resource Manager received Power Event!")); break;
default: // No action
break; } } catch (DWORD dwError) { CalaisWarning( __SUBROUTINE__, DBGT("Smart Card Resource Manager received error on service action: %1"), dwError); } catch (...) { CalaisWarning( __SUBROUTINE__, DBGT("Smart Card Resource Manager recieved exception on service action")); }
l_srvStatus.dwWin32ExitCode = nRetVal; if (!SetServiceStatus(l_hService, &l_srvStatus)) CalaisError(__SUBROUTINE__, 515, GetLastError());
CalaisDebug( (DBGT("SCARDSVR!CalaisHandlerEx: Exit (%lx)\n"), nRetVal)); return nRetVal; }
/*++
CalaisTerminate:
This function is called if the C Run Time Library wants to declare a fault. If we get here, we're not coming back.
Arguments:
None
Return Value:
None (program exits on return)
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 12/2/1998
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("CalaisTerminate")
void __cdecl CalaisTerminate( void) { ResetEvent(AccessStartedEvent()); SetEvent(AccessStoppedEvent()); #ifdef DBG
TCHAR szTid[sizeof(DWORD) * 2 + 3]; _stprintf(szTid, TEXT("0x%p"), GetCurrentThreadId); CalaisError( __SUBROUTINE__, DBGT("Fatal Unhandled Exception: TID=%1"), szTid); DebugBreak(); #endif
}
|