2025-04-27 07:49:33 -04:00

2659 lines
74 KiB
C++

/*++
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 <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.
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;
static HANDLE l_hLegacyEvent = 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 void WINAPI
NonPnPMain(
IN DWORD dwArgc,
IN LPTSTR *pszArgv);
static DWORD WINAPI
CalaisHandlerEx(
IN DWORD dwControl,
IN DWORD dwEventType,
IN PVOID EventData,
IN PVOID pData);
static void WINAPI
NonPnPHandler(
IN DWORD dwOpCode);
static HRESULT UnregisterServer(void);
static HRESULT RegisterServer(void);
static HRESULT AddSounds(void);
static HRESULT RemoveSounds(void);
static HRESULT AddCertProp(void);
static HRESULT RemoveCertProp(void);
static HRESULT AutoLock(DWORD dwOption);
#ifdef _DEBUG
static HRESULT RunNow(void);
#endif
/*++
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[4];
DWORD dwI = 0;
DWORD dwSts = ERROR_SUCCESS;
if (1 < nArgCount)
{
LPCTSTR szArg = rgszArgs[1];
if ((TEXT('-') == *szArg) || (TEXT('/') == *szArg))
szArg += 1;
switch (SelectString(szArg,
TEXT("INSTALL"), TEXT("REMOVE"), TEXT("UNINSTALL"),
TEXT("REINSTALL"), TEXT("SOUNDS"), TEXT("NOSOUNDS"),
TEXT("NOCERTPROP"), TEXT("AUTOLOCK"), TEXT("AUTOLOGOFF"),
TEXT("NOAUTO"),
#ifdef _DEBUG
TEXT("RUNNOW"),
#endif
NULL))
{
case 1:
dwSts = RegisterServer();
break;
case 2:
case 3:
dwSts = UnregisterServer();
break;
case 4:
dwSts = UnregisterServer();
if (ERROR_SUCCESS == dwSts)
dwSts = RegisterServer();
break;
case 5:
dwSts = AddSounds();
break;
case 6:
dwSts = RemoveSounds();
break;
case 7:
dwSts = RemoveCertProp();
break;
case 8: // Auto Lock
dwSts = AutoLock(1);
break;
case 9: // Auto Logoff
dwSts = AutoLock(2);
break;
case 10: // No auto action
dwSts = AutoLock(0);
break;
#ifdef _DEBUG
case 11:
dwSts = RunNow();
break;
#endif
default:
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 = (LPTSTR)CalaisString(CALSTR_LEGACYSERVICE);
rgsteDispatchTable[dwI].lpServiceProc = NonPnPMain;
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
/*++
NonPnPMain:
This helper function is only called if there is a legacy device
in the system that defines 'Group = Smart Card Reader'. This 'service'
is dependent on this group. It is only used to add those readers as known
readers to the smart card resources manager
Arguments:
argc supplies the number of command line arguments
argv supplies pointers to each of the arguments.
Return Value:
None
Throws:
None
Author:
Klaus Schutz July 1998
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("NonPnPMain")
static void WINAPI
NonPnPMain(
IN DWORD dwArgc,
IN LPTSTR *pszArgv)
{
NEW_THREAD;
BOOL fSts;
CalaisWarning(
__SUBROUTINE__,
DBGT("NonPnPMain: Registering Non PnP Devices"));
try
{
l_srvNonPnP.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
l_srvNonPnP.dwCurrentState = SERVICE_START_PENDING;
l_srvNonPnP.dwControlsAccepted = 0;
l_srvNonPnP.dwWin32ExitCode = NO_ERROR;
l_srvNonPnP.dwServiceSpecificExitCode = 0;
l_srvNonPnP.dwCheckPoint = 0;
l_srvNonPnP.dwWaitHint = 10000;
l_hNonPnP = RegisterServiceCtrlHandler(
CalaisString(CALSTR_LEGACYSERVICE),
NonPnPHandler);
if (NULL == l_hNonPnP)
{
CalaisWarning(
__SUBROUTINE__,
DBGT("Failed to register NonPnP service handler: %1"),
GetLastError());
goto ErrorExit;
}
fSts = SetServiceStatus(l_hNonPnP, &l_srvNonPnP);
if (!fSts)
{
CalaisWarning(
__SUBROUTINE__,
DBGT("Failed to update NonPnP service status: %1"),
GetLastError());
goto ErrorExit;
}
try
{
AddAllWdmDrivers();
}
catch (...) {}
l_srvNonPnP.dwCurrentState = SERVICE_STOPPED;
l_srvNonPnP.dwCheckPoint = 0;
l_srvNonPnP.dwWaitHint = 0;
fSts = SetServiceStatus(l_hNonPnP, &l_srvNonPnP);
if (!fSts)
{
CalaisWarning(
__SUBROUTINE__,
DBGT("Failed to finish NonPnP service status: %1"),
GetLastError());
}
}
catch (DWORD dwErr)
{
CalaisWarning(
__SUBROUTINE__,
DBGT("Legacy Main Routine unhandled error: %1"),
dwErr);
}
catch (...)
{
CalaisWarning(
__SUBROUTINE__,
DBGT("Legacy Main Routine received unexpected exception."));
}
ErrorExit:
if (NULL != l_hLegacyEvent)
SetEvent(l_hLegacyEvent);
CalaisWarning(__SUBROUTINE__, DBGT("NonPnPMain: Complete"));
}
/*++
NonPnPHandler:
This routine services the requests for the Non-PnP drivers. If this
service starts, then there's a Legacy Reader Driver on the system. This
routine kicks it off so that the resource manager can deal with it.
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:
Klaus Schutz (kschutz) 8/25/1998
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("NonPnPHandler")
static void WINAPI
NonPnPHandler(
IN DWORD dwOpCode)
{
NEW_THREAD;
try
{
DWORD nRetVal = NO_ERROR;
//
// Process the command.
//
CalaisInfo(__SUBROUTINE__, DBGT("NonPnPHandler: Entered"));
switch (dwOpCode)
{
case SERVICE_CONTROL_PAUSE:
// ?noSupport?
l_srvNonPnP.dwCurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTROL_CONTINUE:
l_srvNonPnP.dwCurrentState = SERVICE_RUNNING;
// ?noSupport?
break;
case SERVICE_CONTROL_INTERROGATE:
break;
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
l_srvNonPnP.dwCurrentState = SERVICE_STOP_PENDING;
l_srvNonPnP.dwCheckPoint = 0;
l_srvNonPnP.dwWaitHint = l_dwWaitHint;
break;
default: // No action
break;
}
l_srvNonPnP.dwWin32ExitCode = nRetVal;
if (!SetServiceStatus(l_hNonPnP, &l_srvNonPnP))
CalaisError(__SUBROUTINE__, 503, GetLastError());
}
catch (DWORD dwErr)
{
CalaisWarning(
__SUBROUTINE__,
DBGT("Legacy Handler Routine unhandled error: %1"),
dwErr);
}
catch (...)
{
CalaisWarning(
__SUBROUTINE__,
DBGT("Legacy Handler Routine received unexpected exception."));
}
CalaisInfo(__SUBROUTINE__, DBGT("NonPnPHandler: Returned"));
}
/*++
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
{
SC_HANDLE schLegacy = NULL;
SC_HANDLE schSCManager = NULL;
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"));
}
//
// 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);
//
// Check for legacy devices
//
try
{
l_hLegacyEvent = CreateEvent(0, TRUE, FALSE, NULL);
if (NULL == l_hLegacyEvent)
{
dwStatus = GetLastError();
CalaisWarning(
__SUBROUTINE__,
DBGT("Failed to create legacy driver ready event: %1"),
dwStatus);
throw dwStatus;
}
schSCManager = OpenSCManager(
NULL, // machine (NULL == local)
NULL, // database (NULL == default)
GENERIC_READ); // access required
if (NULL == schSCManager)
{
dwStatus = GetLastError();
CalaisWarning(
__SUBROUTINE__,
DBGT("Failed to access service manager: %1"),
dwStatus);
throw dwStatus;
}
schLegacy = OpenService(
schSCManager,
CalaisString(CALSTR_LEGACYSERVICE),
SERVICE_QUERY_STATUS | SERVICE_START);
if (NULL == schLegacy)
{
dwStatus = GetLastError();
CalaisWarning(
__SUBROUTINE__,
DBGT("Failed to access legacy driver service: %1"),
dwStatus);
throw dwStatus;
}
// try to start the service
if (!StartService(schLegacy, 0, NULL))
{
dwStatus = GetLastError();
CalaisWarning(
__SUBROUTINE__,
DBGT("Failed to start the legacy driver service: %1"),
dwStatus);
throw dwStatus;
}
CloseServiceHandle(schLegacy);
schLegacy = NULL;
CloseServiceHandle(schSCManager);
schSCManager = NULL;
if (NULL != l_hLegacyEvent)
dwStatus = WaitForSingleObject(l_hLegacyEvent, 5000);
}
catch (...)
{
if (NULL != schLegacy)
CloseServiceHandle(schLegacy);
if (NULL != schSCManager)
CloseServiceHandle(schSCManager);
}
//
// Tell interested parties that we've started.
//
ResetEvent(AccessStoppedEvent());
SetEvent(AccessStartedEvent());
if (NULL != l_hLegacyEvent)
{
fSts = CloseHandle(l_hLegacyEvent);
l_hLegacyEvent = NULL;
if (!fSts)
CalaisWarning(
__SUBROUTINE__,
DBGT("Failed to Close Legacy Service Event: %1"),
GetLastError());
}
//
// 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();
}
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
}
/*++
UnregisterServer:
This service removes the registry entries associated with the Calais
Service.
Arguments:
None
Return Value:
Status code as an HRESULT.
Author:
Doug Barlow (dbarlow) 8/26/1998
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("UnregisterServer")
static HRESULT
UnregisterServer(
void)
{
HRESULT hReturnStatus = NO_ERROR;
SC_HANDLE schService = NULL;
SC_HANDLE schSCManager = NULL;
LPCTSTR rgszServices[3];
DWORD dwIndex;
LPCTSTR szSvc;
//
// Get the service names.
//
rgszServices[0] = CalaisString(CALSTR_PRIMARYSERVICE);
rgszServices[1] = CalaisString(CALSTR_LEGACYSERVICE);
rgszServices[2] = CalaisString(CALSTR_DEBUGSERVICE);
//
// Eliminate the services.
//
try
{
BOOL fSts;
SERVICE_STATUS ssStatus; // current status of the service
schSCManager = OpenSCManager(
NULL, // machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_ALL_ACCESS); // access required
if (NULL == schSCManager)
throw GetLastError();
for (dwIndex = sizeof(rgszServices) / sizeof(LPCTSTR); 0 < dwIndex;)
{
szSvc = rgszServices[--dwIndex];
schService = OpenService(
schSCManager,
szSvc,
SERVICE_ALL_ACCESS);
if (NULL == schService)
continue;
do
{
fSts = QueryServiceStatus(schService, &ssStatus);
if (fSts)
{
switch (ssStatus.dwCurrentState)
{
case SERVICE_START_PENDING:
case SERVICE_STOP_PENDING:
case SERVICE_CONTINUE_PENDING:
case SERVICE_PAUSE_PENDING:
Sleep(1000);
break;
case SERVICE_RUNNING:
case SERVICE_PAUSED:
fSts = ControlService(
schService,
SERVICE_CONTROL_STOP,
&ssStatus);
break;
case SERVICE_STOPPED:
fSts = DeleteService(schService);
if (!fSts)
throw GetLastError();
fSts = FALSE;
break;
default:
fSts = FALSE;
}
}
} while (fSts);
CloseServiceHandle(schService);
schService = NULL;
}
CloseServiceHandle(schSCManager);
schSCManager = NULL;
}
catch (DWORD dwErr)
{
if (NULL != schService)
CloseServiceHandle(schService);
if (NULL != schSCManager)
CloseServiceHandle(schSCManager);
hReturnStatus = HRESULT_FROM_WIN32(dwErr);
}
if (NO_ERROR != hReturnStatus)
goto ErrorExit;
//
// Disable automatic certificate propagation.
//
hReturnStatus = RemoveCertProp();
//
// Delete any left over service registry entries.
//
try
{
CRegistry regServices(
HKEY_LOCAL_MACHINE,
CalaisString(CALSTR_SERVICESREGISTRYKEY));
if (ERROR_SUCCESS == regServices.Status(TRUE))
{
for (dwIndex = sizeof(rgszServices) / sizeof(LPCTSTR); 0 < dwIndex;)
{
szSvc = rgszServices[--dwIndex];
regServices.DeleteKey(szSvc, TRUE);
}
}
}
catch (DWORD) {}
//
// Delete any event log registry entries.
//
try
{
LPCTSTR szCategory;
DWORD dwSubkey = 0;
CRegistry regEventLog(
HKEY_LOCAL_MACHINE,
CalaisString(CALSTR_EVENTLOGREGISTRYKEY));
CRegistry regCategory;
if (ERROR_SUCCESS == regEventLog.Status(TRUE))
{
for (;;)
{
szCategory = regEventLog.Subkey(dwSubkey);
if (NULL == szCategory)
break;
regCategory.Open(regEventLog, szCategory);
if (ERROR_SUCCESS == regCategory.Status(TRUE))
{
for (dwIndex = sizeof(rgszServices) / sizeof(LPCTSTR);
0 < dwIndex;)
{
szSvc = rgszServices[--dwIndex];
regCategory.DeleteKey(szSvc, TRUE);
}
}
dwSubkey += 1;
}
}
}
catch (DWORD) {}
//
// Delete any superfluous registry entries.
//
try
{
CRegistry regCalais(
HKEY_LOCAL_MACHINE,
CalaisString(CALSTR_CALAISREGISTRYKEY));
regCalais.DeleteKey(CalaisString(CALSTR_READERREGISTRYSUBKEY), TRUE);
regCalais.DeleteKey(CalaisString(CALSTR_DEBUGREGISTRYSUBKEY), TRUE);
}
catch (DWORD) {}
//
// All done!
//
ErrorExit:
return hReturnStatus;
}
/*++
RegisterServer:
This function installs the proper registry entries to enable the Calais
service.
Arguments:
None
Return Value:
Status code as an HRESULT.
Author:
Doug Barlow (dbarlow) 8/26/1998
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("RegisterServer")
static HRESULT
RegisterServer(
void)
{
HRESULT hReturnStatus = NO_ERROR;
SC_HANDLE schService = NULL;
SC_HANDLE schSCManager = NULL;
DWORD dwStatus;
BOOL fSts;
TCHAR szServiceFile[MAX_PATH];
SERVICE_DESCRIPTION ServDesc = { NULL };
//
// Find the Service Executable.
//
dwStatus = GetModuleFileName(
NULL,
szServiceFile,
sizeof(szServiceFile) / sizeof(TCHAR));
if (0 == dwStatus)
{
dwStatus = ExpandEnvironmentStrings(
CalaisString(CALSTR_CALAISEXECUTABLE),
szServiceFile,
sizeof(szServiceFile));
if (0 == dwStatus)
{
hReturnStatus = HRESULT_FROM_WIN32(GetLastError());
goto ErrorExit;
}
}
//
// Establish the Event Log Entries.
//
try
{
CRegistry regEventLog(
HKEY_LOCAL_MACHINE,
CalaisString(CALSTR_EVENTLOGREGISTRYKEY));
CRegistry regCategory(
regEventLog,
CalaisString(CALSTR_SYSTEMREGISTRYSUBKEY));
CRegistry regService(
regCategory,
CalaisString(CALSTR_PRIMARYSERVICE),
KEY_ALL_ACCESS,
REG_OPTION_NON_VOLATILE);
regService.SetValue(
CalaisString(CALSTR_EVENTMESSAGEFILESUBKEY),
szServiceFile,
REG_SZ);
regService.SetValue(
CalaisString(CALSTR_TYPESSUPPORTEDSUBKEY),
(DWORD)(EVENTLOG_ERROR_TYPE
| EVENTLOG_WARNING_TYPE
| EVENTLOG_INFORMATION_TYPE));
}
catch (DWORD dwErr)
{
hReturnStatus = HRESULT_FROM_WIN32(dwErr);
}
if (NO_ERROR != hReturnStatus)
goto ErrorExit;
//
// Introduce the services.
//
try
{
schSCManager = OpenSCManager(
NULL, // machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_ALL_ACCESS); // access required
if (NULL == schSCManager)
throw GetLastError();
schService = CreateService(
schSCManager,
CalaisString(CALSTR_PRIMARYSERVICE),
CalaisString(CALSTR_PRIMARYSERVICEDISPLAY),
SERVICE_ALL_ACCESS,
#ifdef DBG
SERVICE_INTERACTIVE_PROCESS |
#endif
SERVICE_WIN32_SHARE_PROCESS,
SERVICE_DEMAND_START,
SERVICE_ERROR_IGNORE,
szServiceFile,
NULL, // Service Group
NULL, // Tag Id
CalaisString(CALSTR_SERVICEDEPENDENCIES),
NULL, // User Account
NULL); // Password
if (NULL == schService)
throw GetLastError();
ServDesc.lpDescription = (LPTSTR)CalaisString(CALSTR_PRIMARYSERVICEDESC);
fSts = ChangeServiceConfig2(
schService,
SERVICE_CONFIG_DESCRIPTION,
&ServDesc);
if (!fSts)
throw GetLastError();
CSecurityDescriptor aclService;
aclService.InitializeFromProcessToken();
aclService.Allow(
&aclService.SID_System,
l_dwSystemAccess);
aclService.Allow(
&aclService.SID_LocalService,
SERVICE_ALL_ACCESS);
aclService.Allow(
&aclService.SID_Admins,
SERVICE_ALL_ACCESS);
aclService.Allow(
&aclService.SID_SrvOps,
SERVICE_ALL_ACCESS);
aclService.Allow(
&aclService.SID_Local,
l_dwInteractiveAccess);
fSts = SetServiceObjectSecurity(
schService,
DACL_SECURITY_INFORMATION,
aclService);
if (!fSts)
throw GetLastError();
CloseServiceHandle(schService);
schService = NULL;
#ifdef DEBUG_SERVICE
schService = CreateService(
schSCManager,
CalaisString(CALSTR_DEBUGSERVICE),
CalaisString(CALSTR_DEBUGSERVICEDISPLAY),
SERVICE_ALL_ACCESS,
SERVICE_INTERACTIVE_PROCESS |
SERVICE_WIN32_SHARE_PROCESS,
SERVICE_DEMAND_START,
SERVICE_ERROR_IGNORE,
szServiceFile,
NULL, // load order group
NULL, // Tag Id
NULL, // Dependencies
NULL, // User Account
NULL); // Password
if (NULL == schService)
throw GetLastError();
ServDesc.lpDescription = (LPTSTR)CalaisString(CALSTR_DEBUGSERVICEDESC);
fSts = ChangeServiceConfig2(
schService,
SERVICE_CONFIG_DESCRIPTION,
&ServDesc);
if (!fSts)
throw GetLastError();
CloseServiceHandle(schService);
schService = NULL;
#endif
schService = CreateService(
schSCManager,
CalaisString(CALSTR_LEGACYSERVICE),
CalaisString(CALSTR_LEGACYSERVICEDISPLAY),
SERVICE_ALL_ACCESS,
#ifdef DBG
SERVICE_INTERACTIVE_PROCESS |
#endif
SERVICE_WIN32_SHARE_PROCESS,
SERVICE_DEMAND_START,
SERVICE_ERROR_IGNORE,
szServiceFile,
NULL, // load order group
NULL, // Tag Id
CalaisString(CALSTR_LEGACYDEPENDONGROUP),
NULL, // User Account
NULL); // Password
if (NULL == schService)
throw GetLastError();
ServDesc.lpDescription = (LPTSTR)CalaisString(CALSTR_LEGACYSERVICEDESC);
fSts = ChangeServiceConfig2(
schService,
SERVICE_CONFIG_DESCRIPTION,
&ServDesc);
if (!fSts)
throw GetLastError();
fSts = SetServiceObjectSecurity(
schService,
DACL_SECURITY_INFORMATION,
aclService);
if (!fSts)
throw GetLastError();
CloseServiceHandle(schService);
schService = NULL;
//
// Enable automatic certificate propagation.
//
hReturnStatus = AddCertProp();
if (NO_ERROR != hReturnStatus)
goto ErrorExit;
CloseServiceHandle(schSCManager);
schSCManager = NULL;
}
catch (DWORD dwErr)
{
if (NULL != schService)
CloseServiceHandle(schService);
if (NULL != schSCManager)
CloseServiceHandle(schSCManager);
hReturnStatus = HRESULT_FROM_WIN32(dwErr);
}
if (NO_ERROR != hReturnStatus)
goto ErrorExit;
//
// All done!
//
return hReturnStatus;
//
// An error was detected. Clean up any outstanding resources and
// return the error.
//
ErrorExit:
UnregisterServer();
return hReturnStatus;
}
/*++
AddSounds:
Enable the sound features of the certificate propper for this user.
Arguments:
None
Return Value:
Status code as an HRESULT.
Author:
Doug Barlow (dbarlow) 1/27/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ DBGT("AddSounds")
static HRESULT
AddSounds(
void)
{
HRESULT hReturnStatus = HRESULT_FROM_WIN32(SCARD_F_UNKNOWN_ERROR);
LPCTSTR szNames[2] =
{ CalaisString(CALSTR_SMARTCARDINSERTION),
CalaisString(CALSTR_SMARTCARDREMOVAL) };
LPCTSTR szDisplay[2] =
{ CalaisString(CALSTR_SMARTCARD_INSERTION),
CalaisString(CALSTR_SMARTCARD_REMOVAL) };
DWORD dwIndex;
try
{
CRegistry regScValue;
CRegistry regDefault;
CRegistry regAppEvents(HKEY_CURRENT_USER, CalaisString(CALSTR_APPEVENTS));
CRegistry regEventLabels(regAppEvents, CalaisString(CALSTR_EVENTLABELS));
CRegistry regDefScheme(regAppEvents, CalaisString(CALSTR_SOUNDSREGISTRY));
for (dwIndex = 0; dwIndex < 2; dwIndex += 1)
{
regScValue.Open(
regEventLabels,
szNames[dwIndex],
KEY_ALL_ACCESS,
REG_OPTION_NON_VOLATILE);
if (!regScValue.ValueExists(NULL))
regScValue.SetValue(NULL, szDisplay[dwIndex]);
regScValue.Close();
regScValue.Open(
regDefScheme,
szNames[dwIndex],
KEY_ALL_ACCESS,
REG_OPTION_NON_VOLATILE);
regDefault.Open(
regScValue,
TEXT(".Current"),
KEY_ALL_ACCESS,
REG_OPTION_NON_VOLATILE);
if (!regDefault.ValueExists(NULL))
regDefault.SetValue(NULL, TEXT(""));
regDefault.Close();
regDefault.Open(
regScValue,
TEXT(".Default"),
KEY_ALL_ACCESS,
REG_OPTION_NON_VOLATILE);
if (ERROR_SUCCESS != regDefault.ValueExists(NULL))
regDefault.SetValue(NULL, TEXT(""));
regDefault.Close();
}
}
catch (DWORD dwErr)
{
hReturnStatus = HRESULT_FROM_WIN32(dwErr);
goto ErrorExit;
}
//
// All done!
//
return NO_ERROR;
//
// An error was detected. Clean up any outstanding resources and
// return the error.
//
ErrorExit:
RemoveSounds();
return hReturnStatus;
}
/*++
RemoveSounds:
This function removes sound entries for the current user.
Arguments:
None
Return Value:
Status code as an HRESULT.
Author:
Doug Barlow (dbarlow) 1/28/1999
--*/
static HRESULT
RemoveSounds(
void)
{
HRESULT hReturnStatus = HRESULT_FROM_WIN32(SCARD_F_UNKNOWN_ERROR);
LPCTSTR szNames[2] =
{ CalaisString(CALSTR_SMARTCARDINSERTION),
CalaisString(CALSTR_SMARTCARDREMOVAL) };
DWORD dwIndex;
try
{
CRegistry regAppEvents(HKEY_CURRENT_USER, CalaisString(CALSTR_APPEVENTS));
CRegistry regEventLabels(regAppEvents, CalaisString(CALSTR_EVENTLABELS));
CRegistry regDefScheme(regAppEvents, CalaisString(CALSTR_SOUNDSREGISTRY));
for (dwIndex = 0; dwIndex < 2; dwIndex += 1)
{
regEventLabels.DeleteKey(szNames[dwIndex], TRUE);
regDefScheme.DeleteKey(szNames[dwIndex], TRUE);
}
}
catch (DWORD dwErr)
{
hReturnStatus = HRESULT_FROM_WIN32(dwErr);
goto ErrorExit;
}
//
// All done!
//
return NO_ERROR;
//
// An error was detected. Clean up any outstanding resources and
// return the error.
//
ErrorExit:
return hReturnStatus;
}
/*++
AddCertProp:
Add the registry entry to enable automatic certificate propagation.
Arguments:
None
Return Value:
Status code as an HRESULT.
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 2/2/1999
--*/
static HRESULT
AddCertProp(
void)
{
HRESULT hReturnStatus = HRESULT_FROM_WIN32(SCARD_F_UNKNOWN_ERROR);
//
// Fill in the new registry key values.
//
try
{
CRegistry regNotify(
HKEY_LOCAL_MACHINE,
CalaisString(CALSTR_CERTPROPREGISTRY));
CRegistry regCertProp(
regNotify,
CalaisString(CALSTR_CERTPROPKEY),
KEY_ALL_ACCESS,
REG_OPTION_NON_VOLATILE);
regCertProp.SetValue(CalaisString(CALSTR_DLLNAME), CalaisString(CALSTR_CERTPROPDLL));
regCertProp.SetValue(CalaisString(CALSTR_LOGON), CalaisString(CALSTR_CERTPROPSTART));
regCertProp.SetValue(CalaisString(CALSTR_LOGOFF), CalaisString(CALSTR_CERTPROPSTOP));
regCertProp.SetValue(CalaisString(CALSTR_LOCK), CalaisString(CALSTR_CERTPROPSUSPEND));
regCertProp.SetValue(CalaisString(CALSTR_UNLOCK), CalaisString(CALSTR_CERTPROPRESUME));
regCertProp.SetValue(CalaisString(CALSTR_ENABLED), 1);
regCertProp.SetValue(CalaisString(CALSTR_IMPERSONATE), 1);
regCertProp.SetValue(CalaisString(CALSTR_ASYNCHRONOUS), 1);
}
catch (DWORD dwErr)
{
hReturnStatus = HRESULT_FROM_WIN32(dwErr);
RemoveCertProp();
goto ErrorExit;
}
//
// All done!
//
return NO_ERROR;
//
// An error was detected. Clean up any outstanding resources and
// return the error.
//
ErrorExit:
return hReturnStatus;
}
/*++
RemoveCertProp:
Remove the registry entry to disable automatic certificate propagation.
Arguments:
None
Return Value:
Status code as an HRESULT.
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 2/2/1999
--*/
static HRESULT
RemoveCertProp(
void)
{
HRESULT hReturnStatus = HRESULT_FROM_WIN32(SCARD_F_UNKNOWN_ERROR);
//
// Only one registry entry to delete.
//
try
{
CRegistry regNotify(
HKEY_LOCAL_MACHINE,
CalaisString(CALSTR_CERTPROPREGISTRY));
regNotify.DeleteKey(CalaisString(CALSTR_CERTPROPKEY), TRUE);
}
catch (DWORD dwErr)
{
hReturnStatus = HRESULT_FROM_WIN32(dwErr);
goto ErrorExit;
}
//
// All done!
//
return NO_ERROR;
//
// An error was detected. Clean up any outstanding resources and
// return the error.
//
ErrorExit:
return hReturnStatus;
}
/*++
AutoLock:
Adjust the registry entry to control logon card removal actions.
Arguments:
dwOption supplies the action to take on card removal. Currently defined
values are:
0 - No action
1 - Lock the workstation
2 - Logoff the workstation
Return Value:
Status code as an HRESULT.
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 4/22/1999
--*/
static HRESULT
AutoLock(
DWORD dwOption)
{
HRESULT hReturnStatus = HRESULT_FROM_WIN32(SCARD_F_UNKNOWN_ERROR);
try
{
TCHAR szNum[36]; // Space for a number
_ultot(dwOption, szNum, 10);
CRegistry regAuto(
HKEY_LOCAL_MACHINE,
CalaisString(CALSTR_LOGONREGISTRY));
regAuto.SetValue(CalaisString(CALSTR_LOGONREMOVEOPTION), szNum);
hReturnStatus = ERROR_SUCCESS;
}
catch (DWORD dwErr)
{
hReturnStatus = HRESULT_FROM_WIN32(dwErr);
}
return hReturnStatus;
}