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