|
|
//*************************************************************
//
// File name: TSrvVC.c
//
// Description: Contains routines to support Virtual Channel
// addins
//
// Microsoft Confidential
// Copyright (c) Microsoft Corporation 1998
// All rights reserved
//
//*************************************************************
#include <tchar.h>
#include <TSrv.h>
#include <TSrvInfo.h>
#include <TSrvVC.h>
#include <TSrvExp.h>
#include <tschannl.h>
//
// Global data
//
CRITICAL_SECTION g_TSrvVCCritSect = {0}; UINT g_AddinCount = 0; PTSRV_VC_ADDIN g_pAddin = NULL; HANDLE g_hVCAddinChangeEvent = NULL; HKEY g_hAddinRegKey = NULL; // handle to Addins reg subkey
BOOL g_bNeedToSetRegNotify = TRUE; LONG g_WsxInitialized = FALSE; BOOL g_DoubleInitialized = FALSE;
//*************************************************************
//
// TSrvInitVC()
//
// Purpose: Initializes the Virtual Channel support
//
// Parameters: None.
//
// Return: TRUE - success
// FALSE - failure
//
// Notes: Function is called by the main processing thread
// during initialization. We store the list of
// addins from the registry.
//
//*************************************************************
BOOL TSrvInitVC(VOID) { BOOL rc = FALSE;
TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Enter TSrvInitVC\n"));
if (InterlockedExchange(&g_WsxInitialized, TRUE) == TRUE) { g_DoubleInitialized = TRUE; }
//
// Set up the critical section structure for access to the VC globals
//
if (RtlInitializeCriticalSection(&g_TSrvVCCritSect) == STATUS_SUCCESS) { //
// Read the Addins registry key for the first time and store the data
// for WinStations to copy when they initialize.
//
EnterCriticalSection(&g_TSrvVCCritSect); TSrvReadVCAddins(); LeaveCriticalSection(&g_TSrvVCCritSect); rc = TRUE; } else { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSRV VC: cannot initialize g_TSrvVCCritSect\n")); }
TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Leave TSrvInitVC - %d\n", rc)); return(rc); }
//*************************************************************
//
// TSrvTermVC()
//
// Purpose: Terminates the Virtual Channel support
//
// Parameters: None.
//
// Return: None.
//
// Notes: Frees data used by VC support.
//
//*************************************************************
VOID TSrvTermVC(VOID) { TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Enter TSrvTermVC\n"));
EnterCriticalSection(&g_TSrvVCCritSect); if (g_pAddin != NULL) { TSHeapFree(g_pAddin); g_pAddin = NULL; } g_AddinCount = 0; LeaveCriticalSection(&g_TSrvVCCritSect);
TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Leave TSrvTermVC\n")); }
//*************************************************************
//
// TSrvReleaseVCAddins()
//
// Purpose: Releases session-specific addin resources
//
// Parameters: None.
//
// Return: None.
//
//*************************************************************
VOID TSrvReleaseVCAddins(PWSX_CONTEXT pWsxContext) { PTSRV_VC_ADDIN pVCAddin; UINT i;
TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Enter TSrvReleaseVCAddins\n"));
//
// We must go through all the addin entries and release each one's
// device handle (if it has one).
//
pVCAddin = (PTSRV_VC_ADDIN)(pWsxContext + 1);
for (i = 0; i < pWsxContext->cVCAddins; i++) { if (pVCAddin[i].hDevice != INVALID_HANDLE_VALUE) { NtClose(pVCAddin[i].hDevice); pVCAddin[i].hDevice = INVALID_HANDLE_VALUE; } }
TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV VC: All handles released for %u addin(s)\n", pWsxContext->cVCAddins));
TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Leave TSrvReleaseVCAddins\n")); }
//*************************************************************
//
// TSrvNotifyVC()
//
// Purpose: Notify Addins of VC events
//
// Parameters: IN pWsxContext
// IN Event - event that has occured (one of the
// TSRV_VC_ constants)
//
// Return: none
//
// Notes: Function is called to notify Virtual Channel addins
// of interesting events
//
//*************************************************************
VOID TSrvNotifyVC(PWSX_CONTEXT pWsxContext, ULONG Event) { TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV VC: Informing %u addin(s) of event %lu\n", pWsxContext->cVCAddins, Event));
//
// Call worker functions to handle different Addin types
//
TSrvNotifyVC_0(pWsxContext, Event); TSrvNotifyVC_3(pWsxContext, Event); }
//*************************************************************
//
// TSrvNotifyVC_0()
//
// Purpose: Notify K-mode system-wide addins of VC events
//
// Parameters: IN pWsxContext
// IN Event - event that has occured (one of the
// TSRV_VC_ constants)
//
// Return: none
//
// Notes: Function is called to notify Virtual Channel addins
// of interesting events
//
//*************************************************************
VOID TSrvNotifyVC_0(PWSX_CONTEXT pWsxContext, ULONG Event) { PCHANNEL_IOCTL_IN pInHdr; PCHANNEL_IOCTL_OUT pOutHdr; char InBuf[sizeof(CHANNEL_CONNECT_IN) + (CHANNEL_MAX_COUNT * sizeof(CHANNEL_DEF))]; char OutBuf[sizeof(CHANNEL_CONNECT_OUT)]; DWORD InBufSize; DWORD OutBufSize; PVOID pOutBuf; UINT Code; UINT BytesReturned; UINT i; BOOL bRc; NTSTATUS ntStatus; UNICODE_STRING FileName; PTSRV_VC_ADDIN pVCAddin; OBJECT_ATTRIBUTES FileAttributes; IO_STATUS_BLOCK IoStatusBlock;
TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Enter TSrvNotifyVC_0: event %d, session %d\n", Event, pWsxContext->LogonId));
//
// Build the InBuf based on the event
//
switch (Event) { case TSRV_VC_SESSION_CONNECT: case TSRV_VC_SESSION_SHADOW_END: { TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV VC: Connect session %d\n", pWsxContext->LogonId));
//
// Ask WD for the list of channels
//
ntStatus = IcaStackIoControl(pWsxContext->hStack, IOCTL_TSHARE_QUERY_CHANNELS, NULL, 0, InBuf, sizeof(InBuf), &InBufSize); if (!NT_SUCCESS(ntStatus)) { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSRV VC: Failed to get channels for session %d, status %#x\n", pWsxContext->LogonId, ntStatus)); //
// WD didn't answer, so return 0 channels
//
InBufSize = sizeof(CHANNEL_CONNECT_IN); ((PCHANNEL_CONNECT_IN)InBuf)->channelCount = 0; }
((PCHANNEL_CONNECT_IN)InBuf)->fAutoClientDrives = pWsxContext->fAutoClientDrives; ((PCHANNEL_CONNECT_IN)InBuf)->fAutoClientLpts = pWsxContext->fAutoClientLpts; ((PCHANNEL_CONNECT_IN)InBuf)->fForceClientLptDef = pWsxContext->fForceClientLptDef; ((PCHANNEL_CONNECT_IN)InBuf)->fDisableCpm = pWsxContext->fDisableCpm; ((PCHANNEL_CONNECT_IN)InBuf)->fDisableCdm = pWsxContext->fDisableCdm; ((PCHANNEL_CONNECT_IN)InBuf)->fDisableCcm = pWsxContext->fDisableCcm; ((PCHANNEL_CONNECT_IN)InBuf)->fDisableLPT = pWsxContext->fDisableLPT; ((PCHANNEL_CONNECT_IN)InBuf)->fDisableClip = pWsxContext->fDisableClip; ((PCHANNEL_CONNECT_IN)InBuf)->fDisableExe = pWsxContext->fDisableExe; ((PCHANNEL_CONNECT_IN)InBuf)->fDisableCam = pWsxContext->fDisableCam;
TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV VC: %d channels returned by WD\n", ((PCHANNEL_CONNECT_IN)InBuf)->channelCount)); //
// Complete the Ioctl
//
Code = IOCTL_CHANNEL_CONNECT; } break;
case TSRV_VC_SESSION_DISCONNECT: case TSRV_VC_SESSION_SHADOW_START: { TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV VC: Disconnect session %d\n", pWsxContext->LogonId));
InBufSize = sizeof(CHANNEL_DISCONNECT_IN); Code = IOCTL_CHANNEL_DISCONNECT; } break;
default: { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSRV VC: Unknown event %d\n", Event)); goto EXIT_POINT; } break; }
//
// Complete the common parts of the IoCtl
//
pInHdr = (PCHANNEL_IOCTL_IN)InBuf; pInHdr->sessionID = pWsxContext->LogonId; pInHdr->IcaHandle = pWsxContext->hIca; pVCAddin = (PTSRV_VC_ADDIN)(pWsxContext + 1);
//
// Send the IoCtl to all addin devices
//
for (i = 0; i < pWsxContext->cVCAddins; i++) { //
// Check it's a K-mode system-wide Addin
//
if (pVCAddin[i].Type != TSRV_VC_TYPE_KERNEL_SYSTEM) { TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV VC: Skipping addin %d type %d\n", i, pVCAddin[i].Type)); continue; }
//
// Open the device if it hasn't already been opened
//
if (pVCAddin[i].hDevice == INVALID_HANDLE_VALUE) { RtlInitUnicodeString(&FileName, pVCAddin[i].Name);
InitializeObjectAttributes(&FileAttributes, &FileName, 0, NULL, NULL);
ntStatus = NtCreateFile(&(pVCAddin[i].hDevice), GENERIC_READ | GENERIC_WRITE, &FileAttributes, &IoStatusBlock, 0, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN_IF, FILE_SEQUENTIAL_ONLY, NULL, 0);
TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV VC: Open addin %d: %S, status = %#x, handle %p\n", i, pVCAddin[i].Name, ntStatus, pVCAddin[i].hDevice));
if (!NT_SUCCESS(ntStatus)) { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSRV VC: Failed to open addin %d: %S, status = %#x\n", i, pVCAddin[i].Name, ntStatus)); pVCAddin[i].hDevice = INVALID_HANDLE_VALUE; } }
//
// Send the IOCtl if it's a valid device
//
if (pVCAddin[i].hDevice != INVALID_HANDLE_VALUE) { memset(OutBuf, 0, sizeof(OutBuf)); pInHdr->contextData = pVCAddin[i].AddinContext; bRc = DeviceIoControl(pVCAddin[i].hDevice, Code, InBuf, InBufSize, OutBuf, sizeof(OutBuf), &BytesReturned, NULL); TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV VC: IOCtl %x to addin %d (device %x), rc %d\n", Code, i, pVCAddin[i].hDevice, bRc)); if (bRc) { pVCAddin[i].AddinContext = ((PCHANNEL_IOCTL_OUT)OutBuf)->contextData; TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV VC: Saved return context data %p\n", pVCAddin[i].AddinContext)); }
} else { TRACE((DEBUG_TSHRSRV_WARN, "TShrSRV VC: Skip IOCtl %#x to invalid addin %d\n", Code, i)); } }
EXIT_POINT: TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Leave TSrvNotifyVC_0\n")); }
//*************************************************************
//
// TSrvNotifyVC_3()
//
// Purpose: Notify U-mode session addins of VC events
//
// Parameters: IN pWsxContext
// IN Event - event that has occured (one of the
// TSRV_VC_ constants)
//
// Return: none
//
// Notes: Function is called to notify Virtual Channel addins
// of interesting events
//
//*************************************************************
#define VCEVT_TYPE_DISCONNECT _T("Disconnect")
#define VCEVT_TYPE_RECONNECT _T("Reconnect")
VOID TSrvNotifyVC_3(PWSX_CONTEXT pWsxContext, ULONG Event) { UINT i; TCHAR EventName[MAX_PATH]; PTSRV_VC_ADDIN pVCAddin; HANDLE hEvent; BOOL fSignalEvent; BOOL fOpenInSessionSpace; LPTSTR szEvtType;
TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Enter TSrvNotifyVC_3: event %d, session %d\n", Event, pWsxContext->LogonId));
pVCAddin = (PTSRV_VC_ADDIN)(pWsxContext+1);
for (i = 0; i < pWsxContext->cVCAddins; i++) { //
// Check it's a U-mode session Addin
//
if (pVCAddin[i].Type != TSRV_VC_TYPE_USER_SESSION) { TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSrv VC: Skipping addin %d type %d\n", i, pVCAddin[i].Type)); continue; }
fSignalEvent = FALSE; if ((Event == TSRV_VC_SESSION_DISCONNECT) || ((Event == TSRV_VC_SESSION_SHADOW_START) && !pVCAddin[i].bShadowPersistent)) { fSignalEvent = TRUE; szEvtType = VCEVT_TYPE_DISCONNECT; } else if ((Event == TSRV_VC_SESSION_CONNECT) || ((Event == TSRV_VC_SESSION_SHADOW_END) && !pVCAddin[i].bShadowPersistent)) { fSignalEvent = TRUE; szEvtType = VCEVT_TYPE_RECONNECT; } //Gilles added the commented out code below....
/*
else if ((Event == TSRV_VC_SESSION_SHADOW_START) && pVCAddin[i].bShadowPersistent) { // Open the event
_stprintf(EventName, _T("Global\\%s-%d-RemoteControlStart"), pVCAddin[i].Name, pWsxContext->LogonId); hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, EventName); if (hEvent != NULL) { TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSrv VC: Opened event %S, handle %p\n", EventName, hEvent));
// Post the event
if (!SetEvent(hEvent)) { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSrv VC: Failed to post shadow start event %d\n", GetLastError())); } CloseHandle(hEvent); } else { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSrv VC: Failed to open shadow start event %S, %d\n", EventName, GetLastError())); } } else if ((Event == TSRV_VC_SESSION_SHADOW_END) && pVCAddin[i].bShadowPersistent) { // Open the event
_stprintf(EventName, _T("Global\\%s-%d-RemoteControlStop"), pVCAddin[i].Name, pWsxContext->LogonId); hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, EventName); if (hEvent != NULL) { TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSrv VC: Opened event %S, handle %p\n", EventName, hEvent));
// Post the event
if (!SetEvent(hEvent)) { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSrv VC: Failed to post shadow stop event %d\n", GetLastError())); } CloseHandle(hEvent); } else { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSrv VC: Failed to open shadow stop event %S, %d\n", EventName, GetLastError())); } } */ else { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSRV VC: Unexpected event %d\n", Event)); }
if(fSignalEvent) { // First try the new style per session event, if that fails
// revert to the old style global event
//
// New style event name format is:
// (in appropriate session namespace) AddinName-Event
// Old style is:
// (always in global namespace) AddinName-SessionId-Event
//
if(pWsxContext->LogonId) { _stprintf(EventName, _T("\\Sessions\\%d\\BaseNamedObjects\\%s-%s"), pWsxContext->LogonId, pVCAddin[i].Name, szEvtType); fOpenInSessionSpace = TRUE; } else { //in SessionID 0 events are in the global namespace
//we still need to open the new style event in global space
_stprintf(EventName, _T("Global\\%s-%s"), pVCAddin[i].Name, szEvtType); //Need to start at the global namespace
fOpenInSessionSpace = FALSE; } if(!TSrvOpenAndSetEvent(EventName, fOpenInSessionSpace)) { TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSrv VC: Failed to OpenAndSet new style event %S, %#x\n", EventName, GetLastError()));
//Try the legacy style global event
_stprintf(EventName, _T("Global\\%s-%d-%s"), pVCAddin[i].Name, pWsxContext->LogonId, szEvtType); if(!TSrvOpenAndSetEvent(EventName, FALSE)) { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSrv VC: Failed OpenAndSet legacy style evt %S, %#x\n", EventName, GetLastError())); } } } }
TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Leave TSrvNotifyVC_3\n")); }
//*************************************************************
//
// TSrvOpenAndSetEvent()
//
// Purpose: Opens and sets an event
// This function is used instead of OpenEvent()
// because it can access events in session space
// OpenEvent is hardcoded to be rooted at the
// global namespace's BaseNamedObjects directory
//
// Parameters:
// szEventName - full path to event
// bPerSessionEvent - TRUE if event is in per-session directory
//
// Return: Success status, sets error state with SetLastError
//
//*************************************************************
BOOL TSrvOpenAndSetEvent(LPCTSTR szEventName, BOOL bPerSessionEvent) { HANDLE hEvent; BOOL bSuccess = FALSE; if(szEventName) { if(bPerSessionEvent) { hEvent = OpenPerSessionEvent(EVENT_MODIFY_STATE, FALSE, szEventName); } else { hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, szEventName); } if (hEvent != NULL) { TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSrv VC: Opened event %S, handle %p\n", szEventName, hEvent));
// Post the event
if (SetEvent(hEvent)) { bSuccess = TRUE; } else { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSrv VC: Failed to post event %s - error %d\n", szEventName, GetLastError())); } CloseHandle(hEvent); } else { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSrv VC: Failed to open event %S, %d\n", szEventName, GetLastError())); } } return bSuccess; }
//*************************************************************
//
// OpenPerSessionEvent()
//
// Purpose: Opens an event in session space
// this has to override nt's OpenEvent in order
// to access events in the sessions directory
//
// Yes, we really need to do this ugliness to access
// per session events because OpenEvent opens
// named events from a basedirectory it chooses.
//
// Parameters: (see OpenEvent api)
// dwDesiredAccess - access level
// bInheritHandle
// szEventName - name of the event
//
// Return: Handle to the event
//
//*************************************************************
HANDLE OpenPerSessionEvent(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR szEventName) { OBJECT_ATTRIBUTES Obja; UNICODE_STRING ObjectName; NTSTATUS Status; HANDLE Object = NULL; PWCHAR pstrNewObjName = NULL;
if(szEventName) { RtlInitUnicodeString(&ObjectName,szEventName); InitializeObjectAttributes( &Obja, &ObjectName, (bInheritHandle ? OBJ_INHERIT : 0), NULL, //root directory
NULL);
Status = NtOpenEvent( &Object, dwDesiredAccess, &Obja );
if ( !NT_SUCCESS(Status) ) { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSRV VC: NtOpenEvent failed, status %#x\n", Status)); SetLastError(Status); } return Object; } else { return NULL; } }
//*************************************************************
//
// TSrvAllocVCContext()
//
// Purpose: Allocates the necessary amount of storage for the
// Addin list, plus the amount specified by extraBytes.
// The Addin list is copied in at an offset of extraBytes
// from the start of the buffer.
//
// Parameters: extraBytes - extra space to alloc
// OUT numAddins - number of TSRV_VC_ADDIN structures allocated
//
// Return: the result of the allocation call
//
//*************************************************************
LPVOID TSrvAllocVCContext(UINT extraBytes, OUT UINT * pNumAddins) { UINT addinsSize; LPVOID pMem;
TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Enter TSrvAllocVCContext\n"));
EnterCriticalSection(&g_TSrvVCCritSect);
//
// If we still need to set up the registry change notification, then
// we may have missed a change in the addins config. This call will also
// try again to set up the change notification.
//
if (g_bNeedToSetRegNotify) { TRACE((DEBUG_TSHRSRV_WARN, "TShrSRV VC: TSrvAllocVCContext: Need to read addins and " "set up registry change notification\n")); TSrvReadVCAddins(); }
addinsSize = g_AddinCount * sizeof(TSRV_VC_ADDIN);
TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV VC: Allocating context for %u addins @ %d each + %u extra\n", g_AddinCount, sizeof(TSRV_VC_ADDIN), extraBytes));
pMem = TSHeapAlloc(HEAP_ZERO_MEMORY, addinsSize + extraBytes, TS_HTAG_TSS_WSXCONTEXT); if (pMem) { //
// Great, the alloc succeeded. Now copy over the addins info.
//
TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV VC: Context allocated at 0x%x for %u bytes\n", pMem, addinsSize + extraBytes));
// g_pAddin will be null if there were no addins in the registry
if (g_pAddin) { memcpy(((LPBYTE)pMem) + extraBytes, g_pAddin, addinsSize); } *pNumAddins = g_AddinCount; } else { //
// The alloc failed, so indicate that zero structures were copied
//
TRACE((DEBUG_TSHRSRV_ERROR, "TShrSRV VC: Context allocation FAILED for %d bytes\n", addinsSize + extraBytes));
*pNumAddins = 0; }
LeaveCriticalSection(&g_TSrvVCCritSect);
TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Leave TSrvAllocVCContext - %p\n", pMem)); return(pMem); }
//*************************************************************
//
// TSrvReadVCAddins()
//
// Purpose: Reads the Addins subkey from the registry into memory.
// New WinStations grab a copy of this data when they start up.
// We expect to be called once at start of day, then again
// each time a change is detected in the Addins subkey.
//
// NB - Caller must hold the g_TSrvVCCritSect
//
// Parameters: none
//
// Return: ERROR_SUCCESS if successful;
// an error code from winerror.h if not.
//
//*************************************************************
LONG TSrvReadVCAddins(VOID) { ULONG rc; PTSRV_VC_ADDIN pNewAddins = NULL; DWORD newAddinCount = 0; HKEY hKeySub = NULL; DWORD Index; UINT SavedCount = 0; WCHAR SubKeyName[TSRV_VC_ADDIN_SUBKEY_LEN]; TCHAR AddinName[TSRV_VC_ADDIN_NAMELEN]; FILETIME FileTime; DWORD Type; DWORD AddinType, dwRCPersistent; BOOL bRCPersistent = FALSE; // false by default - optional value
DWORD cb; UINT i; BOOL dupFound;
TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Enter TSrvReadVCAddins\n"));
if (!g_hAddinRegKey) { TRACE((DEBUG_TSHRSRV_WARN, "TShrSRV VC: Tried to read VC addins with g_hAddinRegKey = NULL\n")); rc = ERROR_FILE_NOT_FOUND; goto EXIT_POINT; }
//
// Query the number of subkeys
//
rc = RegQueryInfoKey(g_hAddinRegKey, NULL, NULL, NULL, &newAddinCount, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (rc != ERROR_SUCCESS) { TRACE((DEBUG_TSHRSRV_WARN, "TShrSRV VC: Failed to query key info, rc %d, count %d\n", rc, newAddinCount)); goto EXIT_POINT; }
if (newAddinCount != 0) { //
// Allocate memory to hold information from all subkeys
//
TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV VC: %d addin(s), %d bytes\n", newAddinCount, newAddinCount * sizeof(*pNewAddins)));
pNewAddins = TSHeapAlloc(HEAP_ZERO_MEMORY, newAddinCount * sizeof(*pNewAddins), TS_HTAG_VC_ADDINS); if (pNewAddins == NULL) { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSRV VC: Failed to alloc %d bytes for Addins\n", newAddinCount * sizeof(*pNewAddins))); goto EXIT_POINT; }
//
// Enumerate the sub-keys
//
for (Index = 0, SavedCount = 0; Index < newAddinCount; Index++) { //
// If there is a sub key open, it's left over from a previous loop
// iteration, so close it now
//
if (hKeySub) { TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV VC: Close sub key %p\n", hKeySub)); RegCloseKey(hKeySub); hKeySub = NULL; }
//
// Enumerate the next key
//
TRACE((DEBUG_TSHRSRV_DEBUG, "TShrSRV VC: Enumerate key %d\n", Index)); cb = TSRV_VC_ADDIN_SUBKEY_LEN; rc = RegEnumKeyEx(g_hAddinRegKey, Index, SubKeyName, &cb, NULL, NULL, NULL, &FileTime); if (rc != ERROR_SUCCESS) { if (rc == ERROR_MORE_DATA) { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSRV VC: Subkey name too long, skipping\n")); continue; } else if (rc == ERROR_NO_MORE_ITEMS) { TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV VC: End of enumeration\n")); } else { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSRV VC: Failed to enumerate key %d, rc %d\n", Index, rc)); } break; }
//
// Open the subkey
//
rc = RegOpenKeyEx(g_hAddinRegKey, SubKeyName, 0, KEY_READ, &hKeySub); if (rc != ERROR_SUCCESS) { TRACE((DEBUG_TSHRSRV_WARN, "TShrSRV VC: Failed to open key %s, rc %d\n", SubKeyName, rc)); continue; }
//
// Read the Addin name
//
cb = TSRV_VC_ADDIN_NAMELEN * sizeof(TCHAR); rc = RegQueryValueEx(hKeySub, TSRV_VC_NAME, NULL, &Type, (LPBYTE)AddinName, &cb); if ((rc != ERROR_SUCCESS) || (Type != REG_SZ) || (cb == 0)) { TRACE((DEBUG_TSHRSRV_WARN, "TShrSRV VC: Failed to read addin name rc %d, type %d, cb %d\n", rc, Type, cb)); continue; }
//
// Read the Addin type
//
cb = sizeof(AddinType); rc = RegQueryValueEx(hKeySub, TSRV_VC_TYPE, NULL, &Type, (LPBYTE)(&AddinType), &cb); if ((rc != ERROR_SUCCESS) || (Type != REG_DWORD)) { TRACE((DEBUG_TSHRSRV_WARN, "TShrSRV VC: Failed to read addin type rc %d, type %d, cb %d\n", rc, Type, cb)); continue; }
//
// Read the Shadow Persistent value
//
cb = sizeof(dwRCPersistent); rc = RegQueryValueEx(hKeySub, TSRV_VC_SHADOW, NULL, &Type, (LPBYTE)(&dwRCPersistent), &cb); if ((rc == ERROR_SUCCESS) && (Type == REG_DWORD) && (dwRCPersistent != 0)) { bRCPersistent = TRUE; }
//
// Check for duplicates
//
TRACE((DEBUG_TSHRSRV_DEBUG, "TShrSRV VC: Check for dups of %S\n", AddinName)); dupFound = FALSE; for (i = 0; i < SavedCount; i++) { TRACE((DEBUG_TSHRSRV_DEBUG, "TShrSRV VC: Test Addin %d (%S)\n", i, pNewAddins[i].Name)); if (0 == _tcscmp(pNewAddins[i].Name, AddinName)) { TRACE((DEBUG_TSHRSRV_WARN, "TShrSRV VC: Duplicate addin name %S (%d)\n", AddinName, i)); //
// We can't directly do a continue here, because we're in
// an inner loop. So set a flag and do it outside.
//
dupFound = TRUE; break; } } if (dupFound) { // Now we can do the continue.
continue; }
//
// Check for supported addin types
//
if ((AddinType == TSRV_VC_TYPE_KERNEL_SYSTEM) || (AddinType == TSRV_VC_TYPE_USER_SESSION)) { TRACE((DEBUG_TSHRSRV_DEBUG, "TShrSRV VC: Supported addin type %d\n", AddinType)); } else if ((AddinType == TSRV_VC_TYPE_KERNEL_SESSION) || (AddinType == TSRV_VC_TYPE_USER_SESSION)) { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSRV VC: Unsupported addin type %d\n", AddinType)); continue; } else { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSRV VC: Unknown addin type %d\n", AddinType)); continue; }
//
// Save all pertinent information.
//
_tcscpy(pNewAddins[SavedCount].Name, AddinName); pNewAddins[SavedCount].Type = AddinType; pNewAddins[SavedCount].hDevice = INVALID_HANDLE_VALUE; pNewAddins[SavedCount].bShadowPersistent = bRCPersistent; TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV VC: Addin %d, %S, type %d\n", SavedCount, AddinName, AddinType)); SavedCount++; } // for
} else { // We have no addins in the registry. SavedCount and pNewAddins are
// already initialized for this case.
TRACE((DEBUG_TSHRSRV_WARN, "TShrSRV VC: No addins found in registry\n")); SavedCount = 0; pNewAddins = NULL; }
//
// It's now safe to free the old Addins information and update the globals.
//
if (g_pAddin != NULL) { TSHeapFree(g_pAddin); } g_pAddin = pNewAddins; g_AddinCount = SavedCount;
//
// Now set up the registry change notification so that we are notified
// next time the registered addins change.
//
TSrvSetAddinChangeNotification();
TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV VC: Saved %d addin(s)\n", SavedCount));
EXIT_POINT: //
// Close the sub key, if there is still one open
//
if (hKeySub) { TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV VC: Close sub key %p\n", hKeySub)); RegCloseKey(hKeySub); }
TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: Leave TSrvReadVCAddins - %lu\n", rc)); return(rc); }
//*************************************************************
//
// TSrvGotAddinChangedEvent()
//
// Purpose: Does the necessary actions when TSrvMainThread gets
// a notification that the Addins registry key has changed.
// Called on the TSrvMainThread thread.
//
// Parameters: None.
//
// Return: None.
//
// History: 05-03-99 a-oking Created
//
//*************************************************************
VOID TSrvGotAddinChangedEvent(void) { TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: TSrvGotAddinChangedEvent entry\n"));
EnterCriticalSection(&g_TSrvVCCritSect);
//
// We're here because the notify event just popped, so
// we set this flag to get it set up again.
//
g_bNeedToSetRegNotify = TRUE;
TSrvReadVCAddins();
LeaveCriticalSection(&g_TSrvVCCritSect);
TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: TSrvGotAddinChangedEvent exit\n")); }
//*************************************************************
//
// TSrvSetAddinChangeNotification()
//
// Purpose: Sets up a notification event that will pop if
// anything in the Addins registry key changes.
//
// NB - Caller must hold the g_TSrvVCCritSect
//
// Parameters: None.
//
// Return: TRUE if successful
// FALSE if not
//
// History: 05-03-99 a-oking Created
//
//*************************************************************
BOOL TSrvSetAddinChangeNotification(void) { LONG rc; BOOL fSuccess; static ULONG count = 0;
TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: TSrvSetAddinChangeNotification entry\n"));
if (g_hAddinRegKey && g_hVCAddinChangeEvent && g_bNeedToSetRegNotify) { rc = RegNotifyChangeKeyValue(g_hAddinRegKey, TRUE, REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET, g_hVCAddinChangeEvent, TRUE);
if (ERROR_SUCCESS == rc) { TRACE((DEBUG_TSHRSRV_NORMAL, "TShrSRV VC: Set up VC Addin change notification OK\n")); g_bNeedToSetRegNotify = FALSE; } else { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSRV VC: Failed to set up VC Addin change " "notification - 0x%x\n", rc)); } } else { TRACE((DEBUG_TSHRSRV_ERROR, "TShrSRV VC: Couldn't set up VC Addin change notification - " "g_hAddinRegKey %p, g_hVCAddinChangeEvent %p\n", g_hAddinRegKey, g_hVCAddinChangeEvent)); }
fSuccess = !g_bNeedToSetRegNotify;
TRACE((DEBUG_TSHRSRV_FLOW, "TShrSRV VC: TSrvSetAddinChangeNotification exit - 0x%x\n", fSuccess));
return(fSuccess); }
|