You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4802 lines
157 KiB
4802 lines
157 KiB
//*************************************************************
|
|
//
|
|
// Group Policy Support
|
|
//
|
|
// Microsoft Confidential
|
|
// Copyright (c) Microsoft Corporation 1997-1998
|
|
// All rights reserved
|
|
//
|
|
//*************************************************************
|
|
|
|
|
|
#include "gphdr.h"
|
|
#include <strsafe.h>
|
|
|
|
//
|
|
// DS Object class types
|
|
//
|
|
|
|
TCHAR szDSClassAny[] = TEXT("(objectClass=*)");
|
|
TCHAR szDSClassGPO[] = TEXT("groupPolicyContainer");
|
|
TCHAR szDSClassSite[] = TEXT("site");
|
|
TCHAR szDSClassDomain[] = TEXT("domainDNS");
|
|
TCHAR szDSClassOU[] = TEXT("organizationalUnit");
|
|
TCHAR szObjectClass[] = TEXT("objectClass");
|
|
|
|
TCHAR wszKerberos[] = TEXT("Kerberos");
|
|
|
|
//
|
|
// Global flags for Gpo shutdown processing. These are accessed outside
|
|
// the lock because its value is either 0 or 1. Even if there is a race,
|
|
// all it means is that shutdown will start one iteration later.
|
|
//
|
|
|
|
BOOL g_bStopMachGPOProcessing = FALSE;
|
|
BOOL g_bStopUserGPOProcessing = FALSE;
|
|
|
|
//
|
|
// Critical section for handling concurrent, asynchronous completion
|
|
//
|
|
|
|
CRITICAL_SECTION g_GPOCS;
|
|
BOOL g_bGPOCSInited = FALSE;
|
|
|
|
//
|
|
// Global pointers for maintaining asynchronous completion context
|
|
//
|
|
|
|
LPGPINFOHANDLE g_pMachGPInfo = 0;
|
|
LPGPINFOHANDLE g_pUserGPInfo = 0;
|
|
|
|
//
|
|
// Status UI critical section, callback, and proto-types
|
|
//
|
|
|
|
CRITICAL_SECTION g_StatusCallbackCS;
|
|
BOOL g_bStatusCallbackInited = FALSE;
|
|
|
|
PFNSTATUSMESSAGECALLBACK g_pStatusMessageCallback = NULL;
|
|
|
|
DWORD WINAPI
|
|
SetPreviousFgPolicyRefreshInfo( LPWSTR szUserSid,
|
|
FgPolicyRefreshInfo info );
|
|
DWORD WINAPI
|
|
SetNextFgPolicyRefreshInfo( LPWSTR szUserSid,
|
|
FgPolicyRefreshInfo info );
|
|
|
|
DWORD WINAPI
|
|
GetCurrentFgPolicyRefreshInfo( LPWSTR szUserSid,
|
|
FgPolicyRefreshInfo* pInfo );
|
|
//*************************************************************
|
|
//
|
|
// ApplyGroupPolicy()
|
|
//
|
|
// Purpose: Processes group policy
|
|
//
|
|
// Parameters: dwFlags - Processing flags
|
|
// hToken - Token (user or machine)
|
|
// hEvent - Termination event for background thread
|
|
// hKeyRoot - Root registry key (HKCU or HKLM)
|
|
// pStatusCallback - Callback function for display status messages
|
|
//
|
|
// Return: Thread handle if successful
|
|
// NULL if an error occurs
|
|
//
|
|
//*************************************************************
|
|
|
|
HANDLE WINAPI ApplyGroupPolicy (DWORD dwFlags, HANDLE hToken, HANDLE hEvent,
|
|
HKEY hKeyRoot, PFNSTATUSMESSAGECALLBACK pStatusCallback)
|
|
{
|
|
HANDLE hThread = NULL;
|
|
DWORD dwThreadID;
|
|
LPGPOINFO lpGPOInfo = NULL;
|
|
SECURITY_ATTRIBUTES sa;
|
|
OLE32_API *pOle32Api = NULL;
|
|
XPtrLF<SECURITY_DESCRIPTOR> xsd;
|
|
CSecDesc Csd;
|
|
XLastError xe;
|
|
HANDLE hProc;
|
|
BOOL bRet;
|
|
|
|
//
|
|
// Verbose output
|
|
//
|
|
DebugMsg((DM_VERBOSE, TEXT("ApplyGroupPolicy: Entering. Flags = %x"), dwFlags));
|
|
|
|
|
|
//
|
|
// Save the status UI callback function
|
|
//
|
|
EnterCriticalSection (&g_StatusCallbackCS);
|
|
g_pStatusMessageCallback = pStatusCallback;
|
|
LeaveCriticalSection (&g_StatusCallbackCS);
|
|
|
|
|
|
//
|
|
// Allocate a GPOInfo structure to work with.
|
|
//
|
|
lpGPOInfo = (LPGPOINFO) LocalAlloc (LPTR, sizeof(GPOINFO));
|
|
|
|
if (!lpGPOInfo) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ApplyGroupPolicy: Failed to alloc lpGPOInfo (%d)."),
|
|
GetLastError()));
|
|
CEvents ev(TRUE, EVENT_FAILED_ALLOCATION);
|
|
ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
goto Exit;
|
|
}
|
|
|
|
lpGPOInfo->dwFlags = dwFlags;
|
|
|
|
//
|
|
// Duplicate handle to prevent closing when winlogon abandons this thread
|
|
//
|
|
|
|
hProc = GetCurrentProcess();
|
|
// this is not expected to fail
|
|
if( hProc == NULL ) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ApplyGroupPolicy: Failed to open current process handle with error (%d)."), GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ApplyGroupPolicy: Duplicating handles")));
|
|
|
|
bRet = DuplicateHandle(
|
|
hProc, // Source of the handle
|
|
hToken, // Source handle
|
|
hProc, // Target of the handle
|
|
&(lpGPOInfo->hToken), // Target handle
|
|
0, // ignored since DUPLICATE_SAME_ACCESS is set
|
|
FALSE, // no inherit on the handle
|
|
DUPLICATE_SAME_ACCESS
|
|
);
|
|
|
|
if( !bRet ) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ApplyGroupPolicy: Failed to open duplicate token handle with error (%d)."), GetLastError()));
|
|
CEvents ev(TRUE, EVENT_FAILED_DUPHANDLE);
|
|
ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
goto Exit;
|
|
}
|
|
|
|
bRet = DuplicateHandle(
|
|
hProc, // Source of the handle
|
|
hEvent, // Source handle
|
|
hProc, // Target of the handle
|
|
&(lpGPOInfo->hEvent), // Target handle
|
|
0, // ignored since DUPLICATE_SAME_ACCESS is set
|
|
FALSE, // no inherit on the handle
|
|
DUPLICATE_SAME_ACCESS
|
|
);
|
|
|
|
if( !bRet ) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ApplyGroupPolicy: Failed to open duplicate event handle with error (%d)."), GetLastError()));
|
|
CEvents ev(TRUE, EVENT_FAILED_DUPHANDLE);
|
|
ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
goto Exit;
|
|
}
|
|
|
|
if (hKeyRoot != HKEY_LOCAL_MACHINE)
|
|
{
|
|
bRet = DuplicateHandle(
|
|
hProc, // Source of the handle
|
|
(HANDLE)hKeyRoot, // Source handle
|
|
hProc, // Target of the handle
|
|
(LPHANDLE)(&(lpGPOInfo->hKeyRoot)), // Target handle
|
|
0, // ignored since DUPLICATE_SAME_ACCESS is set
|
|
FALSE, // no inherit on the handle
|
|
DUPLICATE_SAME_ACCESS
|
|
);
|
|
|
|
if( !bRet ) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ApplyGroupPolicy: Failed to open duplicate key handle with error (%d)."), GetLastError()));
|
|
CEvents ev(TRUE, EVENT_FAILED_DUPHANDLE);
|
|
ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
goto Exit;
|
|
}
|
|
}
|
|
else {
|
|
lpGPOInfo->hKeyRoot = HKEY_LOCAL_MACHINE;
|
|
}
|
|
|
|
if (dwFlags & GP_MACHINE) {
|
|
lpGPOInfo->pStatusCallback = MachinePolicyCallback;
|
|
} else {
|
|
lpGPOInfo->pStatusCallback = UserPolicyCallback;
|
|
}
|
|
|
|
|
|
//
|
|
// Create an event so other processes can trigger policy
|
|
// to be applied immediately
|
|
//
|
|
|
|
|
|
Csd.AddLocalSystem();
|
|
Csd.AddAdministrators();
|
|
|
|
if (!(dwFlags & GP_MACHINE)) {
|
|
|
|
//
|
|
// User events
|
|
//
|
|
XPtrLF<SID> xSid = (SID *)GetUserSid(hToken);
|
|
|
|
if (!xSid) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ApplyGroupPolicy: Failed to find user Sid %d"),
|
|
GetLastError()));
|
|
CEvents ev(TRUE, EVENT_FAILED_SETACLS);
|
|
ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
goto Exit;
|
|
}
|
|
|
|
Csd.AddSid((SID *)xSid,
|
|
STANDARD_RIGHTS_READ | EVENT_QUERY_STATE | // GENERIC_READ mask
|
|
STANDARD_RIGHTS_WRITE | EVENT_MODIFY_STATE); // GENERIC_WRITE mask
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Machine Events
|
|
// Allow Everyone Access by default but can be overridden by policy or preference
|
|
//
|
|
|
|
DWORD dwUsersDenied = 0;
|
|
HKEY hSubKey;
|
|
DWORD dwType=0, dwSize=0;
|
|
|
|
//
|
|
// Check for a preference
|
|
//
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WINLOGON_KEY, 0, KEY_READ,
|
|
&hSubKey) == ERROR_SUCCESS) {
|
|
|
|
dwSize = sizeof(dwUsersDenied);
|
|
RegQueryValueEx(hSubKey, MACHPOLICY_DENY_USERS, NULL, &dwType,
|
|
(LPBYTE) &dwUsersDenied, &dwSize);
|
|
|
|
RegCloseKey(hSubKey);
|
|
}
|
|
|
|
|
|
//
|
|
// Check for a policy
|
|
//
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, SYSTEM_POLICIES_KEY, 0, KEY_READ,
|
|
&hSubKey) == ERROR_SUCCESS) {
|
|
|
|
dwSize = sizeof(dwUsersDenied);
|
|
RegQueryValueEx(hSubKey, MACHPOLICY_DENY_USERS, NULL, &dwType,
|
|
(LPBYTE) &dwUsersDenied, &dwSize);
|
|
|
|
RegCloseKey(hSubKey);
|
|
}
|
|
|
|
|
|
if (!dwUsersDenied) {
|
|
Csd.AddAuthUsers(
|
|
STANDARD_RIGHTS_READ | EVENT_QUERY_STATE | // GENERIC_READ mask
|
|
STANDARD_RIGHTS_WRITE | EVENT_MODIFY_STATE); // GENERIC_WRITE mask
|
|
}
|
|
}
|
|
|
|
xsd = Csd.MakeSD();
|
|
|
|
if (!xsd) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ApplyGroupPolicy: Failed to create Security Descriptor with %d"),
|
|
GetLastError()));
|
|
CEvents ev(TRUE, EVENT_FAILED_SETACLS);
|
|
ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
goto Exit;
|
|
}
|
|
|
|
sa.lpSecurityDescriptor = (SECURITY_DESCRIPTOR *)xsd;
|
|
sa.bInheritHandle = FALSE;
|
|
sa.nLength = sizeof(sa);
|
|
|
|
lpGPOInfo->hTriggerEvent = CreateEvent (&sa, FALSE, FALSE,
|
|
(dwFlags & GP_MACHINE) ?
|
|
MACHINE_POLICY_REFRESH_EVENT : USER_POLICY_REFRESH_EVENT);
|
|
|
|
|
|
if (!lpGPOInfo->hTriggerEvent)
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ApplyGroupPolicy: Failed to create trigger event with %d"),
|
|
GetLastError()));
|
|
CEvents ev(TRUE, EVENT_FAILED_SETACLS);
|
|
ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
goto Exit;
|
|
}
|
|
|
|
lpGPOInfo->hForceTriggerEvent = CreateEvent (&sa, FALSE, FALSE,
|
|
(dwFlags & GP_MACHINE) ?
|
|
MACHINE_POLICY_FORCE_REFRESH_EVENT : USER_POLICY_FORCE_REFRESH_EVENT);
|
|
|
|
|
|
if (!lpGPOInfo->hForceTriggerEvent)
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ApplyGroupPolicy: Failed to create force trigger event with %d"),
|
|
GetLastError()));
|
|
CEvents ev(TRUE, EVENT_FAILED_SETACLS);
|
|
ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Create the notification events.
|
|
// These should already be created in InitializePolicyProcessing..
|
|
//
|
|
|
|
lpGPOInfo->hNotifyEvent = OpenEvent (EVENT_ALL_ACCESS, FALSE,
|
|
(dwFlags & GP_MACHINE) ?
|
|
MACHINE_POLICY_APPLIED_EVENT : USER_POLICY_APPLIED_EVENT);
|
|
|
|
if (!lpGPOInfo->hNotifyEvent)
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ApplyGroupPolicy: Failed to open notify event with %d"),
|
|
GetLastError()));
|
|
CEvents ev(TRUE, EVENT_FAILED_SETACLS);
|
|
ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Create the needfg event
|
|
//
|
|
|
|
lpGPOInfo->hNeedFGEvent = OpenEvent (EVENT_ALL_ACCESS, FALSE,
|
|
(dwFlags & GP_MACHINE) ?
|
|
MACHINE_POLICY_REFRESH_NEEDFG_EVENT :
|
|
USER_POLICY_REFRESH_NEEDFG_EVENT);
|
|
|
|
if (!lpGPOInfo->hNeedFGEvent)
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ApplyGroupPolicy: Failed to open need fg event with %d"),
|
|
GetLastError()));
|
|
CEvents ev(TRUE, EVENT_FAILED_SETACLS);
|
|
ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Create the done event
|
|
//
|
|
|
|
lpGPOInfo->hDoneEvent = OpenEvent (EVENT_ALL_ACCESS, FALSE,
|
|
(dwFlags & GP_MACHINE) ?
|
|
MACHINE_POLICY_DONE_EVENT :
|
|
USER_POLICY_DONE_EVENT);
|
|
|
|
if (!lpGPOInfo->hDoneEvent)
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ApplyGroupPolicy: Failed to open done event with %d"),
|
|
GetLastError()));
|
|
CEvents ev(TRUE, EVENT_FAILED_SETACLS);
|
|
ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Initilialize shutdown gpo processing support
|
|
//
|
|
|
|
if ( dwFlags & GP_MACHINE )
|
|
g_bStopMachGPOProcessing = FALSE;
|
|
else
|
|
g_bStopUserGPOProcessing = FALSE;
|
|
|
|
pOle32Api = LoadOle32Api();
|
|
if ( pOle32Api == NULL ) {
|
|
DebugMsg((DM_WARNING, TEXT("ApplyGroupPolicy: Failed to load ole32.dll.") ));
|
|
}
|
|
else {
|
|
|
|
HRESULT hr = pOle32Api->pfnCoInitializeEx( NULL, COINIT_MULTITHREADED );
|
|
|
|
if ( SUCCEEDED(hr) ) {
|
|
lpGPOInfo->bFGCoInitialized = TRUE;
|
|
}
|
|
else {
|
|
DebugMsg((DM_WARNING, TEXT("ApplyGroupPolicy: CoInitializeEx failed with 0x%x."), hr ));
|
|
}
|
|
}
|
|
|
|
if ( lpGPOInfo->dwFlags & GP_ASYNC_FOREGROUND )
|
|
{
|
|
lpGPOInfo->dwFlags |= GP_BACKGROUND_THREAD;
|
|
}
|
|
|
|
//
|
|
// Process the GPOs
|
|
//
|
|
ProcessGPOs(lpGPOInfo);
|
|
|
|
if ( lpGPOInfo->bFGCoInitialized ) {
|
|
pOle32Api->pfnCoUnInitialize();
|
|
lpGPOInfo->bFGCoInitialized = FALSE;
|
|
}
|
|
|
|
if ( lpGPOInfo->dwFlags & GP_ASYNC_FOREGROUND )
|
|
{
|
|
lpGPOInfo->dwFlags &= ~GP_ASYNC_FOREGROUND;
|
|
lpGPOInfo->dwFlags &= ~GP_BACKGROUND_THREAD;
|
|
}
|
|
|
|
//
|
|
// If requested, create a background thread to keep updating
|
|
// the profile from the gpos
|
|
//
|
|
if (lpGPOInfo->dwFlags & GP_BACKGROUND_REFRESH) {
|
|
// g_p<Mach/User>GPInfo->bNoBackgroupThread is defaulted to FALSE, which translates to this case,
|
|
// so there is no need to set it again.
|
|
|
|
//
|
|
// Create a thread which sleeps and processes GPOs
|
|
//
|
|
|
|
hThread = CreateThread (NULL, 64*1024, // 64k as the stack size
|
|
(LPTHREAD_START_ROUTINE) GPOThread,
|
|
(LPVOID) lpGPOInfo, CREATE_SUSPENDED, &dwThreadID);
|
|
|
|
if (!hThread) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ApplyGroupPolicy: Failed to create background thread (%d)."),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
SetThreadPriority (hThread, THREAD_PRIORITY_IDLE);
|
|
lpGPOInfo->pStatusCallback = NULL;
|
|
ResumeThread (hThread);
|
|
|
|
//
|
|
// Reset the status UI callback function
|
|
//
|
|
|
|
EnterCriticalSection (&g_StatusCallbackCS);
|
|
g_pStatusMessageCallback = NULL;
|
|
LeaveCriticalSection (&g_StatusCallbackCS);
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ApplyGroupPolicy: Leaving successfully.")));
|
|
|
|
return hThread;
|
|
}
|
|
else {
|
|
EnterCriticalSection( &g_GPOCS );
|
|
if ( dwFlags & GP_MACHINE ) {
|
|
if ( g_pMachGPInfo )
|
|
g_pMachGPInfo->bNoBackgroupThread = TRUE;
|
|
} else {
|
|
if ( g_pUserGPInfo )
|
|
g_pUserGPInfo->bNoBackgroupThread = TRUE;
|
|
}
|
|
LeaveCriticalSection( &g_GPOCS );
|
|
|
|
//
|
|
// Reset the status UI callback function
|
|
//
|
|
|
|
EnterCriticalSection (&g_StatusCallbackCS);
|
|
g_pStatusMessageCallback = NULL;
|
|
LeaveCriticalSection (&g_StatusCallbackCS);
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ApplyGroupPolicy: Background refresh not requested. Leaving successfully.")));
|
|
hThread = (HANDLE) 1;
|
|
return hThread;
|
|
}
|
|
|
|
|
|
Exit:
|
|
EnterCriticalSection( &g_GPOCS );
|
|
if ( dwFlags & GP_MACHINE ) {
|
|
|
|
if ( g_pMachGPInfo )
|
|
LocalFree( g_pMachGPInfo );
|
|
g_pMachGPInfo = 0;
|
|
} else {
|
|
if ( g_pUserGPInfo )
|
|
LocalFree( g_pUserGPInfo );
|
|
g_pUserGPInfo = 0;
|
|
}
|
|
LeaveCriticalSection( &g_GPOCS );
|
|
|
|
if (lpGPOInfo) {
|
|
|
|
if (lpGPOInfo->hToken) {
|
|
CloseHandle (lpGPOInfo->hToken);
|
|
}
|
|
|
|
if (lpGPOInfo->hEvent) {
|
|
CloseHandle (lpGPOInfo->hEvent);
|
|
}
|
|
|
|
if (lpGPOInfo->hKeyRoot && (lpGPOInfo->hKeyRoot != HKEY_LOCAL_MACHINE)) {
|
|
RegCloseKey(lpGPOInfo->hKeyRoot);
|
|
}
|
|
|
|
if (lpGPOInfo->hTriggerEvent) {
|
|
CloseHandle (lpGPOInfo->hTriggerEvent);
|
|
}
|
|
|
|
if (lpGPOInfo->hForceTriggerEvent) {
|
|
CloseHandle (lpGPOInfo->hForceTriggerEvent);
|
|
}
|
|
|
|
if (lpGPOInfo->hNotifyEvent) {
|
|
CloseHandle (lpGPOInfo->hNotifyEvent);
|
|
}
|
|
|
|
if (lpGPOInfo->hNeedFGEvent) {
|
|
CloseHandle (lpGPOInfo->hNeedFGEvent);
|
|
}
|
|
|
|
if (lpGPOInfo->lpwszSidUser)
|
|
DeleteSidString( lpGPOInfo->lpwszSidUser );
|
|
|
|
if (lpGPOInfo->szName)
|
|
LocalFree(lpGPOInfo->szName);
|
|
|
|
if (lpGPOInfo->szTargetName)
|
|
LocalFree(lpGPOInfo->szTargetName);
|
|
|
|
LocalFree (lpGPOInfo);
|
|
}
|
|
|
|
//
|
|
// Reset the status UI callback function
|
|
//
|
|
|
|
EnterCriticalSection (&g_StatusCallbackCS);
|
|
g_pStatusMessageCallback = NULL;
|
|
LeaveCriticalSection (&g_StatusCallbackCS);
|
|
|
|
return hThread;
|
|
}
|
|
|
|
|
|
extern "C" void ProfileProcessGPOs( void* );
|
|
|
|
//*************************************************************
|
|
//
|
|
// GPOThread()
|
|
//
|
|
// Purpose: Background thread for GPO processing.
|
|
//
|
|
// Parameters: lpGPOInfo - GPO info
|
|
//
|
|
// Return: 0
|
|
//
|
|
//*************************************************************
|
|
|
|
DWORD WINAPI GPOThread (LPGPOINFO lpGPOInfo)
|
|
{
|
|
HINSTANCE hInst;
|
|
HKEY hKey;
|
|
HANDLE hHandles[4] = {NULL, NULL, NULL, NULL};
|
|
DWORD dwType, dwSize, dwResult;
|
|
DWORD dwTimeout, dwOffset;
|
|
BOOL bSetBkGndFlag, bForceBkGndFlag;
|
|
LARGE_INTEGER DueTime;
|
|
HRESULT hr;
|
|
ULONG TTLMinutes;
|
|
XLastError xe;
|
|
|
|
OLE32_API *pOle32Api = LoadOle32Api();
|
|
|
|
hInst = LoadLibrary (TEXT("userenv.dll"));
|
|
|
|
hHandles[0] = lpGPOInfo->hEvent;
|
|
hHandles[1] = lpGPOInfo->hTriggerEvent;
|
|
hHandles[2] = lpGPOInfo->hForceTriggerEvent;
|
|
|
|
for (;;)
|
|
{
|
|
//
|
|
// Initialize
|
|
//
|
|
|
|
bForceBkGndFlag = FALSE;
|
|
|
|
|
|
if (lpGPOInfo->dwFlags & GP_MACHINE) {
|
|
if (lpGPOInfo->iMachineRole == 3) {
|
|
dwTimeout = GP_DEFAULT_REFRESH_RATE_DC;
|
|
dwOffset = GP_DEFAULT_REFRESH_RATE_OFFSET_DC;
|
|
} else {
|
|
dwTimeout = GP_DEFAULT_REFRESH_RATE;
|
|
dwOffset = GP_DEFAULT_REFRESH_RATE_OFFSET;
|
|
}
|
|
} else {
|
|
dwTimeout = GP_DEFAULT_REFRESH_RATE;
|
|
dwOffset = GP_DEFAULT_REFRESH_RATE_OFFSET;
|
|
}
|
|
|
|
|
|
//
|
|
// Query for the refresh timer value and max offset
|
|
//
|
|
|
|
if (RegOpenKeyEx (lpGPOInfo->hKeyRoot,
|
|
SYSTEM_POLICIES_KEY,
|
|
0, KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
|
|
|
|
if ((lpGPOInfo->iMachineRole == 3) && (lpGPOInfo->dwFlags & GP_MACHINE)) {
|
|
|
|
dwSize = sizeof(dwTimeout);
|
|
RegQueryValueEx (hKey,
|
|
TEXT("GroupPolicyRefreshTimeDC"),
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwTimeout,
|
|
&dwSize);
|
|
|
|
dwSize = sizeof(dwOffset);
|
|
RegQueryValueEx (hKey,
|
|
TEXT("GroupPolicyRefreshTimeOffsetDC"),
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwOffset,
|
|
&dwSize);
|
|
|
|
} else {
|
|
|
|
dwSize = sizeof(dwTimeout);
|
|
RegQueryValueEx (hKey,
|
|
TEXT("GroupPolicyRefreshTime"),
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwTimeout,
|
|
&dwSize);
|
|
|
|
dwSize = sizeof(dwOffset);
|
|
RegQueryValueEx (hKey,
|
|
TEXT("GroupPolicyRefreshTimeOffset"),
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwOffset,
|
|
&dwSize);
|
|
}
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
|
|
//
|
|
// Limit the timeout to once every 64800 minutes (45 days)
|
|
//
|
|
|
|
if (dwTimeout >= 64800) {
|
|
dwTimeout = 64800;
|
|
}
|
|
|
|
|
|
//
|
|
// Convert seconds to milliseconds
|
|
//
|
|
|
|
dwTimeout = dwTimeout * 60 * 1000;
|
|
|
|
|
|
//
|
|
// Limit the offset to 1440 minutes (24 hours)
|
|
//
|
|
|
|
if (dwOffset >= 1440) {
|
|
dwOffset = 1440;
|
|
}
|
|
|
|
|
|
//
|
|
// Special case 0 milliseconds to be 7 seconds
|
|
//
|
|
|
|
if (dwTimeout == 0) {
|
|
dwTimeout = 7000;
|
|
|
|
} else {
|
|
|
|
//
|
|
// If there is an offset, pick a random number
|
|
// from 0 to dwOffset and then add it to the timeout
|
|
//
|
|
|
|
if (dwOffset) {
|
|
dwOffset = GetTickCount() % dwOffset;
|
|
|
|
dwOffset = dwOffset * 60 * 1000;
|
|
dwTimeout += dwOffset;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Setup the timer
|
|
//
|
|
|
|
if (dwTimeout >= 60000) {
|
|
DebugMsg((DM_VERBOSE, TEXT("GPOThread: Next refresh will happen in %d minutes"),
|
|
((dwTimeout / 1000) / 60)));
|
|
} else {
|
|
DebugMsg((DM_VERBOSE, TEXT("GPOThread: Next refresh will happen in %d seconds"),
|
|
(dwTimeout / 1000)));
|
|
}
|
|
|
|
hHandles[3] = CreateWaitableTimer (NULL, TRUE, NULL);
|
|
|
|
if (hHandles[3] == NULL) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("GPOThread: CreateWaitableTimer failed with error %d"),
|
|
GetLastError()));
|
|
CEvents ev(TRUE, EVENT_FAILED_TIMER);
|
|
ev.AddArg( TEXT("CreateWaitableTimer")); ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
break;
|
|
}
|
|
|
|
DueTime.QuadPart = UInt32x32To64(10000, dwTimeout);
|
|
DueTime.QuadPart *= -1;
|
|
|
|
if (!SetWaitableTimer (hHandles[3], &DueTime, 0, NULL, 0, FALSE)) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("GPOThread: Failed to set timer with error %d"),
|
|
GetLastError()));
|
|
CEvents ev(TRUE, EVENT_FAILED_TIMER);
|
|
ev.AddArg(TEXT("SetWaitableTimer")); ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
break;
|
|
}
|
|
|
|
dwResult = WaitForMultipleObjects( 4, hHandles, FALSE, INFINITE );
|
|
|
|
if ( (dwResult - WAIT_OBJECT_0) == 0 )
|
|
{
|
|
//
|
|
// for machine policy thread, this is a shutdown.
|
|
// for user policy thread, this is a logoff.
|
|
//
|
|
goto ExitLoop;
|
|
}
|
|
else if ( (dwResult - WAIT_OBJECT_0) == 2 ) {
|
|
bForceBkGndFlag = TRUE;
|
|
}
|
|
else if ( dwResult == WAIT_FAILED )
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg( ( DM_WARNING, L"GPOThread: MsgWaitForMultipleObjects with error %d", GetLastError() ) );
|
|
CEvents ev(TRUE, EVENT_FAILED_TIMER);
|
|
ev.AddArg(TEXT("WaitForMultipleObjects")); ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
goto ExitLoop;
|
|
}
|
|
|
|
//
|
|
// Check if we should set the background flag. We offer this
|
|
// option for the test team's automation tests. They need to
|
|
// simulate logon / boot policy without actually logging on or
|
|
// booting the machine.
|
|
//
|
|
|
|
bSetBkGndFlag = TRUE;
|
|
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
|
|
WINLOGON_KEY,
|
|
0, KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
|
|
dwSize = sizeof(bSetBkGndFlag);
|
|
RegQueryValueEx (hKey,
|
|
TEXT("SetGroupPolicyBackgroundFlag"),
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &bSetBkGndFlag,
|
|
&dwSize);
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
|
|
lpGPOInfo->dwFlags &= ~GP_REGPOLICY_CPANEL;
|
|
lpGPOInfo->dwFlags &= ~GP_SLOW_LINK;
|
|
lpGPOInfo->dwFlags &= ~GP_VERBOSE;
|
|
lpGPOInfo->dwFlags &= ~GP_BACKGROUND_THREAD;
|
|
lpGPOInfo->dwFlags &= ~GP_FORCED_REFRESH;
|
|
|
|
//
|
|
// In case of forced refresh flag, we override the extensions nobackground policy and prevent
|
|
// it from getting skipped early on in the processing. We bypass the history logic and force
|
|
// policy to be applied for extensions that do not care abt. whether they are run in the
|
|
// foreground or background. for only foreground extensions we write a registry value saying
|
|
// that the extension needs to override the history logic when they get applied in the foreground
|
|
// next.
|
|
// In addition we pulse the needfg event so that the calling app knows a reboot/relogon is needed
|
|
// for application of fgonly extensions
|
|
//
|
|
|
|
if (bForceBkGndFlag) {
|
|
lpGPOInfo->dwFlags |= GP_FORCED_REFRESH;
|
|
}
|
|
|
|
//
|
|
// Set the background thread flag so components known
|
|
// when they are being called from the background thread
|
|
// vs the main thread.
|
|
//
|
|
|
|
if (bSetBkGndFlag) {
|
|
lpGPOInfo->dwFlags |= GP_BACKGROUND_THREAD;
|
|
}
|
|
|
|
if ( !lpGPOInfo->bBGCoInitialized && pOle32Api != NULL ) {
|
|
|
|
hr = pOle32Api->pfnCoInitializeEx( NULL, COINIT_MULTITHREADED );
|
|
if ( SUCCEEDED(hr) ) {
|
|
lpGPOInfo->bBGCoInitialized = TRUE;
|
|
}
|
|
}
|
|
|
|
ProcessGPOs(lpGPOInfo);
|
|
|
|
if ( lpGPOInfo->dwFlags & GP_MACHINE ) {
|
|
|
|
//
|
|
// Delete garbage-collectable namespaces under root\rsop that are
|
|
// older than 1 week. We can have a policy to configure this time-to-live value.
|
|
//
|
|
|
|
TTLMinutes = 24 * 60;
|
|
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
|
|
WINLOGON_KEY,
|
|
0, KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
|
|
dwSize = sizeof(TTLMinutes);
|
|
RegQueryValueEx (hKey,
|
|
TEXT("RSoPGarbageCollectionInterval"),
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &TTLMinutes,
|
|
&dwSize);
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
|
|
SYSTEM_POLICIES_KEY,
|
|
0, KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
|
|
dwSize = sizeof(TTLMinutes);
|
|
RegQueryValueEx (hKey,
|
|
TEXT("RSoPGarbageCollectionInterval"),
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &TTLMinutes,
|
|
&dwSize);
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Synchronize with other processes that may be concurrently creating namespaces,
|
|
// during diagnostic mode or planning mode data generation.
|
|
//
|
|
|
|
XCriticalPolicySection xCritSect( EnterCriticalPolicySection(TRUE ) );
|
|
if ( xCritSect )
|
|
GarbageCollectNamespaces(TTLMinutes);
|
|
}
|
|
|
|
CloseHandle (hHandles[3]);
|
|
hHandles[3] = NULL;
|
|
}
|
|
|
|
ExitLoop:
|
|
|
|
//
|
|
// Cleanup
|
|
//
|
|
|
|
if (hHandles[3]) {
|
|
CloseHandle (hHandles[3]);
|
|
}
|
|
|
|
if (lpGPOInfo->hToken) {
|
|
CloseHandle (lpGPOInfo->hToken);
|
|
}
|
|
|
|
if (lpGPOInfo->hEvent) {
|
|
CloseHandle (lpGPOInfo->hEvent);
|
|
}
|
|
|
|
if (lpGPOInfo->hKeyRoot && (lpGPOInfo->hKeyRoot != HKEY_LOCAL_MACHINE)) {
|
|
RegCloseKey(lpGPOInfo->hKeyRoot);
|
|
}
|
|
|
|
if (lpGPOInfo->hTriggerEvent) {
|
|
CloseHandle (lpGPOInfo->hTriggerEvent);
|
|
}
|
|
|
|
if (lpGPOInfo->hForceTriggerEvent) {
|
|
CloseHandle (lpGPOInfo->hForceTriggerEvent);
|
|
}
|
|
|
|
if (lpGPOInfo->hNotifyEvent) {
|
|
CloseHandle (lpGPOInfo->hNotifyEvent);
|
|
}
|
|
|
|
if (lpGPOInfo->hNeedFGEvent) {
|
|
CloseHandle (lpGPOInfo->hNeedFGEvent);
|
|
}
|
|
|
|
if (lpGPOInfo->hDoneEvent) {
|
|
CloseHandle (lpGPOInfo->hDoneEvent);
|
|
}
|
|
|
|
if ( lpGPOInfo->bBGCoInitialized ) {
|
|
|
|
pOle32Api = LoadOle32Api();
|
|
if ( pOle32Api == NULL ) {
|
|
DebugMsg((DM_WARNING, TEXT("GPOThread: Failed to load ole32.dll.") ));
|
|
}
|
|
else {
|
|
pOle32Api->pfnCoUnInitialize();
|
|
lpGPOInfo->bBGCoInitialized = FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
EnterCriticalSection( &g_GPOCS );
|
|
|
|
if ( lpGPOInfo->dwFlags & GP_MACHINE ) {
|
|
|
|
if ( g_pMachGPInfo )
|
|
LocalFree( g_pMachGPInfo );
|
|
|
|
g_pMachGPInfo = 0;
|
|
} else {
|
|
|
|
if ( g_pUserGPInfo )
|
|
LocalFree( g_pUserGPInfo );
|
|
|
|
g_pUserGPInfo = 0;
|
|
}
|
|
|
|
LeaveCriticalSection( &g_GPOCS );
|
|
|
|
if (lpGPOInfo->lpwszSidUser)
|
|
DeleteSidString( lpGPOInfo->lpwszSidUser );
|
|
|
|
if (lpGPOInfo->szName)
|
|
LocalFree(lpGPOInfo->szName);
|
|
|
|
if (lpGPOInfo->szTargetName)
|
|
LocalFree(lpGPOInfo->szTargetName);
|
|
|
|
LocalFree (lpGPOInfo);
|
|
|
|
FreeLibraryAndExitThread (hInst, 0);
|
|
return 0;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// GPOExceptionFilter()
|
|
//
|
|
// Purpose: Exception filter when procssing GPO extensions
|
|
//
|
|
// Parameters: pExceptionPtrs - Pointer to exception pointer
|
|
//
|
|
// Returns: EXCEPTION_EXECUTE_HANDLER
|
|
//
|
|
//*************************************************************
|
|
|
|
LONG GPOExceptionFilter( PEXCEPTION_POINTERS pExceptionPtrs )
|
|
{
|
|
PEXCEPTION_RECORD pExr = pExceptionPtrs->ExceptionRecord;
|
|
PCONTEXT pCxr = pExceptionPtrs->ContextRecord;
|
|
|
|
DebugMsg(( DM_WARNING, L"GPOExceptionFilter: Caught exception 0x%x, exr = 0x%x, cxr = 0x%x\n",
|
|
pExr->ExceptionCode, pExr, pCxr ));
|
|
|
|
DmAssert( ! L"Caught unhandled exception when processing group policy extension" );
|
|
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
|
|
BOOL WINAPI
|
|
GetFgPolicySetting( HKEY hKeyRoot );
|
|
|
|
//*************************************************************
|
|
//
|
|
// ProcessGPOs()
|
|
//
|
|
// Purpose: Processes GPOs
|
|
//
|
|
// Parameters: lpGPOInfo - GPO information
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL ProcessGPOs (LPGPOINFO lpGPOInfo)
|
|
{
|
|
BOOL bRetVal = FALSE;
|
|
DWORD dwThreadID;
|
|
HANDLE hThread;
|
|
DWORD dwType, dwSize, dwResult;
|
|
HKEY hKey;
|
|
BOOL bResult;
|
|
PDOMAIN_CONTROLLER_INFO pDCI = NULL;
|
|
PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsInfo = NULL;
|
|
LPTSTR lpName = NULL;
|
|
LPTSTR lpDomainDN = NULL;
|
|
LPTSTR lpComputerName;
|
|
PGROUP_POLICY_OBJECT lpGPO = NULL;
|
|
PGROUP_POLICY_OBJECT lpGPOTemp;
|
|
BOOL bAllSkipped;
|
|
LPGPEXT lpExt;
|
|
LPGPINFOHANDLE pGPHandle = NULL;
|
|
ASYNCCOMPLETIONHANDLE pAsyncHandle = 0;
|
|
HANDLE hOldToken;
|
|
UINT uChangedExtensionCount = 0;
|
|
PNETAPI32_API pNetAPI32;
|
|
DWORD dwUserPolicyMode = 0;
|
|
DWORD dwCurrentTime = 0;
|
|
INT iRole;
|
|
BOOL bSlow;
|
|
BOOL bForceNeedFG = FALSE;
|
|
CLocator locator;
|
|
RSOPEXTSTATUS gpCoreStatus;
|
|
XLastError xe;
|
|
LPWSTR szNetworkName = 0;
|
|
FgPolicyRefreshInfo info = { GP_ReasonUnknown, GP_ModeAsyncForeground };
|
|
PTOKEN_GROUPS pTokenGroups = NULL;
|
|
BOOL bAsyncFg = lpGPOInfo->dwFlags & GP_ASYNC_FOREGROUND ? TRUE : FALSE;
|
|
LPWSTR szPolicyMode = 0;
|
|
|
|
if ( lpGPOInfo->dwFlags & GP_ASYNC_FOREGROUND )
|
|
{
|
|
szPolicyMode = L"Async forground";
|
|
}
|
|
else if ( !( lpGPOInfo->dwFlags & GP_BACKGROUND_THREAD ) )
|
|
{
|
|
szPolicyMode = L"Sync forground";
|
|
}
|
|
else
|
|
{
|
|
szPolicyMode = L"Background";
|
|
}
|
|
|
|
//
|
|
// Allow debugging level to be changed dynamically between
|
|
// policy refreshes.
|
|
//
|
|
|
|
InitDebugSupport( FALSE );
|
|
|
|
//
|
|
// Debug spew
|
|
//
|
|
|
|
memset(&gpCoreStatus, 0, sizeof(gpCoreStatus));
|
|
|
|
|
|
if (lpGPOInfo->dwFlags & GP_MACHINE) {
|
|
DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs:")));
|
|
DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs:")));
|
|
DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs: Starting computer Group Policy (%s) processing..."),szPolicyMode ));
|
|
DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs:")));
|
|
DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs:")));
|
|
} else {
|
|
DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs:")));
|
|
DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs:")));
|
|
DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs: Starting user Group Policy (%s) processing..."),szPolicyMode ));
|
|
DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs:")));
|
|
DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs:")));
|
|
}
|
|
|
|
if ( !( lpGPOInfo->dwFlags & GP_MACHINE ) && lpGPOInfo->lpwszSidUser )
|
|
{
|
|
lpGPOInfo->lpwszSidUser = GetSidString( lpGPOInfo->hToken );
|
|
if ( lpGPOInfo->lpwszSidUser == 0 )
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: GetSidString failed.")));
|
|
CEvents ev(TRUE, EVENT_FAILED_GET_SID); ev.Report();
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
GetSystemTimeAsFileTime(&gpCoreStatus.ftStartTime);
|
|
gpCoreStatus.bValid = TRUE;
|
|
|
|
//
|
|
// Check if we should be verbose to the event log
|
|
//
|
|
|
|
if (CheckForVerbosePolicy()) {
|
|
lpGPOInfo->dwFlags |= GP_VERBOSE;
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Verbose output to eventlog requested.")));
|
|
}
|
|
|
|
if (lpGPOInfo->dwFlags & GP_VERBOSE) {
|
|
if (lpGPOInfo->dwFlags & GP_MACHINE) {
|
|
CEvents ev(FALSE, EVENT_START_MACHINE_POLICY); ev.Report();
|
|
} else {
|
|
CEvents ev(FALSE, EVENT_START_USER_POLICY); ev.Report();
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Claim the critical section
|
|
//
|
|
|
|
lpGPOInfo->hCritSection = EnterCriticalPolicySection((lpGPOInfo->dwFlags & GP_MACHINE));
|
|
|
|
if (!lpGPOInfo->hCritSection) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to claim the policy critical section with %d."),
|
|
GetLastError()));
|
|
CEvents ev(TRUE, EVENT_FAILED_CRITICAL_SECTION);
|
|
ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Set the security on the Group Policy registry key
|
|
//
|
|
|
|
if (!MakeRegKeySecure((lpGPOInfo->dwFlags & GP_MACHINE) ? NULL : lpGPOInfo->hToken,
|
|
lpGPOInfo->hKeyRoot,
|
|
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Group Policy"))) {
|
|
xe = ERROR_ACCESS_DENIED;
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to secure reg key.")));
|
|
CEvents ev(TRUE, EVENT_FAILED_CREATE);
|
|
ev.AddArg(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Group Policy"));
|
|
ev.AddArgWin32Error(xe);
|
|
ev.Report();
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Check if user's sid has changed
|
|
// Check the change in user's sid before doing any rsop logging..
|
|
//
|
|
|
|
if ( !CheckForChangedSid( lpGPOInfo, &locator ) ) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Check for changed sid failed")));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// This flag will be used for all further Rsop Logging..
|
|
//
|
|
|
|
lpGPOInfo->bRsopLogging = RsopLoggingEnabled();
|
|
|
|
//
|
|
// Load netapi32
|
|
//
|
|
|
|
pNetAPI32 = LoadNetAPI32();
|
|
|
|
if (!pNetAPI32) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to load netapi32 with %d."),
|
|
GetLastError()));
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Get the role of this computer
|
|
//
|
|
|
|
if (!GetMachineRole (&iRole)) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to get the role of the computer.")));
|
|
CEvents ev(TRUE, EVENT_FAILED_ROLE); ev.Report();
|
|
goto Exit;
|
|
}
|
|
|
|
lpGPOInfo->iMachineRole = iRole;
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Machine role is %d."), iRole));
|
|
|
|
if (lpGPOInfo->dwFlags & GP_VERBOSE) {
|
|
|
|
switch (iRole) {
|
|
case 0:
|
|
{
|
|
CEvents ev(FALSE, EVENT_ROLE_STANDALONE); ev.Report();
|
|
break;
|
|
}
|
|
|
|
case 1:
|
|
{
|
|
CEvents ev(FALSE, EVENT_ROLE_DOWNLEVEL_DOMAIN); ev.Report();
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
CEvents ev(FALSE, EVENT_ROLE_DS_DOMAIN); ev.Report();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If we are going to apply policy from the DS
|
|
// query for the user's DN name, domain name, etc
|
|
//
|
|
|
|
if (lpGPOInfo->dwFlags & GP_APPLY_DS_POLICY)
|
|
{
|
|
//
|
|
// Query for the user's domain name
|
|
//
|
|
|
|
if (!ImpersonateUser(lpGPOInfo->hToken, &hOldToken))
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to impersonate user")));
|
|
goto Exit;
|
|
}
|
|
|
|
lpDomainDN = MyGetDomainDNSName ();
|
|
|
|
RevertToUser(&hOldToken);
|
|
|
|
if (!lpDomainDN) {
|
|
xe = GetLastError();
|
|
dwResult = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: MyGetDomainName failed with %d."),
|
|
dwResult));
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Query for the DS server name
|
|
//
|
|
DWORD dwAdapterIndex = (DWORD) -1;
|
|
|
|
dwResult = GetDomainControllerInfo( pNetAPI32,
|
|
lpDomainDN,
|
|
DS_DIRECTORY_SERVICE_REQUIRED |
|
|
DS_RETURN_DNS_NAME |
|
|
((lpGPOInfo->dwFlags & GP_BACKGROUND_THREAD) ? DS_BACKGROUND_ONLY : 0),
|
|
lpGPOInfo->hKeyRoot,
|
|
&pDCI,
|
|
&bSlow,
|
|
&dwAdapterIndex );
|
|
|
|
if (dwResult != ERROR_SUCCESS) {
|
|
xe = dwResult;
|
|
|
|
if ((dwResult == ERROR_BAD_NETPATH) ||
|
|
(dwResult == ERROR_NETWORK_UNREACHABLE) ||
|
|
(dwResult == ERROR_NO_SUCH_DOMAIN)) {
|
|
|
|
//
|
|
// couldn't find DC. Nothing more we can do, abort
|
|
//
|
|
if ( (!(lpGPOInfo->dwFlags & GP_BACKGROUND_THREAD)) ||
|
|
(lpGPOInfo->dwFlags & GP_ASYNC_FOREGROUND) ||
|
|
(lpGPOInfo->iMachineRole == 3) )
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: The DC for domain %s is not available. aborting"),
|
|
lpDomainDN));
|
|
|
|
CEvents ev(TRUE, EVENT_FAILED_DSNAME);
|
|
ev.AddArgWin32Error(dwResult); ev.Report();
|
|
}
|
|
else {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: The DC for domain %s is not available."), lpDomainDN));
|
|
|
|
if (lpGPOInfo->dwFlags & GP_VERBOSE)
|
|
{
|
|
CEvents ev(FALSE, EVENT_FAILED_DSNAME);
|
|
ev.AddArgWin32Error(dwResult); ev.Report();
|
|
}
|
|
}
|
|
} else {
|
|
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: DSGetDCName failed with %d."),
|
|
dwResult));
|
|
CEvents ev(TRUE, EVENT_FAILED_DSNAME);
|
|
ev.AddArgWin32Error(dwResult); ev.Report();
|
|
}
|
|
|
|
goto Exit;
|
|
} else {
|
|
|
|
//
|
|
// success, slow link?
|
|
//
|
|
if (bSlow) {
|
|
lpGPOInfo->dwFlags |= GP_SLOW_LINK;
|
|
if (lpGPOInfo->dwFlags & GP_VERBOSE) {
|
|
CEvents ev(FALSE, EVENT_SLOWLINK); ev.Report();
|
|
}
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: A slow link was detected.")));
|
|
}
|
|
|
|
if ( ( lpGPOInfo->dwFlags & GP_MACHINE ) != 0 )
|
|
{
|
|
dwResult = GetNetworkName( &szNetworkName, dwAdapterIndex );
|
|
if ( dwResult != ERROR_SUCCESS )
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: GetNetworkName failed with %d."), dwResult ));
|
|
}
|
|
else
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: network name is %s"), szNetworkName ? szNetworkName : L"" ));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the user's DN name
|
|
//
|
|
|
|
if (!ImpersonateUser(lpGPOInfo->hToken, &hOldToken)) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to impersonate user")));
|
|
goto Exit;
|
|
}
|
|
|
|
lpName = MyGetUserName (NameFullyQualifiedDN);
|
|
|
|
RevertToUser(&hOldToken);
|
|
|
|
if (!lpName) {
|
|
xe = GetLastError();
|
|
dwResult = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: MyGetUserName failed with %d."),
|
|
dwResult));
|
|
CEvents ev(TRUE, EVENT_FAILED_USERNAME);
|
|
ev.AddArgWin32Error(dwResult); ev.Report();
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
if (lpGPOInfo->dwFlags & GP_VERBOSE) {
|
|
CEvents ev(FALSE, EVENT_USERNAME); ev.AddArg(L"%.500s", lpName); ev.Report();
|
|
CEvents ev1(FALSE, EVENT_DOMAINNAME); ev1.AddArg(L"%.500s", lpDomainDN); ev1.Report();
|
|
CEvents ev2(FALSE, EVENT_DCNAME); ev2.AddArg(pDCI->DomainControllerName); ev2.Report();
|
|
}
|
|
|
|
lpGPOInfo->lpDNName = lpName;
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: User name is: %s, Domain name is: %s"),
|
|
lpName, lpDomainDN));
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Domain controller is: %s Domain DN is %s"),
|
|
pDCI->DomainControllerName, lpDomainDN));
|
|
|
|
|
|
if (!(lpGPOInfo->dwFlags & GP_MACHINE)) {
|
|
CallDFS(pDCI->DomainName, pDCI->DomainControllerName);
|
|
}
|
|
|
|
|
|
//
|
|
// Save the DC name in the registry for future reference
|
|
//
|
|
DWORD dwDisp;
|
|
|
|
if (RegCreateKeyEx (lpGPOInfo->hKeyRoot,
|
|
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Group Policy\\History"),
|
|
0, NULL, REG_OPTION_NON_VOLATILE,
|
|
KEY_SET_VALUE, NULL, &hKey, &dwDisp) == ERROR_SUCCESS)
|
|
{
|
|
dwSize = (lstrlen(pDCI->DomainControllerName) + 1) * sizeof(TCHAR);
|
|
RegSetValueEx (hKey, TEXT("DCName"), 0, REG_SZ,
|
|
(LPBYTE) pDCI->DomainControllerName, dwSize);
|
|
|
|
if ( ( lpGPOInfo->dwFlags & GP_MACHINE ) != 0 )
|
|
{
|
|
LPWSTR szTemp = szNetworkName ? szNetworkName : L"";
|
|
|
|
dwSize = ( wcslen( szTemp ) + 1 ) * sizeof( WCHAR );
|
|
RegSetValueEx( hKey,
|
|
L"NetworkName",
|
|
0,
|
|
REG_SZ,
|
|
(LPBYTE) szTemp,
|
|
dwSize );
|
|
}
|
|
RegCloseKey (hKey);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Read the group policy extensions from the registry
|
|
//
|
|
|
|
if ( !ReadGPExtensions( lpGPOInfo ) )
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: ReadGPExtensions failed.")));
|
|
CEvents ev(TRUE, EVENT_READ_EXT_FAILED); ev.Report();
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Get the user policy mode if appropriate
|
|
//
|
|
|
|
if (!(lpGPOInfo->dwFlags & GP_MACHINE)) {
|
|
|
|
DWORD dwRet;
|
|
|
|
dwRet = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
|
|
SYSTEM_POLICIES_KEY,
|
|
0, KEY_READ, &hKey);
|
|
|
|
if (dwRet == ERROR_SUCCESS) {
|
|
|
|
dwSize = sizeof(dwUserPolicyMode);
|
|
dwRet = RegQueryValueEx (hKey,
|
|
TEXT("UserPolicyMode"),
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwUserPolicyMode,
|
|
&dwSize);
|
|
|
|
if (dwRet != ERROR_SUCCESS)
|
|
{
|
|
if (dwRet != ERROR_FILE_NOT_FOUND)
|
|
{
|
|
xe = dwRet;
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Read userpolicy mode failed with %d."), dwRet));
|
|
CEvents ev(TRUE, EVENT_USERMODE_FAILED); ev.AddArgWin32Error(dwRet); ev.Report();
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
else {
|
|
if (dwRet != ERROR_FILE_NOT_FOUND)
|
|
{
|
|
xe = dwRet;
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Read userpolicy mode failed with %d."), dwRet));
|
|
CEvents ev(TRUE, EVENT_USERMODE_FAILED); ev.AddArgWin32Error(dwRet); ev.Report();
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if (dwUserPolicyMode > 0) {
|
|
|
|
if (!(lpGPOInfo->dwFlags & GP_APPLY_DS_POLICY)) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Loopback is not allowed for downlevel or local user accounts. Loopback will be disabled.")));
|
|
CEvents ev(FALSE, EVENT_LOOPBACK_DISABLED1); ev.Report();
|
|
dwUserPolicyMode = 0;
|
|
}
|
|
|
|
if (dwUserPolicyMode > 0) {
|
|
if (lpGPOInfo->iMachineRole < 2) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Loopback is not allowed on machines joined to a downlevel domain or running standalone. Loopback will be disabled.")));
|
|
CEvents ev(TRUE, EVENT_LOOPBACK_DISABLED2); ev.Report();
|
|
dwUserPolicyMode = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If the user and computer are in different forests, check policy to override mode with loopback replace.
|
|
if ( lpGPOInfo->dwFlags & GP_APPLY_DS_POLICY )
|
|
{
|
|
BOOL bInSameForest = FALSE;
|
|
dwRet = CheckUserInMachineForest(lpGPOInfo->hToken, &bInSameForest);
|
|
if ( dwRet != ERROR_SUCCESS )
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to check whether user is in machine forest with %d."), dwRet));
|
|
|
|
CEvents ev(TRUE, EVENT_X_FOREST_DISCOVERY_FAILED); ev.AddArgWin32Error(dwRet); ev.Report();
|
|
goto Exit;
|
|
}
|
|
|
|
if ( !bInSameForest )
|
|
{
|
|
DWORD dwAllowXForestPolicyAndRUP = 0;
|
|
|
|
dwRet = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
|
|
SYSTEM_POLICIES_KEY,
|
|
0, KEY_READ, &hKey);
|
|
|
|
if (dwRet == ERROR_SUCCESS) {
|
|
|
|
dwSize = sizeof(dwAllowXForestPolicyAndRUP);
|
|
dwRet = RegQueryValueEx (hKey,
|
|
TEXT("AllowX-ForestPolicy-and-RUP"),
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE) &dwAllowXForestPolicyAndRUP,
|
|
&dwSize);
|
|
|
|
if (dwRet != ERROR_SUCCESS)
|
|
{
|
|
if (dwRet != ERROR_FILE_NOT_FOUND)
|
|
{
|
|
xe = dwRet;
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Read allow xforest policy failed with %d."), dwRet));
|
|
CEvents ev(TRUE, EVENT_USERMODE_FAILED); ev.AddArgWin32Error(dwRet); ev.Report();
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
else {
|
|
if (dwRet != ERROR_FILE_NOT_FOUND)
|
|
{
|
|
xe = dwRet;
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Read allow xforest policy failed with %d."), dwRet));
|
|
CEvents ev(TRUE, EVENT_USERMODE_FAILED); ev.AddArgWin32Error(dwRet); ev.Report();
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if ( dwAllowXForestPolicyAndRUP != 1 )
|
|
{
|
|
dwUserPolicyMode = 2;
|
|
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Loopback enforced for user logging in from different forest.")));
|
|
|
|
// Only log the xforest disabled event for foreground policy application
|
|
if ( ! ( lpGPOInfo->dwFlags & GP_BACKGROUND_THREAD ) )
|
|
{
|
|
CEvents ev(EVENT_WARNING_TYPE, EVENT_X_FOREST_GP_DISABLED); ev.AddArg(lpGPOInfo->lpDNName); ev.Report();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if (!ImpersonateUser(lpGPOInfo->hToken, &hOldToken)) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to impersonate user")));
|
|
CEvents ev(TRUE, EVENT_FAILED_IMPERSONATE);
|
|
ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Read each of the extensions status..
|
|
//
|
|
|
|
if (!ReadExtStatus(lpGPOInfo)) {
|
|
// event logged by ReadExtStatus
|
|
xe = GetLastError();
|
|
RevertToUser(&hOldToken);
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Check if any extensions can be skipped. If there is ever a case where
|
|
// all extensions can be skipped, then exit successfully right after this check.
|
|
// Currently RegistryExtension is always run unless there are no GPO changes,
|
|
// but the GPO changes check is done much later.
|
|
//
|
|
|
|
if ( !CheckForSkippedExtensions( lpGPOInfo, FALSE ) ) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Checking extensions for skipping failed")));
|
|
//
|
|
// LogEvent() is called by CheckForSkippedExtensions()
|
|
//
|
|
RevertToUser(&hOldToken);
|
|
goto Exit;
|
|
}
|
|
|
|
LPWSTR szSiteName;
|
|
dwResult = pNetAPI32->pfnDsGetSiteName(0, &szSiteName);
|
|
|
|
if ( dwResult != ERROR_SUCCESS )
|
|
{
|
|
if ( dwResult == ERROR_NO_SITENAME )
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: No site name defined. Skipping site policy.")));
|
|
|
|
if ( lpGPOInfo->dwFlags & GP_VERBOSE )
|
|
{
|
|
CEvents ev(TRUE, EVENT_NO_SITENAME);
|
|
ev.Report();
|
|
}
|
|
szSiteName = 0;
|
|
}
|
|
else
|
|
{
|
|
xe = dwResult;
|
|
CEvents ev(TRUE, EVENT_FAILED_QUERY_SITE);
|
|
ev.AddArgWin32Error(dwResult); ev.Report();
|
|
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: DSGetSiteName failed with %d, exiting."), dwResult));
|
|
RevertToUser(&hOldToken);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
lpGPOInfo->szSiteName = szSiteName;
|
|
|
|
//
|
|
// Query for the GPO list based upon the mode
|
|
//
|
|
// 0 is normal
|
|
// 1 is merge. Merge user list + machine list
|
|
// 2 is replace. use machine list instead of user list
|
|
//
|
|
|
|
|
|
if (dwUserPolicyMode == 0) {
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Calling GetGPOInfo for normal policy mode")));
|
|
|
|
bResult = GetGPOInfo ((lpGPOInfo->dwFlags & GP_MACHINE) ? GPO_LIST_FLAG_MACHINE : 0,
|
|
lpDomainDN, lpName, NULL, &lpGPOInfo->lpGPOList,
|
|
&lpGPOInfo->lpSOMList,
|
|
&lpGPOInfo->lpGpContainerList,
|
|
pNetAPI32, TRUE, 0, szSiteName, 0, &locator);
|
|
|
|
if (!bResult) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: GetGPOInfo failed.")));
|
|
CEvents ev(TRUE, EVENT_GPO_QUERY_FAILED); ev.Report();
|
|
}
|
|
|
|
|
|
} else if (dwUserPolicyMode == 2) {
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Calling GetGPOInfo for replacement user policy mode")));
|
|
|
|
lpComputerName = MyGetComputerName (NameFullyQualifiedDN);
|
|
|
|
if (lpComputerName) {
|
|
|
|
PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsInfo = NULL;
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Using computer name %s for query."), lpComputerName));
|
|
|
|
dwResult = pNetAPI32->pfnDsRoleGetPrimaryDomainInformation( NULL,
|
|
DsRolePrimaryDomainInfoBasic,
|
|
(PBYTE *)&pDsInfo );
|
|
|
|
if ( dwResult == 0 )
|
|
{
|
|
bResult = GetGPOInfo (0, pDsInfo->DomainNameDns, lpComputerName, NULL,
|
|
&lpGPOInfo->lpGPOList,
|
|
&lpGPOInfo->lpLoopbackSOMList,
|
|
&lpGPOInfo->lpLoopbackGpContainerList,
|
|
pNetAPI32, FALSE, 0, szSiteName, 0, &locator );
|
|
|
|
if (!bResult) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: GetGPOInfo failed.")));
|
|
CEvents ev(TRUE, EVENT_GPO_QUERY_FAILED); ev.Report();
|
|
}
|
|
|
|
pNetAPI32->pfnDsRoleFreeMemory( pDsInfo );
|
|
}
|
|
else
|
|
{
|
|
xe = dwResult;
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to get the computer domain name with %d"),
|
|
GetLastError()));
|
|
CEvents ev(TRUE, EVENT_NO_MACHINE_DOMAIN);
|
|
ev.AddArg(lpComputerName); ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
bResult = FALSE;
|
|
}
|
|
LocalFree (lpComputerName);
|
|
|
|
} else {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to get the computer name with %d"),
|
|
GetLastError()));
|
|
|
|
CEvents ev(TRUE, EVENT_FAILED_MACHINENAME);
|
|
ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
bResult = FALSE;
|
|
}
|
|
} else {
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Calling GetGPOInfo for merging user policy mode")));
|
|
|
|
lpComputerName = MyGetComputerName (NameFullyQualifiedDN);
|
|
|
|
if (lpComputerName) {
|
|
|
|
lpGPOInfo->lpGPOList = NULL;
|
|
bResult = GetGPOInfo (0, lpDomainDN, lpName, NULL,
|
|
&lpGPOInfo->lpGPOList,
|
|
&lpGPOInfo->lpSOMList,
|
|
&lpGPOInfo->lpGpContainerList,
|
|
pNetAPI32, FALSE, 0, szSiteName, 0, &locator );
|
|
|
|
if (bResult) {
|
|
|
|
PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsInfo = NULL;
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Using computer name %s for query."), lpComputerName));
|
|
|
|
lpGPO = NULL;
|
|
|
|
dwResult = pNetAPI32->pfnDsRoleGetPrimaryDomainInformation( NULL,
|
|
DsRolePrimaryDomainInfoBasic,
|
|
(PBYTE *)&pDsInfo );
|
|
|
|
if ( dwResult == 0 )
|
|
{
|
|
bResult = GetGPOInfo (0, pDsInfo->DomainNameDns, lpComputerName, NULL,
|
|
&lpGPO,
|
|
&lpGPOInfo->lpLoopbackSOMList,
|
|
&lpGPOInfo->lpLoopbackGpContainerList,
|
|
pNetAPI32, FALSE, 0, szSiteName, 0, &locator );
|
|
|
|
if (bResult) {
|
|
|
|
if (lpGPOInfo->lpGPOList && lpGPO) {
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Both user and machine lists are defined. Merging them together.")));
|
|
|
|
//
|
|
// Need to merge the lists together
|
|
//
|
|
|
|
lpGPOTemp = lpGPOInfo->lpGPOList;
|
|
|
|
while (lpGPOTemp->pNext) {
|
|
lpGPOTemp = lpGPOTemp->pNext;
|
|
}
|
|
|
|
lpGPOTemp->pNext = lpGPO;
|
|
|
|
} else if (!lpGPOInfo->lpGPOList && lpGPO) {
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Only machine list is defined.")));
|
|
lpGPOInfo->lpGPOList = lpGPO;
|
|
|
|
} else {
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Only user list is defined.")));
|
|
}
|
|
|
|
} else {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: GetGPOInfo failed for computer name.")));
|
|
CEvents ev(TRUE, EVENT_GPO_QUERY_FAILED); ev.Report();
|
|
}
|
|
|
|
pNetAPI32->pfnDsRoleFreeMemory( pDsInfo );
|
|
}
|
|
else
|
|
{
|
|
xe = dwResult;
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to get the computer domain name with %d"),
|
|
GetLastError()));
|
|
CEvents ev(TRUE, EVENT_NO_MACHINE_DOMAIN);
|
|
ev.AddArg(lpComputerName); ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
bResult = FALSE;
|
|
}
|
|
|
|
} else {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: GetGPOInfo failed for user name.")));
|
|
CEvents ev(TRUE, EVENT_GPO_QUERY_FAILED); ev.Report();
|
|
}
|
|
|
|
LocalFree (lpComputerName);
|
|
|
|
} else {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to get the computer name with %d"),
|
|
GetLastError()));
|
|
CEvents ev(TRUE, EVENT_FAILED_MACHINENAME);
|
|
ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
bResult = FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if (!RevertToUser(&hOldToken)) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to revert to self")));
|
|
}
|
|
|
|
|
|
if (!bResult) {
|
|
goto Exit;
|
|
}
|
|
|
|
bResult = SetupGPOFilter( lpGPOInfo );
|
|
|
|
if (!bResult) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: SetupGPOFilter failed.")));
|
|
CEvents ev(TRUE, EVENT_SETUP_GPOFILTER_FAILED); ev.Report();
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Log Gpo info to WMI's database
|
|
//
|
|
|
|
//
|
|
// Need to check if the security group membership has changed the first time around
|
|
//
|
|
|
|
if ( !(lpGPOInfo->dwFlags & GP_BACKGROUND_THREAD) || (lpGPOInfo->dwFlags & GP_ASYNC_FOREGROUND) ) {
|
|
|
|
if ((lpGPOInfo->dwFlags & GP_MACHINE) && (lpGPOInfo->dwFlags & GP_APPLY_DS_POLICY)) {
|
|
|
|
|
|
HANDLE hLocToken=NULL;
|
|
|
|
//
|
|
// if it is machine policy processing, get the machine token so that we can check
|
|
// security group membership using the right token. This causes GetMachineToken to be called twice
|
|
// but moving it to the beginning requires too much change.
|
|
//
|
|
|
|
|
|
hLocToken = GetMachineToken();
|
|
|
|
if (hLocToken) {
|
|
CheckGroupMembership( lpGPOInfo, hLocToken, &lpGPOInfo->bMemChanged, &lpGPOInfo->bUserLocalMemChanged, &pTokenGroups);
|
|
CloseHandle(hLocToken);
|
|
}
|
|
else {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to get the machine token with %d"), GetLastError()));
|
|
goto Exit;
|
|
}
|
|
}
|
|
else {
|
|
|
|
//
|
|
// In the user case just use the token passed in
|
|
//
|
|
|
|
CheckGroupMembership( lpGPOInfo, lpGPOInfo->hToken, &lpGPOInfo->bMemChanged, &lpGPOInfo->bUserLocalMemChanged, &pTokenGroups);
|
|
}
|
|
}
|
|
|
|
|
|
if ( lpGPOInfo->bRsopLogging )
|
|
{
|
|
if ( SetRsopTargetName(lpGPOInfo) )
|
|
{
|
|
RSOPSESSIONDATA rsopSessionData;
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Logging Data for Target <%s>."), lpGPOInfo->szTargetName));
|
|
|
|
//
|
|
// fill up the rsop data
|
|
//
|
|
rsopSessionData.pwszTargetName = lpGPOInfo->szName;
|
|
rsopSessionData.pwszSOM = lpGPOInfo->lpDNName ? GetSomPath( lpGPOInfo->lpDNName ) : TEXT("Local");
|
|
rsopSessionData.pSecurityGroups = pTokenGroups;
|
|
rsopSessionData.bLogSecurityGroup = lpGPOInfo->bMemChanged || lpGPOInfo->bUserLocalMemChanged;
|
|
rsopSessionData.pwszSite = lpGPOInfo->szSiteName;
|
|
rsopSessionData.bMachine = (lpGPOInfo->dwFlags & GP_MACHINE);
|
|
rsopSessionData.bSlowLink = bSlow;
|
|
rsopSessionData.dwFlags = 0;
|
|
|
|
//
|
|
// Fill in the current time
|
|
//
|
|
|
|
BOOL bStateChanged = FALSE;
|
|
BOOL bLinkChanged = FALSE;
|
|
BOOL bNoState = FALSE;
|
|
|
|
//
|
|
// log RSoP data only when policy has changed
|
|
//
|
|
dwResult = ComparePolicyState( lpGPOInfo, &bLinkChanged, &bStateChanged, &bNoState );
|
|
if ( dwResult != ERROR_SUCCESS )
|
|
{
|
|
DebugMsg((DM_WARNING, L"ProcessGPOs: ComparePolicyState failed %d, assuming policy changed.", dwResult ));
|
|
}
|
|
|
|
//
|
|
// bStateChanged is TRUE if dwResult is not kosher
|
|
//
|
|
|
|
if ( bStateChanged || bNoState || bLinkChanged || (lpGPOInfo->dwFlags & GP_FORCED_REFRESH) ||
|
|
lpGPOInfo->bMemChanged || lpGPOInfo->bUserLocalMemChanged ) {
|
|
|
|
//
|
|
// Any changes get the wmi interface
|
|
//
|
|
|
|
lpGPOInfo->bRsopLogging =
|
|
GetWbemServices( lpGPOInfo, RSOP_NS_DIAG_ROOT, FALSE, &(lpGPOInfo->bRsopCreated), &(lpGPOInfo->pWbemServices) );
|
|
|
|
if (!lpGPOInfo->bRsopLogging)
|
|
{
|
|
CEvents ev(TRUE, EVENT_FAILED_WBEM_SERVICES); ev.Report();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// all changes except link changes
|
|
//
|
|
|
|
if ( bStateChanged || bNoState || (lpGPOInfo->dwFlags & GP_FORCED_REFRESH) )
|
|
{
|
|
//
|
|
// treat no state as newly created
|
|
//
|
|
|
|
lpGPOInfo->bRsopCreated = (lpGPOInfo->bRsopCreated || bNoState);
|
|
|
|
lpGPOInfo->bRsopLogging = LogExtSessionStatus( lpGPOInfo->pWbemServices,
|
|
0,
|
|
TRUE,
|
|
lpGPOInfo->bRsopCreated || (lpGPOInfo->dwFlags & GP_FORCED_REFRESH)
|
|
/* log the event sources only if the namespace is newly created or force refresh */
|
|
);
|
|
|
|
if (!lpGPOInfo->bRsopLogging)
|
|
{
|
|
CEvents ev(TRUE, EVENT_FAILED_RSOPCORE_SESSION_STATUS); ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
}
|
|
else
|
|
{
|
|
bResult = LogRsopData( lpGPOInfo, &rsopSessionData );
|
|
|
|
if (!bResult)
|
|
{
|
|
CEvents ev(TRUE, EVENT_RSOP_FAILED); ev.Report();
|
|
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Error when logging Rsop data. Continuing.")));
|
|
lpGPOInfo->bRsopLogging = FALSE;
|
|
}
|
|
else
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Logged Rsop Data successfully.")));
|
|
//
|
|
// save state only when policy has changed and RSoP logging is successful
|
|
//
|
|
dwResult = SavePolicyState( lpGPOInfo );
|
|
if ( dwResult != ERROR_SUCCESS )
|
|
{
|
|
DebugMsg((DM_WARNING, L"ProcessGPOs: SavePolicyState failed %d.", dwResult ));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( bLinkChanged || lpGPOInfo->bMemChanged || lpGPOInfo->bUserLocalMemChanged )
|
|
{
|
|
bResult = LogSessionData( lpGPOInfo, &rsopSessionData );
|
|
|
|
if (!bResult)
|
|
{
|
|
CEvents ev(TRUE, EVENT_RSOP_FAILED); ev.Report();
|
|
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Error when logging Rsop session. Continuing.")));
|
|
lpGPOInfo->bRsopLogging = FALSE;
|
|
}
|
|
else
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Logged Rsop Session successfully.")));
|
|
//
|
|
// save state only when policy has changed and RSoP logging is successful
|
|
//
|
|
dwResult = SaveLinkState( lpGPOInfo );
|
|
if ( dwResult != ERROR_SUCCESS )
|
|
{
|
|
DebugMsg((DM_WARNING, L"ProcessGPOs: SaveLinkState failed %d.", dwResult ));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Error querying for targetname. not logging Gpos.Error = %d"), GetLastError()));
|
|
}
|
|
}
|
|
|
|
|
|
DebugPrintGPOList( lpGPOInfo );
|
|
|
|
//================================================================
|
|
//
|
|
// Now walk through the list of extensions
|
|
//
|
|
//================================================================
|
|
|
|
EnterCriticalSection( &g_GPOCS );
|
|
|
|
pGPHandle = (LPGPINFOHANDLE) LocalAlloc( LPTR, sizeof(GPINFOHANDLE) );
|
|
|
|
//
|
|
// Continue even if pGPHandle is 0, because all it means is that async completions (if any)
|
|
// will fail. Remove old asynch completion context.
|
|
//
|
|
|
|
if ( pGPHandle )
|
|
{
|
|
pGPHandle->pGPOInfo = lpGPOInfo;
|
|
pGPHandle->bNoBackgroupThread = FALSE; // Defaulting to this
|
|
}
|
|
|
|
if ( lpGPOInfo->dwFlags & GP_MACHINE ) {
|
|
if ( g_pMachGPInfo )
|
|
LocalFree( g_pMachGPInfo );
|
|
|
|
g_pMachGPInfo = pGPHandle;
|
|
} else {
|
|
if ( g_pUserGPInfo )
|
|
LocalFree( g_pUserGPInfo );
|
|
|
|
g_pUserGPInfo = pGPHandle;
|
|
}
|
|
|
|
LeaveCriticalSection( &g_GPOCS );
|
|
|
|
pAsyncHandle = (ASYNCCOMPLETIONHANDLE) pGPHandle;
|
|
|
|
dwCurrentTime = GetCurTime();
|
|
|
|
lpExt = lpGPOInfo->lpExtensions;
|
|
|
|
//
|
|
// Before going in, get the thread token and reset the thread token in case
|
|
// one of the extensions hit an exception.
|
|
//
|
|
|
|
if (!OpenThreadToken (GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_READ,
|
|
TRUE, &hOldToken)) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: OpenThreadToken failed with error %d, assuming thread is not impersonating"), GetLastError()));
|
|
hOldToken = NULL;
|
|
}
|
|
|
|
while ( lpExt )
|
|
{
|
|
BOOL bProcessGPOs, bNoChanges, bUsePerUserLocalSetting;
|
|
PGROUP_POLICY_OBJECT pDeletedGPOList;
|
|
DWORD dwRet;
|
|
HRESULT hrCSERsopStatus = S_OK;
|
|
GPEXTSTATUS gpExtStatus;
|
|
|
|
//
|
|
// Check for early shutdown or user logoff
|
|
//
|
|
if ( (lpGPOInfo->dwFlags & GP_MACHINE) && g_bStopMachGPOProcessing
|
|
|| !(lpGPOInfo->dwFlags & GP_MACHINE) && g_bStopUserGPOProcessing ) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Aborting GPO processing due to machine shutdown or logoff")));
|
|
CEvents ev(TRUE, EVENT_GPO_PROC_STOPPED); ev.Report();
|
|
break;
|
|
|
|
}
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: -----------------------")));
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Processing extension %s"),
|
|
lpExt->lpDisplayName));
|
|
|
|
//
|
|
// The extension has not gotten skipped at this point
|
|
//
|
|
bUsePerUserLocalSetting = lpExt->dwUserLocalSetting && !(lpGPOInfo->dwFlags & GP_MACHINE);
|
|
|
|
//
|
|
// read the CSEs status
|
|
//
|
|
ReadStatus( lpExt->lpKeyName,
|
|
lpGPOInfo,
|
|
bUsePerUserLocalSetting ? lpGPOInfo->lpwszSidUser : 0,
|
|
&gpExtStatus );
|
|
|
|
|
|
//
|
|
// Reset lpGPOInfo->lpGPOList based on extension filter list. If the extension
|
|
// is being called to do delete processing on the history then the current GpoList
|
|
// is null.
|
|
//
|
|
|
|
if ( lpExt->bHistoryProcessing )
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Extension %s is being called to do delete processing on cached history."),
|
|
lpExt->lpDisplayName));
|
|
lpGPOInfo->lpGPOList = NULL;
|
|
}
|
|
else
|
|
FilterGPOs( lpExt, lpGPOInfo );
|
|
|
|
DebugPrintGPOList( lpGPOInfo );
|
|
|
|
if ( !CheckGPOs( lpExt, lpGPOInfo, dwCurrentTime,
|
|
&bProcessGPOs, &bNoChanges, &pDeletedGPOList ) )
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: CheckGPOs failed.")));
|
|
lpExt = lpExt->pNext;
|
|
continue;
|
|
}
|
|
|
|
if ( lpExt->dwNoBackgroundPolicy && ( lpGPOInfo->dwFlags & GP_BACKGROUND_THREAD ) )
|
|
{
|
|
if ( bProcessGPOs && ( pDeletedGPOList || lpGPOInfo->lpGPOList || lpExt->bRsopTransition ) )
|
|
{
|
|
info.mode = GP_ModeSyncForeground;
|
|
info.reason = GP_ReasonCSERequiresSync;
|
|
}
|
|
}
|
|
|
|
if ( lpExt->bSkipped )
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Extension %s skipped with flags 0x%x."),
|
|
lpExt->lpDisplayName, lpGPOInfo->dwFlags));
|
|
if (lpGPOInfo->dwFlags & GP_VERBOSE)
|
|
{
|
|
CEvents ev(FALSE, EVENT_EXT_SKIPPED);
|
|
ev.AddArg(lpExt->lpDisplayName); ev.AddArgHex(lpGPOInfo->dwFlags); ev.Report();
|
|
}
|
|
|
|
lpExt = lpExt->pNext;
|
|
continue;
|
|
}
|
|
|
|
if ( bProcessGPOs )
|
|
{
|
|
if ( !pDeletedGPOList && !lpGPOInfo->lpGPOList && !lpExt->bRsopTransition )
|
|
{
|
|
DebugMsg((DM_VERBOSE,
|
|
TEXT("ProcessGPOs: Extension %s skipped because both deleted and changed GPO lists are empty."),
|
|
lpExt->lpDisplayName ));
|
|
if (lpGPOInfo->dwFlags & GP_VERBOSE)
|
|
{
|
|
CEvents ev(FALSE, EVENT_EXT_HAS_EMPTY_LISTS);
|
|
ev.AddArg(lpExt->lpDisplayName); ev.Report();
|
|
}
|
|
|
|
// clear out any previous extension status if this extension
|
|
// is not applicable any more. We should do this only first time
|
|
// and that means that we should have a state change for rsop.
|
|
// ie. ComparePolicyState should notice a difference first time around
|
|
// and never again for this reason. which means we should have the
|
|
// wbemservices is we could connect to WMI
|
|
|
|
if (lpGPOInfo->pWbemServices)
|
|
{
|
|
// ignore errors since the extension status might not actually be there
|
|
(void)DeleteExtSessionStatus(lpGPOInfo->pWbemServices, lpExt->lpKeyName);
|
|
}
|
|
|
|
lpExt = lpExt->pNext;
|
|
|
|
continue;
|
|
}
|
|
|
|
if ( !(lpExt->bForcedRefreshNextFG) )
|
|
{
|
|
dwRet = ERROR_SUCCESS;
|
|
|
|
if ( lpExt->dwEnableAsynch )
|
|
{
|
|
//
|
|
// Save now to shadow area to avoid race between thread that returns from
|
|
// ProcessGPOList and the thread that does ProcessGroupPolicyCompleted and
|
|
// reads from shadow area.
|
|
//
|
|
if ( ! SaveGPOList( lpExt->lpKeyName, lpGPOInfo,
|
|
HKEY_LOCAL_MACHINE,
|
|
bUsePerUserLocalSetting ? lpGPOInfo->lpwszSidUser : NULL,
|
|
TRUE, lpGPOInfo->lpGPOList ) )
|
|
{
|
|
dwRet = GetLastError();
|
|
}
|
|
}
|
|
|
|
__try
|
|
{
|
|
if ( ERROR_SUCCESS == dwRet )
|
|
{
|
|
dwRet = E_FAIL;
|
|
dwRet = ProcessGPOList( lpExt, lpGPOInfo, pDeletedGPOList,
|
|
lpGPOInfo->lpGPOList, bNoChanges, pAsyncHandle, &hrCSERsopStatus );
|
|
}
|
|
}
|
|
__except( GPOExceptionFilter( GetExceptionInformation() ) )
|
|
{
|
|
|
|
(void) SetThreadToken(NULL, hOldToken); // SetThreadtoken(NULL, NULL) is not expected to fail which the case in the GP Engine threads
|
|
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Extension %s ProcessGroupPolicy threw unhandled exception 0x%x."),
|
|
lpExt->lpDisplayName, GetExceptionCode() ));
|
|
|
|
CEvents ev(TRUE, EVENT_CAUGHT_EXCEPTION);
|
|
ev.AddArg(lpExt->lpDisplayName); ev.AddArgHex(GetExceptionCode()); ev.Report();
|
|
}
|
|
|
|
(void) SetThreadToken(NULL, hOldToken); // SetThreadtoken(NULL, NULL) is not expected to fail which the case in the GP Engine threads
|
|
|
|
FreeGPOList( pDeletedGPOList );
|
|
pDeletedGPOList = NULL;
|
|
|
|
if ( dwRet == ERROR_SUCCESS || dwRet == ERROR_OVERRIDE_NOCHANGES )
|
|
{
|
|
bResult = SaveGPOList( lpExt->lpKeyName, lpGPOInfo,
|
|
HKEY_LOCAL_MACHINE,
|
|
NULL,
|
|
FALSE, lpGPOInfo->lpGPOList );
|
|
|
|
if ( bResult && bUsePerUserLocalSetting )
|
|
{
|
|
bResult = SaveGPOList( lpExt->lpKeyName, lpGPOInfo,
|
|
HKEY_LOCAL_MACHINE,
|
|
lpGPOInfo->lpwszSidUser,
|
|
FALSE, lpGPOInfo->lpGPOList );
|
|
}
|
|
|
|
if ( ! bResult )
|
|
dwRet = GetLastError();
|
|
}
|
|
|
|
if ( dwRet == ERROR_SUCCESS || dwRet == ERROR_OVERRIDE_NOCHANGES )
|
|
{
|
|
//
|
|
// ERROR_OVERRIDE_NOCHANGES means that extension processed the list and so the cached list
|
|
// must be updated, but the extension will be called the next time even if there are
|
|
// no changes. Duplicate the saved data in the PerUserLocalSetting case to allow for deleted
|
|
// GPO information to be generated from a combination of HKCU and HKLM\{sid-user} data.
|
|
//
|
|
|
|
if ( ! bNoChanges )
|
|
{
|
|
uChangedExtensionCount++;
|
|
}
|
|
|
|
//
|
|
// the CSE required sync foreground previously and now returned ERROR_OVERRIDE_NOCHANGES,
|
|
// maintain the require sync foreground refresh flag
|
|
//
|
|
if ( gpExtStatus.dwStatus == ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED &&
|
|
dwRet == ERROR_OVERRIDE_NOCHANGES )
|
|
{
|
|
info.mode = GP_ModeSyncForeground;
|
|
info.reason = GP_ReasonCSESyncError;
|
|
}
|
|
}
|
|
else if ( dwRet == E_PENDING )
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Extension %s ProcessGroupPolicy returned e_pending."),
|
|
lpExt->lpDisplayName));
|
|
}
|
|
else if ( dwRet == ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED )
|
|
{
|
|
//
|
|
// a CSE returned ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED.
|
|
// Raise a flag to sync foreground refresh.
|
|
//
|
|
info.mode = GP_ModeSyncForeground;
|
|
info.reason = GP_ReasonCSERequiresSync;
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Extension %s ProcessGroupPolicy returned sync_foreground."),
|
|
lpExt->lpDisplayName));
|
|
if ( lpGPOInfo->dwFlags & GP_FORCED_REFRESH )
|
|
{
|
|
bForceNeedFG = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Extension %s ProcessGroupPolicy failed, status 0x%x."),
|
|
lpExt->lpDisplayName, dwRet));
|
|
if (lpGPOInfo->dwFlags & GP_VERBOSE) {
|
|
CEvents ev(FALSE, EVENT_CHANGES_FAILED);
|
|
ev.AddArg(lpExt->lpDisplayName); ev.AddArgWin32Error(dwRet); ev.Report();
|
|
}
|
|
|
|
//
|
|
// the CSE required foreground previously and now returned an error,
|
|
// maintain the require sync foreground refresh flag
|
|
//
|
|
if ( gpExtStatus.dwStatus == ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED )
|
|
{
|
|
info.mode = GP_ModeSyncForeground;
|
|
info.reason = GP_ReasonCSESyncError;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Fill up the status data.
|
|
//
|
|
ZeroMemory( &gpExtStatus, sizeof(gpExtStatus) );
|
|
gpExtStatus.dwSlowLink = (lpGPOInfo->dwFlags & GP_SLOW_LINK) != 0;
|
|
gpExtStatus.dwRsopLogging = lpGPOInfo->bRsopLogging;
|
|
gpExtStatus.dwStatus = dwRet;
|
|
gpExtStatus.dwTime = dwCurrentTime;
|
|
gpExtStatus.bForceRefresh = bForceNeedFG;
|
|
gpExtStatus.dwRsopStatus = hrCSERsopStatus;
|
|
|
|
WriteStatus(lpExt->lpKeyName,
|
|
lpGPOInfo,
|
|
bUsePerUserLocalSetting ? lpGPOInfo->lpwszSidUser : NULL,
|
|
&gpExtStatus);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// if it is force refresh next time around, all we need to do is readstatus and
|
|
// writestatus back with forcerefresh value set.
|
|
//
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Extensions %s needs to run in ForeGround. Skipping after setting forceflag."),
|
|
lpExt->lpDisplayName));
|
|
|
|
if ( gpExtStatus.bStatus )
|
|
{
|
|
gpExtStatus.bForceRefresh = TRUE;
|
|
|
|
WriteStatus( lpExt->lpKeyName, lpGPOInfo,
|
|
bUsePerUserLocalSetting ? lpGPOInfo->lpwszSidUser : NULL,
|
|
&gpExtStatus );
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We can ignore this because absence of a status automatically means processing
|
|
//
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Couldn't read status data for %s. Error %d. ignoring.. "),
|
|
lpExt->lpDisplayName, GetLastError()));
|
|
}
|
|
|
|
//
|
|
// There is a policy that can only be force refreshed in foreground
|
|
//
|
|
bForceNeedFG = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Process next extension
|
|
//
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: -----------------------")));
|
|
lpExt = lpExt->pNext;
|
|
}
|
|
|
|
if ( hOldToken )
|
|
{
|
|
CloseHandle(hOldToken);
|
|
}
|
|
|
|
//================================================================
|
|
//
|
|
// Success
|
|
//
|
|
//================================================================
|
|
bRetVal = TRUE;
|
|
|
|
Exit:
|
|
//
|
|
// change engine modes only if there is no error
|
|
//
|
|
if ( bRetVal )
|
|
{
|
|
//
|
|
// if policy sez sync. mark it sync
|
|
//
|
|
if ( GetFgPolicySetting( HKEY_LOCAL_MACHINE ) )
|
|
{
|
|
info.mode = GP_ModeSyncForeground;
|
|
info.reason = GP_ReasonSyncPolicy;
|
|
}
|
|
|
|
//
|
|
// async only on Pro
|
|
//
|
|
OSVERSIONINFOEXW version;
|
|
version.dwOSVersionInfoSize = sizeof(version);
|
|
if ( !GetVersionEx( (LPOSVERSIONINFO) &version ) )
|
|
{
|
|
//
|
|
// conservatively assume non Pro SKU
|
|
//
|
|
info.mode = GP_ModeSyncForeground;
|
|
info.reason = GP_ReasonSKU;
|
|
}
|
|
else
|
|
{
|
|
if ( version.wProductType != VER_NT_WORKSTATION )
|
|
{
|
|
//
|
|
// force sync refresh on non Pro SKU
|
|
//
|
|
info.mode = GP_ModeSyncForeground;
|
|
info.reason = GP_ReasonSKU;
|
|
}
|
|
}
|
|
|
|
if ( !( lpGPOInfo->dwFlags & GP_BACKGROUND_THREAD ) || ( lpGPOInfo->dwFlags & GP_ASYNC_FOREGROUND ) )
|
|
{
|
|
//
|
|
// set the previous info only in the foreground refreshes
|
|
//
|
|
LPWSTR szSid = lpGPOInfo->dwFlags & GP_MACHINE ? 0 : lpGPOInfo->lpwszSidUser;
|
|
FgPolicyRefreshInfo curInfo = { GP_ReasonUnknown, GP_ModeUnknown };
|
|
if ( GetCurrentFgPolicyRefreshInfo( szSid, &curInfo ) != ERROR_SUCCESS )
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: GetCurrentFgPolicyRefreshInfo failed.")));
|
|
}
|
|
else
|
|
{
|
|
if ( lpGPOInfo->dwFlags & GP_ASYNC_FOREGROUND )
|
|
{
|
|
curInfo.mode = GP_ModeAsyncForeground;
|
|
}
|
|
else
|
|
{
|
|
curInfo.mode = GP_ModeSyncForeground;
|
|
}
|
|
|
|
if ( SetPreviousFgPolicyRefreshInfo( szSid, curInfo ) != ERROR_SUCCESS )
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: SetPreviousFgPolicyRefreshInfo failed.") ));
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( info.mode == GP_ModeSyncForeground )
|
|
{
|
|
//
|
|
// need sync foreground, set in all refreshes
|
|
//
|
|
LPWSTR szSid = lpGPOInfo->dwFlags & GP_MACHINE ? 0 : lpGPOInfo->lpwszSidUser;
|
|
if ( SetNextFgPolicyRefreshInfo( szSid, info ) != ERROR_SUCCESS )
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: SetNextFgPolicyRefreshInfo failed.")));
|
|
}
|
|
}
|
|
else if ( info.mode == GP_ModeAsyncForeground )
|
|
{
|
|
//
|
|
// sync foreground policy successfully applied, nobody needs sync foreground,
|
|
// reset the GP_ModeSyncForeground only in the async foreground and background
|
|
// refreshes
|
|
//
|
|
LPWSTR szSid = lpGPOInfo->dwFlags & GP_MACHINE ? 0 : lpGPOInfo->lpwszSidUser;
|
|
if ( !( lpGPOInfo->dwFlags & GP_BACKGROUND_THREAD ) &&
|
|
!( lpGPOInfo->dwFlags & GP_ASYNC_FOREGROUND ) )
|
|
{
|
|
if ( SetNextFgPolicyRefreshInfo( szSid, info ) != ERROR_SUCCESS )
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: SetNextFgPolicyRefreshInfo failed.")));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !lpGPOInfo->pWbemServices )
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: No WMI logging done in this policy cycle.")));
|
|
}
|
|
|
|
if (!bRetVal)
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Processing failed with error %d."), (DWORD)(xe)));
|
|
|
|
GetSystemTimeAsFileTime(&gpCoreStatus.ftEndTime);
|
|
gpCoreStatus.bValid = TRUE;
|
|
gpCoreStatus.dwStatus = bRetVal ?
|
|
ERROR_SUCCESS:
|
|
((xe ==ERROR_SUCCESS) ? E_FAIL : xe);
|
|
|
|
// if rsop logging is not supported gp core status will appear dirty
|
|
gpCoreStatus.dwLoggingStatus = RsopLoggingEnabled() ? ((lpGPOInfo->bRsopLogging) ? S_OK : E_FAIL) : HRESULT_FROM_WIN32(ERROR_CANCELLED);
|
|
|
|
|
|
// No point in checking for error code here.
|
|
// The namespace is marked dirty. Diagnostic mode provider should expect all
|
|
// values here or mark the namespace dirty.
|
|
|
|
|
|
if ((lpGPOInfo->dwFlags & GP_MACHINE) || (lpGPOInfo->lpwszSidUser)) {
|
|
|
|
SaveLoggingStatus(
|
|
(lpGPOInfo->dwFlags & GP_MACHINE) ? NULL : (lpGPOInfo->lpwszSidUser),
|
|
NULL, &gpCoreStatus);
|
|
}
|
|
|
|
//
|
|
// Unload the Group Policy Extensions
|
|
//
|
|
|
|
UnloadGPExtensions (lpGPOInfo);
|
|
|
|
FreeLists( lpGPOInfo );
|
|
|
|
lpGPOInfo->lpGPOList = NULL;
|
|
lpGPOInfo->lpExtFilterList = NULL;
|
|
|
|
if (szNetworkName) {
|
|
LocalFree (szNetworkName );
|
|
szNetworkName = NULL;
|
|
}
|
|
|
|
FreeSOMList( lpGPOInfo->lpSOMList );
|
|
FreeSOMList( lpGPOInfo->lpLoopbackSOMList );
|
|
FreeGpContainerList( lpGPOInfo->lpGpContainerList );
|
|
FreeGpContainerList( lpGPOInfo->lpLoopbackGpContainerList );
|
|
|
|
if ( lpGPOInfo->szSiteName )
|
|
{
|
|
pNetAPI32->pfnNetApiBufferFree(lpGPOInfo->szSiteName);
|
|
lpGPOInfo->szSiteName = 0;
|
|
}
|
|
|
|
lpGPOInfo->lpSOMList = NULL;
|
|
lpGPOInfo->lpLoopbackSOMList = NULL;
|
|
lpGPOInfo->lpGpContainerList = NULL;
|
|
lpGPOInfo->lpLoopbackGpContainerList = NULL;
|
|
lpGPOInfo->bRsopCreated = FALSE; // reset this to false always.
|
|
// we will know in the next iteration
|
|
|
|
ReleaseWbemServices( lpGPOInfo );
|
|
|
|
//
|
|
// Token groups can change only at logon time, so reset to false
|
|
//
|
|
|
|
lpGPOInfo->bMemChanged = FALSE;
|
|
lpGPOInfo->bUserLocalMemChanged = FALSE;
|
|
|
|
//
|
|
// We migrate the policy data from old sid only at logon time.
|
|
// reset it to false.
|
|
//
|
|
|
|
lpGPOInfo->bSidChanged = FALSE;
|
|
|
|
if (pDCI) {
|
|
pNetAPI32->pfnNetApiBufferFree(pDCI);
|
|
}
|
|
|
|
lpGPOInfo->lpDNName = 0;
|
|
if (lpName) {
|
|
LocalFree (lpName);
|
|
}
|
|
|
|
if (lpDomainDN) {
|
|
LocalFree (lpDomainDN);
|
|
}
|
|
|
|
if (pTokenGroups) {
|
|
LocalFree(pTokenGroups);
|
|
pTokenGroups = NULL;
|
|
}
|
|
|
|
//
|
|
// Release the critical section
|
|
//
|
|
|
|
if (lpGPOInfo->hCritSection) {
|
|
LeaveCriticalPolicySection (lpGPOInfo->hCritSection);
|
|
lpGPOInfo->hCritSection = NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Announce that policies have changed
|
|
//
|
|
|
|
if (bRetVal) {
|
|
|
|
//
|
|
// This needs to be set before NotifyEvent
|
|
//
|
|
|
|
if (bForceNeedFG)
|
|
{
|
|
info.reason = GP_ReasonSyncForced;
|
|
info.mode = GP_ModeSyncForeground;
|
|
LPWSTR szSid = lpGPOInfo->dwFlags & GP_MACHINE ? 0 : lpGPOInfo->lpwszSidUser;
|
|
if ( SetNextFgPolicyRefreshInfo( szSid, info ) != ERROR_SUCCESS )
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: SetNextFgPolicyRefreshInfo failed.")));
|
|
}
|
|
else
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Forced option changed policy mode.")));
|
|
}
|
|
|
|
DmAssert(lpGPOInfo->dwFlags & GP_FORCED_REFRESH);
|
|
SetEvent(lpGPOInfo->hNeedFGEvent);
|
|
}
|
|
|
|
//
|
|
// If any extensions successfully processed gpo changes, we should notify components
|
|
// so they can process the updated settings accordingly. If no policy has changed,
|
|
// we should not perform the notification, even if we called extensions, since
|
|
// this could cause a costly broadcast on every single policy refresh, hurting
|
|
// performance particularly on dc's that have a frequent refresh interval (5 minutes)
|
|
// by default and cannot afford to have every desktop and every application updating
|
|
// its settings
|
|
//
|
|
|
|
if (uChangedExtensionCount) {
|
|
|
|
//
|
|
// First, update User with new colors, bitmaps, etc.
|
|
//
|
|
|
|
if (lpGPOInfo->dwFlags & GP_REGPOLICY_CPANEL) {
|
|
|
|
//
|
|
// Something has changed in the control panel section
|
|
// Start control.exe with the /policy switch so the
|
|
// display is refreshed.
|
|
//
|
|
|
|
RefreshDisplay (lpGPOInfo);
|
|
}
|
|
|
|
|
|
//
|
|
// Notify anyone waiting on an event handle
|
|
//
|
|
|
|
if (lpGPOInfo->hNotifyEvent) {
|
|
PulseEvent (lpGPOInfo->hNotifyEvent);
|
|
}
|
|
|
|
|
|
//
|
|
// Create a thread to broadcast the WM_SETTINGCHANGE message
|
|
//
|
|
|
|
// copy the data to another structure so that this thread can safely free its structures
|
|
|
|
LPPOLICYCHANGEDINFO lpPolicyChangedInfo;
|
|
|
|
lpPolicyChangedInfo = (LPPOLICYCHANGEDINFO)LocalAlloc(LPTR, sizeof(POLICYCHANGEDINFO));
|
|
|
|
if (lpPolicyChangedInfo)
|
|
{
|
|
HANDLE hProc;
|
|
BOOL bDupSucceeded = TRUE;
|
|
|
|
lpPolicyChangedInfo->bMachine = (lpGPOInfo->dwFlags & GP_MACHINE) ? 1 : 0;
|
|
|
|
if (!(lpPolicyChangedInfo->bMachine))
|
|
{
|
|
hProc = GetCurrentProcess();
|
|
|
|
if( hProc == NULL ) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to get process handle with error (%d)."), GetLastError()));
|
|
bDupSucceeded = FALSE;
|
|
}
|
|
|
|
if (bDupSucceeded &&
|
|
(!DuplicateHandle(
|
|
hProc, // Source of the handle
|
|
lpGPOInfo->hToken, // Source handle
|
|
hProc, // Target of the handle
|
|
&(lpPolicyChangedInfo->hToken), // Target handle
|
|
0, // ignored since DUPLICATE_SAME_ACCESS is set
|
|
FALSE, // no inherit on the handle
|
|
DUPLICATE_SAME_ACCESS
|
|
))) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to open duplicate token handle with error (%d)."), GetLastError()));
|
|
bDupSucceeded = FALSE;
|
|
}
|
|
}
|
|
|
|
if (bDupSucceeded) {
|
|
hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) PolicyChangedThread,
|
|
(LPVOID) lpPolicyChangedInfo,
|
|
CREATE_SUSPENDED, &dwThreadID);
|
|
|
|
if (hThread) {
|
|
SetThreadPriority (hThread, THREAD_PRIORITY_IDLE);
|
|
ResumeThread (hThread);
|
|
CloseHandle (hThread);
|
|
|
|
} else {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to create background thread (%d)."),
|
|
GetLastError()));
|
|
|
|
// free the resources if the thread didn't get launched
|
|
if (!(lpPolicyChangedInfo->bMachine)) {
|
|
if (lpPolicyChangedInfo->hToken) {
|
|
CloseHandle(lpPolicyChangedInfo->hToken);
|
|
lpPolicyChangedInfo->hToken = NULL;
|
|
}
|
|
}
|
|
|
|
LocalFree(lpPolicyChangedInfo);
|
|
}
|
|
}
|
|
else {
|
|
LocalFree(lpPolicyChangedInfo);
|
|
}
|
|
}
|
|
else {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to allocate memory for policy changed structure with %d."), GetLastError()));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lpGPOInfo->dwFlags & GP_VERBOSE) {
|
|
if (lpGPOInfo->dwFlags & GP_MACHINE) {
|
|
CEvents ev(FALSE, EVENT_MACHINE_POLICY_APPLIED); ev.Report();
|
|
} else {
|
|
CEvents ev(FALSE, EVENT_USER_POLICY_APPLIED); ev.Report();
|
|
}
|
|
}
|
|
|
|
if (lpGPOInfo->hDoneEvent) {
|
|
PulseEvent (lpGPOInfo->hDoneEvent);
|
|
}
|
|
|
|
if (lpGPOInfo->dwFlags & GP_MACHINE) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Computer Group Policy has been applied.")));
|
|
} else {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: User Group Policy has been applied.")));
|
|
}
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Leaving with %d."), bRetVal));
|
|
|
|
return bRetVal;
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// PolicyChangedThread()
|
|
//
|
|
// Purpose: Sends the WM_SETTINGCHANGE message announcing
|
|
// that policy has changed. This is done on a
|
|
// separate thread because this could take many
|
|
// seconds to succeed if an application is hung
|
|
//
|
|
// Parameters: lpPolicyChangedInfo - GPO info
|
|
//
|
|
// Return: 0
|
|
//
|
|
//*************************************************************
|
|
|
|
DWORD WINAPI PolicyChangedThread (LPPOLICYCHANGEDINFO lpPolicyChangedInfo)
|
|
{
|
|
HINSTANCE hInst;
|
|
NTSTATUS Status;
|
|
BOOLEAN WasEnabled;
|
|
HANDLE hOldToken = NULL;
|
|
XLastError xe;
|
|
|
|
|
|
hInst = LoadLibrary (TEXT("userenv.dll"));
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("PolicyChangedThread: Calling UpdateUser with %d."), lpPolicyChangedInfo->bMachine));
|
|
|
|
// impersonate and update system parameter if it is not machine
|
|
if (!(lpPolicyChangedInfo->bMachine)) {
|
|
if (!ImpersonateUser(lpPolicyChangedInfo->hToken, &hOldToken))
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("PolicyChangedThread: Failed to impersonate user")));
|
|
goto Exit;
|
|
}
|
|
|
|
if (!UpdatePerUserSystemParameters(NULL, UPUSP_POLICYCHANGE)) {
|
|
DebugMsg((DM_WARNING, TEXT("PolicyChangedThread: UpdateUser failed with %d."), GetLastError()));
|
|
// ignoring error and continuing the next notifications
|
|
}
|
|
|
|
if (!RevertToUser(&hOldToken)) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("PolicyChangedThread: Failed to revert user")));
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("PolicyChangedThread: Broadcast message for %d."), lpPolicyChangedInfo->bMachine));
|
|
|
|
//
|
|
// Broadcast the WM_SETTINGCHANGE message
|
|
//
|
|
|
|
Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, FALSE, &WasEnabled);
|
|
|
|
if ( NT_SUCCESS(Status) )
|
|
{
|
|
DWORD dwBSM = BSM_ALLDESKTOPS | BSM_APPLICATIONS;
|
|
|
|
BroadcastSystemMessage (BSF_IGNORECURRENTTASK | BSF_FORCEIFHUNG,
|
|
&dwBSM,
|
|
WM_SETTINGCHANGE,
|
|
lpPolicyChangedInfo->bMachine, (LPARAM) TEXT("Policy"));
|
|
|
|
RtlAdjustPrivilege(SE_TCB_PRIVILEGE, WasEnabled, FALSE, &WasEnabled);
|
|
}
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("PolicyChangedThread: Leaving")));
|
|
|
|
Exit:
|
|
if (!(lpPolicyChangedInfo->bMachine)) {
|
|
if (lpPolicyChangedInfo->hToken) {
|
|
CloseHandle(lpPolicyChangedInfo->hToken);
|
|
lpPolicyChangedInfo->hToken = NULL;
|
|
}
|
|
}
|
|
|
|
LocalFree(lpPolicyChangedInfo);
|
|
|
|
FreeLibraryAndExitThread (hInst, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// GetCurTime()
|
|
//
|
|
// Purpose: Returns current time in minutes, or 0 if there
|
|
// is a failure
|
|
//
|
|
//*************************************************************
|
|
|
|
DWORD GetCurTime()
|
|
{
|
|
DWORD dwCurTime = 0;
|
|
LARGE_INTEGER liCurTime;
|
|
|
|
if ( NT_SUCCESS( NtQuerySystemTime( &liCurTime) ) ) {
|
|
|
|
if ( RtlTimeToSecondsSince1980 ( &liCurTime, &dwCurTime) ) {
|
|
|
|
dwCurTime /= 60; // seconds to minutes
|
|
}
|
|
}
|
|
|
|
return dwCurTime;
|
|
}
|
|
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// LoadGPExtension()
|
|
//
|
|
// Purpose: Loads a GP extension.
|
|
//
|
|
// Parameters: lpExt -- GP extension
|
|
// bRsopPlanningMode -- Is this during Rsop planning mode ?
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL LoadGPExtension( LPGPEXT lpExt, BOOL bRsopPlanningMode )
|
|
{
|
|
XLastError xe;
|
|
|
|
if ( !lpExt->bRegistryExt && lpExt->hInstance == NULL )
|
|
{
|
|
lpExt->hInstance = LoadLibrary( lpExt->lpDllName );
|
|
if ( lpExt->hInstance )
|
|
{
|
|
if ( lpExt->bNewInterface )
|
|
{
|
|
lpExt->pEntryPointEx = (PFNPROCESSGROUPPOLICYEX)GetProcAddress(lpExt->hInstance,
|
|
lpExt->lpFunctionName);
|
|
if ( lpExt->pEntryPointEx == NULL )
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING,
|
|
TEXT("LoadGPExtension: Failed to query ProcessGroupPolicyEx function entry point in dll <%s> with %d"),
|
|
lpExt->lpDllName, GetLastError()));
|
|
CEvents ev(TRUE, EVENT_EXT_FUNCEX_FAIL);
|
|
ev.AddArg(lpExt->lpDllName); ev.Report();
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lpExt->pEntryPoint = (PFNPROCESSGROUPPOLICY)GetProcAddress(lpExt->hInstance,
|
|
lpExt->lpFunctionName);
|
|
if ( lpExt->pEntryPoint == NULL )
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING,
|
|
TEXT("LoadGPExtension: Failed to query ProcessGroupPolicy function entry point in dll <%s> with %d"),
|
|
lpExt->lpDllName, GetLastError()));
|
|
CEvents ev(TRUE, EVENT_EXT_FUNC_FAIL);
|
|
ev.AddArg(lpExt->lpDllName); ev.Report();
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if ( bRsopPlanningMode ) {
|
|
|
|
if ( lpExt->lpRsopFunctionName ) {
|
|
|
|
lpExt->pRsopEntryPoint = (PFNGENERATEGROUPPOLICY)GetProcAddress(lpExt->hInstance,
|
|
lpExt->lpRsopFunctionName);
|
|
if ( lpExt->pRsopEntryPoint == NULL )
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING,
|
|
TEXT("LoadGPExtension: Failed to query GenerateGroupPolicy function entry point in dll <%s> with %d"),
|
|
lpExt->lpDllName, GetLastError()));
|
|
|
|
CEvents ev(TRUE, EVENT_EXT_FUNCRSOP_FAIL);
|
|
ev.AddArg(lpExt->lpDisplayName); ev.AddArg(lpExt->lpDllName); ev.Report();
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
} else {
|
|
|
|
xe = ERROR_PROC_NOT_FOUND;
|
|
DebugMsg((DM_WARNING,
|
|
TEXT("LoadGPExtension: Failed to find Rsop entry point in dll <%s>"), lpExt->lpDllName ));
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("LoadGPExtension: Failed to load dll <%s> with %d"),
|
|
lpExt->lpDllName, GetLastError()));
|
|
CEvents ev(TRUE, EVENT_EXT_LOAD_FAIL);
|
|
ev.AddArg(lpExt->lpDllName); ev.AddArgWin32Error(GetLastError()); ev.Report();
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// UnloadGPExtensions()
|
|
//
|
|
// Purpose: Unloads the Group Policy extension dlls
|
|
//
|
|
// Parameters: lpGPOInfo - GP Information
|
|
//
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL UnloadGPExtensions (LPGPOINFO lpGPOInfo)
|
|
{
|
|
if ( !lpGPOInfo )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
LPGPEXT lpExt, lpTemp;
|
|
lpExt = lpGPOInfo->lpExtensions;
|
|
|
|
while ( lpExt )
|
|
{
|
|
lpTemp = lpExt->pNext;
|
|
|
|
if ( lpExt->hInstance )
|
|
{
|
|
FreeLibrary( lpExt->hInstance );
|
|
}
|
|
|
|
if ( lpExt->szEventLogSources )
|
|
{
|
|
LocalFree( lpExt->szEventLogSources );
|
|
}
|
|
if (lpExt->lpPrevStatus)
|
|
{
|
|
LocalFree(lpExt->lpPrevStatus);
|
|
}
|
|
|
|
LocalFree( lpExt );
|
|
lpExt = lpTemp;
|
|
}
|
|
|
|
lpGPOInfo->lpExtensions = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// ProcessGPOList()
|
|
//
|
|
// Purpose: Calls client side extensions to process gpos
|
|
//
|
|
// Parameters: lpExt - GP extension
|
|
// lpGPOInfo - GPT Information
|
|
// pDeletedGPOList - Deleted GPOs
|
|
// pChangedGPOList - New/changed GPOs
|
|
// bNoChanges - True if there are no GPO changes
|
|
// and GPO processing is forced
|
|
// pAsyncHandle - Context for async completion
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
//*************************************************************
|
|
|
|
DWORD ProcessGPOList (LPGPEXT lpExt,
|
|
LPGPOINFO lpGPOInfo,
|
|
PGROUP_POLICY_OBJECT pDeletedGPOList,
|
|
PGROUP_POLICY_OBJECT pChangedGPOList,
|
|
BOOL bNoChanges, ASYNCCOMPLETIONHANDLE pAsyncHandle,
|
|
HRESULT *phrRsopStatus )
|
|
{
|
|
LPTSTR lpGPTPath, lpDSPath;
|
|
INT iStrLen;
|
|
DWORD dwRet = ERROR_SUCCESS;
|
|
DWORD dwFlags = 0;
|
|
PGROUP_POLICY_OBJECT lpGPO;
|
|
TCHAR szStatusFormat[50];
|
|
TCHAR szVerbose[100];
|
|
DWORD dwSlowLinkCur = (lpGPOInfo->dwFlags & GP_SLOW_LINK) != 0;
|
|
IWbemServices *pLocalWbemServices;
|
|
HRESULT hr2 = S_OK;
|
|
XLastError xe;
|
|
|
|
*phrRsopStatus=S_OK;
|
|
|
|
|
|
//
|
|
// Verbose output
|
|
//
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOList: Entering for extension %s"), lpExt->lpDisplayName));
|
|
|
|
if (lpGPOInfo->pStatusCallback) {
|
|
if (!LoadString (g_hDllInstance, IDS_CALLEXTENSION, szStatusFormat, ARRAYSIZE(szStatusFormat))) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOList: LoadString failed with error %d."), GetLastError()));
|
|
// continue without showing per cse status UI.
|
|
}
|
|
else {
|
|
hr2 = StringCchPrintf (szVerbose, ARRAYSIZE(szVerbose), szStatusFormat, lpExt->lpDisplayName);
|
|
|
|
ASSERT(SUCCEEDED(hr2));
|
|
|
|
lpGPOInfo->pStatusCallback(TRUE, szVerbose);
|
|
}
|
|
}
|
|
|
|
if (lpGPOInfo->dwFlags & GP_MACHINE) {
|
|
dwFlags |= GPO_INFO_FLAG_MACHINE;
|
|
}
|
|
|
|
if (lpGPOInfo->dwFlags & GP_BACKGROUND_THREAD)
|
|
{
|
|
dwFlags |= GPO_INFO_FLAG_BACKGROUND;
|
|
}
|
|
|
|
if ( lpGPOInfo->dwFlags & GP_ASYNC_FOREGROUND )
|
|
{
|
|
dwFlags |= GPO_INFO_FLAG_ASYNC_FOREGROUND;
|
|
}
|
|
|
|
if (lpGPOInfo->dwFlags & GP_SLOW_LINK) {
|
|
dwFlags |= GPO_INFO_FLAG_SLOWLINK;
|
|
}
|
|
|
|
if ( dwSlowLinkCur != lpExt->lpPrevStatus->dwSlowLink ) {
|
|
dwFlags |= GPO_INFO_FLAG_LINKTRANSITION;
|
|
}
|
|
|
|
if (lpGPOInfo->dwFlags & GP_VERBOSE) {
|
|
dwFlags |= GPO_INFO_FLAG_VERBOSE;
|
|
}
|
|
|
|
if ( bNoChanges ) {
|
|
dwFlags |= GPO_INFO_FLAG_NOCHANGES;
|
|
}
|
|
|
|
//
|
|
// flag safe mode boot to CSE so that they can made a decision
|
|
// whether or not to apply policy
|
|
//
|
|
if ( GetSystemMetrics( SM_CLEANBOOT ) )
|
|
{
|
|
dwFlags |= GPO_INFO_FLAG_SAFEMODE_BOOT;
|
|
}
|
|
|
|
if (lpExt->bRsopTransition) {
|
|
dwFlags |= GPO_INFO_FLAG_LOGRSOP_TRANSITION;
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOList: Passing in the rsop transition flag to Extension %s"),
|
|
lpExt->lpDisplayName));
|
|
}
|
|
|
|
|
|
if ( (lpGPOInfo->dwFlags & GP_FORCED_REFRESH) ||
|
|
((!(lpGPOInfo->dwFlags & GP_BACKGROUND_THREAD)) && (lpExt->lpPrevStatus->bForceRefresh))) {
|
|
|
|
dwFlags |= GPO_INFO_FLAG_FORCED_REFRESH;
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOList: Passing in the force refresh flag to Extension %s"),
|
|
lpExt->lpDisplayName));
|
|
}
|
|
|
|
//
|
|
// if it is rsop transition or changes case get the intf ptr
|
|
//
|
|
|
|
if ( (lpGPOInfo->bRsopLogging) &&
|
|
((lpExt->bRsopTransition) || (!bNoChanges) || (dwFlags & GPO_INFO_FLAG_FORCED_REFRESH)) ) {
|
|
|
|
if (!(lpGPOInfo->pWbemServices) ) {
|
|
BOOL bCreated;
|
|
|
|
//
|
|
// Note that this code shouldn't be creating a namespace ever..
|
|
//
|
|
|
|
if (!GetWbemServices(lpGPOInfo, RSOP_NS_DIAG_ROOT, FALSE, NULL, &(lpGPOInfo->pWbemServices))) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOList: Couldn't get the wbemservices intf pointer")));
|
|
lpGPOInfo->bRsopLogging = FALSE;
|
|
hr2 = *phrRsopStatus = E_FAIL;
|
|
}
|
|
}
|
|
|
|
pLocalWbemServices = lpGPOInfo->pWbemServices;
|
|
}
|
|
else {
|
|
pLocalWbemServices = NULL;
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOList: No changes. CSE will not be passed in the IwbemServices intf ptr")));
|
|
}
|
|
|
|
dwRet = ERROR_SUCCESS;
|
|
|
|
if ( lpExt->bRegistryExt )
|
|
{
|
|
//
|
|
// Registry pseudo extension.
|
|
//
|
|
|
|
|
|
//
|
|
// Log the extension specific status
|
|
//
|
|
|
|
if (pLocalWbemServices) {
|
|
lpGPOInfo->bRsopLogging = LogExtSessionStatus( pLocalWbemServices,
|
|
lpExt,
|
|
TRUE,
|
|
(lpExt->bRsopTransition || (dwFlags & GPO_INFO_FLAG_FORCED_REFRESH)
|
|
|| (!bNoChanges)));
|
|
|
|
|
|
if (!lpGPOInfo->bRsopLogging) {
|
|
hr2 = E_FAIL;
|
|
}
|
|
}
|
|
|
|
if (!ProcessGPORegistryPolicy (lpGPOInfo, pChangedGPOList, phrRsopStatus)) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOList: ProcessGPORegistryPolicy failed.")));
|
|
dwRet = E_FAIL;
|
|
}
|
|
|
|
} else { // if lpExt->bRegistryExt
|
|
|
|
//
|
|
// Regular extension
|
|
//
|
|
|
|
BOOL *pbAbort;
|
|
ASYNCCOMPLETIONHANDLE pAsyncHandleTemp;
|
|
|
|
if ( lpExt->dwRequireRegistry ) {
|
|
|
|
GPEXTSTATUS gpExtStatus;
|
|
|
|
ReadStatus( c_szRegistryExtName, lpGPOInfo, NULL, &gpExtStatus );
|
|
|
|
if ( !gpExtStatus.bStatus || gpExtStatus.dwStatus != ERROR_SUCCESS ) {
|
|
|
|
DebugMsg((DM_VERBOSE,
|
|
TEXT("ProcessGPOList: Skipping extension %s due to failed Registry extension."),
|
|
lpExt->lpDisplayName));
|
|
if (lpGPOInfo->dwFlags & GP_VERBOSE) {
|
|
CEvents ev(FALSE, EVENT_EXT_SKIPPED_DUETO_FAILED_REG);
|
|
ev.AddArg(lpExt->lpDisplayName); ev.Report();
|
|
}
|
|
|
|
dwRet = E_FAIL;
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Log the extension specific status
|
|
//
|
|
|
|
if (pLocalWbemServices)
|
|
{
|
|
lpGPOInfo->bRsopLogging = LogExtSessionStatus( pLocalWbemServices,
|
|
lpExt,
|
|
lpExt->bNewInterface,
|
|
(lpExt->bRsopTransition || (dwFlags & GPO_INFO_FLAG_FORCED_REFRESH)
|
|
|| (!bNoChanges)));
|
|
if (!lpGPOInfo->bRsopLogging) {
|
|
hr2 = E_FAIL;
|
|
}
|
|
}
|
|
|
|
BOOL bLoadedExtension = TRUE;
|
|
|
|
if ( !LoadGPExtension( lpExt, FALSE ) ) {
|
|
DebugMsg((DM_WARNING, TEXT("ProcessGPOList: LoadGPExtension %s failed."), lpExt->lpDisplayName));
|
|
|
|
dwRet = GetLastError();
|
|
|
|
//
|
|
// Note that we don't just leave here -- we
|
|
// continue so that we will log an extension
|
|
// status that indicates that this extension
|
|
// did not process
|
|
//
|
|
bLoadedExtension = FALSE;
|
|
}
|
|
|
|
if ( lpGPOInfo->dwFlags & GP_MACHINE )
|
|
pbAbort = &g_bStopMachGPOProcessing;
|
|
else
|
|
pbAbort = &g_bStopUserGPOProcessing;
|
|
|
|
//
|
|
// Check if asynchronous processing is enabled
|
|
//
|
|
|
|
if ( lpExt->dwEnableAsynch )
|
|
pAsyncHandleTemp = pAsyncHandle;
|
|
else
|
|
pAsyncHandleTemp = 0;
|
|
|
|
if ( bLoadedExtension )
|
|
{
|
|
if ( lpExt->bNewInterface ) {
|
|
dwRet = lpExt->pEntryPointEx( dwFlags,
|
|
lpGPOInfo->hToken,
|
|
lpGPOInfo->hKeyRoot,
|
|
pDeletedGPOList,
|
|
pChangedGPOList,
|
|
pAsyncHandleTemp,
|
|
pbAbort,
|
|
lpGPOInfo->pStatusCallback,
|
|
pLocalWbemServices,
|
|
phrRsopStatus);
|
|
} else {
|
|
dwRet = lpExt->pEntryPoint( dwFlags,
|
|
lpGPOInfo->hToken,
|
|
lpGPOInfo->hKeyRoot,
|
|
pDeletedGPOList,
|
|
pChangedGPOList,
|
|
pAsyncHandleTemp,
|
|
pbAbort,
|
|
lpGPOInfo->pStatusCallback );
|
|
}
|
|
}
|
|
|
|
RevertToSelf();
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOList: Extension %s returned 0x%x."),
|
|
lpExt->lpDisplayName, dwRet));
|
|
|
|
if ( dwRet != ERROR_SUCCESS &&
|
|
dwRet != ERROR_OVERRIDE_NOCHANGES &&
|
|
dwRet != E_PENDING &&
|
|
dwRet != ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED )
|
|
{
|
|
CEvents ev(TRUE, EVENT_EXT_FAILED);
|
|
ev.AddArg(lpExt->lpDisplayName); ev.Report();
|
|
}
|
|
|
|
} // else of if lpext->bregistryext
|
|
|
|
|
|
if (pLocalWbemServices) {
|
|
if ((dwRet != E_PENDING) && (SUCCEEDED(*phrRsopStatus)) && (lpExt->bNewInterface)) {
|
|
|
|
//
|
|
// for the legacy extensions it will be marked clean
|
|
//
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOList: Extension %s was able to log data. RsopStatus = 0x%x, dwRet = %d, Clearing the dirty bit"),
|
|
lpExt->lpDisplayName, *phrRsopStatus, dwRet));
|
|
|
|
(void)UpdateExtSessionStatus(pLocalWbemServices, lpExt->lpKeyName, FALSE, dwRet);
|
|
}
|
|
else {
|
|
|
|
if (!lpExt->bNewInterface) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOList: Extension %s doesn't support rsop logging"),
|
|
lpExt->lpDisplayName));
|
|
|
|
(void)UpdateExtSessionStatus(pLocalWbemServices, lpExt->lpKeyName, TRUE, dwRet);
|
|
// extension status will be marked dirty if it fails
|
|
}
|
|
else if (FAILED(*phrRsopStatus)) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOList: Extension %s was not able to log data. Error = 0x%x, dwRet = %d,leaving the log dirty"),
|
|
lpExt->lpDisplayName, *phrRsopStatus, dwRet ));
|
|
|
|
CEvents ev(TRUE, EVENT_EXT_RSOP_FAILED);
|
|
ev.AddArg(lpExt->lpDisplayName); ev.Report();
|
|
|
|
(void)UpdateExtSessionStatus(pLocalWbemServices, lpExt->lpKeyName, TRUE, dwRet);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGPOList: Extension %s status was not updated because there was no changes and no transition or rsop wasn't enabled"),
|
|
lpExt->lpDisplayName));
|
|
}
|
|
|
|
//
|
|
// if any of the things provider is supposed to log fails, log it as an error
|
|
// so that provider tries to log it again next time
|
|
//
|
|
|
|
*phrRsopStatus = (SUCCEEDED(*phrRsopStatus)) && (FAILED(hr2)) ? hr2 : *phrRsopStatus;
|
|
*phrRsopStatus = (!lpExt->bNewInterface) ? HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED) : *phrRsopStatus;
|
|
|
|
|
|
Exit:
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// RefreshDisplay()
|
|
//
|
|
// Purpose: Starts control.exe
|
|
//
|
|
// Parameters: lpGPOInfo - GPT information
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL RefreshDisplay (LPGPOINFO lpGPOInfo)
|
|
{
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
TCHAR szCmdLine[50];
|
|
BOOL Result;
|
|
HANDLE hOldToken;
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
//
|
|
// Verbose output
|
|
//
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("RefreshDisplay: Starting control.exe")));
|
|
|
|
|
|
//
|
|
// Initialize process startup info
|
|
//
|
|
|
|
si.cb = sizeof(STARTUPINFO);
|
|
si.lpReserved = NULL;
|
|
si.lpTitle = NULL;
|
|
si.dwX = si.dwY = si.dwXSize = si.dwYSize = 0L;
|
|
si.dwFlags = 0;
|
|
si.wShowWindow = SW_HIDE;
|
|
si.lpReserved2 = NULL;
|
|
si.cbReserved2 = 0;
|
|
si.lpDesktop = TEXT("");
|
|
|
|
|
|
//
|
|
// Impersonate the user so we get access checked correctly on
|
|
// the file we're trying to execute
|
|
//
|
|
|
|
if (!ImpersonateUser(lpGPOInfo->hToken, &hOldToken)) {
|
|
DebugMsg((DM_WARNING, TEXT("RefreshDisplay: Failed to impersonate user")));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Create the app
|
|
//
|
|
|
|
hr = StringCchCopy (szCmdLine, ARRAYSIZE(szCmdLine), TEXT("control /policy"));
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
Result = CreateProcessAsUser(lpGPOInfo->hToken, NULL, szCmdLine, NULL,
|
|
NULL, FALSE, 0, NULL, NULL, &si, &pi);
|
|
|
|
|
|
//
|
|
// Revert to being 'ourself'
|
|
//
|
|
|
|
if (!RevertToUser(&hOldToken)) {
|
|
DebugMsg((DM_WARNING, TEXT("RefreshDisplay: Failed to revert to self")));
|
|
}
|
|
|
|
|
|
if (Result) {
|
|
WaitForSingleObject (pi.hProcess, 120000);
|
|
CloseHandle (pi.hThread);
|
|
CloseHandle (pi.hProcess);
|
|
|
|
} else {
|
|
DebugMsg((DM_WARNING, TEXT("RefreshDisplay: Failed to start control.exe with %d"), GetLastError()));
|
|
}
|
|
|
|
return(Result);
|
|
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// RefreshPolicy()
|
|
//
|
|
// Purpose: External api that causes policy to be refreshed now
|
|
//
|
|
// Parameters: bMachine - Machine policy vs user policy
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if not
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL WINAPI RefreshPolicy (BOOL bMachine)
|
|
{
|
|
HANDLE hEvent;
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("RefreshPolicy: Entering with %d"), bMachine));
|
|
|
|
hEvent = OpenEvent (EVENT_MODIFY_STATE, FALSE,
|
|
bMachine ? MACHINE_POLICY_REFRESH_EVENT : USER_POLICY_REFRESH_EVENT);
|
|
|
|
if (hEvent) {
|
|
BOOL bRet = SetEvent (hEvent);
|
|
|
|
CloseHandle (hEvent);
|
|
|
|
if (!bRet) {
|
|
DebugMsg((DM_WARNING, TEXT("RefreshPolicy: Failed to set event with %d"), GetLastError()));
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
DebugMsg((DM_WARNING, TEXT("RefreshPolicy: Failed to open event with %d"), GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("RefreshPolicy: Leaving.")));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// RefreshPolicyEx()
|
|
//
|
|
// Purpose: External api that causes policy to be refreshed now
|
|
//
|
|
// Parameters: bMachine - Machine policy vs user policy.
|
|
// This API is synchronous and waits for the refresh to
|
|
// finish.
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if not
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL WINAPI RefreshPolicyEx (BOOL bMachine, DWORD dwOption)
|
|
{
|
|
XHandle xhEvent;
|
|
|
|
if (!dwOption)
|
|
return RefreshPolicy(bMachine);
|
|
|
|
if (dwOption == RP_FORCE) {
|
|
DebugMsg((DM_VERBOSE, TEXT("RefreshPolicyEx: Entering with force refresh %d"), bMachine));
|
|
|
|
xhEvent = OpenEvent (EVENT_MODIFY_STATE, FALSE,
|
|
bMachine ? MACHINE_POLICY_FORCE_REFRESH_EVENT : USER_POLICY_FORCE_REFRESH_EVENT);
|
|
|
|
}
|
|
else {
|
|
DebugMsg((DM_WARNING, TEXT("RefreshPolicyEx: Invalid option")));
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if (!xhEvent) {
|
|
DebugMsg((DM_WARNING, TEXT("RefreshPolicyEx: Failed to open event with %d"), GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if (!SetEvent (xhEvent)) {
|
|
DebugMsg((DM_WARNING, TEXT("RefreshPolicyEx: Failed to set event with %d"), GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("RefreshPolicyEx: Leaving.")));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// EnterCriticalPolicySection()
|
|
//
|
|
// Purpose: External api that causes policy to pause
|
|
// This allows an application to pause policy
|
|
// so that values don't change while it reads
|
|
// the settings.
|
|
//
|
|
// Parameters: bMachine - Pause machine policy or user policy
|
|
// dwTimeOut- Amount of time to wait for the policy handle
|
|
// dwFlags - Various flags. Look at the defn.
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if not
|
|
//
|
|
//*************************************************************
|
|
|
|
HANDLE WINAPI EnterCriticalPolicySectionEx (BOOL bMachine, DWORD dwTimeOut, DWORD dwFlags )
|
|
{
|
|
HANDLE hSection;
|
|
DWORD dwRet;
|
|
WCHAR* wszMutex;
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("EnterCriticalPolicySectionEx: Entering with timeout %d and flags 0x%x"), dwTimeOut, dwFlags ));
|
|
|
|
//
|
|
// Determine which lock to acquire
|
|
//
|
|
if ( ECP_REGISTRY_ONLY & dwFlags )
|
|
{
|
|
if ( bMachine )
|
|
{
|
|
wszMutex = MACH_REGISTRY_EXT_MUTEX;
|
|
}
|
|
else
|
|
{
|
|
wszMutex = USER_REGISTRY_EXT_MUTEX;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( bMachine )
|
|
{
|
|
wszMutex = MACHINE_POLICY_MUTEX;
|
|
}
|
|
else
|
|
{
|
|
wszMutex = USER_POLICY_MUTEX;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Open the mutex
|
|
//
|
|
|
|
hSection = OpenMutex (SYNCHRONIZE, FALSE, wszMutex);
|
|
|
|
if (!hSection) {
|
|
DebugMsg((DM_WARNING, TEXT("EnterCriticalPolicySectionEx: Failed to open mutex with %d"),
|
|
GetLastError()));
|
|
DebugMsg((DM_VERBOSE, TEXT("EnterCriticalPolicySectionEx: Leaving unsuccessfully.")));
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Claim the mutex
|
|
//
|
|
|
|
dwRet = WaitForSingleObject (hSection, dwTimeOut);
|
|
|
|
if ( dwRet == WAIT_FAILED) {
|
|
DebugMsg((DM_WARNING, TEXT("EnterCriticalPolicySectionEx: Failed to wait on the mutex. Error = %d."),
|
|
GetLastError()));
|
|
CloseHandle( hSection );
|
|
DebugMsg((DM_VERBOSE, TEXT("EnterCriticalPolicySectionEx: Leaving unsuccessfully.")));
|
|
return NULL;
|
|
}
|
|
|
|
if ( (dwFlags & ECP_FAIL_ON_WAIT_TIMEOUT) && (dwRet == WAIT_TIMEOUT) ) {
|
|
DebugMsg((DM_WARNING, TEXT("EnterCriticalPolicySectionEx: Wait timed out on the mutex.")));
|
|
CloseHandle( hSection );
|
|
SetLastError(dwRet);
|
|
DebugMsg((DM_VERBOSE, TEXT("EnterCriticalPolicySectionEx: Leaving unsuccessfully.")));
|
|
return NULL;
|
|
}
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("EnterCriticalPolicySectionEx: %s critical section has been claimed. Handle = 0x%x"),
|
|
(bMachine ? TEXT("Machine") : TEXT("User")), hSection));
|
|
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("EnterCriticalPolicySectionEx: Leaving successfully.")));
|
|
|
|
return hSection;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// LeaveCriticalPolicySection()
|
|
//
|
|
// Purpose: External api that causes policy to resume
|
|
// This api assumes the app has called
|
|
// EnterCriticalPolicySection first
|
|
//
|
|
// Parameters: hSection - mutex handle
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if not
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL WINAPI LeaveCriticalPolicySection (HANDLE hSection)
|
|
{
|
|
|
|
if (!hSection) {
|
|
DebugMsg((DM_WARNING, TEXT("LeaveCriticalPolicySection: null mutex handle.")));
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
ReleaseMutex (hSection);
|
|
CloseHandle (hSection);
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("LeaveCriticalPolicySection: Critical section 0x%x has been released."),
|
|
hSection));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// EnterCriticalPolicySection()
|
|
//
|
|
// Purpose: External api that causes policy to pause
|
|
// This allows an application to pause policy
|
|
// so that values don't change while it reads
|
|
// the settings.
|
|
//
|
|
// Parameters: bMachine - Pause machine policy or user policy
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if not
|
|
//
|
|
//*************************************************************
|
|
|
|
HANDLE WINAPI EnterCriticalPolicySection (BOOL bMachine)
|
|
{
|
|
return EnterCriticalPolicySectionEx(bMachine, 600000, 0);
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// FreeGpoInfo()
|
|
//
|
|
// Purpose: Deletes an LPGPOINFO struct
|
|
//
|
|
// Parameters: pGpoInfo - Gpo info to free
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL FreeGpoInfo( LPGPOINFO pGpoInfo )
|
|
{
|
|
if ( pGpoInfo == NULL )
|
|
return TRUE;
|
|
|
|
FreeLists( pGpoInfo );
|
|
FreeSOMList( pGpoInfo->lpSOMList );
|
|
FreeSOMList( pGpoInfo->lpLoopbackSOMList );
|
|
FreeGpContainerList( pGpoInfo->lpGpContainerList );
|
|
FreeGpContainerList( pGpoInfo->lpLoopbackGpContainerList );
|
|
|
|
LocalFree( pGpoInfo->lpDNName );
|
|
RsopDeleteToken( pGpoInfo->pRsopToken );
|
|
ReleaseWbemServices( pGpoInfo );
|
|
|
|
DeleteSidString(pGpoInfo->lpwszSidUser);
|
|
|
|
LocalFree( pGpoInfo );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// FreeGPOList()
|
|
//
|
|
// Purpose: Free's the link list of GPOs
|
|
//
|
|
// Parameters: pGPOList - Pointer to the head of the list
|
|
//
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL WINAPI FreeGPOList (PGROUP_POLICY_OBJECT pGPOList)
|
|
{
|
|
PGROUP_POLICY_OBJECT pGPOTemp;
|
|
|
|
while (pGPOList) {
|
|
pGPOTemp = pGPOList->pNext;
|
|
LocalFree (pGPOList);
|
|
pGPOList = pGPOTemp;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// FreeLists()
|
|
//
|
|
// Purpose: Free's the lpExtFilterList and/or lpGPOList
|
|
//
|
|
// Parameters: lpGPOInfo - GPO info
|
|
//
|
|
//*************************************************************
|
|
|
|
void FreeLists( LPGPOINFO lpGPOInfo )
|
|
{
|
|
LPEXTFILTERLIST pExtFilterList = lpGPOInfo->lpExtFilterList;
|
|
|
|
//
|
|
// If bXferToExtList is True then it means that lpGPOInfo->lpExtFilterList
|
|
// owns the list of GPOs. Otherwise lpGPOInfo->lpGPOList owns the list
|
|
// of GPOs.
|
|
//
|
|
|
|
while ( pExtFilterList ) {
|
|
|
|
LPEXTFILTERLIST pTemp = pExtFilterList->pNext;
|
|
|
|
FreeExtList( pExtFilterList->lpExtList );
|
|
|
|
if ( lpGPOInfo->bXferToExtList )
|
|
LocalFree( pExtFilterList->lpGPO );
|
|
|
|
LocalFree( pExtFilterList );
|
|
pExtFilterList = pTemp;
|
|
}
|
|
|
|
if ( !lpGPOInfo->bXferToExtList )
|
|
FreeGPOList( lpGPOInfo->lpGPOList );
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// FreeExtList()
|
|
//
|
|
// Purpose: Free's the lpExtList
|
|
//
|
|
// Parameters: pExtList - Extensions list
|
|
//
|
|
//*************************************************************
|
|
|
|
void FreeExtList( LPEXTLIST pExtList )
|
|
{
|
|
while (pExtList) {
|
|
|
|
LPEXTLIST pTemp = pExtList->pNext;
|
|
LocalFree( pExtList );
|
|
pExtList = pTemp;
|
|
}
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// ShutdownGPOProcessing()
|
|
//
|
|
// Purpose: Begins aborting GPO processing
|
|
//
|
|
// Parameters: bMachine - Shutdown machine or user processing ?
|
|
//
|
|
//*************************************************************
|
|
|
|
void WINAPI ShutdownGPOProcessing( BOOL bMachine )
|
|
{
|
|
LPGPOINFO lpGPOInfo = NULL;
|
|
|
|
EnterCriticalSection( &g_GPOCS );
|
|
if ( bMachine )
|
|
{
|
|
if ( g_pMachGPInfo )
|
|
{
|
|
if ( g_pMachGPInfo->bNoBackgroupThread )
|
|
{
|
|
lpGPOInfo = g_pMachGPInfo->pGPOInfo;
|
|
LocalFree( g_pMachGPInfo );
|
|
g_pMachGPInfo = 0;
|
|
}
|
|
}
|
|
g_bStopMachGPOProcessing = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if ( g_pUserGPInfo )
|
|
{
|
|
if ( g_pUserGPInfo->bNoBackgroupThread )
|
|
{
|
|
lpGPOInfo = g_pUserGPInfo->pGPOInfo;
|
|
LocalFree( g_pUserGPInfo );
|
|
g_pUserGPInfo = 0;
|
|
}
|
|
}
|
|
g_bStopUserGPOProcessing = TRUE;
|
|
}
|
|
LeaveCriticalSection( &g_GPOCS );
|
|
|
|
if (lpGPOInfo) {
|
|
|
|
if (lpGPOInfo->hToken) {
|
|
CloseHandle (lpGPOInfo->hToken);
|
|
}
|
|
|
|
if (lpGPOInfo->hEvent) {
|
|
CloseHandle (lpGPOInfo->hEvent);
|
|
}
|
|
|
|
if (lpGPOInfo->hKeyRoot && (lpGPOInfo->hKeyRoot != HKEY_LOCAL_MACHINE)) {
|
|
RegCloseKey(lpGPOInfo->hKeyRoot);
|
|
}
|
|
|
|
if (lpGPOInfo->hTriggerEvent) {
|
|
CloseHandle (lpGPOInfo->hTriggerEvent);
|
|
}
|
|
|
|
if (lpGPOInfo->hForceTriggerEvent) {
|
|
CloseHandle (lpGPOInfo->hForceTriggerEvent);
|
|
}
|
|
|
|
if (lpGPOInfo->hNotifyEvent) {
|
|
CloseHandle (lpGPOInfo->hNotifyEvent);
|
|
}
|
|
|
|
if (lpGPOInfo->hNeedFGEvent) {
|
|
CloseHandle (lpGPOInfo->hNeedFGEvent);
|
|
}
|
|
|
|
if (lpGPOInfo->lpwszSidUser)
|
|
DeleteSidString( lpGPOInfo->lpwszSidUser );
|
|
|
|
if (lpGPOInfo->szName)
|
|
LocalFree(lpGPOInfo->szName);
|
|
|
|
if (lpGPOInfo->szTargetName)
|
|
LocalFree(lpGPOInfo->szTargetName);
|
|
|
|
LocalFree (lpGPOInfo);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// InitializeGPOCriticalSection, CloseGPOCriticalSection
|
|
//
|
|
// Purpose: Initialization and cleanup routines for critical sections
|
|
//
|
|
//*************************************************************
|
|
|
|
void InitializeGPOCriticalSection()
|
|
{
|
|
InitializeCriticalSection( &g_GPOCS );
|
|
g_bGPOCSInited = TRUE;
|
|
InitializeCriticalSection( &g_StatusCallbackCS );
|
|
g_bStatusCallbackInited = TRUE;
|
|
}
|
|
|
|
|
|
void CloseGPOCriticalSection()
|
|
{
|
|
if (g_bStatusCallbackInited)
|
|
DeleteCriticalSection( &g_StatusCallbackCS );
|
|
|
|
if (g_bGPOCSInited)
|
|
DeleteCriticalSection( &g_GPOCS );
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// ProcessGroupPolicyCompletedEx()
|
|
//
|
|
// Purpose: Callback for asynchronous completion of an extension
|
|
//
|
|
// Parameters: refExtensionId - Unique guid of extension
|
|
// pAsyncHandle - Completion context
|
|
// dwStatus - Asynchronous completion status
|
|
// hrRsopStatus - Rsop Logging Status
|
|
//
|
|
// Returns: Win32 error code
|
|
//
|
|
//*************************************************************
|
|
|
|
DWORD ProcessGroupPolicyCompletedEx( REFGPEXTENSIONID extensionGuid,
|
|
ASYNCCOMPLETIONHANDLE pAsyncHandle,
|
|
DWORD dwStatus, HRESULT hrRsopStatus )
|
|
{
|
|
DWORD dwRet = E_FAIL;
|
|
TCHAR szExtension[64];
|
|
PGROUP_POLICY_OBJECT pGPOList = NULL;
|
|
LPGPOINFO lpGPOInfo = NULL;
|
|
BOOL bUsePerUserLocalSetting = FALSE;
|
|
DWORD dwCurrentTime = GetCurTime();
|
|
HRESULT hr = S_OK;
|
|
|
|
LPGPINFOHANDLE pGPHandle = (LPGPINFOHANDLE) pAsyncHandle;;
|
|
|
|
if( !pGPHandle ) // Fixing bug 561426
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
if ( extensionGuid == 0 )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
GuidToString( extensionGuid, szExtension );
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGroupPolicyCompleted: Entering. Extension = %s, dwStatus = 0x%x"),
|
|
szExtension, dwStatus));
|
|
|
|
EnterCriticalSection( &g_GPOCS );
|
|
|
|
if ( !(pGPHandle == g_pMachGPInfo || pGPHandle == g_pUserGPInfo) ) {
|
|
DebugMsg((DM_WARNING, TEXT("Extension %s asynchronous completion is stale"),
|
|
szExtension));
|
|
goto Exit;
|
|
}
|
|
|
|
DmAssert( pGPHandle->pGPOInfo != NULL );
|
|
|
|
if ( pGPHandle->pGPOInfo == NULL ) {
|
|
DebugMsg((DM_WARNING, TEXT("Extension %s asynchronous completion has invalid pGPHandle->pGPOInfo"),
|
|
szExtension));
|
|
goto Exit;
|
|
}
|
|
|
|
lpGPOInfo = pGPHandle->pGPOInfo;
|
|
|
|
if ( (lpGPOInfo->dwFlags & GP_MACHINE) && g_bStopMachGPOProcessing
|
|
|| !(lpGPOInfo->dwFlags & GP_MACHINE) && g_bStopUserGPOProcessing ) {
|
|
|
|
DebugMsg((DM_WARNING, TEXT("Extension %s asynchronous completion, aborting due to machine shutdown or logoff"),
|
|
szExtension));
|
|
CEvents ev(TRUE, EVENT_GPO_PROC_STOPPED); ev.Report();
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
if ( dwStatus != ERROR_SUCCESS ) {
|
|
|
|
//
|
|
// Extension returned error code, so no need to update history
|
|
//
|
|
|
|
dwRet = ERROR_SUCCESS;
|
|
goto Exit;
|
|
}
|
|
|
|
if ( pGPHandle == 0 ) {
|
|
DebugMsg((DM_WARNING, TEXT("Extension %s is using 0 as asynchronous completion handle"),
|
|
szExtension));
|
|
goto Exit;
|
|
}
|
|
|
|
bUsePerUserLocalSetting = !(lpGPOInfo->dwFlags & GP_MACHINE)
|
|
&& ExtensionHasPerUserLocalSetting( szExtension, HKEY_LOCAL_MACHINE );
|
|
|
|
if ( ReadGPOList( szExtension, lpGPOInfo->hKeyRoot,
|
|
HKEY_LOCAL_MACHINE,
|
|
lpGPOInfo->lpwszSidUser,
|
|
TRUE, &pGPOList ) ) {
|
|
|
|
if ( SaveGPOList( szExtension, lpGPOInfo,
|
|
HKEY_LOCAL_MACHINE,
|
|
NULL,
|
|
FALSE, pGPOList ) ) {
|
|
|
|
if ( bUsePerUserLocalSetting ) {
|
|
|
|
if ( SaveGPOList( szExtension, lpGPOInfo,
|
|
HKEY_LOCAL_MACHINE,
|
|
lpGPOInfo->lpwszSidUser,
|
|
FALSE, pGPOList ) ) {
|
|
dwRet = ERROR_SUCCESS;
|
|
} else {
|
|
DebugMsg((DM_WARNING, TEXT("Extension %s asynchronous completion, failed to save GPOList"),
|
|
szExtension));
|
|
}
|
|
|
|
} else
|
|
dwRet = ERROR_SUCCESS;
|
|
|
|
} else {
|
|
DebugMsg((DM_WARNING, TEXT("Extension %s asynchronous completion, failed to save GPOList"),
|
|
szExtension));
|
|
}
|
|
} else {
|
|
DebugMsg((DM_WARNING, TEXT("Extension %s asynchronous completion, failed to read shadow GPOList"),
|
|
szExtension));
|
|
}
|
|
|
|
Exit:
|
|
|
|
FgPolicyRefreshInfo info = { GP_ReasonUnknown, GP_ModeAsyncForeground };
|
|
LPWSTR szSid = 0;
|
|
|
|
if (lpGPOInfo)
|
|
{
|
|
szSid = lpGPOInfo->dwFlags & GP_MACHINE ? 0 : lpGPOInfo->lpwszSidUser;
|
|
|
|
DWORD dwError;
|
|
if ( dwStatus == ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED )
|
|
{
|
|
FgPolicyRefreshInfo curInfo = { GP_ReasonUnknown, GP_ModeUnknown};
|
|
GetCurrentFgPolicyRefreshInfo( szSid, &curInfo );
|
|
SetPreviousFgPolicyRefreshInfo( szSid, curInfo );
|
|
|
|
info.mode = GP_ModeSyncForeground;
|
|
info.reason = GP_ReasonCSERequiresSync;
|
|
dwError = SetNextFgPolicyRefreshInfo( szSid,
|
|
info );
|
|
if ( dwError != ERROR_SUCCESS )
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGroupPolicyCompletedEx: SetNextFgPolicyRefreshInfo failed, %x."), dwError ));
|
|
}
|
|
}
|
|
|
|
if ( dwRet == ERROR_SUCCESS )
|
|
{
|
|
//
|
|
// clear E_PENDING status code with status returned
|
|
//
|
|
bUsePerUserLocalSetting = !(lpGPOInfo->dwFlags & GP_MACHINE) && lpGPOInfo->lpwszSidUser != NULL;
|
|
GPEXTSTATUS gpExtStatus;
|
|
|
|
gpExtStatus.dwSlowLink = (lpGPOInfo->dwFlags & GP_SLOW_LINK) != 0;
|
|
gpExtStatus.dwRsopLogging = lpGPOInfo->bRsopLogging;
|
|
gpExtStatus.dwStatus = dwStatus;
|
|
gpExtStatus.dwTime = dwCurrentTime;
|
|
gpExtStatus.bForceRefresh = FALSE;
|
|
|
|
WriteStatus( szExtension, lpGPOInfo,
|
|
bUsePerUserLocalSetting ? lpGPOInfo->lpwszSidUser : NULL,
|
|
&gpExtStatus);
|
|
|
|
//
|
|
// Building up a dummy gpExt structure so that we can log the info required.
|
|
//
|
|
|
|
GPEXT gpExt;
|
|
TCHAR szSubKey[MAX_PATH]; // same as the path in readgpextensions
|
|
HKEY hKey;
|
|
TCHAR szDisplayName[50]; // same as the path in readgpextensions
|
|
DWORD dwSize, dwType;
|
|
CHAR szFunctionName[100]; // same as the path in readgpextensions
|
|
|
|
gpExt.lpKeyName = szExtension;
|
|
|
|
hr = StringCchCopy(szSubKey, ARRAYSIZE(szSubKey), GP_EXTENSIONS);
|
|
ASSERT(SUCCEEDED(hr));
|
|
CheckSlash(szSubKey);
|
|
hr = StringCchCat(szSubKey, ARRAYSIZE(szSubKey), szExtension);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
|
|
//
|
|
// Read the displayname so that we can log it..
|
|
//
|
|
|
|
szDisplayName[0] = TEXT('\0');
|
|
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
|
|
szSubKey,
|
|
0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
|
|
dwSize = sizeof(szDisplayName);
|
|
if (RegQueryValueEx (hKey, NULL, NULL,
|
|
&dwType, (LPBYTE) szDisplayName,
|
|
&dwSize) != ERROR_SUCCESS)
|
|
{
|
|
lstrcpyn (szDisplayName, szExtension, ARRAYSIZE(szDisplayName));
|
|
}
|
|
|
|
|
|
dwSize = sizeof(szFunctionName);
|
|
if ( RegQueryValueExA (hKey, "ProcessGroupPolicyEx", NULL,
|
|
&dwType, (LPBYTE) szFunctionName,
|
|
&dwSize) == ERROR_SUCCESS )
|
|
{
|
|
gpExt.bNewInterface = TRUE;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
gpExt.lpDisplayName = szDisplayName;
|
|
|
|
if ((lpGPOInfo->bRsopLogging))
|
|
{
|
|
|
|
XInterface<IWbemServices> xWbemServices;
|
|
|
|
GetWbemServices( lpGPOInfo, RSOP_NS_DIAG_ROOT, TRUE, FALSE, &xWbemServices);
|
|
|
|
if (xWbemServices)
|
|
{
|
|
|
|
if (!gpExt.bNewInterface)
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGroupPolicyCompletedEx: Extension %s doesn't support rsop logging."),
|
|
szExtension));
|
|
|
|
UpdateExtSessionStatus(xWbemServices, szExtension, TRUE, dwRet);
|
|
}
|
|
else if (SUCCEEDED(hrRsopStatus))
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGroupPolicyCompletedEx: Extension %s was able to log data. Error = 0x%x, dwRet = %d. Clearing the dirty bit"),
|
|
szExtension, hrRsopStatus, dwStatus));
|
|
|
|
UpdateExtSessionStatus(xWbemServices, szExtension, FALSE, dwRet);
|
|
}
|
|
else
|
|
{
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessroupPolicyCompletedEx: Extension %s was not able to log data. Error = 0x%x, dwRet = %d. leaving the log dirty"),
|
|
szExtension, hrRsopStatus, dwStatus));
|
|
|
|
CEvents ev(TRUE, EVENT_EXT_RSOP_FAILED);
|
|
ev.AddArg(gpExt.lpDisplayName); ev.Report();
|
|
|
|
UpdateExtSessionStatus(xWbemServices, szExtension, TRUE, dwRet);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection( &g_GPOCS );
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ProcessGroupPolicyCompleted: Leaving. Extension = %s, Return status dwRet = 0x%x"),
|
|
szExtension, dwRet));
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// ProcessGroupPolicyCompleted()
|
|
//
|
|
// Purpose: Callback for asynchronous completion of an extension
|
|
//
|
|
// Parameters: refExtensionId - Unique guid of extension
|
|
// pAsyncHandle - Completion context
|
|
// dwStatus - Asynchronous completion status
|
|
//
|
|
// Returns: Win32 error code
|
|
//
|
|
//*************************************************************
|
|
|
|
DWORD ProcessGroupPolicyCompleted( REFGPEXTENSIONID extensionGuid,
|
|
ASYNCCOMPLETIONHANDLE pAsyncHandle,
|
|
DWORD dwStatus )
|
|
{
|
|
//
|
|
// Mark RSOP data as clean for legacy extensions
|
|
//
|
|
|
|
return ProcessGroupPolicyCompletedEx(extensionGuid, pAsyncHandle, dwStatus,
|
|
HRESULT_FROM_WIN32(S_OK));
|
|
}
|
|
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// DebugPrintGPOList()
|
|
//
|
|
// Purpose: Prints GPO list
|
|
//
|
|
// Parameters: lpGPOInfo - GPO Info
|
|
//
|
|
//*************************************************************
|
|
|
|
void DebugPrintGPOList( LPGPOINFO lpGPOInfo )
|
|
{
|
|
//
|
|
// If we are in verbose mode, put the list of GPOs in the event log
|
|
//
|
|
|
|
PGROUP_POLICY_OBJECT lpGPO = NULL;
|
|
DWORD dwSize;
|
|
HRESULT hr = S_OK;
|
|
|
|
#if DBG
|
|
if (TRUE) {
|
|
#else
|
|
if (lpGPOInfo->dwFlags & GP_VERBOSE) {
|
|
#endif
|
|
LPTSTR lpTempList;
|
|
|
|
dwSize = 10;
|
|
lpGPO = lpGPOInfo->lpGPOList;
|
|
while (lpGPO) {
|
|
if (lpGPO->lpDisplayName) {
|
|
dwSize += (lstrlen (lpGPO->lpDisplayName) + 4);
|
|
}
|
|
lpGPO = lpGPO->pNext;
|
|
}
|
|
|
|
lpTempList = (LPWSTR) LocalAlloc (LPTR, (dwSize * sizeof(TCHAR)));
|
|
|
|
if (lpTempList) {
|
|
|
|
hr = StringCchCopy (lpTempList, dwSize, TEXT(""));
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
lpGPO = lpGPOInfo->lpGPOList;
|
|
while (lpGPO) {
|
|
if (lpGPO->lpDisplayName) {
|
|
hr = StringCchCat (lpTempList, dwSize, TEXT("\""));
|
|
ASSERT(SUCCEEDED(hr));
|
|
hr = StringCchCat (lpTempList, dwSize, lpGPO->lpDisplayName);
|
|
ASSERT(SUCCEEDED(hr));
|
|
hr = StringCchCat (lpTempList, dwSize, TEXT("\" "));
|
|
ASSERT(SUCCEEDED(hr));
|
|
}
|
|
lpGPO = lpGPO->pNext;
|
|
}
|
|
|
|
if (lpGPOInfo->dwFlags & GP_VERBOSE) {
|
|
CEvents ev(FALSE, EVENT_GPO_LIST);
|
|
ev.AddArg(lpTempList); ev.Report();
|
|
}
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("DebugPrintGPOList: List of GPO(s) to process: %s"),
|
|
lpTempList));
|
|
|
|
LocalFree (lpTempList);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// UserPolicyCallback()
|
|
//
|
|
// Purpose: Callback function for status UI messages
|
|
//
|
|
// Parameters: bVerbose - Verbose message or not
|
|
// lpMessage - Message text
|
|
//
|
|
// Return: ERROR_SUCCESS if successful
|
|
// Win32 error code if an error occurs
|
|
//
|
|
//*************************************************************
|
|
|
|
DWORD UserPolicyCallback (BOOL bVerbose, LPWSTR lpMessage)
|
|
{
|
|
WCHAR szMsg[100];
|
|
LPWSTR lpMsg;
|
|
DWORD dwResult = ERROR_INVALID_FUNCTION;
|
|
|
|
|
|
if (lpMessage) {
|
|
lpMsg = lpMessage;
|
|
} else {
|
|
if (!LoadString (g_hDllInstance, IDS_USER_SETTINGS, szMsg, 100))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("UserPolicyCallback: Couldn't load string from resource with %d"), GetLastError()));
|
|
return GetLastError();
|
|
}
|
|
|
|
lpMsg = szMsg;
|
|
}
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("UserPolicyCallback: Setting status UI to %s"), lpMsg));
|
|
|
|
EnterCriticalSection (&g_StatusCallbackCS);
|
|
|
|
if (g_pStatusMessageCallback) {
|
|
dwResult = g_pStatusMessageCallback(bVerbose, lpMsg);
|
|
} else {
|
|
DebugMsg((DM_VERBOSE, TEXT("UserPolicyCallback: Extension requested status UI when status UI is not available.")));
|
|
}
|
|
|
|
LeaveCriticalSection (&g_StatusCallbackCS);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// MachinePolicyCallback()
|
|
//
|
|
// Purpose: Callback function for status UI messages
|
|
//
|
|
// Parameters: bVerbose - Verbose message or not
|
|
// lpMessage - Message text
|
|
//
|
|
// Return: ERROR_SUCCESS if successful
|
|
// Win32 error code if an error occurs
|
|
//
|
|
//*************************************************************
|
|
|
|
DWORD MachinePolicyCallback (BOOL bVerbose, LPWSTR lpMessage)
|
|
{
|
|
WCHAR szMsg[100];
|
|
LPWSTR lpMsg;
|
|
DWORD dwResult = ERROR_INVALID_FUNCTION;
|
|
|
|
|
|
if (lpMessage) {
|
|
lpMsg = lpMessage;
|
|
} else {
|
|
if (!LoadString (g_hDllInstance, IDS_COMPUTER_SETTINGS, szMsg, 100))
|
|
{
|
|
DebugMsg((DM_WARNING, TEXT("MachinePolicyCallback: Couldn't load string from resource with %d"), GetLastError()));
|
|
return GetLastError();
|
|
}
|
|
|
|
lpMsg = szMsg;
|
|
}
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("MachinePolicyCallback: Setting status UI to %s"), lpMsg));
|
|
|
|
EnterCriticalSection (&g_StatusCallbackCS);
|
|
|
|
if (g_pStatusMessageCallback) {
|
|
dwResult = g_pStatusMessageCallback(bVerbose, lpMsg);
|
|
} else {
|
|
DebugMsg((DM_VERBOSE, TEXT("MachinePolicyCallback: Extension requested status UI when status UI is not available.")));
|
|
}
|
|
|
|
LeaveCriticalSection (&g_StatusCallbackCS);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// CallDFS()
|
|
//
|
|
// Purpose: Calls DFS to initialize the domain / DC name
|
|
//
|
|
// Parameters: lpDomainName - Domain name
|
|
// lpDCName - DC name
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
//
|
|
//*************************************************************
|
|
|
|
//
|
|
// Once upon a time when this file was a C file,
|
|
// the definition of POINTER_TO_OFFSET looked like this,
|
|
//
|
|
// #define POINTER_TO_OFFSET(field, buffer) \
|
|
// ( ((PCHAR)field) -= ((ULONG_PTR)buffer) )
|
|
//
|
|
// Now, that we have decided to end antiquity and made this a C++ file,
|
|
// the new definition is,
|
|
//
|
|
|
|
#define POINTER_TO_OFFSET(field, buffer) \
|
|
( field = (LPWSTR) ( (PCHAR)field -(ULONG_PTR)buffer ) )
|
|
|
|
NTSTATUS CallDFS(LPWSTR lpDomainName, LPWSTR lpDCName)
|
|
{
|
|
HANDLE DfsDeviceHandle = NULL;
|
|
PDFS_SPC_REFRESH_INFO DfsInfo;
|
|
ULONG lpDomainNameLen, lpDCNameLen, sizeNeeded;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
NTSTATUS status;
|
|
UNICODE_STRING unicodeServerName;
|
|
|
|
|
|
lpDomainNameLen = (wcslen(lpDomainName) + 1) * sizeof(WCHAR);
|
|
lpDCNameLen = (wcslen(lpDCName) + 1) * sizeof(WCHAR);
|
|
|
|
sizeNeeded = sizeof(DFS_SPC_REFRESH_INFO) + lpDomainNameLen + lpDCNameLen;
|
|
|
|
DfsInfo = (PDFS_SPC_REFRESH_INFO)LocalAlloc(LPTR, sizeNeeded);
|
|
|
|
if (DfsInfo == NULL) {
|
|
DebugMsg((DM_WARNING, TEXT("CallDFS: LocalAlloc failed with %d"), GetLastError()));
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
DfsInfo->DomainName = (WCHAR *)((PCHAR)DfsInfo + sizeof(DFS_SPC_REFRESH_INFO));
|
|
DfsInfo->DCName = (WCHAR *)((PCHAR)DfsInfo->DomainName + lpDomainNameLen);
|
|
|
|
|
|
RtlCopyMemory(DfsInfo->DomainName,
|
|
lpDomainName,
|
|
lpDomainNameLen);
|
|
|
|
RtlCopyMemory(DfsInfo->DCName,
|
|
lpDCName,
|
|
lpDCNameLen);
|
|
|
|
POINTER_TO_OFFSET(DfsInfo->DomainName, DfsInfo);
|
|
POINTER_TO_OFFSET(DfsInfo->DCName, DfsInfo);
|
|
|
|
RtlInitUnicodeString( &unicodeServerName, L"\\Dfs");
|
|
|
|
InitializeObjectAttributes(
|
|
&objectAttributes,
|
|
&unicodeServerName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
status = NtOpenFile(
|
|
&DfsDeviceHandle,
|
|
SYNCHRONIZE | FILE_WRITE_DATA,
|
|
&objectAttributes,
|
|
&ioStatusBlock,
|
|
0,
|
|
FILE_SYNCHRONOUS_IO_NONALERT
|
|
);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status) ) {
|
|
DebugMsg((DM_WARNING, TEXT("CallDFS: NtOpenFile failed with 0x%x"), status));
|
|
LocalFree(DfsInfo);
|
|
return status;
|
|
}
|
|
|
|
status = NtFsControlFile(
|
|
DfsDeviceHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&ioStatusBlock,
|
|
FSCTL_DFS_SPC_REFRESH,
|
|
DfsInfo, sizeNeeded,
|
|
NULL, 0);
|
|
|
|
if (!NT_SUCCESS(status) ) {
|
|
DebugMsg((DM_WARNING, TEXT("CallDFS: NtFsControlFile failed with 0x%x"), status));
|
|
}
|
|
|
|
|
|
LocalFree(DfsInfo);
|
|
NtClose(DfsDeviceHandle);
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// InitializePolicyProcessing
|
|
//
|
|
// Purpose: Initialises mutexes corresponding to user and machine
|
|
//
|
|
// Parameters: bMachine - Whether it is machine or user
|
|
//
|
|
// Return:
|
|
//
|
|
// Comments:
|
|
// These events/Mutexes need to be initialised right at the beginning
|
|
// because the ACls on these needs to be set before ApplyGroupPolicy can
|
|
// be called..
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL InitializePolicyProcessing(BOOL bMachine)
|
|
{
|
|
HANDLE hSection, hEvent;
|
|
XPtrLF<SECURITY_DESCRIPTOR> xsd;
|
|
SECURITY_ATTRIBUTES sa;
|
|
CSecDesc Csd;
|
|
XLastError xe;
|
|
|
|
|
|
Csd.AddLocalSystem();
|
|
Csd.AddAdministrators();
|
|
Csd.AddEveryOne(SYNCHRONIZE);
|
|
|
|
xsd = Csd.MakeSD();
|
|
|
|
if (!xsd) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("InitializePolicyProcessing: Failed to create Security Descriptor with %d"),
|
|
GetLastError()));
|
|
// since this is happening in dll load we cannot log an event at this point..
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
sa.lpSecurityDescriptor = (SECURITY_DESCRIPTOR *)xsd;
|
|
sa.bInheritHandle = FALSE;
|
|
sa.nLength = sizeof(sa);
|
|
|
|
|
|
//
|
|
// Synch mutex for group policies
|
|
//
|
|
|
|
hSection = CreateMutex (&sa, FALSE,
|
|
(bMachine ? MACHINE_POLICY_MUTEX : USER_POLICY_MUTEX));
|
|
|
|
if (!hSection) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("InitializePolicyProcessing: Failed to create mutex with %d"),
|
|
GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
if (bMachine)
|
|
g_hPolicyCritMutexMach = hSection;
|
|
else
|
|
g_hPolicyCritMutexUser = hSection;
|
|
|
|
//
|
|
// Mutex for registry policy only
|
|
//
|
|
HANDLE hRegistrySection = CreateMutex(&sa, FALSE,
|
|
(bMachine ? MACH_REGISTRY_EXT_MUTEX : USER_REGISTRY_EXT_MUTEX ));
|
|
|
|
if (!hRegistrySection) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("InitializePolicyProcessing: Failed to create mutex with %d"),
|
|
GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
if (bMachine)
|
|
g_hRegistryPolicyCritMutexMach = hRegistrySection;
|
|
else
|
|
g_hRegistryPolicyCritMutexUser = hRegistrySection;
|
|
|
|
|
|
|
|
//
|
|
// Group Policy Notification events
|
|
//
|
|
|
|
|
|
//
|
|
// Create the changed notification event
|
|
//
|
|
|
|
hEvent = CreateEvent (&sa, TRUE, FALSE,
|
|
(bMachine) ? MACHINE_POLICY_APPLIED_EVENT : USER_POLICY_APPLIED_EVENT);
|
|
|
|
|
|
if (!hEvent) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("InitializePolicyProcessing: Failed to create NotifyEvent with %d"),
|
|
GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
if (bMachine)
|
|
g_hPolicyNotifyEventMach = hEvent;
|
|
else
|
|
g_hPolicyNotifyEventUser = hEvent;
|
|
|
|
//
|
|
// Create the needfg event
|
|
//
|
|
|
|
hEvent = CreateEvent (&sa, FALSE, FALSE,
|
|
(bMachine) ? MACHINE_POLICY_REFRESH_NEEDFG_EVENT : USER_POLICY_REFRESH_NEEDFG_EVENT);
|
|
|
|
if (!hEvent) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("InitializePolicyProcessing: Failed to create NeedFGEvent with %d"),
|
|
GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
if (bMachine)
|
|
g_hPolicyNeedFGEventMach = hEvent;
|
|
else
|
|
g_hPolicyNeedFGEventUser = hEvent;
|
|
|
|
|
|
//
|
|
// Create the done event
|
|
//
|
|
hEvent = CreateEvent (&sa, TRUE, FALSE,
|
|
(bMachine) ? MACHINE_POLICY_DONE_EVENT : USER_POLICY_DONE_EVENT);
|
|
if (!hEvent) {
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("InitializePolicyProcessing: Failed to create hNotifyDoneEvent with %d"),
|
|
GetLastError()));
|
|
return FALSE;
|
|
}
|
|
|
|
if (bMachine)
|
|
g_hPolicyDoneEventMach = hEvent;
|
|
else
|
|
g_hPolicyDoneEventUser = hEvent;
|
|
|
|
//
|
|
// Create the machine policy - user policy sync event
|
|
//
|
|
if ( bMachine )
|
|
{
|
|
hEvent = CreateEvent( &sa,
|
|
TRUE,
|
|
FALSE,
|
|
MACH_POLICY_FOREGROUND_DONE_EVENT );
|
|
if ( !hEvent )
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("InitializePolicyProcessing: Failed to create m/c-user policy sync event with %d"),
|
|
GetLastError()));
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
g_hPolicyForegroundDoneEventMach = hEvent;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hEvent = CreateEvent( &sa,
|
|
TRUE,
|
|
FALSE,
|
|
USER_POLICY_FOREGROUND_DONE_EVENT );
|
|
if ( !hEvent )
|
|
{
|
|
xe = GetLastError();
|
|
DebugMsg((DM_WARNING, TEXT("InitializePolicyProcessing: Failed to create user policy/logon script sync event with %d"),
|
|
GetLastError()));
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
g_hPolicyForegroundDoneEventUser = hEvent;
|
|
}
|
|
}
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("InitializePolicyProcessing: Initialised %s Mutex/Events"),
|
|
bMachine ? TEXT("Machine"): TEXT("User")));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
USERENVAPI
|
|
DWORD
|
|
WINAPI
|
|
WaitForUserPolicyForegroundProcessing()
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
HANDLE hEvent = OpenEvent( SYNCHRONIZE, FALSE, USER_POLICY_FOREGROUND_DONE_EVENT );
|
|
|
|
if ( hEvent )
|
|
{
|
|
if ( WaitForSingleObject( hEvent, INFINITE ) == WAIT_FAILED )
|
|
{
|
|
dwError = GetLastError();
|
|
DebugMsg((DM_VERBOSE, TEXT("WaitForUserPolicyForegroundProcessing: Failed, %x"), dwError ));
|
|
}
|
|
CloseHandle( hEvent );
|
|
}
|
|
else
|
|
{
|
|
dwError = GetLastError();
|
|
DebugMsg((DM_VERBOSE, TEXT("WaitForUserPolicyForegroundProcessing: Failed, %x"), dwError ));
|
|
}
|
|
return dwError;
|
|
}
|
|
|
|
USERENVAPI
|
|
DWORD
|
|
WINAPI
|
|
WaitForMachinePolicyForegroundProcessing()
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
HANDLE hEvent = OpenEvent( SYNCHRONIZE, FALSE, MACH_POLICY_FOREGROUND_DONE_EVENT );
|
|
|
|
if ( hEvent )
|
|
{
|
|
if ( WaitForSingleObject( hEvent, INFINITE ) == WAIT_FAILED )
|
|
{
|
|
dwError = GetLastError();
|
|
DebugMsg((DM_VERBOSE, TEXT("WaitForMachinePolicyForegroundProcessing: Failed, %x"), dwError ));
|
|
}
|
|
CloseHandle( hEvent );
|
|
}
|
|
else
|
|
{
|
|
dwError = GetLastError();
|
|
DebugMsg((DM_VERBOSE, TEXT("WaitForMachinePolicyForegroundProcessing: Failed, %x"), dwError ));
|
|
}
|
|
return dwError;
|
|
}
|
|
|
|
extern "C" DWORD
|
|
SignalUserPolicyForegroundProcessingDone()
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
if ( !SetEvent( g_hPolicyForegroundDoneEventUser ) )
|
|
{
|
|
dwError = GetLastError();
|
|
DebugMsg((DM_VERBOSE, TEXT("SignalUserPolicyForegroundProcessingDone: Failed, %x"), dwError ));
|
|
}
|
|
return dwError;
|
|
}
|
|
|
|
extern "C" DWORD
|
|
SignalMachinePolicyForegroundProcessingDone()
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
if ( !SetEvent( g_hPolicyForegroundDoneEventMach ) )
|
|
{
|
|
dwError = GetLastError();
|
|
DebugMsg((DM_VERBOSE, TEXT("SignalForMachinePolicyForegroundProcessingDone: Failed, %x"), dwError ));
|
|
}
|
|
return dwError;
|
|
}
|
|
|