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