Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4802 lines
157 KiB

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