windows-nt/Source/XPSP1/NT/ds/security/gina/userenv/policy/gpnotif.cpp
2020-09-26 16:20:57 +08:00

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