449 lines
12 KiB
C++
449 lines
12 KiB
C++
|
//*************************************************************
|
||
|
//
|
||
|
// Group Policy Notification
|
||
|
//
|
||
|
// Microsoft Confidential
|
||
|
// Copyright (c) Microsoft Corporation 1997-1998
|
||
|
// All rights reserved
|
||
|
//
|
||
|
// Notes: There is a small window where notifications
|
||
|
// can be lost. If while processing an eMonitor workitem
|
||
|
// a policy event is Pulsed then that notification will
|
||
|
// be lost. This window can be closed by using two threads.
|
||
|
//
|
||
|
// History: 28-Sep-98 SitaramR Created
|
||
|
//
|
||
|
//*************************************************************
|
||
|
|
||
|
#include "gphdr.h"
|
||
|
|
||
|
//
|
||
|
// Work items for notification thread
|
||
|
//
|
||
|
enum EWorkType { eMonitor, // Monitor events
|
||
|
eTerminate }; // Stop monitoring
|
||
|
|
||
|
//
|
||
|
// Entry in list of registered events
|
||
|
//
|
||
|
typedef struct _GPNOTIFINFO
|
||
|
{
|
||
|
HANDLE hEvent; // Event to be signaled
|
||
|
BOOL bMachine; // Machine policy notifcation ?
|
||
|
struct _GPNOTIFINFO * pNext; // Singly linked list ptr
|
||
|
} GPNOTIFINFO;
|
||
|
|
||
|
|
||
|
typedef struct _GPNOTIFICATION
|
||
|
{
|
||
|
HANDLE hThread; // Notification thread
|
||
|
HANDLE hThreadEvent; // For signaling notification thread (Ordering of fields is important)
|
||
|
HANDLE hMachEvent; // Event signaled by machine policy change
|
||
|
HANDLE hUserEvent; // Event signaled by user policy change
|
||
|
enum EWorkType eWorkType; // Work descrpition for notification thread
|
||
|
GPNOTIFINFO * pNotifList; // List of registered events
|
||
|
} GPNOTIFICATION;
|
||
|
|
||
|
GPNOTIFICATION g_Notif = { NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
eMonitor,
|
||
|
NULL };
|
||
|
|
||
|
CRITICAL_SECTION g_NotifyCS; // Lock
|
||
|
|
||
|
|
||
|
//
|
||
|
// Forward decls
|
||
|
//
|
||
|
DWORD WINAPI NotificationThread();
|
||
|
void NotifyEvents( BOOL bMachine );
|
||
|
|
||
|
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// InitNotifSupport, ShutdownNotifSupport
|
||
|
//
|
||
|
// Purpose: Initialization and cleanup routines
|
||
|
//
|
||
|
//*************************************************************
|
||
|
|
||
|
void InitializeNotifySupport()
|
||
|
{
|
||
|
InitializeCriticalSection( &g_NotifyCS );
|
||
|
}
|
||
|
|
||
|
void ShutdownNotifySupport()
|
||
|
{
|
||
|
BOOL fWait = FALSE;
|
||
|
DWORD dwResult;
|
||
|
|
||
|
{
|
||
|
EnterCriticalSection( &g_NotifyCS );
|
||
|
|
||
|
if ( g_Notif.hThread != NULL )
|
||
|
{
|
||
|
//
|
||
|
// Set up terminate workitem and then signal thread
|
||
|
//
|
||
|
|
||
|
fWait = TRUE;
|
||
|
g_Notif.eWorkType = eTerminate;
|
||
|
SetEvent( g_Notif.hThreadEvent );
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection( &g_NotifyCS );
|
||
|
}
|
||
|
|
||
|
if ( fWait )
|
||
|
WaitForSingleObject( g_Notif.hThread, INFINITE );
|
||
|
|
||
|
{
|
||
|
EnterCriticalSection( &g_NotifyCS );
|
||
|
|
||
|
//
|
||
|
// Close all opened handles
|
||
|
//
|
||
|
|
||
|
if ( g_Notif.hThread != NULL )
|
||
|
CloseHandle( g_Notif.hThread );
|
||
|
|
||
|
if ( g_Notif.hThreadEvent != NULL )
|
||
|
CloseHandle( g_Notif.hThreadEvent );
|
||
|
|
||
|
if ( g_Notif.hUserEvent != NULL )
|
||
|
CloseHandle( g_Notif.hUserEvent );
|
||
|
|
||
|
if ( g_Notif.hMachEvent != NULL )
|
||
|
CloseHandle( g_Notif.hMachEvent );
|
||
|
|
||
|
LeaveCriticalSection( &g_NotifyCS );
|
||
|
}
|
||
|
|
||
|
DeleteCriticalSection( &g_NotifyCS );
|
||
|
}
|
||
|
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// RegisterGPNotification
|
||
|
//
|
||
|
// Purpose: Registers for a group policy change notification
|
||
|
//
|
||
|
// Parameters: hEvent - Event to be notified
|
||
|
// bMachine - If true, then register for
|
||
|
// machine policy notification, else
|
||
|
// user policy notification
|
||
|
//
|
||
|
// Returns: True if successful
|
||
|
// False if error occurs
|
||
|
//
|
||
|
//*************************************************************
|
||
|
|
||
|
BOOL WINAPI RegisterGPNotification( IN HANDLE hEvent, IN BOOL bMachine )
|
||
|
{
|
||
|
BOOL bResult = FALSE;
|
||
|
BOOL bNotifyThread = FALSE;
|
||
|
GPNOTIFINFO *pNotifInfo = NULL;
|
||
|
|
||
|
EnterCriticalSection( &g_NotifyCS );
|
||
|
|
||
|
//
|
||
|
// Create events and thread as needed
|
||
|
//
|
||
|
|
||
|
if ( g_Notif.hThreadEvent == NULL )
|
||
|
{
|
||
|
g_Notif.hThreadEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
|
||
|
if ( g_Notif.hThreadEvent == NULL )
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
if ( g_Notif.hMachEvent == NULL )
|
||
|
{
|
||
|
g_Notif.hMachEvent = OpenEvent (SYNCHRONIZE, FALSE, MACHINE_POLICY_APPLIED_EVENT);
|
||
|
|
||
|
if ( g_Notif.hMachEvent == NULL ) {
|
||
|
DebugMsg((DM_WARNING, TEXT("RegisterGPNotification: CreateEvent failed with %d"),
|
||
|
GetLastError()));
|
||
|
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
bNotifyThread = TRUE;
|
||
|
}
|
||
|
|
||
|
if ( !bMachine && g_Notif.hUserEvent == NULL )
|
||
|
{
|
||
|
g_Notif.hUserEvent = OpenEvent (SYNCHRONIZE, FALSE, USER_POLICY_APPLIED_EVENT);
|
||
|
|
||
|
if ( g_Notif.hUserEvent == NULL ) {
|
||
|
DebugMsg((DM_WARNING, TEXT("RegisterGPNotification: CreateEvent failed with %d"),
|
||
|
GetLastError()));
|
||
|
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
bNotifyThread = TRUE;
|
||
|
}
|
||
|
|
||
|
if ( g_Notif.hThread == NULL )
|
||
|
{
|
||
|
DWORD dwThreadId;
|
||
|
g_Notif.hThread = CreateThread( NULL,
|
||
|
0,
|
||
|
(LPTHREAD_START_ROUTINE) NotificationThread,
|
||
|
0,
|
||
|
0,
|
||
|
&dwThreadId );
|
||
|
if ( g_Notif.hThread == NULL ) {
|
||
|
DebugMsg((DM_WARNING, TEXT("RegisterGPNotification: CreateThread failed with %d"),
|
||
|
GetLastError()));
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
bNotifyThread = TRUE;
|
||
|
}
|
||
|
|
||
|
if ( bNotifyThread )
|
||
|
{
|
||
|
//
|
||
|
// Notify thread that there is a new workitem, possibly
|
||
|
// user event has been added.
|
||
|
//
|
||
|
|
||
|
g_Notif.eWorkType = eMonitor;
|
||
|
SetEvent( g_Notif.hThreadEvent );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Add event to beginning of list
|
||
|
//
|
||
|
|
||
|
pNotifInfo = (GPNOTIFINFO *) LocalAlloc( LPTR, sizeof(GPNOTIFINFO) );
|
||
|
if ( pNotifInfo == NULL ) {
|
||
|
DebugMsg((DM_WARNING, TEXT("RegisterGPNotification: LocalAlloc failed with %d"),
|
||
|
GetLastError()));
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
pNotifInfo->hEvent = hEvent;
|
||
|
pNotifInfo->bMachine = bMachine;
|
||
|
pNotifInfo->pNext = g_Notif.pNotifList;
|
||
|
g_Notif.pNotifList = pNotifInfo;
|
||
|
|
||
|
bResult = TRUE;
|
||
|
|
||
|
Exit:
|
||
|
|
||
|
LeaveCriticalSection( &g_NotifyCS );
|
||
|
return bResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// UnregisterGPNotification
|
||
|
//
|
||
|
// Purpose: Removes registration for a group policy change notification
|
||
|
//
|
||
|
// Parameters: hEvent - Event to be removed
|
||
|
//
|
||
|
// Return: True if successful
|
||
|
// False if error occurs
|
||
|
//
|
||
|
//*************************************************************
|
||
|
|
||
|
BOOL WINAPI UnregisterGPNotification( IN HANDLE hEvent )
|
||
|
{
|
||
|
BOOL bFound = FALSE;
|
||
|
GPNOTIFINFO *pTrailPtr = NULL;
|
||
|
GPNOTIFINFO *pCurPtr = NULL;
|
||
|
|
||
|
EnterCriticalSection( &g_NotifyCS );
|
||
|
|
||
|
pCurPtr = g_Notif.pNotifList;
|
||
|
|
||
|
while ( pCurPtr != NULL )
|
||
|
{
|
||
|
if ( pCurPtr->hEvent == hEvent )
|
||
|
{
|
||
|
//
|
||
|
// Found match, so delete entry
|
||
|
//
|
||
|
if ( pTrailPtr == NULL )
|
||
|
{
|
||
|
//
|
||
|
// First elem of list matched
|
||
|
//
|
||
|
g_Notif.pNotifList = pCurPtr->pNext;
|
||
|
}
|
||
|
else
|
||
|
pTrailPtr->pNext = pCurPtr->pNext;
|
||
|
|
||
|
LocalFree( pCurPtr );
|
||
|
bFound = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Advance down the list
|
||
|
//
|
||
|
|
||
|
pTrailPtr = pCurPtr;
|
||
|
pCurPtr = pCurPtr->pNext;
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection( &g_NotifyCS );
|
||
|
return bFound;
|
||
|
}
|
||
|
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// CGPNotification::NotificationThread
|
||
|
//
|
||
|
// Purpose: Separate thread for notifications
|
||
|
//
|
||
|
// Returns: 0
|
||
|
//
|
||
|
//*************************************************************
|
||
|
|
||
|
DWORD WINAPI NotificationThread()
|
||
|
{
|
||
|
DWORD cEvents = 2;
|
||
|
BOOL fShutdown = FALSE;
|
||
|
|
||
|
HINSTANCE hInst = LoadLibrary (TEXT("userenv.dll"));
|
||
|
|
||
|
{
|
||
|
EnterCriticalSection( &g_NotifyCS );
|
||
|
|
||
|
//
|
||
|
// The event fields in g_Notif are ordered as hThreadEvent,
|
||
|
// hMachEvent and finally hUserEvent. The first two events have
|
||
|
// to be successfully created in order for this thread to run
|
||
|
// (see asserts). If the user event has been successfully created
|
||
|
// then that too is monitored.
|
||
|
//
|
||
|
|
||
|
DmAssert( g_Notif.hThreadEvent != NULL && g_Notif.hMachEvent != NULL );
|
||
|
|
||
|
if ( g_Notif.hUserEvent != NULL )
|
||
|
cEvents = 3;
|
||
|
|
||
|
LeaveCriticalSection( &g_NotifyCS );
|
||
|
}
|
||
|
|
||
|
while ( !fShutdown )
|
||
|
{
|
||
|
DWORD dwResult = WaitForMultipleObjects( cEvents,
|
||
|
&g_Notif.hThreadEvent,
|
||
|
FALSE,
|
||
|
INFINITE );
|
||
|
|
||
|
EnterCriticalSection( &g_NotifyCS );
|
||
|
|
||
|
if ( dwResult == WAIT_FAILED )
|
||
|
{
|
||
|
DebugMsg((DM_WARNING, TEXT("GPNotification: WaitforMultipleObjects failed")));
|
||
|
fShutdown = TRUE;
|
||
|
}
|
||
|
else if ( dwResult == WAIT_OBJECT_0 )
|
||
|
{
|
||
|
ResetEvent( g_Notif.hThreadEvent );
|
||
|
|
||
|
if ( g_Notif.eWorkType == eMonitor )
|
||
|
{
|
||
|
//
|
||
|
// Start monitoring user events too
|
||
|
//
|
||
|
if ( g_Notif.hUserEvent != NULL )
|
||
|
cEvents = 3;
|
||
|
}
|
||
|
else
|
||
|
fShutdown = TRUE;
|
||
|
}
|
||
|
else if ( dwResult == WAIT_OBJECT_0 + 1 || dwResult == WAIT_OBJECT_0 + 2 )
|
||
|
{
|
||
|
BOOL bMachine = (dwResult == WAIT_OBJECT_0 + 1);
|
||
|
NotifyEvents( bMachine );
|
||
|
|
||
|
if ( g_Notif.pNotifList == NULL )
|
||
|
fShutdown = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( dwResult == WAIT_ABANDONED_0 || dwResult == WAIT_ABANDONED_0 + 1 )
|
||
|
fShutdown = TRUE;
|
||
|
else
|
||
|
{
|
||
|
CloseHandle( g_Notif.hUserEvent );
|
||
|
g_Notif.hUserEvent = NULL;
|
||
|
|
||
|
cEvents = 2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( fShutdown )
|
||
|
{
|
||
|
//
|
||
|
// Close all handles and thread
|
||
|
//
|
||
|
CloseHandle( g_Notif.hThreadEvent );
|
||
|
g_Notif.hThreadEvent = NULL;
|
||
|
|
||
|
if ( g_Notif.hMachEvent != NULL )
|
||
|
{
|
||
|
CloseHandle( g_Notif.hMachEvent );
|
||
|
g_Notif.hMachEvent = NULL;
|
||
|
}
|
||
|
|
||
|
if ( g_Notif.hUserEvent != NULL )
|
||
|
{
|
||
|
CloseHandle( g_Notif.hUserEvent );
|
||
|
g_Notif.hUserEvent = NULL;
|
||
|
}
|
||
|
|
||
|
CloseHandle( g_Notif.hThread );
|
||
|
g_Notif.hThread = NULL;
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection( &g_NotifyCS );
|
||
|
}
|
||
|
|
||
|
if ( hInst != NULL )
|
||
|
FreeLibraryAndExitThread (hInst, 0);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// NotifyEvents
|
||
|
//
|
||
|
// Purpose: Notifies registered events
|
||
|
//
|
||
|
// Parameters: bMachine - Is this a machine policy change ?
|
||
|
//
|
||
|
//*************************************************************
|
||
|
|
||
|
void NotifyEvents( BOOL bMachine )
|
||
|
{
|
||
|
GPNOTIFINFO *pNotifInfo = NULL;
|
||
|
|
||
|
pNotifInfo = g_Notif.pNotifList;
|
||
|
while ( pNotifInfo != NULL )
|
||
|
{
|
||
|
if ( pNotifInfo->bMachine == bMachine )
|
||
|
{
|
||
|
SetEvent( pNotifInfo->hEvent );
|
||
|
}
|
||
|
|
||
|
pNotifInfo = pNotifInfo->pNext;
|
||
|
}
|
||
|
}
|