/* * ReactOS kernel * Copyright (C) 2006 ReactOS Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * FILE: dll/win32/userenv/gpolicy.c * PURPOSE: Group policy functions * PROGRAMMER: Thomas Weidenmueller */ #include "precomp.h" #define NDEBUG #include typedef struct _GP_NOTIFY { struct _GP_NOTIFY *Next; HANDLE hEvent; BOOL bMachine; } GP_NOTIFY, *PGP_NOTIFY; typedef enum { gpaUpdate = 0, gpaTerminate } GP_ACTION; static const WCHAR szLocalGPApplied[] = L"userenv: User Group Policy has been applied"; static const WCHAR szLocalGPMutex[] = L"userenv: user policy mutex"; static const WCHAR szLocalGPRefreshEvent[] = L"userenv: user policy refresh event"; static const WCHAR szLocalGPForceRefreshEvent[] = L"userenv: user policy force refresh event"; static const WCHAR szLocalGPDoneEvent[] = L"userenv: User Policy Foreground Done Event"; static const WCHAR szMachineGPApplied[] = L"Global\\userenv: Machine Group Policy has been applied"; static const WCHAR szMachineGPMutex[] = L"Global\\userenv: machine policy mutex"; static const WCHAR szMachineGPRefreshEvent[] = L"Global\\userenv: machine policy refresh event"; static const WCHAR szMachineGPForceRefreshEvent[] = L"Global\\userenv: machine policy force refresh event"; static const WCHAR szMachineGPDoneEvent[] = L"Global\\userenv: Machine Policy Foreground Done Event"; static CRITICAL_SECTION GPNotifyLock; static PGP_NOTIFY NotificationList = NULL; static GP_ACTION GPNotificationAction = gpaUpdate; static HANDLE hNotificationThread = NULL; static HANDLE hNotificationThreadEvent = NULL; static HANDLE hLocalGPAppliedEvent = NULL; static HANDLE hMachineGPAppliedEvent = NULL; VOID InitializeGPNotifications(VOID) { InitializeCriticalSection(&GPNotifyLock); } VOID UninitializeGPNotifications(VOID) { EnterCriticalSection(&GPNotifyLock); /* rundown the notification thread */ if (hNotificationThread != NULL) { ASSERT(hNotificationThreadEvent != NULL); /* notify the thread */ GPNotificationAction = gpaTerminate; SetEvent(hNotificationThreadEvent); LeaveCriticalSection(&GPNotifyLock); /* wait for the thread to terminate itself */ WaitForSingleObject(hNotificationThread, INFINITE); EnterCriticalSection(&GPNotifyLock); if (hNotificationThread != NULL) { /* the handle should be closed by the thread, just in case that didn't happen for an unknown reason */ CloseHandle(hNotificationThread); hNotificationThread = NULL; } } if (hNotificationThreadEvent != NULL) { CloseHandle(hNotificationThreadEvent); hNotificationThreadEvent = NULL; } LeaveCriticalSection(&GPNotifyLock); DeleteCriticalSection(&GPNotifyLock); } static VOID NotifyGPEvents(IN BOOL bMachine) { PGP_NOTIFY Notify = NotificationList; while (Notify != NULL) { if (Notify->bMachine == bMachine) { SetEvent(Notify->hEvent); } Notify = Notify->Next; } } static DWORD WINAPI GPNotificationThreadProc(IN LPVOID lpParameter) { HMODULE hModule; DWORD WaitResult, WaitCount; HANDLE WaitHandles[3]; /* reference the library so we don't screw up if the application causes the DLL to unload while this thread is still running */ if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)hInstance, &hModule)) { ASSERT(hModule == hInstance); EnterCriticalSection(&GPNotifyLock); ASSERT(hNotificationThreadEvent != NULL); WaitHandles[0] = hNotificationThreadEvent; for (;;) { ASSERT(hMachineGPAppliedEvent != NULL); if (NotificationList == NULL) break; WaitCount = 2; WaitHandles[1] = hMachineGPAppliedEvent; if (hLocalGPAppliedEvent != NULL) { WaitHandles[2] = hLocalGPAppliedEvent; WaitCount++; } LeaveCriticalSection(&GPNotifyLock); WaitResult = WaitForMultipleObjects(WaitCount, WaitHandles, FALSE, INFINITE); EnterCriticalSection(&GPNotifyLock); if (WaitResult != WAIT_FAILED) { if (WaitResult == WAIT_OBJECT_0) { ResetEvent(hNotificationThreadEvent); if (GPNotificationAction == gpaTerminate) { /* terminate the thread */ break; } } else if (WaitResult == WAIT_OBJECT_0 + 1 || WaitResult == WAIT_OBJECT_0 + 2) { /* group policies have been applied */ if (NotificationList != NULL) { NotifyGPEvents((WaitResult == WAIT_OBJECT_0 + 1)); } } else if (WaitResult == WAIT_ABANDONED_0 + 2) { /* In case the local group policies event was abandoned, keep watching! But close the handle as it's no longer of any use. */ if (hLocalGPAppliedEvent != NULL) { CloseHandle(hLocalGPAppliedEvent); hLocalGPAppliedEvent = NULL; } } else if (WaitResult == WAIT_ABANDONED_0 || WaitResult == WAIT_ABANDONED_0 + 1) { /* terminate the thread if the machine group policies event was abandoned or for some reason the rundown event got abandoned. */ break; } else { DPRINT("Unexpected wait result watching the group policy events: 0x%x\n", WaitResult); ASSERT(FALSE); break; } if (NotificationList == NULL) break; } else break; } /* cleanup handles no longer used */ ASSERT(hNotificationThread != NULL); ASSERT(hNotificationThreadEvent != NULL); CloseHandle(hNotificationThread); CloseHandle(hNotificationThreadEvent); hNotificationThread = NULL; hNotificationThreadEvent = NULL; if (hLocalGPAppliedEvent != NULL) { CloseHandle(hLocalGPAppliedEvent); hLocalGPAppliedEvent = NULL; } if (hMachineGPAppliedEvent != NULL) { CloseHandle(hMachineGPAppliedEvent); hMachineGPAppliedEvent = NULL; } LeaveCriticalSection(&GPNotifyLock); /* dereference the library and exit */ FreeLibraryAndExitThread(hModule, 0); } else { DPRINT1("Referencing the library failed!\n"); } return 1; } static HANDLE CreateGPEvent(IN BOOL bMachine, IN PSECURITY_DESCRIPTOR lpSecurityDescriptor) { HANDLE hEvent; SECURITY_ATTRIBUTES SecurityAttributes; SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); SecurityAttributes.lpSecurityDescriptor = lpSecurityDescriptor; SecurityAttributes.bInheritHandle = FALSE; hEvent = CreateEventW(&SecurityAttributes, TRUE, FALSE, (bMachine ? szMachineGPApplied : szLocalGPApplied)); return hEvent; } BOOL WINAPI RegisterGPNotification(IN HANDLE hEvent, IN BOOL bMachine) { PGP_NOTIFY Notify; PSECURITY_DESCRIPTOR lpSecurityDescriptor = NULL; BOOL Ret = FALSE; EnterCriticalSection(&GPNotifyLock); /* create the thread notification event */ if (hNotificationThreadEvent == NULL) { hNotificationThreadEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (hNotificationThreadEvent == NULL) { goto Cleanup; } } /* create or open the machine group policy event */ if (hMachineGPAppliedEvent == NULL) { lpSecurityDescriptor = CreateDefaultSecurityDescriptor(); if (lpSecurityDescriptor == NULL) { goto Cleanup; } hMachineGPAppliedEvent = CreateGPEvent(TRUE, lpSecurityDescriptor); if (hMachineGPAppliedEvent == NULL) { goto Cleanup; } } /* create or open the local group policy event only if necessary */ if (!bMachine && hLocalGPAppliedEvent == NULL) { if (lpSecurityDescriptor == NULL) { lpSecurityDescriptor = CreateDefaultSecurityDescriptor(); if (lpSecurityDescriptor == NULL) { goto Cleanup; } } hLocalGPAppliedEvent = CreateGPEvent(FALSE, lpSecurityDescriptor); if (hLocalGPAppliedEvent == NULL) { goto Cleanup; } } if (hNotificationThread == NULL) { hNotificationThread = CreateThread(NULL, 0, GPNotificationThreadProc, NULL, 0, NULL); } if (hNotificationThread != NULL) { Notify = (PGP_NOTIFY)LocalAlloc(LMEM_FIXED, sizeof(GP_NOTIFY)); if (Notify != NULL) { /* add the item to the beginning of the list */ Notify->Next = NotificationList; Notify->hEvent = hEvent; Notify->bMachine = bMachine; NotificationList = Notify; /* notify the thread */ GPNotificationAction = gpaUpdate; SetEvent(hNotificationThreadEvent); Ret = TRUE; } } Cleanup: LeaveCriticalSection(&GPNotifyLock); if (lpSecurityDescriptor != NULL) { LocalFree((HLOCAL)lpSecurityDescriptor); } /* NOTE: don't delete the events or close the handles created */ return Ret; } BOOL WINAPI UnregisterGPNotification(IN HANDLE hEvent) { PGP_NOTIFY Notify = NULL, *NotifyLink; BOOL Ret = FALSE; EnterCriticalSection(&GPNotifyLock); Notify = NotificationList; NotifyLink = &NotificationList; while (Notify != NULL) { if (Notify->hEvent == hEvent) { /* remove and free the item */ *NotifyLink = Notify->Next; LocalFree((HLOCAL)Notify); /* notify the thread */ if (hNotificationThread != NULL && hNotificationThreadEvent != NULL) { GPNotificationAction = gpaUpdate; SetEvent(hNotificationThreadEvent); } Ret = TRUE; break; } NotifyLink = &Notify->Next; Notify = Notify->Next; } LeaveCriticalSection(&GPNotifyLock); return Ret; } BOOL WINAPI RefreshPolicy(IN BOOL bMachine) { HANDLE hEvent; BOOL Ret = TRUE; hEvent = OpenEventW(EVENT_MODIFY_STATE, FALSE, (bMachine ? szMachineGPRefreshEvent : szLocalGPRefreshEvent)); if (hEvent != NULL) { Ret = SetEvent(hEvent); CloseHandle(hEvent); } /* return TRUE even if the mutex doesn't exist! */ return Ret; } BOOL WINAPI RefreshPolicyEx(IN BOOL bMachine, IN DWORD dwOptions) { if (dwOptions & ~RP_FORCE) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } if (dwOptions & RP_FORCE) { HANDLE hEvent; BOOL Ret = TRUE; hEvent = OpenEventW(EVENT_MODIFY_STATE, FALSE, (bMachine ? szMachineGPForceRefreshEvent : szLocalGPForceRefreshEvent)); if (hEvent != NULL) { Ret = SetEvent(hEvent); CloseHandle(hEvent); } /* return TRUE even if the mutex doesn't exist! */ return Ret; } else { return RefreshPolicy(bMachine); } } HANDLE WINAPI EnterCriticalPolicySection(IN BOOL bMachine) { SECURITY_ATTRIBUTES SecurityAttributes; PSECURITY_DESCRIPTOR lpSecurityDescriptor; HANDLE hSection; /* create or open the mutex */ lpSecurityDescriptor = CreateDefaultSecurityDescriptor(); if (lpSecurityDescriptor != NULL) { SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); SecurityAttributes.lpSecurityDescriptor = lpSecurityDescriptor; SecurityAttributes.bInheritHandle = FALSE; hSection = CreateMutexW(&SecurityAttributes, FALSE, (bMachine ? szMachineGPMutex : szLocalGPMutex)); LocalFree((HLOCAL)lpSecurityDescriptor); if (hSection != NULL) { /* wait up to 10 minutes */ if (WaitForSingleObject(hSection, 600000) != WAIT_FAILED) { return hSection; } CloseHandle(hSection); } } return NULL; } BOOL WINAPI LeaveCriticalPolicySection(IN HANDLE hSection) { BOOL Ret; if (hSection == NULL) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } Ret = ReleaseMutex(hSection); CloseHandle(hSection); return Ret; } BOOL WINAPI WaitForUserPolicyForegroundProcessing(VOID) { HANDLE hEvent; BOOL Ret = FALSE; hEvent = OpenEventW(SYNCHRONIZE, FALSE, szLocalGPDoneEvent); if (hEvent != NULL) { Ret = WaitForSingleObject(hEvent, INFINITE) != WAIT_FAILED; CloseHandle(hEvent); } return Ret; } BOOL WINAPI WaitForMachinePolicyForegroundProcessing(VOID) { HANDLE hEvent; BOOL Ret = FALSE; hEvent = OpenEventW(SYNCHRONIZE, FALSE, szMachineGPDoneEvent); if (hEvent != NULL) { Ret = WaitForSingleObject(hEvent, INFINITE) != WAIT_FAILED; CloseHandle(hEvent); } return Ret; } DWORD WINAPI GetAppliedGPOListA( _In_ DWORD dwFlags, _In_ LPCSTR pMachineName, _In_ PSID pSidUser, _In_ GUID *pGuidExtension, _Out_ PGROUP_POLICY_OBJECTA *ppGPOList ) { DPRINT1("GetAppliedGPOListA is UNIMPLEMENTED!\n"); return ERROR_CALL_NOT_IMPLEMENTED; } DWORD WINAPI GetAppliedGPOListW( _In_ DWORD dwFlags, _In_ LPCWSTR pMachineName, _In_ PSID pSidUser, _In_ GUID *pGuidExtension, _Out_ PGROUP_POLICY_OBJECTW *ppGPOList ) { DPRINT1("GetAppliedGPOListW is UNIMPLEMENTED!\n"); return ERROR_CALL_NOT_IMPLEMENTED; }