//************************************************************* // // 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\ - LocalSystem (Full), Admin Group (Full), (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\\". // 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 ); } }