mirror of
https://github.com/reactos/reactos.git
synced 2024-08-22 19:33:01 +00:00
603 lines
16 KiB
C
603 lines
16 KiB
C
/*
|
|
* 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 <w3seek@reactos.com>
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
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;
|
|
}
|