|
|
//*************************************************************
//
// Copyright (c) Microsoft Corporation 1998
// All rights reserved
//
// manapp.cxx
//
//*************************************************************
#include "appmgext.hxx"
#pragma warning(disable:4355)
CManagedAppProcessor::CManagedAppProcessor( DWORD dwFlags, HANDLE hUserToken, HKEY hKeyRoot, PFNSTATUSMESSAGECALLBACK pfnStatusCallback, BOOL bIncludeLegacy, BOOL bRegularPolicyRun, CRsopAppContext* pRsopContext, DWORD & Status ) : _Apps( this, &_RsopContext ), _LocalScripts( this ), _pfnStatusCallback(pfnStatusCallback) { DWORD Size; DWORD LastArchLang; BOOL bFullPolicy; HRESULT hr;
_bUser = ! (dwFlags & GPO_INFO_FLAG_MACHINE); _bNoChanges = (dwFlags & GPO_INFO_FLAG_NOCHANGES) && ! (gDebugLevel & DL_APPLY) && ! ( dwFlags & GPO_INFO_FLAG_LOGRSOP_TRANSITION ); _bAsync = (dwFlags & GPO_INFO_FLAG_ASYNC_FOREGROUND) && ! (gDebugLevel & DL_APPLY) && ! ( dwFlags & GPO_INFO_FLAG_LOGRSOP_TRANSITION ); _bARPList = FALSE; _hkRoot = 0; _hkPolicy = 0; _hkAppmgmt = 0; _hUserToken = 0; _NewUsn = 0; _ArchLang = 0; _pwszLocalPath = 0; _bIncludeLegacy = bIncludeLegacy; _bDeleteGPOs = FALSE; _bRegularPolicyRun = bRegularPolicyRun; _ErrorReason = 0;
//
// In the case of gpo removal, we cannot apply this during an async refresh
//
if ( _bAsync && ! bRegularPolicyRun ) { _ErrorReason = ERRORREASON_PROCESS; DebugMsg((DM_VERBOSE, IDS_ABORT_OPERATION));
Status = ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED;
return; } if ( CRsopAppContext::POLICY_REFRESH == pRsopContext->GetContext() ) { if ( _bAsync ) { DebugMsg((DM_VERBOSE, IDS_ASYNC_REFRESH)); } else { DebugMsg((DM_VERBOSE, IDS_SYNC_REFRESH)); } }
hr = GetRsopContext()->MoveAppContextState( pRsopContext );
if ( FAILED( hr ) ) { Status = GetWin32ErrFromHResult( hr ); goto CManagedAppProcessor__CManagedAppProcessor_Exit; }
if ( _bUser && ! GetRsopContext()->IsPlanningModeEnabled() ) { if ( ! DuplicateToken( hUserToken, SecurityImpersonation, &_hUserToken ) ) { goto CManagedAppProcessor__CManagedAppProcessor_Exit; } }
//
// Act as if there are changes when planning mode is enabled
//
if ( GetRsopContext()->IsPlanningModeEnabled() ) { _bNoChanges = FALSE; }
if ( ! GetRsopContext()->IsPlanningModeEnabled() ) { Status = RegOpenKeyEx( hKeyRoot, NULL, 0, KEY_READ | KEY_WRITE, &_hkRoot );
if ( Status != ERROR_SUCCESS ) goto CManagedAppProcessor__CManagedAppProcessor_Exit;
Status = RegCreateKeyEx( _hkRoot, POLICYKEY, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &_hkPolicy, NULL );
if ( Status != ERROR_SUCCESS ) goto CManagedAppProcessor__CManagedAppProcessor_Exit;
Status = RegCreateKeyEx( _hkPolicy, APPMGMTSUBKEY, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &_hkAppmgmt, NULL );
if ( Status != ERROR_SUCCESS ) goto CManagedAppProcessor__CManagedAppProcessor_Exit; }
BOOL bForcedRefresh;
bForcedRefresh = FALSE;
if ( bRegularPolicyRun ) { SYSTEM_INFO SystemInfo;
//
// The service sets the FULLPOLICY value when the user does an uninstall.
// This forces us to do a full policy run to pick up any new app that may
// need to be applied now.
//
bFullPolicy = FALSE; Size = sizeof( bFullPolicy );
if (!GetRsopContext()->IsPlanningModeEnabled()) { (void) RegQueryValueEx( _hkAppmgmt, FULLPOLICY, NULL, NULL, (LPBYTE) &bFullPolicy, &Size ); (void) RegDeleteValue( _hkAppmgmt, FULLPOLICY );
if ( _bNoChanges ) { bForcedRefresh = bFullPolicy; } } else { bFullPolicy = TRUE; }
if ( bFullPolicy ) _bNoChanges = FALSE;
_ArchLang = GetSystemDefaultLangID(); GetSystemInfo( &SystemInfo ); _ArchLang |= (SystemInfo.wProcessorArchitecture << 16);
if (!GetRsopContext()->IsPlanningModeEnabled()) { Size = sizeof( LastArchLang );
Status = RegQueryValueEx( _hkAppmgmt, LASTARCHLANG, NULL, NULL, (LPBYTE) &LastArchLang, &Size );
if ( (ERROR_SUCCESS == Status) && _bNoChanges && (_ArchLang != LastArchLang) ) { if ( _bNoChanges ) { bForcedRefresh = TRUE; }
_bNoChanges = FALSE;
if ( Async() ) { DebugMsg((DM_VERBOSE, IDS_ABORT_OPERATION)); } } } }
Status = GetScriptDirPath( _bUser ? _hUserToken : NULL, 0, &_pwszLocalPath );
if ( ERROR_SUCCESS == Status && ! GetRsopContext()->IsPlanningModeEnabled() ) Status = CreateAndSecureScriptDir();
if ( (ERROR_SUCCESS == Status) && ! GetRsopContext()->IsPlanningModeEnabled() ) Status = GetLocalScriptAppList( _LocalScripts );
if ( Status != ERROR_SUCCESS ) { DebugMsg((DM_WARNING, IDS_CREATEDIR_FAIL, Status)); goto CManagedAppProcessor__CManagedAppProcessor_Exit; }
if ( _bNoChanges ) { if ( DetectLostApps() ) { bForcedRefresh = TRUE; _bNoChanges = FALSE; } }
//
// Ensure that the rsop context is properly initialized, even if the
// group policy engine did not give us a context but we need to log data
//
(void) GetRsopContext()->InitializeRsopContext( UserToken(), AppmgmtKey(), bForcedRefresh, &_bNoChanges); CManagedAppProcessor__CManagedAppProcessor_Exit:
return; }
#pragma warning(default:4355)
CManagedAppProcessor::~CManagedAppProcessor() { if ( _hkPolicy ) RegCloseKey( _hkPolicy );
if ( _hkAppmgmt ) RegCloseKey( _hkAppmgmt );
if ( _hkRoot ) RegCloseKey( _hkRoot );
if ( _hUserToken ) CloseHandle( _hUserToken );
delete _pwszLocalPath; }
BOOL CManagedAppProcessor::AddGPO( PGROUP_POLICY_OBJECT pGPOInfo ) { CGPOInfo * pGPO; BOOL bStatus;
//
// Prevent duplicates in the list. A GPO could be linked to multiple
// OUs, so only keep the last instance of a policy.
//
pGPO = _GPOs.Find( pGPOInfo->szGPOName ); if ( pGPO ) { pGPO->Remove(); delete pGPO; }
return _GPOs.Add( pGPOInfo ); }
DWORD CManagedAppProcessor::Delete() { DWORD Status;
_bDeleteGPOs = TRUE;
ASSERT( ! Async() );
Status = GetRemovedApps();
if ( Status != ERROR_SUCCESS ) { _ErrorReason = ERRORREASON_LOCAL; return Status; }
_CSPath.Commit(_hUserToken);
Status = _Apps.ProcessPolicy();
if ( Status != ERROR_SUCCESS ) _ErrorReason = ERRORREASON_PROCESS;
return Status; }
DWORD CManagedAppProcessor::GetRemovedApps() { CAppList LocalApps( NULL ); CGPOInfo * pGPOInfo; CAppInfo * pAppInfo; DWORD Status;
Status = GetOrderedLocalAppList( LocalApps );
if ( ERROR_SUCCESS == Status ) Status = Impersonate();
if ( Status != ERROR_SUCCESS ) return Status;
_GPOs.Reset();
for ( pGPOInfo = (CGPOInfo *) _GPOs.GetCurrentItem(); pGPOInfo; _GPOs.MoveNext(), pGPOInfo = (CGPOInfo *) _GPOs.GetCurrentItem() ) { DebugMsg((DM_VERBOSE, IDS_REMOVE_POLICY, pGPOInfo->_pwszGPOName));
LocalApps.Reset();
for ( pAppInfo = (CAppInfo *) LocalApps.GetCurrentItem(); pAppInfo; pAppInfo = (CAppInfo *) LocalApps.GetCurrentItem() ) { //
// Look for apps in the removed policy.
//
// Ignore apps which are not currently assigned or published from the removed
// policy except for apps which have been uninstalled from machines other
// than this one. This is what the second logic check is doing. In this case
// we have to uninstall it at this machine as well.
//
if ( ! (pAppInfo->_State & (APPSTATE_ASSIGNED | APPSTATE_PUBLISHED | APPSTATE_UNINSTALLED)) || ((pAppInfo->_State & APPSTATE_UNINSTALLED) && ! (pAppInfo->_State & APPSTATE_SCRIPT_PRESENT)) || (lstrcmpi( pAppInfo->_pwszGPOId, pGPOInfo->_pwszGPOId ) != 0) ) { LocalApps.MoveNext(); continue; }
//
// On very rare occasion, a policy could be removed at the same time a
// first time logon to a machine is made. In this case we will need
// to copy scripts for uninstalled apps. We attempt to get the script
// path here. This may fail for permission reasons, if the policy
// is being removed, it's likely it will not be accessible for this
// user/machine.
//
if ( (pAppInfo->_State & APPSTATE_POLICYREMOVE_UNINSTALL) && ! (pAppInfo->_State & APPSTATE_SCRIPT_PRESENT) ) { PACKAGEDISPINFO PackageInfo; HRESULT hr;
hr = GetDsPackageFromGPO( pGPOInfo, &(pAppInfo->_DeploymentId), &PackageInfo);
if ( S_OK == hr ) { pAppInfo->_pwszGPTScriptPath = StringDuplicate( PackageInfo.pszScriptPath ); ReleasePackageInfo( &PackageInfo ); if ( ! pAppInfo->_pwszGPTScriptPath ) { Revert(); return ERROR_OUTOFMEMORY; } } }
if ( pAppInfo->_State & APPSTATE_POLICYREMOVE_UNINSTALL ) { pAppInfo->SetAction( ACTION_UNINSTALL, APP_ATTRIBUTE_REMOVALCAUSE_SCOPELOSS, NULL); } else { pAppInfo->SetAction( ACTION_ORPHAN, APP_ATTRIBUTE_REMOVALCAUSE_SCOPELOSS, NULL); }
LocalApps.MoveNext(); pAppInfo->Remove(); _Apps.InsertFIFO( pAppInfo ); }
LocalApps.ResetEnd(); }
_GPOs.ResetEnd();
Revert();
return Status; }
DWORD CManagedAppProcessor::Process() { CGPOInfo * pGPOInfo; DWORD Status;
Status = Impersonate();
if ( Status != ERROR_SUCCESS ) return Status;
for ( _GPOs.Reset(); pGPOInfo = (CGPOInfo *) _GPOs.GetCurrentItem(); _GPOs.MoveNext() ) { Status = _CSPath.AddComponent( pGPOInfo->_pwszGPOPath, pGPOInfo->_pwszGPOName ); if ( Status != ERROR_SUCCESS ) break; }
Revert();
_GPOs.ResetEnd(); if ( ! GetRsopContext()->IsPlanningModeEnabled() ) { if ( ERROR_SUCCESS == Status ) { Status = _CSPath.Commit( _hUserToken ); }
if ( Status != ERROR_SUCCESS ) { if ( CS_E_NO_CLASSSTORE == Status ) { return ERROR_SUCCESS; } else { _ErrorReason = ERRORREASON_CSPATH; return Status; } } }
if ( _bNoChanges ) { DebugMsg((DM_VERBOSE, IDS_NOCHANGES)); } else { if ( ! GetRsopContext()->IsPlanningModeEnabled() ) { LogonMsgApplying(); }
// Really returns an HRESULT.
Status = (DWORD) GetAppsFromDirectory();
if ( Status != ERROR_SUCCESS ) _ErrorReason = ERRORREASON_ENUM; }
if ( ERROR_SUCCESS == Status ) Status = GetAppsFromLocal();
if ( ERROR_SUCCESS == Status ) Status = CommitPolicyList();
if ( ERROR_SUCCESS == Status ) Status = GetLostApps();
if ( Status != ERROR_SUCCESS ) _ErrorReason = ERRORREASON_LOCAL;
if ( ERROR_SUCCESS == Status ) Status = _Apps.ProcessPolicy();
if ( Status != ERROR_SUCCESS ) _ErrorReason = ERRORREASON_PROCESS;
if ( ! GetRsopContext()->IsPlanningModeEnabled() ) { if ( (ERROR_SUCCESS == Status) && (_ArchLang != 0) ) { (void) RegSetValueEx( _hkAppmgmt, LASTARCHLANG, 0, REG_DWORD, (LPBYTE) &_ArchLang, sizeof(_ArchLang) ); }
if ( ! _bNoChanges ) LogonMsgDefault(); }
//
// If we are processing asynchronously and changes are detected,
// we should ensure that a synchronous refresh occurs next time
//
if ( ( ERROR_SUCCESS == Status ) && Async() && ! _bNoChanges ) { Status = ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED; }
return Status; }
void CManagedAppProcessor::WriteRsopLogs() { HRESULT hr; BOOL ResultantSetChanged; hr = S_OK;
//
// By default, the resultant set changes only if policy has changed
//
ResultantSetChanged = ! _bNoChanges;
#if DBG
DWORD DebugStatus; #endif // DBG
//
// If we're in diagnostic mode, make sure we reset
// the diagnostic namespace if policy has changed
//
if ( ( GetRsopContext()->IsDiagnosticModeEnabled() && ResultantSetChanged ) && ( CRsopAppContext::POLICY_REFRESH == GetRsopContext()->GetContext() ) ) { if ( ! GetRsopContext()->IsPlanningModeEnabled() && ! GetRsopContext()->ForcedRefresh() ) { //
// Reset the namespace
//
GetRsopContext()->DeleteSavedNameSpace(); } }
//
// For ARP, ensure that no one tries to read the namespace to
// which we are logging until we are finished.
//
if ( ARPList() ) { hr = GetRsopContext()->GetExclusiveLoggingAccess( NULL == UserToken() ); }
//
// First, make sure rsop logging is enabled
//
if ( SUCCEEDED(hr) && GetRsopContext()->IsRsopEnabled() ) { if ( ResultantSetChanged ) { hr = _Apps.WriteLog();
if (FAILED(hr)) { GetRsopContext()->DisableRsop( hr ); } } else { //
// Disable rsop if there are no changes -- there is nothing
// to log
//
GetRsopContext()->DisableRsop( S_OK ); } }
if ( GetRsopContext()->IsRsopEnabled() && GetRsopContext()->IsPlanningModeEnabled() && ARPList() ) { CCategoryInfoLog CategoryLog( GetRsopContext(), NULL);
hr = CategoryLog.WriteLog();
if (FAILED(hr)) { GetRsopContext()->DisableRsop( hr ); } }
//
// We will not set ARP's logging namespace if logging is not enabled
//
if ( GetRsopContext()->IsRsopEnabled() && ! GetRsopContext()->ForcedRefresh() ) { //
// First, record the namespace so that app management
// service can perform rsop logging
//
if ( ! ARPList() && ! GetRsopContext()->IsPlanningModeEnabled() ) { (void) GetRsopContext()->SaveNameSpace();
//
// For users, whose apps will roam if they have a user profile,
// write a version into the profile so we can determine if their
// profile is in sync with the machine's current rsop data -- this
// gets updated at each policy run and each time an app is installed
//
if ( IsUserPolicy() ) { (void) GetRsopContext()->WriteCurrentRsopVersion( AppmgmtKey() ); } } }
//
// For ARP, we are now finished logging and users may read
// the logged data now -- release our lock
//
if ( ARPList() ) { (void) GetRsopContext()->ReleaseExclusiveLoggingAccess(); } }
HRESULT CManagedAppProcessor::GetAppsFromDirectory() { IEnumPackage * pEnumPackage; DWORD Size; DWORD Type; DWORD AppFlags; DWORD Status; HRESULT hr;
Status = Impersonate(); if ( Status != ERROR_SUCCESS ) return HRESULT_FROM_WIN32( Status );
//
// Determine what apps to ask the Diretory for
//
AppFlags = GetDSQuery();
if ( DebugLevelOn( DM_VERBOSE ) ) { WCHAR Name[32]; DWORD NameLength = sizeof(Name) / sizeof(WCHAR);
Name[0] = 0;
if ( _bUser ) { if ( ! GetUserName( Name, &NameLength) ) { if ( LoadLoadString() ) (*pfnLoadStringW)( ghDllInstance, IDS_UNKNOWN, Name, NameLength ); }
DebugMsg((DM_VERBOSE, IDS_USERAPPS_NOCAT, Name, AppFlags)); } else { if ( ! GetComputerName( Name, &NameLength) ) { if ( LoadLoadString() ) (*pfnLoadStringW)( ghDllInstance, IDS_UNKNOWN, Name, NameLength ); }
DebugMsg((DM_VERBOSE, IDS_MACHINEAPPS, Name, AppFlags)); } }
//
// If we are not in planning mode, we can use a function that uses
// the cached class store ds paths to determine which parts of the
// ds to query -- this function obtains an enumerator that returns
// query results from the cached ds paths
//
if ( ! GetRsopContext()->IsPlanningModeEnabled() ) { hr = CsEnumApps( NULL, NULL, NULL, AppFlags, &pEnumPackage ); } else { //
// In planning mode, we have no cached ds paths and must explicitly
// specify it in order to obtain an enumerator
//
hr = GetPackageEnumeratorFromPath( _CSPath.GetPath(), NULL, AppFlags, &pEnumPackage); }
if ( S_OK == hr ) { hr = EnumerateApps(pEnumPackage); pEnumPackage->Release(); } else { DebugMsg((DM_WARNING, IDS_CSENUMAPPS_FAIL, hr)); }
Revert();
return hr; }
HRESULT CManagedAppProcessor::EnumerateApps( IEnumPackage * pEnumPackages ) { PACKAGEDISPINFO rgPackages[PACKAGEINFO_ALLOC_COUNT]; ULONG cRetrieved; CAppList AppList( this ); CAppInfo * pAppInfo; CAppInfo * pAppInfoOldest; CGPOInfo * pGPOInfo; WCHAR * pwszGPOName; DWORD AppCount; HRESULT hr; BOOL bStatus;
memset( rgPackages, 0, sizeof(rgPackages) );
for (;;) { hr = pEnumPackages->Next( PACKAGEINFO_ALLOC_COUNT, rgPackages, &cRetrieved);
if ( FAILED(hr) ) return hr;
// This call only fails on out of memory.
bStatus = AddAppsFromDirectory( cRetrieved, rgPackages, AppList );
for ( DWORD n = 0; n < cRetrieved; n++ ) ReleasePackageInfo( &rgPackages[n] );
if ( ! bStatus ) return E_OUTOFMEMORY;
if ( hr == S_FALSE ) break; }
//
// Now that we have all the packages from the DS, we sort them within each policy
// from oldest to newest deployment time and put them in our final app list.
//
for ( _GPOs.Reset(); pGPOInfo = (CGPOInfo *) _GPOs.GetCurrentItem(); _GPOs.MoveNext() ) { pwszGPOName = 0; AppCount = 0;
for (;;) { pAppInfoOldest = 0;
for ( AppList.Reset(); pAppInfo = (CAppInfo *) AppList.GetCurrentItem(); AppList.MoveNext() ) { if ( lstrcmpi( pGPOInfo->_pwszGPOId, pAppInfo->_pwszGPOId ) != 0 ) break;
if ( ! pAppInfoOldest || (CompareFileTime( &pAppInfo->_USN, &pAppInfoOldest->_USN ) < 0) ) { pAppInfoOldest = pAppInfo; } }
AppList.ResetEnd();
if ( ! pAppInfoOldest ) break;
if ( 0 == AppCount ) { pwszGPOName = pAppInfoOldest->_pwszGPOName; DebugMsg((DM_VERBOSE, IDS_GPOAPPS, pwszGPOName)); }
AppCount++;
if ( DebugLevelOn( DM_VERBOSE ) ) { if ( pAppInfoOldest->_ActFlags & ACTFLG_Assigned ) { DebugMsg((DM_VERBOSE, IDS_ADDASSIGNED, pAppInfoOldest->_pwszDeploymentName, pAppInfoOldest->_ActFlags)); } else if ( pAppInfoOldest->_ActFlags & ACTFLG_Published ) { DebugMsg((DM_VERBOSE, IDS_ADDPUBLISHED, pAppInfoOldest->_pwszDeploymentName, pAppInfoOldest->_ActFlags)); } else if ( pAppInfoOldest->_ActFlags & ACTFLG_Orphan ) { DebugMsg((DM_VERBOSE, IDS_ADDORPHANED, pAppInfoOldest->_pwszDeploymentName)); } else if ( pAppInfoOldest->_ActFlags & ACTFLG_Uninstall ) { DebugMsg((DM_VERBOSE, IDS_ADDUNINSTALLED, pAppInfoOldest->_pwszDeploymentName)); } else { DebugMsg((DM_VERBOSE, IDS_ADDUNKNOWN, pAppInfoOldest->_pwszDeploymentName)); } }
pAppInfoOldest->Remove(); _Apps.InsertFIFO( pAppInfoOldest ); }
if ( AppCount > 0 ) DebugMsg((DM_VERBOSE, IDS_NUMAPPS, AppCount, pwszGPOName)); } _GPOs.ResetEnd();
return S_OK; }
BOOL CManagedAppProcessor::AddAppsFromDirectory( ULONG cApps, PACKAGEDISPINFO * rgPackageInfo, CAppList & AppList ) { CAppInfo * pAppInfo; BOOL bStatus;
for ( DWORD App = 0; App < cApps; App++) { switch ( rgPackageInfo[App].PathType ) { case DrwFilePath : break; case SetupNamePath : if ( ! _bIncludeLegacy ) continue; break; default : continue; }
bStatus = FALSE;
pAppInfo = new CAppInfo( this, &(rgPackageInfo[App]), FALSE, bStatus );
if ( ! bStatus ) { if ( pAppInfo ) delete pAppInfo; pAppInfo = 0; }
if ( ! pAppInfo ) return FALSE;
AppList.InsertLIFO( pAppInfo ); }
return TRUE; }
DWORD CManagedAppProcessor::GetDSQuery() { DWORD AppFlags;
//
// We perform different queries depending on whether or not RSoP
// is enabled as well as whether we are doing a query for the
// ARP list of apps or for a policy run
//
if ( GetRsopContext()->IsRsopEnabled() ) { if (ARPList()) { AppFlags = APPQUERY_RSOP_ARP; } else { AppFlags = APPQUERY_RSOP_LOGGING; } } else { if (ARPList()) { AppFlags = APPQUERY_USERDISPLAY; } else { AppFlags = APPQUERY_POLICY; } }
return AppFlags; }
DWORD CManagedAppProcessor::GetManagedApplications( GUID * pCategory, ARPCONTEXT* pArpContext /* allocated on separate waiting thread */ ) { WCHAR wszCategoryGuid[40]; DWORD Status; BOOL bStatus; MANAGED_APPLIST * pAppList; BOOL fPlanningMode;
_bARPList = TRUE;
fPlanningMode = pArpContext == NULL;
//
// *********IMPORTANT********
// Note that we should not access the pArpContext structure after we've signaled
// that enumeration is complete using the hEventAppsEnumerated member --
// otherwise, the stack on which this structure is allocated will disappear
// once its thread unblocks waiting for us
//
if ( ! fPlanningMode ) { pAppList = pArpContext->pAppList; }
Status = ERROR_SUCCESS;
//
// GPO precedence list is needed for sorting the apps based on USN
// and because the upgrade processing logic requires having the GPO
// precedence list.
//
if ( ! GetRsopContext()->IsPlanningModeEnabled() ) { Status = LoadPolicyList(); } else { CGPOInfo* pGPOInfo;
for ( _GPOs.Reset(); pGPOInfo = (CGPOInfo *) _GPOs.GetCurrentItem(); _GPOs.MoveNext() ) { Status = _CSPath.AddComponent( pGPOInfo->_pwszGPOPath, pGPOInfo->_pwszGPOName ); if ( Status != ERROR_SUCCESS ) break; } }
if ( ERROR_SUCCESS == Status ) Status = GetAppsFromDirectory();
//
// Not all managed applications should be visible to the caller --
// filter out the ones the caller doesn't want
//
if ( ERROR_SUCCESS == Status ) Status = _Apps.ProcessARPList();
if ( ( Status != ERROR_SUCCESS ) || GetRsopContext()->IsPlanningModeEnabled() ) { goto GetManagedApplications_WriteLogsAndExit; }
if ( pCategory ) { GuidToString( *pCategory, wszCategoryGuid); DebugMsg((DM_VERBOSE, IDS_USERAPPS_CAT, wszCategoryGuid)); }
//
// Now that we have the correct list of apps,
// we need to allocate space for all the apps
// and copy the data for each app to give back to the user
//
//
// First we must count the number of apps we're giving back.
//
// We also determine which apps have common display names and tag them
// to have their policy name catenated to their display names.
//
DWORD dwCount; CAppInfo * pAppInfo; CAppInfo * pAppInfoOther;
dwCount = 0; _Apps.Reset();
for ( pAppInfo = (CAppInfo *) _Apps.GetCurrentItem(); pAppInfo; _Apps.MoveNext(), pAppInfo = (CAppInfo *) _Apps.GetCurrentItem() ) { if ( (pAppInfo->_Action != ACTION_INSTALL) ) continue; if ( pCategory && ! pAppInfo->HasCategory( wszCategoryGuid ) ) { pAppInfo->SetAction( ACTION_UNINSTALL, 0, NULL);
continue; }
dwCount++; }
_Apps.ResetEnd();
//
// Now that we know how many apps we have, we can allocate
// space for them.
//
if ( ! fPlanningMode ) { pAppList->rgApps = (MANAGED_APP*) midl_user_allocate( sizeof(MANAGED_APP) * dwCount);
if (!(pAppList->rgApps)) { pArpContext->Status = ERROR_NOT_ENOUGH_MEMORY;
return ERROR_NOT_ENOUGH_MEMORY; }
memset(pAppList->rgApps, 0, dwCount * sizeof(MANAGED_APP));
//
// Now we do the copying
//
DWORD dwApp; dwApp = 0; _Apps.Reset();
for (;;) { CAppInfo* pAppInfoCopy;
pAppInfoCopy = (CAppInfo *) _Apps.GetCurrentItem();
if ( ! pAppInfoCopy ) break;
_Apps.MoveNext();
if ( ACTION_INSTALL == pAppInfoCopy->_Action) { Status = pAppInfoCopy->CopyToManagedApplication(&(pAppList->rgApps[dwApp])); if ( Status != ERROR_SUCCESS ) break;
dwApp++; } } _Apps.ResetEnd();
if ( Status != ERROR_SUCCESS ) { DWORD dwCopiedApp;
//
// On failure, we need to clear any apps we allocated
// before the failure occurred
//
for ( dwCopiedApp = 0; dwCopiedApp < dwApp; dwCopiedApp++ ) { ClearManagedApp( & ( pAppList->rgApps[ dwCopiedApp ] ) ); }
midl_user_free( pAppList->rgApps ); pAppList->rgApps = 0;
pArpContext->Status = Status;
return Status; }
pAppList->Applications = dwApp; }
GetManagedApplications_WriteLogsAndExit:
//
// Store the status of this operation in the waiting thread's context --
// note that this is the last time we can safely access this structure
// since we will next signal its thread to unblock, and the stack
// frame in which this structure is allocated will disappear
//
if ( ! fPlanningMode ) { pArpContext->Status = Status;
//
// Signal the waiting thread that we are finished enumerating
//
GetRsopContext()->SetAppsEnumerated(); }
//
// Write any Rsop logs -- this is a no op if
// rsop logging is not enabled
//
WriteRsopLogs();
return Status; }
DWORD CManagedAppProcessor::GetAppsFromLocal() { CAppList LocalApps( NULL ); CAppInfo * pAppInfo; CAppInfo * pAppInfoInsert; CAppInfo * pScriptInfo; int GPOCompare; DWORD Count; DWORD Status; HRESULT hr; BOOL bStatus;
if ( GetRsopContext()->IsPlanningModeEnabled() ) { return ERROR_SUCCESS; }
Status = GetOrderedLocalAppList( LocalApps );
if ( ERROR_SUCCESS == Status ) Status = Impersonate();
if ( Status != ERROR_SUCCESS ) return Status;
Count = 0;
LocalApps.Reset();
for ( pAppInfo = (CAppInfo *) LocalApps.GetCurrentItem(); pAppInfo; pAppInfo = (CAppInfo *) LocalApps.GetCurrentItem() ) { //
// Remember which scripts are associated with app entries we find
// in the registry. We'll use this later as a hint to detect roaming
// profile merge problems with our app entries in hkcu.
//
pScriptInfo = _LocalScripts.Find( pAppInfo->_DeploymentId ); if ( pScriptInfo ) pScriptInfo->_State = APPSTATE_SCRIPT_PRESENT;
if ( _Apps.Find( pAppInfo->_DeploymentId ) != NULL ) { LocalApps.MoveNext(); continue; }
if ( pAppInfo->_State & APPSTATE_ASSIGNED ) { DebugMsg((DM_VERBOSE, IDS_LOCALASSIGN_APP, pAppInfo->_pwszDeploymentName, pAppInfo->_pwszGPOName)); } else if ( pAppInfo->_State & APPSTATE_PUBLISHED ) { DebugMsg((DM_VERBOSE, IDS_LOCALPUBLISHED_APP, pAppInfo->_pwszDeploymentName, pAppInfo->_pwszGPOName)); } else if ( pAppInfo->_State & APPSTATE_ORPHANED ) { DebugMsg((DM_VERBOSE, IDS_LOCALORPHAN_APP, pAppInfo->_pwszDeploymentName, pAppInfo->_pwszGPOName)); } else if ( pAppInfo->_State & APPSTATE_UNINSTALLED ) { DebugMsg((DM_VERBOSE, IDS_LOCALUNINSTALL_APP, pAppInfo->_pwszDeploymentName, pAppInfo->_pwszGPOName)); }
LocalApps.MoveNext(); pAppInfo->Remove(); Count++;
//
// If this app is currently applied, check it's real state in the DS. We
// didn't get in the query results either because it didn't match the search
// criteria or because it really did go out of scope. Currently applied apps include
// those listed in the registry as published or assigned, as well as those listed
// in the registry as unmanaged or uninstalled that currently have a script present
// on this machine.
// In the case of no-changes, we have to query for published apps which we
// don't have scripts for so that we can retrieve the proper sysvol path to
// get the script.
//
if ( (! _bNoChanges && (pAppInfo->_State & (APPSTATE_ASSIGNED | APPSTATE_PUBLISHED | APPSTATE_SCRIPT_EXISTED))) || (_bNoChanges && (pAppInfo->_State & APPSTATE_PUBLISHED) && (pAppInfo->_State & APPSTATE_SCRIPT_NOT_EXISTED)) ) { uCLSSPEC ClassSpec; PACKAGEDISPINFO PackageInfo;
memset( &PackageInfo, 0, sizeof(PackageInfo) );
ClassSpec.tyspec = TYSPEC_OBJECTID; memcpy( &ClassSpec.tagged_union.ByObjectId.ObjectId, &pAppInfo->_DeploymentId, sizeof(GUID) ); StringToGuid( pAppInfo->_pwszGPOId, &ClassSpec.tagged_union.ByObjectId.PolicyId );
DebugMsg((DM_VERBOSE, IDS_CHECK_APP, pAppInfo->_pwszDeploymentName, pAppInfo->_pwszGPOName));
hr = CsGetAppInfo( &ClassSpec, NULL, &PackageInfo );
if ( S_OK == hr ) { BOOL bRestored;
bRestored = pAppInfo->_bRestored;
DebugMsg((DM_VERBOSE, IDS_CHECK_APP_FOUND, pAppInfo->_pwszDeploymentName, pAppInfo->_pwszGPOName, PackageInfo.dwActFlags)); delete pAppInfo; pAppInfo = new CAppInfo( this, &PackageInfo, FALSE, bStatus ); if ( ! bStatus ) { delete pAppInfo; pAppInfo = 0; } if ( ! pAppInfo ) Status = ERROR_OUTOFMEMORY; ReleasePackageInfo( &PackageInfo );
if ( pAppInfo ) pAppInfo->_bRestored = bRestored; } else if ( CS_E_PACKAGE_NOTFOUND == hr ) { DebugMsg((DM_VERBOSE, IDS_CHECK_APP_NOTFOUND, pAppInfo->_pwszDeploymentName, pAppInfo->_pwszGPOName)); } else { Status = (DWORD) hr; }
if ( Status != ERROR_SUCCESS ) { DebugMsg((DM_VERBOSE, IDS_CHECK_APP_FAIL, pAppInfo->_pwszDeploymentName, pAppInfo->_pwszGPOName, Status)); Revert(); return Status; } }
pAppInfoInsert = 0;
//
// Now we insert the locally discovered app into the proper sorted spot in
// our master list generated from the initial DS query.
//
for ( _Apps.Reset(); pAppInfoInsert = (CAppInfo *) _Apps.GetCurrentItem(); _Apps.MoveNext() ) { GPOCompare = _GPOs.Compare( pAppInfoInsert->_pwszGPOId, pAppInfo->_pwszGPOId );
if ( -1 == GPOCompare ) continue;
if ( 1 == GPOCompare ) break;
// Smallest USN is oldest. We sort from oldest to newest.
if ( CompareFileTime( &pAppInfoInsert->_USN, &pAppInfo->_USN ) >= 0 ) break; }
// FIFO insert handles both the empty list and end of list conditions.
if ( ! pAppInfoInsert ) _Apps.InsertFIFO( pAppInfo ); else pAppInfoInsert->InsertBefore( pAppInfo ); }
LocalApps.ResetEnd();
Revert();
DebugMsg((DM_VERBOSE, IDS_LOCALAPP_COUNT, Count)); return ERROR_SUCCESS; }
BOOL CManagedAppProcessor::DetectLostApps() { HKEY hkApp; WCHAR wszDeploymentId[GUIDSTRLEN+1]; CAppInfo * pScriptInfo; DWORD Size; DWORD State; DWORD Status;
if ( GetRsopContext()->IsPlanningModeEnabled() || ! _bUser ) return FALSE;
for ( _LocalScripts.Reset(); pScriptInfo = (CAppInfo *) _LocalScripts.GetCurrentItem(); _LocalScripts.MoveNext() ) { GuidToString( pScriptInfo->_DeploymentId, wszDeploymentId);
Status = RegOpenKeyEx( _hkAppmgmt, wszDeploymentId, 0, KEY_READ, &hkApp );
if ( Status != ERROR_SUCCESS ) { _LocalScripts.ResetEnd(); DebugMsg((DM_VERBOSE, IDS_DETECTED_LOST_APPS)); return TRUE; } else { Size = sizeof(DWORD); State = 0;
Status = RegQueryValueEx( hkApp, APPSTATEVALUE, 0, NULL, (LPBYTE) &State, &Size );
RegCloseKey( hkApp );
//
// This isn't a lost app, but rather an app which was orphaned or
// uninstalled on another computer. We will force a full policy
// run in this case as well to process the removal. This is similar
// to the case where we find the FullPolicy value set.
//
if ( ! (State & (APPSTATE_PUBLISHED | APPSTATE_ASSIGNED)) ) return TRUE; } }
_LocalScripts.ResetEnd();
return FALSE; }
DWORD CManagedAppProcessor::GetLostApps() { uCLSSPEC ClassSpec; PACKAGEDISPINFO PackageInfo; CAppInfo * pScriptInfo; CAppInfo * pAppInfo; CAppInfo * pAppInfoInsert; GUID GPOId; int GPOCompare; LONG RedeployCount; DWORD Status; HRESULT hr; BOOL bStatus; BOOL bInsertNew;
if ( GetRsopContext()->IsPlanningModeEnabled() || ! _bUser ) return ERROR_SUCCESS;
//
// In this routine we are detecting app entries which are erroneously
// missing from our hkcu data. This can occur in various scenarios
// involving roaming profiles. An unassociated script file and our
// rsop data is used for the detection.
//
// Note:
// There is quite a bit of duplicated code here and in the above routine
// ::GetAppsFromLocal. That is because this change was added late in
// WindowsXP and we wanted to isolate it from existing functionality.
// In future this could be cleaned up if this codebase is taken forward.
//
Status = ERROR_SUCCESS;
for ( _LocalScripts.Reset(); pScriptInfo = (CAppInfo *) _LocalScripts.GetCurrentItem(); _LocalScripts.MoveNext() ) { if ( pScriptInfo->_State != 0 ) continue;
DebugMsg((DM_VERBOSE, IDS_UNMATCHED_SCRIPT));
pAppInfo = 0;
hr = FindAppInRSoP( pScriptInfo, &GPOId, &RedeployCount );
if ( ! SUCCEEDED(hr) ) { if ( WBEM_E_NOT_FOUND == hr ) { DebugMsg((DM_VERBOSE, IDS_SCRIPTNOTINRSOP1)); DeleteScriptFile( pScriptInfo->_DeploymentId ); continue; } else { Status = (DWORD) hr; DebugMsg((DM_VERBOSE, IDS_SCRIPTNOTINRSOP2, hr)); break; } }
DebugMsg((DM_VERBOSE, IDS_SCRIPTINRSOP)); pAppInfo = _Apps.Find( pScriptInfo->_DeploymentId );
if ( pAppInfo ) { bInsertNew = FALSE; DebugMsg((DM_VERBOSE, IDS_SCRIPTAPP_INDS2, pAppInfo->_pwszDeploymentName, pAppInfo->_pwszGPOName)); goto GetLostAppsInsert; }
memset( &PackageInfo, 0, sizeof(PackageInfo) ); ClassSpec.tyspec = TYSPEC_OBJECTID; memcpy( &ClassSpec.tagged_union.ByObjectId.ObjectId, &pScriptInfo->_DeploymentId, sizeof(GUID) ); memcpy( &ClassSpec.tagged_union.ByObjectId.PolicyId, &GPOId, sizeof(GUID) );
Status = Impersonate(); if ( ERROR_SUCCESS == Status ) { hr = CsGetAppInfo( &ClassSpec, NULL, &PackageInfo ); Revert(); } else { hr = HRESULT_FROM_WIN32( Status ); }
if ( S_OK == hr ) { bStatus = TRUE; pAppInfo = new CAppInfo( this, &PackageInfo, FALSE, bStatus ); ReleasePackageInfo( &PackageInfo ); bInsertNew = TRUE;
if ( ! bStatus ) { delete pAppInfo; pAppInfo = 0; } if ( ! pAppInfo ) Status = ERROR_OUTOFMEMORY; else DebugMsg((DM_VERBOSE, IDS_SCRIPTAPP_INDS, pAppInfo->_pwszDeploymentName, pAppInfo->_pwszGPOName)); } else if ( CS_E_PACKAGE_NOTFOUND == hr ) { DebugMsg((DM_VERBOSE, IDS_SCRIPTAPP_NODS));
//
// Since the app is not visible to this user, delete the
// orphaned script.
//
DeleteScriptFile( pScriptInfo->_DeploymentId ); } else { Status = (DWORD) hr; }
if ( Status != ERROR_SUCCESS ) { DebugMsg((DM_VERBOSE, IDS_SCRIPTAPP_ERRORDS, Status)); break; }
if ( ! pAppInfo ) continue;
GetLostAppsInsert: //
// Because we're restoring this app, much of the persisted state is lost.
// We artifically re-create the key aspects here.
//
pAppInfo->_State |= APPSTATE_PUBLISHED | APPSTATE_RESTORED; pAppInfo->_AssignCount = 1; pAppInfo->_LocalRevision = (DWORD) RedeployCount; pAppInfo->_ScriptTime = pScriptInfo->_ScriptTime;
// Switch to full policy mode whenever we force a lost app back into scope.
_bNoChanges = FALSE;
if ( ! bInsertNew ) continue;
//
// Our newly discovered app now needs to be added to our processing list.
//
for ( _Apps.Reset(); pAppInfoInsert = (CAppInfo *) _Apps.GetCurrentItem(); _Apps.MoveNext() ) { GPOCompare = _GPOs.Compare( pAppInfoInsert->_pwszGPOId, pAppInfo->_pwszGPOId );
if ( -1 == GPOCompare ) continue;
if ( 1 == GPOCompare ) break;
// Smallest USN is oldest. We sort from oldest to newest.
if ( CompareFileTime( &pAppInfoInsert->_USN, &pAppInfo->_USN ) >= 0 ) break; }
// FIFO insert handles both the empty list and end of list conditions.
if ( ! pAppInfoInsert ) _Apps.InsertFIFO( pAppInfo ); else pAppInfoInsert->InsertBefore( pAppInfo ); }
_LocalScripts.ResetEnd();
return Status; }
HRESULT CManagedAppProcessor::FindAppInRSoP( CAppInfo * pScriptInfo, GUID * pGPOId, LONG * pRedeployCount ) { WCHAR wszGPOId[128]; WCHAR * pwszGPOId; LONG ValueLen; HRESULT hr;
hr = _Apps.InitRsopLog();
if ( ! SUCCEEDED(hr) ) return hr;
pwszGPOId = wszGPOId; ValueLen = sizeof(wszGPOId) / sizeof(wszGPOId[0]);
//
// Close your eyes, this is ugly. The CAppInfo which is only used to track
// script files only have the _DeploymentId member set. However, OpenExistingRecord
// needs a couple of other fields to operate correctly. We feed those here.
//
pScriptInfo->_pManApp = this; pScriptInfo->_State = APPSTATE_PUBLISHED;
CConflict ScriptRecord( pScriptInfo ); hr = _Apps.OpenExistingRecord( &ScriptRecord );
if ( SUCCEEDED(hr) ) { hr = ScriptRecord.GetValue( RSOP_ATTRIBUTE_GPOID, pwszGPOId, &ValueLen ); if ( S_FALSE == hr ) { pwszGPOId = new WCHAR[ValueLen]; if ( pwszGPOId ) hr = ScriptRecord.GetValue( RSOP_ATTRIBUTE_GPOID, pwszGPOId, &ValueLen ); else hr = E_OUTOFMEMORY; }
if ( SUCCEEDED(hr) ) hr = ScriptRecord.GetValue( APP_ATTRIBUTE_REDEPLOYCOUNT, pRedeployCount ); }
if ( SUCCEEDED(hr) ) { WCHAR * pwszNull;
// The GPOId comes back from GetValue like CN={gpoguid},CN=Policies,...
pwszNull = wcschr( pwszGPOId, L'}' ); if ( pwszNull ) { pwszNull[1] = 0; StringToGuid( &pwszGPOId[3], pGPOId ); } else { hr = E_UNEXPECTED; } }
if ( pwszGPOId != wszGPOId ) delete [] pwszGPOId;
return hr; }
void CManagedAppProcessor::DeleteScriptFile( GUID & DeploymentId ) { DWORD Length; WCHAR * pwszLocalScriptPath;
Length = lstrlen( LocalScriptDir() ); pwszLocalScriptPath = new WCHAR[Length + GUIDSTRLEN + 5]; if ( ! pwszLocalScriptPath ) return; (void) StringCchCopy( pwszLocalScriptPath, Length+GUIDSTRLEN+5, LocalScriptDir() ); GuidToString( DeploymentId, &pwszLocalScriptPath[Length]);
(void) StringCchCopy( &pwszLocalScriptPath[Length+GUIDSTRLEN], 5, L".aas" ); DeleteFile( pwszLocalScriptPath );
delete [] pwszLocalScriptPath; }
HRESULT CManagedAppProcessor::GetPackageEnumeratorFromPath( WCHAR* wszClassStorePath, GUID* pCategory, DWORD dwAppFlags, IEnumPackage** ppIEnumPackage) { HRESULT hr; IClassAccess * pIClassAccess = NULL;
//
// Get an IClassAccess
//
hr = GetClassAccessFromPath( wszClassStorePath, &pIClassAccess);
if (SUCCEEDED(hr)) { //
// Get the enumerator
//
hr = pIClassAccess->EnumPackages( NULL, pCategory, NULL, dwAppFlags, ppIEnumPackage );
pIClassAccess->Release(); }
return hr; }
HRESULT CManagedAppProcessor::GetDsPackageFromGPO( CGPOInfo* pGpoInfo, GUID* pDeploymentId, PACKAGEDISPINFO* pPackageInfo) { HRESULT hr;
memset( pPackageInfo, 0, sizeof(*pPackageInfo) );
//
// Determine the class store path for this gpo
//
WCHAR* pwszClassStorePath;
pwszClassStorePath = NULL;
//
// The path returned is allocated by the callee so we must
// free it later
//
hr = CsGetClassStorePath( pGpoInfo->GetGPOPath(), &pwszClassStorePath );
if ( FAILED(hr) ) { return hr; }
//
// Terminate the class store path list with a delimiter to satisfy
// class store syntax requirements
//
WCHAR* pwszTerminatedClassStorePath; ULONG ulSize;
ulSize = lstrlen( pwszClassStorePath ) + 1 + 1; pwszTerminatedClassStorePath = new WCHAR[ ulSize ];
if ( pwszTerminatedClassStorePath ) { IClassAccess * pIClassAccess = NULL; uCLSSPEC ClassSpec;
ClassSpec.tyspec = TYSPEC_OBJECTID; memcpy( &ClassSpec.tagged_union.ByObjectId.ObjectId, pDeploymentId, sizeof(GUID) ); StringToGuid( pGpoInfo->_pwszGPOId, &ClassSpec.tagged_union.ByObjectId.PolicyId );
//
// Perform the actual termination
//
hr = StringCchCopy( pwszTerminatedClassStorePath, ulSize, pwszClassStorePath ); if (SUCCEEDED(hr)) { hr = StringCchCat( pwszTerminatedClassStorePath, ulSize, L";" ); }
if (SUCCEEDED(hr)) { //
// Get an IClassAccess using this class store path
//
hr = GetClassAccessFromPath( pwszTerminatedClassStorePath, &pIClassAccess); }
if (SUCCEEDED(hr)) { //
// Perform the search for the requested deployment
//
hr = pIClassAccess->GetAppInfo( &ClassSpec, NULL, pPackageInfo); pIClassAccess->Release(); } } else { hr = E_OUTOFMEMORY; } if ( pwszClassStorePath ) { LocalFree( pwszClassStorePath ); }
delete [] pwszTerminatedClassStorePath;
return hr; }
HRESULT CManagedAppProcessor::GetClassAccessFromPath( WCHAR* wszClassStorePath, IClassAccess** ppIClassAccess) { HRESULT hr; PRSOP_TARGET pRsopTarget; *ppIClassAccess = NULL;
pRsopTarget = GetRsopContext()->_pRsopTarget;
//
// Get an IClassAccess
//
hr = CsGetClassAccess(ppIClassAccess);
//
// Set the IClassAccess to use the class stores
// corresponding to the class store path passed in
//
if (SUCCEEDED(hr)) { hr = (*ppIClassAccess)->SetClassStorePath( wszClassStorePath, pRsopTarget ? pRsopTarget->pRsopToken : NULL ); }
return hr; }
DWORD CManagedAppProcessor::CommitPolicyList() { CGPOInfo * pGPO; WCHAR * pwszGPOList; DWORD Length; DWORD Status; HRESULT hr;
if ( GetRsopContext()->IsPlanningModeEnabled() ) { return ERROR_SUCCESS; }
Length = 1; _GPOs.Reset();
for ( pGPO = (CGPOInfo *) _GPOs.GetCurrentItem(); pGPO; _GPOs.MoveNext(), pGPO = (CGPOInfo *) _GPOs.GetCurrentItem() ) { Length += lstrlen( pGPO->_pwszGPOId ) + 1; }
_GPOs.ResetEnd();
pwszGPOList = new WCHAR[Length]; if ( ! pwszGPOList ) return ERROR_OUTOFMEMORY; pwszGPOList[0] = 0;
_GPOs.Reset();
for ( pGPO = (CGPOInfo *) _GPOs.GetCurrentItem(); pGPO; _GPOs.MoveNext(), pGPO = (CGPOInfo *) _GPOs.GetCurrentItem() ) { hr = StringCchCat( pwszGPOList, Length, pGPO->_pwszGPOId ); if (SUCCEEDED(hr)) { hr = StringCchCat( pwszGPOList, Length, L";" ); }
if (FAILED(hr)) { delete [] pwszGPOList; return hr; } }
_GPOs.ResetEnd();
Status = RegSetValueEx( _hkAppmgmt, POLICYLISTVALUE, 0, REG_SZ, (LPBYTE) pwszGPOList, Length * sizeof(WCHAR) );
delete [] pwszGPOList;
return Status; }
DWORD CManagedAppProcessor::LoadPolicyList() { PGROUP_POLICY_OBJECT pGPOList = NULL; DWORD Status;
Status = Impersonate();
if ( ERROR_SUCCESS == Status ) { Status = GetCurrentUserGPOList( &pGPOList );
Revert(); }
if (ERROR_SUCCESS == Status) { Status = SetPolicyListFromGPOList( pGPOList ); }
if ( pGPOList ) { FreeGPOList( pGPOList ); }
if ( ERROR_SUCCESS == Status ) { MergePolicyList(); }
return Status; }
DWORD CManagedAppProcessor::SetPolicyListFromGPOList( PGROUP_POLICY_OBJECT pGPOList ) { DWORD Status; WCHAR * pwszGPOList; WCHAR * pwszGPO; WCHAR * pwszGPOEnd; DWORD Size;
Status = ERROR_SUCCESS; pwszGPOList = 0; Size = 0;
PGROUP_POLICY_OBJECT pCurrentGPO;
for (pCurrentGPO = pGPOList; NULL != pCurrentGPO; pCurrentGPO = pCurrentGPO->pNext) { BOOL bStatus;
DebugMsg((DM_VERBOSE, IDS_GPO_NAME, pCurrentGPO->lpDisplayName, pCurrentGPO->szGPOName)); DebugMsg((DM_VERBOSE, IDS_GPO_FILESYSPATH, pCurrentGPO->lpFileSysPath)); DebugMsg((DM_VERBOSE, IDS_GPO_DSPATH, pCurrentGPO->lpDSPath));
bStatus = AddGPO( pCurrentGPO );
if ( ! bStatus ) { Status = ERROR_OUTOFMEMORY; break; } }
return Status; }
DWORD CManagedAppProcessor::MergePolicyList() { WCHAR * pwszGPOList; WCHAR * pwszGPO; WCHAR * pwszGPOEnd; DWORD Size; DWORD Status; BOOL bStatus;
pwszGPOList = 0; Size = 0;
Status = RegQueryValueEx( _hkAppmgmt, POLICYLISTVALUE, 0, NULL, (LPBYTE) NULL, &Size );
if ( ERROR_FILE_NOT_FOUND == Status ) return ERROR_SUCCESS;
if ( ERROR_SUCCESS == Status ) { pwszGPOList = new WCHAR[Size/2]; if ( ! pwszGPOList ) return ERROR_OUTOFMEMORY;
Status = RegQueryValueEx( _hkAppmgmt, POLICYLISTVALUE, 0, NULL, (LPBYTE) pwszGPOList, &Size ); }
if ( ERROR_SUCCESS == Status ) { GROUP_POLICY_OBJECT GPOInfo;
memset( &GPOInfo, 0, sizeof( GPOInfo ) );
for ( pwszGPO = pwszGPOList; *pwszGPO; pwszGPO = pwszGPOEnd + 1 ) { pwszGPOEnd = wcschr( pwszGPO, L';' );
if ( ! pwszGPOEnd ) { Status = ERROR_INVALID_PARAMETER; break; }
*pwszGPOEnd = 0;
if ( ! _GPOs.Find( pwszGPO ) ) { HRESULT hr;
hr = StringCchCopy( GPOInfo.szGPOName, sizeof(GPOInfo.szGPOName)/sizeof(GPOInfo.szGPOName[0]), pwszGPO ); if (FAILED(hr)) { Status = HRESULT_CODE(hr); break; }
GPOInfo.lpDisplayName = L""; GPOInfo.lpDSPath = L""; GPOInfo.lpLink = L"";
bStatus = _GPOs.Add( &GPOInfo );
if ( ! bStatus ) { Status = ERROR_OUTOFMEMORY; break; } } } }
delete [] pwszGPOList;
return Status; }
DWORD CManagedAppProcessor::CreateAndSecureScriptDir() { SECURITY_DESCRIPTOR SecDesc; SECURITY_ATTRIBUTES SecAttr; SID_IDENTIFIER_AUTHORITY AuthorityNT = SECURITY_NT_AUTHORITY; SID_IDENTIFIER_AUTHORITY AuthorityEveryone = SECURITY_WORLD_SID_AUTHORITY; PSID pSidUser; PSID pSidEveryone; PSID pSidSystem; PSID pSidAdmin; PACL pAcl; ACE_HEADER * pAceHeader; PSID pSid; DWORD AclSize; DWORD AceIndex; DWORD Length; DWORD Attributes; DWORD Size; DWORD Status; BOOL bStatus;
Status = ERROR_SUCCESS;
//
// The following check is used to determine if the appmgmt directories
// for this user/machine exist in the proper win2001 format. If so we
// can quickly exit.
// When the directories exist but without the system bit set, this means
// we need to migrate to the new win2001 ACL format.
//
Attributes = GetFileAttributes( _pwszLocalPath );
if ( (Attributes != (DWORD) -1) && (Attributes & FILE_ATTRIBUTE_SYSTEM) ) return ERROR_SUCCESS;
//
// If a user object is moved within a domain forest the SID will change.
// Here we check for that case and rename the previous SID dir to the
// new SID. This is only a necessary check if a script dir by the current
// SID name does not exist.
//
if ( ((DWORD) -1 == Attributes) && _bUser ) { WCHAR * pwszPreviousSid = 0;
Status = GetPreviousSid( _hUserToken, _pwszLocalPath, &pwszPreviousSid );
if ( (ERROR_SUCCESS == Status) && pwszPreviousSid ) { Status = RenameScriptDir( pwszPreviousSid, _pwszLocalPath ); delete pwszPreviousSid; return Status; }
if ( Status != ERROR_SUCCESS ) return Status; }
pSidEveryone = 0; pSidSystem = 0; pSidAdmin = 0; pSidUser = 0; pAcl = 0;
if ( _bUser ) { pSidUser = AppmgmtGetUserSid( _hUserToken ); if ( ! pSidUser ) return ERROR_OUTOFMEMORY; }
bStatus = AllocateAndInitializeSid( &AuthorityEveryone, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pSidEveryone );
if ( bStatus ) bStatus = AllocateAndInitializeSid( &AuthorityNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pSidSystem );
if ( bStatus ) bStatus = AllocateAndInitializeSid( &AuthorityNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pSidAdmin );
if ( ! bStatus ) { Status = GetLastError(); goto SecureScriptDirEnd; }
AclSize = GetLengthSid(pSidSystem) + GetLengthSid(pSidAdmin) + sizeof(ACL) + (3 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD))); if ( _bUser ) AclSize += GetLengthSid(pSidUser); else AclSize += GetLengthSid(pSidEveryone);
pAcl = (PACL) LocalAlloc( 0, AclSize );
if ( pAcl ) { bStatus = InitializeAcl( pAcl, AclSize, ACL_REVISION ); if ( ! bStatus ) Status = GetLastError(); } else { Status = ERROR_OUTOFMEMORY; }
if ( Status != ERROR_SUCCESS ) goto SecureScriptDirEnd;
//
// Access is as follows :
// %systemroot%\system32
// appmgmt - LocalSystem (Full), Admin Group (Full), Everyone (Read/Execute, this folder only)
// appmgmt\machine - LocalSystem (Full), Admin Group (Full)
// appmgmt\<usersid> - LocalSystem (Full), Admin Group (Full), <usersid> (Read/Execute)
//
AceIndex = 0;
bStatus = AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, pSidSystem);
if ( bStatus ) { bStatus = GetAce(pAcl, AceIndex, (void **) &pAceHeader); if ( bStatus ) pAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE); }
if ( bStatus ) { AceIndex++; bStatus = AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, pSidAdmin);
if ( bStatus ) { bStatus = GetAce(pAcl, AceIndex, (void **) &pAceHeader); if ( bStatus ) pAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE); } }
if ( bStatus ) { AceIndex++; bStatus = AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_GENERIC_READ | FILE_GENERIC_EXECUTE, pSidEveryone); }
if ( ! bStatus ) { Status = GetLastError(); goto SecureScriptDirEnd; }
bStatus = InitializeSecurityDescriptor( &SecDesc, SECURITY_DESCRIPTOR_REVISION );
if ( bStatus ) bStatus = SetSecurityDescriptorDacl( &SecDesc, TRUE, pAcl, FALSE );
if ( bStatus ) { PWCHAR pwszSlash1, pwszSlash2;
//
// We are always creating dirs of the form "%systemroot%\system32\appmgmt\<sid>\".
//
pwszSlash1 = wcsrchr( _pwszLocalPath, L'\\' ); *pwszSlash1 = 0; pwszSlash2 = wcsrchr( _pwszLocalPath, L'\\' ); *pwszSlash2 = 0;
SecAttr.nLength = sizeof( SecAttr ); SecAttr.lpSecurityDescriptor = &SecDesc; SecAttr.bInheritHandle = FALSE;
// This creates the root appmgmt dir.
bStatus = CreateDirectory( _pwszLocalPath, &SecAttr );
if ( ! bStatus && (ERROR_ALREADY_EXISTS == GetLastError()) ) { bStatus = SetFileSecurity( _pwszLocalPath, DACL_SECURITY_INFORMATION, &SecDesc ); }
*pwszSlash1 = L'\\'; *pwszSlash2 = L'\\';
if ( bStatus ) { //
// We always remove the Everyone ACE, but only in the case of a user
// (rather then the machine) subdir do we then add in a user specific
// ACE to replace it below.
//
bStatus = DeleteAce( pAcl, AceIndex );
if ( _bUser ) { if ( bStatus ) bStatus = AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_GENERIC_READ | FILE_GENERIC_EXECUTE, pSidUser);
if ( bStatus ) { bStatus = GetAce(pAcl, AceIndex, (void **) &pAceHeader); if ( bStatus ) pAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE); } }
// This now creates the user specific subdir.
if ( bStatus ) bStatus = CreateDirectory( _pwszLocalPath, &SecAttr ); }
if ( ! bStatus && (ERROR_ALREADY_EXISTS == GetLastError()) ) { bStatus = SetFileSecurity( _pwszLocalPath, DACL_SECURITY_INFORMATION, &SecDesc ); if ( bStatus ) bStatus = SetFileAttributes( _pwszLocalPath, FILE_ATTRIBUTE_SYSTEM ); } }
if ( ! bStatus ) Status = GetLastError();
SecureScriptDirEnd:
FreeSid( pSidUser ); FreeSid( pSidEveryone ); FreeSid( pSidSystem ); FreeSid( pSidAdmin ); LocalFree( pAcl );
return Status; }
DWORD CManagedAppProcessor::GetOrderedLocalAppList( CAppList & AppList ) { CAppList RegAppList( NULL ); CAppInfo * pAppInfo; WCHAR wszDeploymentId[44]; WCHAR * pwszGPOList; WCHAR * pwszGPO; WCHAR * pwszGPOEnd; DWORD Index; DWORD Size; DWORD Status; BOOL bStatus;
DebugMsg((DM_VERBOSE, IDS_GET_LOCAL_APPS));
pwszGPOList = 0; Size = 0;
Status = ERROR_FILE_NOT_FOUND;
if ( !GetRsopContext()->IsPlanningModeEnabled() ) { Status = RegQueryValueEx( _hkAppmgmt, POLICYLISTVALUE, 0, NULL, (LPBYTE) NULL, &Size );
}
if ( ERROR_SUCCESS == Status ) { pwszGPOList = new WCHAR[Size/2]; if ( ! pwszGPOList ) { Status = ERROR_OUTOFMEMORY; goto GetOrderedLocalAppListEnd; }
Status = RegQueryValueEx( _hkAppmgmt, POLICYLISTVALUE, 0, NULL, (LPBYTE) pwszGPOList, &Size ); } else { //
// The policylist named value will not exist the first time policy
// runs. Therefor there will be no apps already on the machine if
// this value is not present.
//
// Note however, that because this is a new value for NT5 beta3,
// beta2+ clients may have apps, but won't have this value. For
// those machines, this new value will be written during the first
// full policy run. That will not pose any problems.
//
return ERROR_SUCCESS; }
if ( Status != ERROR_SUCCESS ) goto GetOrderedLocalAppListEnd;
Index = 0;
for (;;) { Status = RegEnumKey( _hkAppmgmt, Index++, wszDeploymentId, sizeof(wszDeploymentId) / sizeof(WCHAR) );
if ( ERROR_NO_MORE_ITEMS == Status ) { Index--; Status = ERROR_SUCCESS; break; }
if ( Status != ERROR_SUCCESS ) break;
pAppInfo = new CAppInfo( this, wszDeploymentId, bStatus );
if ( ! pAppInfo || ! bStatus ) Status = ERROR_OUTOFMEMORY;
if ( Status != ERROR_SUCCESS ) { if ( pAppInfo ) delete pAppInfo; break; }
RegAppList.InsertFIFO( pAppInfo ); }
if ( Status != ERROR_SUCCESS ) goto GetOrderedLocalAppListEnd;
if ( 0 == Index ) { DebugMsg((DM_VERBOSE, IDS_NO_LOCAL_APPS)); } else { DebugMsg((DM_VERBOSE, IDS_LOCAL_APP_COUNT, Index)); }
//
// We first gather all apps for policies we know about and order them
// according to the policy precedences.
//
for ( pwszGPO = pwszGPOList; *pwszGPO; pwszGPO = pwszGPOEnd + 1 ) { pwszGPOEnd = wcschr( pwszGPO, L';' ); *pwszGPOEnd = 0;
RegAppList.Reset();
for ( pAppInfo = (CAppInfo *) RegAppList.GetCurrentItem(); pAppInfo; pAppInfo = (CAppInfo *) RegAppList.GetCurrentItem() ) { if ( lstrcmpi( pAppInfo->_pwszGPOId, pwszGPO ) != 0 ) { RegAppList.MoveNext(); continue; }
DebugMsg((DM_VERBOSE, IDS_LOCAL_APP_DUMP, pAppInfo->_pwszDeploymentName, pAppInfo->_pwszGPOName, pAppInfo->_State, pAppInfo->_AssignCount));
RegAppList.MoveNext(); pAppInfo->Remove(); AppList.InsertFIFO( pAppInfo ); }
RegAppList.ResetEnd(); }
//
// In some instances we will still have apps in the registry that are not in the
// current list of policies. We add them to the front of the final list.
//
for ( RegAppList.Reset(); pAppInfo = (CAppInfo *) RegAppList.GetCurrentItem(); ) { DebugMsg((DM_VERBOSE, IDS_LOCAL_APP_DUMP, pAppInfo->_pwszDeploymentName, pAppInfo->_pwszGPOName, pAppInfo->_State, pAppInfo->_AssignCount));
RegAppList.MoveNext(); pAppInfo->Remove(); AppList.InsertLIFO( pAppInfo ); }
RegAppList.ResetEnd();
GetOrderedLocalAppListEnd:
delete [] pwszGPOList;
if ( Status != ERROR_SUCCESS ) DebugMsg((DM_WARNING, IDS_GETLOCALAPPS_FAIL, Status));
return Status; }
DWORD CManagedAppProcessor::GetLocalScriptAppList( CAppList & AppList ) { WIN32_FIND_DATA FindData; CAppInfo * pAppInfo; WCHAR * pwszPath; HANDLE hFind; DWORD Status; HRESULT hr; ULONG ulSize;
ulSize = lstrlen(_pwszLocalPath) + 7; pwszPath = new WCHAR[ulSize]; if ( ! pwszPath ) return ERROR_OUTOFMEMORY;
hr = StringCchCopy( pwszPath, ulSize, _pwszLocalPath ); if (SUCCEEDED(hr)) { hr = StringCchCat( pwszPath, ulSize, L"\\*.aas" ); }
if (FAILED(hr)) { delete [] pwszPath; return HRESULT_CODE(hr); }
hFind = FindFirstFile( pwszPath, &FindData );
delete [] pwszPath;
if ( INVALID_HANDLE_VALUE == hFind ) return ERROR_SUCCESS;
do { if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) continue;
pwszPath = wcschr( FindData.cFileName, L'.' ); if ( ! pwszPath ) continue; *pwszPath = 0;
pAppInfo = new CAppInfo( FindData.cFileName ); if ( ! pAppInfo ) return ERROR_OUTOFMEMORY; pAppInfo->_ScriptTime = FindData.ftLastWriteTime;
AppList.InsertFIFO( pAppInfo ); } while ( FindNextFile( hFind, &FindData ) );
FindClose( hFind ); return ERROR_SUCCESS; }
DWORD GetScriptDirPath( HANDLE hToken, DWORD ExtraPathChars, WCHAR ** ppwszPath, DWORD *pdwAllocatedLength ) { WCHAR wszPath[MAX_PATH]; WCHAR * pwszSystemDir; DWORD AllocLength; DWORD Length; DWORD Status; UNICODE_STRING SidString;
Status = ERROR_SUCCESS; *ppwszPath = 0; if (NULL != pdwAllocatedLength) { *pdwAllocatedLength = 0; }
pwszSystemDir = wszPath; AllocLength = sizeof(wszPath) / sizeof(WCHAR);
RtlInitUnicodeString( &SidString, NULL );
for (;;) { Length = GetSystemDirectory( pwszSystemDir, AllocLength );
if ( 0 == Length ) return GetLastError();
if ( Length >= AllocLength ) { AllocLength = Length + 1; pwszSystemDir = (WCHAR *) LocalAlloc( 0, AllocLength * sizeof(WCHAR) ); if ( ! pwszSystemDir ) return ERROR_OUTOFMEMORY; continue; }
break; }
if ( hToken ) { Status = GetSidString( hToken, &SidString ); } else { RtlInitUnicodeString( &SidString, L"MACHINE" ); }
if ( ERROR_SUCCESS == Status ) { HRESULT hr; ULONG ulSize;
// System dir + \appmgmt\ + Sid + \ + null
ulSize = Length + 11 + (SidString.Length / 2) + ExtraPathChars; *ppwszPath = new WCHAR[ulSize];
if ( *ppwszPath ) { hr = StringCchCopy( *ppwszPath, ulSize, pwszSystemDir ); if (SUCCEEDED(hr)) { if ( pwszSystemDir[lstrlen(pwszSystemDir)-1] != L'\\' ) { hr = StringCchCat( *ppwszPath, ulSize, L"\\" ); } if (SUCCEEDED(hr)) { hr = StringCchCat( *ppwszPath, ulSize, L"appmgmt\\" ); if (SUCCEEDED(hr)) { hr = StringCchCat( *ppwszPath, ulSize, SidString.Buffer ); if (SUCCEEDED(hr)) { hr = StringCchCat( *ppwszPath, ulSize, L"\\" ); } } } }
if (SUCCEEDED(hr)) { if (NULL != pdwAllocatedLength) { *pdwAllocatedLength = ulSize; } } else { delete [] *ppwszPath; *ppwszPath = NULL; Status = HRESULT_CODE(hr); } } else { Status = ERROR_OUTOFMEMORY; } }
if ( hToken ) RtlFreeUnicodeString( &SidString );
if ( pwszSystemDir != wszPath ) LocalFree( pwszSystemDir );
return Status; }
void CManagedAppProcessor::LogonMsg( DWORD MsgId, ... ) { WCHAR wszMsg[80]; WCHAR wszBuffer[256]; va_list VAList; int Status;
if ( ! _pfnStatusCallback || ! LoadLoadString() ) return;
Status = (*pfnLoadStringW)( ghDllInstance, MsgId, wszMsg, sizeof(wszMsg) / sizeof(WCHAR) );
if ( 0 == Status ) return;
va_start( VAList, MsgId );
(void) StringCchVPrintf( wszBuffer, sizeof(wszBuffer)/sizeof(wszBuffer[0]), wszMsg, VAList); va_end( VAList );
_pfnStatusCallback( FALSE, wszBuffer ); }
//
// CGPOInfoList
//
CGPOInfoList::~CGPOInfoList() { CGPOInfo * pGPO;
Reset();
while ( pGPO = (CGPOInfo *) GetCurrentItem() ) { MoveNext();
pGPO->Remove(); delete pGPO; }
ResetEnd(); }
BOOL CGPOInfoList::Add( PGROUP_POLICY_OBJECT pGPOInfo ) { CGPOInfo * pGPO; BOOL bStatus = FALSE;
pGPO = new CGPOInfo( pGPOInfo, bStatus );
if ( ! bStatus ) { if ( pGPO ) delete pGPO; pGPO = 0; }
if ( ! pGPO ) return FALSE;
InsertFIFO( pGPO );
return TRUE; }
CGPOInfo * CGPOInfoList::Find( WCHAR * pwszGPOId ) { CGPOInfo * pGPO;
pGPO = NULL;
for ( Reset(); pGPO = (CGPOInfo *) GetCurrentItem(); MoveNext() ) { if ( lstrcmpi( pwszGPOId, pGPO->_pwszGPOId ) == 0 ) break; }
ResetEnd();
return pGPO; }
int CGPOInfoList::Compare( WCHAR * pwszGPOId1, WCHAR * pwszGPOId2 ) { CGPOInfo * pGPO; int Index; int Index1; int Index2;
Index1 = Index2 = -1;
Reset();
Index = 0;
while ( pGPO = (CGPOInfo *) GetCurrentItem() ) { if ( lstrcmpi( pGPO->_pwszGPOId, pwszGPOId1 ) == 0 ) Index1 = Index;
if ( lstrcmpi( pGPO->_pwszGPOId, pwszGPOId2 ) == 0 ) Index2 = Index;
MoveNext(); Index++; }
ResetEnd();
if ( Index1 == Index2 ) return 0;
if ( Index1 < Index2 ) return -1; else return 1; }
//
// CGPOInfo
//
CGPOInfo::CGPOInfo( PGROUP_POLICY_OBJECT pGPOInfo, BOOL & bStatus ) { bStatus = TRUE;
_pwszGPOId = StringDuplicate( (PWCHAR) pGPOInfo->szGPOName ); _pwszGPOName = StringDuplicate( (PWCHAR) pGPOInfo->lpDisplayName ); _pwszGPOPath = StringDuplicate( (PWCHAR) pGPOInfo->lpDSPath );
if ( pGPOInfo->lpLink ) { _pwszSOMPath = StringDuplicate( StripLinkPrefix(pGPOInfo->lpLink) ); } else { _pwszSOMPath = NULL; }
if ( ! _pwszGPOId || ! _pwszGPOName || ! _pwszGPOPath || ! _pwszSOMPath ) bStatus = FALSE; }
CGPOInfo::~CGPOInfo() { delete [] _pwszGPOId; delete [] _pwszGPOName; delete [] _pwszGPOPath; delete [] _pwszSOMPath; }
CRsopAppContext::CRsopAppContext( DWORD dwContext, HANDLE hEventAppsEnumerated, // = NULL
APPKEY* pAppType) : // = NULL
CRsopContext( APPMGMTEXTENSIONGUID ), _dwContext( dwContext ), _wszDemandSpec( NULL ), _bTransition( FALSE ), _dwInstallType( DEMAND_INSTALL_NONE ), _bRemovalPurge( FALSE ), _bRemoveGPOApps( FALSE ), _bForcedRefresh( FALSE ), _dwCurrentRsopVersion( 0 ), _hEventAppsEnumerated( hEventAppsEnumerated ), _StatusAbort( ERROR_SUCCESS ) { WCHAR wszClsid[ MAX_SZGUID_LEN ]; WCHAR* wszDemandSpec;
if ( pAppType ) { switch (pAppType->Type) { case FILEEXT : _dwInstallType = DEMAND_INSTALL_FILEEXT; wszDemandSpec = pAppType->uType.FileExt; break;
case PROGID : _dwInstallType = DEMAND_INSTALL_PROGID; wszDemandSpec = pAppType->uType.ProgId; break;
case COMCLASS : _dwInstallType = DEMAND_INSTALL_CLSID; GuidToString( pAppType->uType.COMClass.Clsid, wszClsid); wszDemandSpec = wszClsid; break;
case APPNAME : _dwInstallType = DEMAND_INSTALL_NAME; wszDemandSpec = NULL; break; default: wszDemandSpec = NULL; } _wszDemandSpec = StringDuplicate( wszDemandSpec ); } }
CRsopAppContext::~CRsopAppContext() { //
// If policy was aborted before we attempted to apply it,
// we will have logged only the applications that caused us to
// abort. So in this case, the rsop data is incomplete
//
if ( ERROR_SUCCESS != _StatusAbort ) { HRESULT hr;
hr = HRESULT_FROM_WIN32( _StatusAbort );
//
// The rsop data is incomplete, so disable rsop with the
// error code below so that the administrator will know
// that the data are not complete.
//
(void) DisableRsop( hr ); } }
void CRsopAppContext::InitializeRsopContext( HANDLE hUserToken, HKEY hkUser, BOOL bForcedRefresh, BOOL* pbNoChanges) { //
// In planning mode, all initialization is
// already done, there is nothing to do here
//
if ( IsPlanningModeEnabled() ) { return; }
//
// To get an rsop namespace, we need to know the user's sid
//
PSID pSid; BOOL bProfileConsistent;
pSid = NULL; bProfileConsistent = TRUE;
//
// The token will only be non-NULL if we are in user policy
//
if ( hUserToken ) { pSid = AppmgmtGetUserSid( hUserToken );
if ( ! pSid ) { (void) DisableRsop( ERROR_OUTOFMEMORY ); return; } }
//
// Perform the base context initialization -- pSid will be NULL
// here if we are in machine policy, which is ok.
//
(void) InitializeContext( pSid );
if ( pSid ) { (void) FreeSid( pSid );
DWORD dwMachineVersion; DWORD dwUserVersion; DWORD dwSize;
dwMachineVersion = 0; dwUserVersion = 0;
dwSize = sizeof( dwMachineVersion ); //
// Read machine version
//
(void) RegQueryValueEx( GetNameSpaceKey(), RSOPVERSION, NULL, NULL, (LPBYTE) &dwMachineVersion, &dwSize); dwSize = sizeof( dwUserVersion );
//
// Read user version
//
(void) RegQueryValueEx( hkUser, RSOPVERSION, NULL, NULL, (LPBYTE) &dwUserVersion, &dwSize);
//
// Always sync the current version for this machine to the profile's version
//
_dwCurrentRsopVersion = dwUserVersion; bProfileConsistent = dwUserVersion == dwMachineVersion; }
//
// In the policy refresh case, we are done initializing if
// a forced refresh isn't demanded
//
if ( ( CRsopAppContext::POLICY_REFRESH == GetContext() ) && ! bForcedRefresh ) { //
// Force a refresh if the profile is not consitent with the machine's rsop
//
if ( *pbNoChanges && ! bProfileConsistent ) { bForcedRefresh = TRUE; *pbNoChanges = FALSE;
DebugMsg((DM_VERBOSE, IDS_CHANGES_RSOP_CHANGE)); } else { return; } }
_bForcedRefresh = bForcedRefresh;
//
// In this case, the gp engine did not pass in a
// namespace for logging, either because we are executing outside of
// policy refresh context or because there were no changes and
// we decided to reapply policy regardless. Since the gp engine did
// not give us a namespace, we must initialize from a saved namespace
//
(void) InitializeSavedNameSpace(); }
HRESULT CRsopAppContext::MoveAppContextState( CRsopAppContext* pRsopContext ) { HRESULT hr;
hr = S_OK;
if ( pRsopContext->_wszDemandSpec ) { _wszDemandSpec = StringDuplicate( pRsopContext->_wszDemandSpec );
if ( ! _wszDemandSpec ) { hr = E_OUTOFMEMORY; } }
if ( SUCCEEDED( hr ) ) { hr = MoveContextState( pRsopContext ); }
_dwContext = pRsopContext->_dwContext; _dwInstallType = pRsopContext->_dwInstallType; _bTransition = pRsopContext->_bTransition; _bRemovalPurge = pRsopContext->_bRemovalPurge; _bRemoveGPOApps = pRsopContext->_bRemoveGPOApps; _bForcedRefresh = pRsopContext->_bForcedRefresh; _dwCurrentRsopVersion = pRsopContext->_dwCurrentRsopVersion; _hEventAppsEnumerated = pRsopContext->_hEventAppsEnumerated; _StatusAbort = pRsopContext->_StatusAbort;
return hr; }
HRESULT CRsopAppContext::SetARPContext() { if ( ! IsPlanningModeEnabled() ) { return E_INVALIDARG; }
_dwContext = ARPLIST;
return S_OK; }
DWORD CRsopAppContext::WriteCurrentRsopVersion( HKEY hkUser ) { if ( ! IsRsopEnabled() || IsPlanningModeEnabled() ) { return ERROR_SUCCESS; }
DWORD dwCurrentVersion; LONG Status;
dwCurrentVersion = _dwCurrentRsopVersion + 1;
//
// Write the machine version
//
Status = RegSetValueEx( GetNameSpaceKey(), RSOPVERSION, 0, REG_DWORD, (LPBYTE) &dwCurrentVersion, sizeof( DWORD ) );
LONG StatusUser; //
// Read user version
//
StatusUser = RegSetValueEx( hkUser, RSOPVERSION, 0, REG_DWORD, (LPBYTE) &dwCurrentVersion, sizeof( DWORD ) );
if ( ERROR_SUCCESS == Status ) { Status = StatusUser; }
return Status; }
void CRsopAppContext::SetPolicyAborted( DWORD Status ) { if ( ERROR_SUCCESS == _StatusAbort ) { _StatusAbort = Status; } }
BOOL CRsopAppContext::HasPolicyAborted() { return ERROR_SUCCESS != _StatusAbort; }
void CRsopAppContext::SetAppsEnumerated() { if ( _hEventAppsEnumerated ) { (void) SetEvent( _hEventAppsEnumerated ); } }
|