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.
 
 
 
 
 
 

1647 lines
50 KiB

/*++
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
}