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

3122 lines
81 KiB

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