|
|
//*************************************************************
//
// Copyright (c) Microsoft Corporation 1998
// All rights reserved
//
// apis.cxx
//
//*************************************************************
#include "appmgext.hxx"
typedef struct { CManagedAppProcessor * pManApp; CAppInfo * pAppInfo; BOOL bUninstallsCompleted; CLoadMsi * pLoadMsi; CLoadSfc * pLoadSfc; boolean bStatus; INT64 SRSequence; } APPCONTEXT, * PAPPCONTEXT;
CRITICAL_SECTION gAppCS;
static BOOL SetSystemRestorePoint( IN WCHAR * pwszApplicationName, IN OUT PAPPCONTEXT pAppContext );
static void CheckLocalCall( IN handle_t hRpc );
WCHAR* GetGpoNameFromGuid( IN PGROUP_POLICY_OBJECT pGpoList, IN GUID* pGpoGuid );
DWORD GetPlatformCompatibleCOMClsCtx( DWORD Architecture, DWORD dwClsCtx );
void LogRsopInstallData( CManagedAppProcessor* pManApp, CAppInfo* pAppInfo );
DWORD WINAPI GetManagedAppsProc( LPVOID pvArpContext );
error_status_t InstallBegin( IN handle_t hRpc, IN APPKEY * pAppType, OUT PINSTALLCONTEXT * ppInstallContext, OUT APPLICATION_INFO * pInstallInfo, OUT UNINSTALL_APPS * pUninstallApps ) { CManagedAppProcessor * pManApp; CAppList LocalApps( NULL ); HANDLE hUserToken; HKEY hkRoot; uCLSSPEC ClassSpec; QUERYCONTEXT QueryContext; PACKAGEDISPINFO PackageInfo; PAPPCONTEXT pAppContext; GUID DeploymentId; CAppInfo * pAppInfo; CAppInfo * pUpgradedApp; CAppInfo * pLocalApp; WCHAR wszGuid[40]; WCHAR wszProductId[40]; WCHAR * pwszDeploymentId; DWORD Size; DWORD UninstallApps; DWORD n; DWORD Status; HRESULT hr; BOOL bEnterCritSec; BOOL bStatus;
CRsopAppContext RsopContext( CRsopAppContext::INSTALL, NULL, pAppType ); PGROUP_POLICY_OBJECT pGPOList;
*ppInstallContext = 0; memset( pInstallInfo, 0, sizeof(APPLICATION_INFO) ); memset( pUninstallApps, 0, sizeof(UNINSTALL_APPS) );
CheckLocalCall( hRpc );
pManApp = 0; pAppInfo = 0; hUserToken = 0; hkRoot = 0; pAppContext = 0;
bEnterCritSec = FALSE;
pGPOList = NULL;
Status = RpcImpersonateClient( NULL );
if ( Status != ERROR_SUCCESS ) return Status;
if ( ERROR_SUCCESS == Status ) { bStatus = OpenThreadToken( GetCurrentThread(), TOKEN_READ | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, TRUE, &hUserToken );
if ( ! bStatus ) Status = GetLastError(); }
if ( ERROR_SUCCESS == Status ) Status = RegOpenCurrentUser( GENERIC_ALL, &hkRoot );
if ( Status != ERROR_SUCCESS ) { CloseHandle( hUserToken ); RevertToSelf(); return Status; }
gpEvents->SetToken( hUserToken );
LogTime();
//
// Set the query context -- the LANG_SYSTEM_DEFAULT value
// tells CsGetAppInfo that we should use our built-in language precedence
// algorithm in filtering packages -- otherwise, it will only consider
// packages that match exactly the locale specified in the .Locale member
//
QueryContext.Locale = LANG_SYSTEM_DEFAULT;
//
// For architecture, we use the architecture of the calling process to override
// the architecture of this process
//
GetDefaultPlatform( &QueryContext.Platform, TRUE, pAppType->ProcessorArchitecture );
QueryContext.dwContext = CLSCTX_ALL;
QueryContext.dwVersionHi = -1; QueryContext.dwVersionLo = -1;
switch ( pAppType->Type ) { case APPNAME : ClassSpec.tyspec = TYSPEC_PACKAGENAME; ClassSpec.tagged_union.ByName.pPackageName = pAppType->uType.AppName.Name; ClassSpec.tagged_union.ByName.PolicyId = pAppType->uType.AppName.PolicyId; DebugMsg((DM_VERBOSE, IDS_INSTALL_APPNAME, pAppType->uType.AppName.Name)); break; case FILEEXT : ClassSpec.tyspec = TYSPEC_FILEEXT; ClassSpec.tagged_union.pFileExt = pAppType->uType.FileExt; DebugMsg((DM_VERBOSE, IDS_INSTALL_FILEEXT, pAppType->uType.FileExt)); break; case PROGID : ClassSpec.tyspec = TYSPEC_PROGID; ClassSpec.tagged_union.pProgId = pAppType->uType.ProgId; DebugMsg((DM_VERBOSE, IDS_INSTALL_PROGID, pAppType->uType.ProgId)); break; case COMCLASS : ClassSpec.tyspec = TYSPEC_CLSID; ClassSpec.tagged_union.clsid = pAppType->uType.COMClass.Clsid; QueryContext.dwContext = GetPlatformCompatibleCOMClsCtx( pAppType->ProcessorArchitecture, pAppType->uType.COMClass.ClsCtx ); GuidToString( pAppType->uType.COMClass.Clsid, wszGuid ); DebugMsg((DM_VERBOSE, IDS_INSTALL_COMCLASS, wszGuid, QueryContext.dwContext)); break; }
hr = CsGetAppInfo( &ClassSpec, &QueryContext, &PackageInfo );
RevertToSelf();
if ( S_OK == hr ) { WCHAR* pszPolicyName;
Status = RpcImpersonateClient( NULL );
if ( ERROR_SUCCESS == Status ) { Status = GetCurrentUserGPOList( &pGPOList );
RevertToSelf(); }
if ( ERROR_SUCCESS != Status ) goto InstallAppExit;
pszPolicyName = GetGpoNameFromGuid( pGPOList, &(PackageInfo.GpoId) );
//
// We've seen instance where getting the policy names fails because the gpo
// history key for appmgmt in hklm was missing. This is remotely possible
// if some registry api fails. In this instance we can't just let every
// install from ARP fail, so we'll just have to chug along with an empty
// policy name.
//
if ( ! pszPolicyName ) pszPolicyName = L"";
switch ( PackageInfo.PathType ) { case DrwFilePath : DebugMsg((DM_VERBOSE, IDS_INSTALL_DARWIN, PackageInfo.pszPackageName, pszPolicyName)); break; case SetupNamePath : DebugMsg((DM_VERBOSE, IDS_INSTALL_SETUP, PackageInfo.pszPackageName, pszPolicyName)); pInstallInfo->pwszDeploymentName = StringDuplicate( PackageInfo.pszPackageName ); pInstallInfo->pwszGPOName = StringDuplicate( pszPolicyName ); pInstallInfo->pwszSetupCommand = StringDuplicate( PackageInfo.pszScriptPath ); goto InstallAppExit; default : DebugMsg((DM_VERBOSE, IDS_INSTALL_UNKNOWN, PackageInfo.PathType, PackageInfo.pszPackageName, pszPolicyName)); Status = CS_E_PACKAGE_NOTFOUND; goto InstallAppExit; } } else { DebugMsg((DM_VERBOSE, IDS_GETAPPINFO_FAIL, hr)); memset( &PackageInfo, 0, sizeof(PackageInfo) ); Status = (DWORD) hr; }
if ( ERROR_SUCCESS == Status ) { pAppContext = new APPCONTEXT; if ( pAppContext ) { pAppContext->pManApp = 0; pAppContext->pAppInfo = 0; pAppContext->bUninstallsCompleted = FALSE; pAppContext->pLoadMsi = new CLoadMsi( Status ); pAppContext->pLoadSfc = 0; pAppContext->bStatus = FALSE; pAppContext->SRSequence = 0;
if ( Status != ERROR_SUCCESS ) { delete pAppContext->pLoadMsi; pAppContext->pLoadMsi = 0; }
if ( ! pAppContext->pLoadMsi ) { delete pAppContext; pAppContext = 0; } }
if ( ! pAppContext ) { Status = ERROR_OUTOFMEMORY; } }
if ( Status != ERROR_SUCCESS ) goto InstallAppExit;
RtlEnterCriticalSection( &gAppCS ); bEnterCritSec = TRUE;
pManApp = new CManagedAppProcessor( 0, hUserToken, hkRoot, NULL, TRUE, FALSE, &RsopContext, Status );
if ( ! pManApp ) Status = ERROR_OUTOFMEMORY;
if ( ERROR_SUCCESS == Status ) Status = pManApp->SetPolicyListFromGPOList( pGPOList );
if ( ERROR_SUCCESS == Status ) { pAppInfo = new CAppInfo( pManApp, &PackageInfo, TRUE, bStatus );
if ( ! pAppInfo || ! bStatus ) Status = ERROR_OUTOFMEMORY; }
if ( ERROR_SUCCESS == Status ) { GuidToString( PackageInfo.ProductCode, wszProductId);
Status = pManApp->GetOrderedLocalAppList( LocalApps ); }
if ( ERROR_SUCCESS == Status ) Status = pManApp->Impersonate();
if ( Status != ERROR_SUCCESS ) goto InstallAppExit;
pAppContext->pManApp = pManApp; pAppContext->pAppInfo = pAppInfo;
//
// When servicing a demand install outside of ARP we prevent faulting in
// any deployment of a particular product different from what is already
// on the machine (if any) and we also prevent faulting in any app which
// upgrades another app already on the machine. This is to prevent a
// subsequent upgrade, transform conflict, or language mismatch from
// occuring while the app is likely in use.
//
// So below we are checking these cases plus, in the case of an ARP install,
// adding any such apps to an additional list for processing of orphan and
// uninstall actions.
//
for ( LocalApps.Reset(), pLocalApp = (CAppInfo *) LocalApps.GetCurrentItem(); pLocalApp; pLocalApp = (CAppInfo *) LocalApps.GetCurrentItem() ) { if ( ! (pLocalApp->_State & (APPSTATE_ASSIGNED | APPSTATE_PUBLISHED)) ) { LocalApps.MoveNext(); continue; }
//
// This is the check for a similar product id but a different
// deployment instance.
//
if ( (0 == lstrcmpi( pLocalApp->_pwszProductId, wszProductId )) && (memcmp( &pLocalApp->_DeploymentId, &PackageInfo.PackageGuid, sizeof(GUID) ) != 0) ) { if ( pAppType->Type != APPNAME ) { // Abort if not doing an ARP install.
Status = CS_E_PACKAGE_NOTFOUND; DebugMsg((DM_VERBOSE, IDS_DEMAND_BLOCK1, pAppInfo->_pwszDeploymentName)); break; } else { LocalApps.MoveNext(); pLocalApp->Remove(); pManApp->AppList().InsertFIFO( pLocalApp ); continue; } }
//
// This is the check to see if this new package is set to upgrade any
// existing app we have.
//
for ( n = 0; n < PackageInfo.cUpgrades; n++ ) { if ( (PackageInfo.prgUpgradeInfoList[n].Flag & (UPGFLG_Uninstall | UPGFLG_NoUninstall)) && (0 == memcmp( &pLocalApp->_DeploymentId, &PackageInfo.prgUpgradeInfoList[n].PackageGuid, sizeof(GUID) )) ) { if ( pAppType->Type != APPNAME ) { // Abort if not doing an ARP install.
Status = CS_E_PACKAGE_NOTFOUND; DebugMsg((DM_VERBOSE, IDS_DEMAND_BLOCK2, pAppInfo->_pwszDeploymentName)); } else { LocalApps.MoveNext(); pLocalApp->Remove(); pManApp->AppList().InsertFIFO( pLocalApp ); } break; } }
if ( CS_E_PACKAGE_NOTFOUND == Status ) break;
if ( n < PackageInfo.cUpgrades ) continue;
//
// This is the check to see if this app is superceded by an app which is
// already installed. Note that in some instances this may actually be
// a case where the new app upgrades the local app because of
// policy precedence upgrade reversal. The result is the same for demand
// installs, but slightly different for ARP installs where we must ensure
// that the upgrade logic is invoked.
//
for ( pwszDeploymentId = pLocalApp->_pwszSupercededIds; pwszDeploymentId && *pwszDeploymentId; pwszDeploymentId += GUIDSTRLEN + 1 ) { StringToGuid( pwszDeploymentId, &DeploymentId ); if ( 0 == memcmp( &DeploymentId, &PackageInfo.PackageGuid, sizeof(GUID) ) ) { if ( pAppType->Type != APPNAME ) { // Abort if not doing an ARP install.
Status = CS_E_PACKAGE_NOTFOUND; DebugMsg((DM_VERBOSE, IDS_DEMAND_BLOCK2, pAppInfo->_pwszDeploymentName)); } else { //
// There is an app already installed which has the new package
// in it's override list. Either a previous upgrade setting is no
// longer set or this is a policy precedence violation case where
// the upgrade needs to be reversed.
// Not the prettiest solution, trading a late product change for least
// invasive code change.
//
if ( pManApp->GPOList().Compare( pLocalApp->_pwszGPOId, pAppInfo->_pwszGPOId ) < 0 ) { PACKAGEDISPINFO LocalAppPackageInfo; CAppInfo * pNewApp = 0;
memset( &LocalAppPackageInfo, 0, sizeof(LocalAppPackageInfo) );
ClassSpec.tyspec = TYSPEC_OBJECTID; memcpy( &ClassSpec.tagged_union.ByObjectId.ObjectId, &pLocalApp->_DeploymentId, sizeof(GUID) ); StringToGuid( pLocalApp->_pwszGPOId, &ClassSpec.tagged_union.ByObjectId.PolicyId );
hr = CsGetAppInfo( &ClassSpec, NULL, &LocalAppPackageInfo );
if ( S_OK == hr ) { pNewApp = new CAppInfo( pManApp, &LocalAppPackageInfo, FALSE, bStatus ); if ( ! bStatus ) { delete pNewApp; pNewApp = 0; } ReleasePackageInfo( &LocalAppPackageInfo ); }
if ( pNewApp ) { pManApp->AppList().InsertFIFO( pAppInfo ); Status = pNewApp->InitializePass0(); pAppInfo->Remove(); pManApp->AppList().InsertFIFO( pNewApp ); }
if ( ! pNewApp || (Status != ERROR_SUCCESS) ) Status = CS_E_PACKAGE_NOTFOUND; } } break; } }
if ( CS_E_PACKAGE_NOTFOUND == Status ) break;
LocalApps.MoveNext(); }
LocalApps.ResetEnd();
if ( ERROR_SUCCESS == Status ) { //
// When doing a fileext/progid/clsid demand install, we don't want to
// set the full install state bit for the first time. This will enable
// the full install option to still be applied at the next foreground
// policy processing.
//
if ( (pAppType->Type != APPNAME) && ! (pAppInfo->_State & APPSTATE_INSTALL) ) pAppInfo->_ActFlags &= ~ACTFLG_InstallUserAssign;
pAppInfo->InitializePass0(); pAppInfo->SetActionPass1(); pAppInfo->SetActionPass2(); pAppInfo->SetActionPass3(); pAppInfo->SetActionPass4();
Status = pAppInfo->_Status; }
pManApp->Revert();
if ( ERROR_SUCCESS == Status ) { bStatus = pAppInfo->CopyToApplicationInfo( pInstallInfo ); if ( ! bStatus ) Status = ERROR_OUTOFMEMORY; }
if ( Status != ERROR_SUCCESS ) goto InstallAppExit;
for ( pManApp->AppList().Reset(), pUpgradedApp = (CAppInfo *) pManApp->AppList().GetCurrentItem(); pUpgradedApp; pManApp->AppList().MoveNext(), pUpgradedApp = (CAppInfo *) pManApp->AppList().GetCurrentItem() ) { APPLICATION_INFO * pOldApplicationInfo;
bStatus = FALSE;
if ( (pUpgradedApp->_Action != ACTION_UNINSTALL) && (pUpgradedApp->_Action != ACTION_ORPHAN) ) continue;
pOldApplicationInfo = pUninstallApps->ApplicationInfo; pUninstallApps->ApplicationInfo = (APPLICATION_INFO *) LocalAlloc( 0, (pUninstallApps->Products + 1) * sizeof(APPLICATION_INFO) );
if ( pUninstallApps->ApplicationInfo ) { if ( pOldApplicationInfo ) memcpy( pUninstallApps->ApplicationInfo, pOldApplicationInfo, pUninstallApps->Products * sizeof(APPLICATION_INFO) ); bStatus = pUpgradedApp->CopyToApplicationInfo( &pUninstallApps->ApplicationInfo[pUninstallApps->Products] ); }
LocalFree( pOldApplicationInfo );
if ( ! bStatus ) { pUninstallApps->Products = 0; Status = ERROR_OUTOFMEMORY; goto InstallAppExit; } else { pUninstallApps->Products++; } }
pManApp->AppList().ResetEnd();
//
// If we're doing a progid, file extension, or clsid based activation, we search
// for the specific Darwin identifier.
//
if ( pAppType->Type != APPNAME ) { const DWORD dwMaxStrLen = 128; HKEY hkPolicy; HKEY hkClasses; HKEY hkProgId; HKEY hkScratch; WCHAR wszScratch[dwMaxStrLen]; WCHAR wszDarwinId[128]; WCHAR * pwszProgId; DWORD ScriptFlags;
hkPolicy = 0; hkClasses = 0;
wszDarwinId[0] = 0;
Status = RegOpenKeyEx( hkRoot, POLICYKEY, 0, KEY_ALL_ACCESS, &hkPolicy );
if ( ERROR_SUCCESS == Status ) { //
// We can use a fixed temp name since we are in a crit sec here. This
// key must be non volatile since that is how Darwin will do all of
// their creates under this key.
//
Status = RegCreateKeyEx( hkPolicy, L"TempClasses", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkClasses, NULL ); }
if ( ERROR_SUCCESS == Status ) { Status = pManApp->Impersonate(); if ( ERROR_SUCCESS == Status ) { Status = pAppInfo->CopyScriptIfNeeded(); pManApp->Revert(); } }
if ( ERROR_SUCCESS == Status ) { //
// Must include the MACHINEASSIGN flag since we are not impersonating.
// That's a little quirk in the semantics of the Msi API.
//
ScriptFlags = SCRIPTFLAGS_MACHINEASSIGN;
//
// In the progid case we need to advertise both extension and class data.
// This is because different progids are registered in these two
// cases and we want to catch both. In the former case they are progids
// associated with file extensions and in the latter case with clsids.
//
if ( (FILEEXT == pAppType->Type) || (PROGID == pAppType->Type) ) ScriptFlags |= SCRIPTFLAGS_REGDATA_EXTENSIONINFO;
if ( (PROGID == pAppType->Type) || (COMCLASS == pAppType->Type) ) ScriptFlags |= SCRIPTFLAGS_REGDATA_CLASSINFO;
Status = (*gpfnMsiAdvertiseScript)( pAppInfo->LocalScriptPath(), ScriptFlags, &hkClasses, FALSE ); }
if ( Status != ERROR_SUCCESS ) { gpEvents->Install( Status, pAppInfo);
goto InstallAppDescriptorAbort; }
//
// Now we grovel our temporary registry dump for a darwin id under the
// class info that was requested.
//
if ( pAppType->Type != COMCLASS ) { //
// Looking for a shell-open command verb. First figure out the
// ProgID.
//
if ( FILEEXT == pAppType->Type ) { Status = RegOpenKeyEx( hkClasses, pAppType->uType.FileExt, 0, KEY_ALL_ACCESS, &hkScratch );
Size = sizeof(wszScratch);
if ( ERROR_SUCCESS == Status ) { Status = RegQueryValueEx( hkScratch, L"", NULL, NULL, (PBYTE) wszScratch, &Size );
RegCloseKey( hkScratch ); }
pwszProgId = wszScratch; } else { pwszProgId = pAppType->uType.ProgId; }
if ( ERROR_SUCCESS == Status ) { Status = RegOpenKeyEx( hkClasses, pwszProgId, 0, KEY_ALL_ACCESS, &hkProgId ); }
if ( ERROR_SUCCESS == Status ) { Status = RegOpenKeyEx( hkProgId, L"shell\\open\\command", 0, KEY_ALL_ACCESS, &hkScratch );
RegCloseKey( hkProgId ); }
Size = sizeof(wszDarwinId);
if ( ERROR_SUCCESS == Status ) { Status = RegQueryValueEx( hkScratch, L"command", NULL, NULL, (PBYTE) wszDarwinId, &Size );
if ( (ERROR_SUCCESS == Status) && DebugLevelOn( DM_VERBOSE ) ) { DebugMsg((DM_VERBOSE, IDS_PROGID_FOUND, pwszProgId)); }
RegCloseKey( hkScratch ); } } else // COMCLASS == pAppType->Type
{ //
// Looking for a com clsid. We check both the inproc & localserver
// keys if those clsctx bits are set.
//
hr = StringCchCopy( wszScratch, dwMaxStrLen, L"CLSID\\" ); if (FAILED(hr)) { Status = HRESULT_CODE(hr); goto InstallAppDescriptorAbort; } hr = StringCchCopy( &wszScratch[6], dwMaxStrLen-6, wszGuid ); if (FAILED(hr)) { Status = HRESULT_CODE(hr); goto InstallAppDescriptorAbort; } if ( pAppType->uType.COMClass.ClsCtx & CLSCTX_INPROC_SERVER ) { hr = StringCchCopy( &wszScratch[6+GUIDSTRLEN], dwMaxStrLen-(6+GUIDSTRLEN),L"\\InprocServer32" );
if (FAILED(hr)) { Status = HRESULT_CODE(hr); goto InstallAppDescriptorAbort; }
Status = RegOpenKeyEx( hkClasses, wszScratch, 0, KEY_ALL_ACCESS, &hkScratch );
Size = sizeof(wszDarwinId);
if ( ERROR_SUCCESS == Status ) { Status = RegQueryValueEx( hkScratch, L"InprocServer32", NULL, NULL, (PBYTE) wszDarwinId, &Size );
if ( ERROR_SUCCESS == Status ) DebugMsg((DM_VERBOSE, IDS_CLSID_INPROC_FOUND));
RegCloseKey( hkScratch ); } }
if ( (0 == wszDarwinId[0]) && (pAppType->uType.COMClass.ClsCtx & CLSCTX_LOCAL_SERVER) ) { hr = StringCchCopy( &wszScratch[6+GUIDSTRLEN], dwMaxStrLen-(6+GUIDSTRLEN),L"\\LocalServer32" ); if (FAILED(hr)) { Status = HRESULT_CODE(hr); goto InstallAppDescriptorAbort; } Status = RegOpenKeyEx( hkClasses, wszScratch, 0, KEY_ALL_ACCESS, &hkScratch );
Size = sizeof(wszDarwinId);
if ( ERROR_SUCCESS == Status ) { Status = RegQueryValueEx( hkScratch, L"LocalServer32", NULL, NULL, (PBYTE) wszDarwinId, &Size );
if ( ERROR_SUCCESS == Status ) DebugMsg((DM_VERBOSE, IDS_CLSID_LOCAL_FOUND));
RegCloseKey( hkScratch ); } } }
//
// We're done with the temp reg data, so blow it away now.
//
// Must include the MACHINEASSIGN flag since we are not impersonating.
//
(void) (*gpfnMsiAdvertiseScript)( pAppInfo->LocalScriptPath(), ScriptFlags, &hkClasses, TRUE );
InstallAppDescriptorAbort:
if ( hkClasses ) { RegCloseKey( hkClasses ); RegDeleteKey( hkPolicy, L"TempClasses" ); }
if ( hkPolicy ) RegCloseKey( hkPolicy );
if ( ERROR_SUCCESS == Status ) { pInstallInfo->pwszDescriptor = (PWCHAR) LocalAlloc( 0, (lstrlen(wszDarwinId) + 1) * sizeof(WCHAR) ); if ( pInstallInfo->pwszDescriptor ) { hr = StringCchCopy( pInstallInfo->pwszDescriptor,lstrlen(wszDarwinId) + 1, wszDarwinId );
if (FAILED(hr)) { Status = HRESULT_CODE(hr); } } else Status = ERROR_OUTOFMEMORY; }
//
// If we fail to find a darwin id under the specific class data that
// was requested, then we fall back to doing a full product based
// install. Since the DS query succeeded, we have a valid app, but
// there just isn't any darwin id registered for the specific class
// data in the advertisement data.
//
// This could be a packaging problem, limitation, or design.
//
} // if ( pAppType->Type != APPNAME )
if ( (ERROR_SUCCESS == Status) && (pAppInfo->_State & APPSTATE_SCRIPT_NOT_EXISTED) ) { SetSystemRestorePoint( pAppInfo->_pwszDeploymentName, pAppContext ); }
InstallAppExit:
if ( bEnterCritSec ) RtlLeaveCriticalSection( &gAppCS );
if ( Status != ERROR_SUCCESS ) { for ( ; pUninstallApps->Products; ) FreeApplicationInfo( &pUninstallApps->ApplicationInfo[--pUninstallApps->Products] ); LocalFree( pUninstallApps->ApplicationInfo ); pUninstallApps->Products = 0; pUninstallApps->ApplicationInfo = 0;
FreeApplicationInfo( pInstallInfo ); memset( pInstallInfo, 0, sizeof(APPLICATION_INFO) );
if ( pManApp ) { if ( pAppInfo ) { //
// Since this call has failed, the client will not call
// the InstallEnd method to log the failure, so we must
// log the failure in this call
//
(void) LogRsopInstallData( pManApp, pAppInfo ); } delete pManApp; }
if ( pAppInfo ) delete pAppInfo;
if ( pAppContext ) { delete pAppContext->pLoadMsi; delete pAppContext; } } else { *ppInstallContext = pAppContext; }
if ( ((long)Status) > 0 ) DebugMsg((DM_VERBOSE, IDS_INSTALL_STATUS1, Status)); else DebugMsg((DM_VERBOSE, IDS_INSTALL_STATUS2, Status));
gpEvents->ClearToken();
if ( hUserToken ) CloseHandle( hUserToken );
if ( hkRoot ) RegCloseKey( hkRoot );
if ( pGPOList ) FreeGPOList( pGPOList );
ReleasePackageInfo( &PackageInfo );
return Status; }
error_status_t InstallManageApp( IN PINSTALLCONTEXT pInstallContext, IN PWSTR pwszDeploymentId, IN DWORD RollbackStatus, OUT boolean * pbInstall ) { PAPPCONTEXT pAppContext; CAppInfo * pAppInfo; GUID DeploymentId; DWORD Status;
*pbInstall = FALSE;
pAppContext = (PAPPCONTEXT) pInstallContext; StringToGuid( pwszDeploymentId, &DeploymentId );
Status = pAppContext->pManApp->Impersonate(); if ( Status != ERROR_SUCCESS ) return Status;
gpEvents->SetToken( pAppContext->pManApp->UserToken() );
if ( memcmp( &DeploymentId, &pAppContext->pAppInfo->_DeploymentId, sizeof(GUID) ) == 0 ) { pAppContext->bUninstallsCompleted = TRUE; Status = pAppContext->pAppInfo->ProcessApplyActions();
if ( ERROR_SUCCESS == Status ) { if ( pAppContext->pManApp->GetRsopContext()->IsRsopEnabled() && pAppContext->pManApp->GetRsopContext()->IsDiagnosticModeEnabled() ) Status = pAppContext->pAppInfo->ProcessTransformConflicts(); }
goto InstallManageAppEnd; }
for ( pAppContext->pManApp->AppList().Reset(); pAppInfo = (CAppInfo *) pAppContext->pManApp->AppList().GetCurrentItem(); pAppContext->pManApp->AppList().MoveNext() ) { if ( memcmp( &DeploymentId, &pAppInfo->_DeploymentId, sizeof(GUID) ) == 0 ) break; }
if ( ! pAppInfo ) { Status = ERROR_NOT_FOUND; goto InstallManageAppEnd; }
//
// Re-assigning one of the upgraded apps because of a failed upgrade. Not needed for
// apps orphaned during the upgrade.
//
if ( ACTION_UNINSTALL == pAppInfo->_Action ) { DWORD ScriptFlags = SCRIPTFLAGS_REGDATA_CNFGINFO | SCRIPTFLAGS_CACHEINFO | SCRIPTFLAGS_SHORTCUTS;
*pbInstall = (pAppInfo->_State & APPSTATE_INSTALL) ? 1 : 0;
if ( pAppInfo->_State & APPSTATE_ASSIGNED ) ScriptFlags |= SCRIPTFLAGS_REGDATA_EXTENSIONINFO; Status = pAppInfo->Assign( ScriptFlags, TRUE, FALSE );
//
// Record an event so that we can track this as an RSoP failed setting if
// necessary
//
if ( ERROR_SUCCESS != Status ) { gpEvents->Assign( Status, pAppInfo ); } }
//
// Remember that this application was rolled back
//
pAppInfo->_bRollback = TRUE;
gpEvents->UpgradeAbort( RollbackStatus, pAppContext->pAppInfo, pAppInfo, ! pAppContext->bUninstallsCompleted );
InstallManageAppEnd:
gpEvents->ClearToken(); pAppContext->pManApp->Revert(); return Status; }
error_status_t InstallUnmanageApp( IN PINSTALLCONTEXT pInstallContext, IN PWSTR pwszDeploymentId, IN boolean bUnadvertiseOnly ) { PAPPCONTEXT pAppContext; CAppInfo * pAppInfo; GUID DeploymentId; DWORD Status;
pAppContext = (PAPPCONTEXT) pInstallContext; StringToGuid( pwszDeploymentId, &DeploymentId );
Status = pAppContext->pManApp->Impersonate(); if ( Status != ERROR_SUCCESS ) goto InstallUnmanageAppRemoveScript;
gpEvents->SetToken( pAppContext->pManApp->UserToken() );
if ( memcmp( &DeploymentId, &pAppContext->pAppInfo->_DeploymentId, sizeof(GUID) ) == 0 ) { Status = pAppContext->pAppInfo->Unassign( SCRIPTFLAGS_REGDATA_CNFGINFO | SCRIPTFLAGS_CACHEINFO, TRUE );
//
// Record an event so that we can track this as an RSoP failed setting if
// necessary
//
if ( ERROR_SUCCESS != Status ) { gpEvents->Unassign( Status, pAppContext->pAppInfo ); }
goto InstallUnmanageAppEnd; }
for ( pAppContext->pManApp->AppList().Reset(); pAppInfo = (CAppInfo *) pAppContext->pManApp->AppList().GetCurrentItem(); pAppContext->pManApp->AppList().MoveNext() ) { if ( memcmp( &DeploymentId, &pAppInfo->_DeploymentId, sizeof(GUID) ) == 0 ) break; }
if ( ! pAppInfo ) { Status = ERROR_NOT_FOUND; goto InstallUnmanageAppEnd; }
//
// Unassigning one of the upgraded apps.
//
if ( bUnadvertiseOnly ) { Status = pAppInfo->Unassign( SCRIPTFLAGS_REGDATA_CNFGINFO | SCRIPTFLAGS_CACHEINFO | SCRIPTFLAGS_SHORTCUTS | SCRIPTFLAGS_REGDATA_EXTENSIONINFO, FALSE ); } else { Status = pAppInfo->Unassign( 0, TRUE );
//
// Record an event so that we can track this as an RSoP failed setting if
// necessary
//
if ( ERROR_SUCCESS != Status ) { gpEvents->Unassign( Status, pAppInfo ); } gpEvents->UpgradeComplete( pAppContext->pAppInfo, pAppInfo ); }
InstallUnmanageAppEnd:
gpEvents->ClearToken(); pAppContext->pManApp->Revert();
InstallUnmanageAppRemoveScript:
//
// Be sure to remove the script for a failed upgrade app
//
if ( ( ERROR_SUCCESS != Status ) && ! bUnadvertiseOnly ) { DeleteFile( pAppContext->pAppInfo->_pwszLocalScriptPath ); }
return Status; }
error_status_t InstallEnd( IN boolean bStatus, IN OUT PINSTALLCONTEXT * ppInstallContext ) { //
// We are done installing -- now log the results
//
if ( ppInstallContext && *ppInstallContext ) { PAPPCONTEXT pAppContext; CManagedAppProcessor* pManApp; pAppContext = (PAPPCONTEXT) *ppInstallContext; if ( pAppContext ) pAppContext->bStatus = (boolean) bStatus;
pManApp = pAppContext->pManApp;
if ( pManApp && pAppContext ) { (void) LogRsopInstallData( pManApp, pAppContext->pAppInfo ); } }
if ( ppInstallContext ) { PINSTALLCONTEXT_rundown( *ppInstallContext ); *ppInstallContext = 0; }
return ERROR_SUCCESS; }
void PINSTALLCONTEXT_rundown( IN PINSTALLCONTEXT pInstallContext ) { PAPPCONTEXT pAppContext;
pAppContext = (PAPPCONTEXT) pInstallContext;
if ( pAppContext && (pAppContext->SRSequence != 0) ) { RESTOREPOINTINFO RestoreInfo; STATEMGRSTATUS SRStatus;
RestoreInfo.dwEventType = END_NESTED_SYSTEM_CHANGE; RestoreInfo.dwRestorePtType = pAppContext->bStatus ? 0 : CANCELLED_OPERATION; RestoreInfo.llSequenceNumber = pAppContext->SRSequence; RestoreInfo.szDescription[0] = 0;
(void) (*gpfnSRSetRetorePointW)( &RestoreInfo, &SRStatus ); }
//
// If this app failed to be installed, ensure that the status is
// set properly (in upgrade cases, the status for the application may
// not be set. If this status is not set as a failure, the
// application's state (such as the script) may not be set
//
if ( pAppContext && pAppContext->pAppInfo && ! pAppContext->bStatus ) { pAppContext->pAppInfo->ForceFailureStatus(); }
if (pAppContext) { delete pAppContext->pManApp; delete pAppContext->pAppInfo; delete pAppContext->pLoadMsi; if ( pAppContext->pLoadSfc ) delete pAppContext->pLoadSfc; delete pAppContext; } }
DWORD RemoveAppHelper( IN WCHAR * ProductCode, IN HANDLE hUserToken, IN HKEY hKeyRoot, IN DWORD ARPStatus, OUT BOOL * pbProductFound ) { CAppInfo * pAppInfo; CAppInfo * pHighestAssignedApp; CAppInfo * pRemovedApp; DWORD Status;
*pbProductFound = FALSE;
CRsopAppContext RsopContext( CRsopAppContext::REMOVAL );
CManagedAppProcessor ManApps( hUserToken ? 0 : GPO_INFO_FLAG_MACHINE, hUserToken, hKeyRoot, NULL, FALSE, FALSE, &RsopContext, Status );
if ( ERROR_SUCCESS != Status ) return Status;
CAppList LocalApps( NULL, ManApps.GetRsopContext() );
Status = ManApps.LoadPolicyList();
if ( ERROR_SUCCESS != Status ) return Status;
Status = ManApps.GetOrderedLocalAppList( LocalApps );
if ( ERROR_SUCCESS == Status ) Status = ManApps.Impersonate();
if ( Status != ERROR_SUCCESS ) return Status;
pHighestAssignedApp = 0; pRemovedApp = 0;
LocalApps.Reset();
for ( pAppInfo = (CAppInfo *) LocalApps.GetCurrentItem(); pAppInfo; LocalApps.MoveNext(), pAppInfo = (CAppInfo *) LocalApps.GetCurrentItem() ) { if ( (lstrcmpi( pAppInfo->_pwszProductId, ProductCode ) != 0) || ! (pAppInfo->_State & (APPSTATE_ASSIGNED | APPSTATE_PUBLISHED)) ) { continue; }
pRemovedApp = pAppInfo;
*pbProductFound = TRUE;
if ( pAppInfo->_State & APPSTATE_PUBLISHED ) { //
// We perform no actual unassignments unless ARP actually uninstalled the app
//
//
// We unassign using the same scriptflags we do during assignment
// to handle cases where the initial install action fails and
// we are called to undo the original assigment. In normal success
// cases this is redundant.
//
if ( ERROR_SUCCESS == ARPStatus ) { DebugMsg((DM_VERBOSE, IDS_REMOVEAPP_MATCH1, pAppInfo->_pwszDeploymentName, ProductCode)); pAppInfo->Unassign( SCRIPTFLAGS_REGDATA_CNFGINFO | SCRIPTFLAGS_CACHEINFO | SCRIPTFLAGS_SHORTCUTS | SCRIPTFLAGS_REGDATA_EXTENSIONINFO, TRUE ); }
//
// Set this action for RSOP as a way to remember to log a removal entry for this app
//
pAppInfo->SetAction( ACTION_UNINSTALL, APP_ATTRIBUTE_REMOVALCAUSE_USER, NULL); } else { //
// We only reassign if ARP was able to uninstall the app
//
if ( ERROR_SUCCESS == ARPStatus ) { DebugMsg((DM_VERBOSE, IDS_REMOVEAPP_MATCH2, pAppInfo->_pwszDeploymentName, ProductCode)); }
pHighestAssignedApp = pAppInfo; } } if ( ( ERROR_SUCCESS != ARPStatus ) && pRemovedApp ) { //
// If ARP failed to uninstall the highest app, log a failure status
//
gpEvents->Uninstall( ARPStatus, pRemovedApp); }
//
// Reassign the highest priority assigned app with this product id if
// one exists.
//
BOOL bRsopLogReassign;
bRsopLogReassign = FALSE;
if ( pHighestAssignedApp ) { //
// We only reassign the app if it was successfully uninstalled
//
if ( ERROR_SUCCESS == ARPStatus ) { Status = pHighestAssignedApp->Assign( SCRIPTFLAGS_REGDATA_CNFGINFO | SCRIPTFLAGS_CACHEINFO | SCRIPTFLAGS_SHORTCUTS | SCRIPTFLAGS_REGDATA_EXTENSIONINFO, TRUE, FALSE ); if ( Status != ERROR_SUCCESS ) gpEvents->Assign( Status, pHighestAssignedApp ); }
if ( ManApps.GetRsopContext()->IsRsopEnabled() ) { //
// Remember to write a removal entry for this reassigned app if it
// was the app that was removed
//
bRsopLogReassign = ( pHighestAssignedApp == pRemovedApp ); } }
ManApps.Revert();
//
// We must log rsop data after we revert because the user may not have
// access to her own rsop namespace
//
//
// Obtain exclusive access to log data -- this will disable rsop
// if implicit access cannot be obtained
//
(void) ManApps.GetRsopContext()->GetExclusiveLoggingAccess( NULL == hUserToken );
if ( ManApps.GetRsopContext()->IsRsopEnabled() ) { //
// Now log all the uninstalled published apps which would have been marked above
// as having the action to uninstall
//
(void) LocalApps.WriteLog( CAppList::RSOP_FILTER_REMOVALSONLY ); //
// Now log the highest reassigned app
//
if ( bRsopLogReassign ) { //
// Log the actual uninstall entry
//
(void) LocalApps.MarkRSOPEntryAsRemoved( pHighestAssignedApp, FALSE ); } else if ( pHighestAssignedApp ) { //
// We need to write a new entry for the assigned app that was not previously
// applied but is now due to the fact that the higher precedence application
// was removed
//
(void) LocalApps.WriteAppToRsopLog( pHighestAssignedApp ); } }
(void) ManApps.GetRsopContext()->ReleaseExclusiveLoggingAccess(); //
// Whenever the user does an app uninstall, we force a full run of policy
// during the next logon to pick up any app that should now apply. Note that
// later we use a gp engine api to do this due to the NT 5.1 foreground async
// gp refresh feature, but for compatibility with NT 5.0 (roaming), we must
// continue to set our own registry value
//
if ( *pbProductFound && hUserToken ) { Status = RegSetValueEx( ManApps.AppmgmtKey(), FULLPOLICY, 0, REG_DWORD, (LPBYTE) pbProductFound, sizeof(*pbProductFound) );
//
// Ensure that if async policy is enabled, we get a synchronous refresh at
// the next logon
//
if ( ERROR_SUCCESS == Status ) { Status = ForceSynchronousRefresh( ManApps.UserToken() ); } }
return Status; }
error_status_t ARPRemoveApp( IN handle_t hRpc, IN WCHAR * pwszProductCode, IN DWORD ARPStatus ) { HANDLE hUserToken; HKEY hKeyRoot; DWORD Status; BOOL bStatus; BOOL bProductFound;
CheckLocalCall( hRpc );
hUserToken = NULL; hKeyRoot = NULL;
bProductFound = FALSE;
CLoadMsi LoadMsi( Status );
if ( ERROR_SUCCESS == Status ) Status = RpcImpersonateClient( NULL );
if ( ERROR_SUCCESS == Status ) { Status = RegOpenCurrentUser( GENERIC_ALL, &hKeyRoot );
if ( ERROR_SUCCESS == Status ) { bStatus = OpenThreadToken( GetCurrentThread(), TOKEN_READ | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, TRUE, &hUserToken );
if ( ! bStatus ) { Status = GetLastError(); RegCloseKey( hKeyRoot ); } }
RevertToSelf(); }
if ( Status != ERROR_SUCCESS ) return Status;
gpEvents->SetToken( hUserToken );
LogTime();
DebugMsg((DM_VERBOSE, IDS_REMOVEAPP, pwszProductCode));
Status = RemoveAppHelper( pwszProductCode, hUserToken, hKeyRoot, ARPStatus, &bProductFound );
if ( ! bProductFound ) { if ( IsMemberOfAdminGroup( hUserToken ) ) Status = RemoveAppHelper( pwszProductCode, NULL, HKEY_LOCAL_MACHINE, ARPStatus, &bProductFound ); }
DebugMsg((DM_VERBOSE, IDS_REMOVEAPP_STATUS, Status)); gpEvents->ClearToken();
if ( hUserToken ) CloseHandle( hUserToken );
if ( hKeyRoot ) RegCloseKey( hKeyRoot );
return Status; }
error_status_t GetManagedApps( IN handle_t hRpc, IN GUID * pCategory, IN DWORD dwQueryFlags, IN DWORD dwInfoLevel, OUT MANAGED_APPLIST * pAppList ) { HANDLE hUserToken; HANDLE hEventAppsEnumerated; error_status_t Status; BOOL bStatus;
CheckLocalCall( hRpc );
hUserToken = NULL; hEventAppsEnumerated = NULL;
if ( ! pAppList ) return ERROR_INVALID_PARAMETER;
//
// Clear this structure so that random
// garbage doesn't get marshalled back.
//
memset(pAppList, 0, sizeof(*pAppList));
//
// Validate the parameters passed in by the client.
//
if ( dwInfoLevel != MANAGED_APPS_INFOLEVEL_DEFAULT ) return ERROR_INVALID_PARAMETER;
switch (dwQueryFlags) {
case MANAGED_APPS_USERAPPLICATIONS: if (pCategory) return ERROR_INVALID_PARAMETER; break;
case MANAGED_APPS_FROMCATEGORY: if (!pCategory) return ERROR_INVALID_PARAMETER; break;
default: return ERROR_INVALID_PARAMETER; }
//
// Now prepare to initiate the query -- first
// we need to get some user specific information
// to build the object which performs the query,
// so we impersonate.
//
Status = RpcImpersonateClient( NULL ); if ( Status != ERROR_SUCCESS ) return Status;
bStatus = OpenThreadToken( GetCurrentThread(), TOKEN_READ | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, TRUE, &hUserToken );
if ( ! bStatus ) Status = GetLastError();
RevertToSelf();
if ( Status != ERROR_SUCCESS ) goto GetManagedAppsExit;
//
// We will create a separate thread to retrieve the ARP apps -- this allows
// this thread to wait for a signal from the ARP thread that app enumeration is done,
// and we can return the list at that point. The second thread will continue to
// execute since it needs to log rsop data -- this approach frees us from having to
// wait for rsop logging, which can take 10 times longer than it took us to retrieve
// the apps from the ds
//
//
// Below we create the event that the enumeration thread will use to signal this
// thread that enumeration is finished.
//
hEventAppsEnumerated = CreateEvent( NULL, TRUE, // manual reset
FALSE, // initially nonsignaled
NULL);
if ( ! hEventAppsEnumerated ) { Status = GetLastError(); goto GetManagedAppsExit; }
//
// We allocate a structure to pass to the enumeration thread containing all the
// context it needs to enumerate apps. Note that this structure is stack allocated,
// so the enumeration thread may only access it as long as this thread lives -- once
// it signals us that enumeration is complete, it may no longer access this structure
//
ARPCONTEXT ArpContext;
ArpContext.pCategory = pCategory; ArpContext.pAppList = pAppList; ArpContext.hUserToken = hUserToken; ArpContext.hEventAppsEnumerated = hEventAppsEnumerated; ArpContext.Status = ERROR_SUCCESS; // out parameter for the second thread to indicate status
HANDLE hThread;
hThread = CreateThread( NULL, 0, GetManagedAppsProc, &ArpContext, 0, NULL);
if ( ! hThread ) Status = GetLastError();
if ( ERROR_SUCCESS != Status ) goto GetManagedAppsExit;
//
// Wait for enumeration in the second thread to complete, or
// for the second thread itself to complete
//
HANDLE rgTasks[] = { hEventAppsEnumerated, hThread };
(void) WaitForMultipleObjects( sizeof(rgTasks) / sizeof(*rgTasks), rgTasks, FALSE, INFINITE);
//
// Retrieve the enumeration thread's status
//
Status = ArpContext.Status;
//
// Because tests assume they can check RSoP data as soon as
// the api has completed, if the tests are waiting for policy
// events to be signaled already, we'll also wait for rsop to finish
//
if ( gDebugLevel & DL_EVENT ) { (void) WaitForSingleObject( hThread, INFINITE ); }
CloseHandle( hThread );
GetManagedAppsExit:
if ( hUserToken ) CloseHandle( hUserToken );
if ( hEventAppsEnumerated ) CloseHandle( hEventAppsEnumerated );
return Status; }
error_status_t RsopReportInstallFailure( IN PINSTALLCONTEXT pInstallContext, IN PWSTR pwszDeploymentId, IN DWORD dwEventId ) { GUID DeploymentId; PAPPCONTEXT pAppContext; CManagedAppProcessor* pManApp; CAppInfo* pAppInfo;
pAppContext = (PAPPCONTEXT) pInstallContext;
pManApp = pAppContext->pManApp;
if ( ! pManApp || ! pManApp->GetRsopContext()->IsDiagnosticModeEnabled() ) { return ERROR_SUCCESS; }
//
// Assume that the failure happened in the app that
// we're trying to install
//
pAppInfo = pAppContext->pAppInfo;
if ( ! pAppInfo ) { return ERROR_SUCCESS; }
StringToGuid( pwszDeploymentId, &DeploymentId );
//
// Check to see if the failure was in the app that we're
// trying to install
//
if ( ! IsEqualGUID( pAppInfo->DeploymentId(), DeploymentId ) ) { //
// If not, see if the requested app is one of the apps
// that was uninstalled before trying to apply the
// target app, or was reinstalled as part of a rollback
// from failure
//
pAppInfo = pManApp->AppList().Find( DeploymentId );
if ( pAppInfo ) { //
// The failure happened during an uninstall for
// a rip and replace upgrade, so we need to
// log a failure for the upgrade as well
//
pAppContext->pAppInfo->SetRsopFailureStatus( ERROR_GEN_FAILURE, dwEventId); } } //
// If we found the app requested by the caller, log a failure
// status for it -- the error we pass to the method is only
// used as a check against ERROR_SUCCESS, so we do not
// need to pass the actual error that occurred
//
if ( pAppInfo ) { pAppInfo->SetRsopFailureStatus( ERROR_GEN_FAILURE, dwEventId); }
return ERROR_SUCCESS; }
error_status_t GetManagedAppCategories( IN handle_t hRpc, IN OUT APPCATEGORYLIST* pCategoryList ) { DWORD Status; HRESULT hr; APPCATEGORYINFOLIST AppCategories; HANDLE hUserToken; HKEY hkRoot; CheckLocalCall( hRpc );
hr = S_OK;
hUserToken = NULL;
hkRoot = NULL;
memset( pCategoryList, 0, sizeof( *pCategoryList ) ); memset( &AppCategories, 0, sizeof( AppCategories ) );
//
// Now prepare to initiate the query -- first
// we need to get some user specific information
// to build the object which performs the query,
// so we impersonate.
//
Status = RpcImpersonateClient( NULL ); if ( ERROR_SUCCESS != Status ) return Status;
BOOL bStatus;
bStatus = OpenThreadToken( GetCurrentThread(), TOKEN_READ | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, TRUE, &hUserToken );
if ( ! bStatus ) Status = GetLastError();
if ( ERROR_SUCCESS == Status ) Status = RegOpenCurrentUser( GENERIC_ALL, &hkRoot );
if ( ERROR_SUCCESS == Status ) hr = CsGetAppCategories( &AppCategories );
RevertToSelf();
if ( ( ERROR_SUCCESS != Status ) || FAILED( hr ) ) goto GetManagedAppCategoriesExit;
gpEvents->SetToken( hUserToken );
//
// The rpc interface is such that our out parameter is just
// one allocation -- references within each array element are allocated
// within the block, so we must first calculate how big the block is
//
if ( SUCCEEDED( hr ) ) { DWORD cbSize; DWORD iCat;
cbSize = sizeof( APPCATEGORY ) * AppCategories.cCategory;
for (iCat = 0; iCat < AppCategories.cCategory; iCat++) { cbSize += ( lstrlen( AppCategories.pCategoryInfo[iCat].pszDescription ) + 1 ) * sizeof( WCHAR ); }
pCategoryList->pCategoryInfo = (APPCATEGORY*) midl_user_allocate( cbSize );
if ( ! pCategoryList->pCategoryInfo ) { hr = E_OUTOFMEMORY; } }
//
// Now that we have sufficient memory, we can copy the data
//
if ( SUCCEEDED( hr ) ) { WCHAR* wszDescriptions; DWORD iCat;
wszDescriptions = (WCHAR*) &( pCategoryList->pCategoryInfo[ AppCategories.cCategory ] );
pCategoryList->cCategory = AppCategories.cCategory;
for (iCat = 0; iCat < AppCategories.cCategory; iCat++) { pCategoryList->pCategoryInfo[ iCat ].Locale = AppCategories.pCategoryInfo[iCat].Locale; pCategoryList->pCategoryInfo[ iCat ].AppCategoryId = AppCategories.pCategoryInfo[iCat].AppCategoryId; pCategoryList->pCategoryInfo[ iCat ].pszDescription = wszDescriptions;
hr = StringCchCopy( wszDescriptions, lstrlen(AppCategories.pCategoryInfo[iCat].pszDescription)+1, AppCategories.pCategoryInfo[iCat].pszDescription ); if (FAILED(hr)) { break; } wszDescriptions += lstrlen( wszDescriptions ) + 1; } }
//
// If we have successfully generated results to return to the caller, log
// those results
//
if ( SUCCEEDED( hr ) ) { HRESULT hrLog; DWORD StatusLog;
CRsopAppContext RsopContext( CRsopAppContext::ARPLIST );
CManagedAppProcessor AppProcessor( 0, hUserToken, hkRoot, NULL, TRUE, FALSE, &RsopContext, StatusLog );
if ( ERROR_SUCCESS == StatusLog ) { CCategoryInfoLog CategoryLog( AppProcessor.GetRsopContext(), &AppCategories );
Status = AppProcessor.GetRsopContext()->GetExclusiveLoggingAccess( NULL == hUserToken );
if ( ERROR_SUCCESS == Status ) { hrLog = CategoryLog.WriteLog(); }
AppProcessor.GetRsopContext()->ReleaseExclusiveLoggingAccess(); } else { hrLog = HRESULT_FROM_WIN32( StatusLog ); }
if ( FAILED(hrLog) ) { RsopContext.DisableRsop( hrLog ); } }
Status = GetWin32ErrFromHResult( hr );
//
// Free the internal version of the category list
//
ReleaseAppCategoryInfoList( &AppCategories );
GetManagedAppCategoriesExit:
if ( hUserToken ) { CloseHandle( hUserToken ); }
if ( hkRoot ) { RegCloseKey( hkRoot ); }
return Status; }
DWORD WINAPI GetManagedAppsProc( LPVOID pvArpContext ) { ARPCONTEXT* pArpContext;
pArpContext = (ARPCONTEXT*) pvArpContext;
HANDLE hUserToken; error_status_t Status; BOOL bStatus; HKEY hkRoot;
hUserToken = NULL; hkRoot = NULL;
Status = ERROR_SUCCESS;
bStatus = DuplicateTokenEx( pArpContext->hUserToken, TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_IMPERSONATE, NULL, SecurityImpersonation, TokenImpersonation, &hUserToken);
if ( ! bStatus ) Status = GetLastError();
if ( bStatus ) { bStatus = ImpersonateLoggedOnUser( hUserToken ); if ( ! bStatus ) Status = GetLastError(); }
if ( ERROR_SUCCESS == Status ) Status = RegOpenCurrentUser( GENERIC_ALL, &hkRoot );
RevertToSelf();
if ( Status != ERROR_SUCCESS ) { pArpContext->Status = Status;
goto GetManagedAppsProcExit; }
gpEvents->SetToken( hUserToken );
LogTime();
//
// Now that we have a valid GPOInfo object, we can construct
// an app processor object to do the query
//
{ CRsopAppContext RsopContext( CRsopAppContext::ARPLIST, pArpContext->hEventAppsEnumerated );
CManagedAppProcessor AppProcessor( 0, hUserToken, hkRoot, NULL, TRUE, FALSE, &RsopContext, Status );
if ( ERROR_SUCCESS == Status ) { Status = AppProcessor.GetManagedApplications( pArpContext->pCategory, pArpContext ); } }
GetManagedAppsProcExit:
gpEvents->ClearToken();
if ( hkRoot ) RegCloseKey( hkRoot );
if ( hUserToken ) CloseHandle( hUserToken );
return 0; }
BOOL SetSystemRestorePoint( IN WCHAR * pwszApplicationName, IN OUT PAPPCONTEXT pAppContext ) { RESTOREPOINTINFO RestoreInfo; STATEMGRSTATUS SRStatus; HKEY hkInstallerPolicy; DWORD CheckpointPolicy; DWORD CheckpointPolicySize; DWORD InstallLen, NameLen; DWORD Status; BOOL bStatus;
Status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, L"Software\\Policies\\Microsoft\\Windows\\Installer", 0, KEY_READ, &hkInstallerPolicy );
if ( Status != ERROR_SUCCESS ) return FALSE;
CheckpointPolicy = 0; CheckpointPolicySize = sizeof(CheckpointPolicy);
(void) RegQueryValueEx( hkInstallerPolicy, L"LimitSystemRestoreCheckpointing", NULL, NULL, (LPBYTE) &CheckpointPolicy, &CheckpointPolicySize );
RegCloseKey( hkInstallerPolicy );
if ( CheckpointPolicy != 0 ) return FALSE;
if ( ! LoadLoadString() ) return FALSE;
Status = (*pfnLoadStringW)( ghDllInstance, IDS_INSTALLED, RestoreInfo.szDescription, sizeof(RestoreInfo.szDescription) / sizeof(WCHAR) ); if ( 0 == Status ) return FALSE;
pAppContext->pLoadSfc = new CLoadSfc( Status );
if ( Status != ERROR_SUCCESS ) { delete pAppContext->pLoadSfc; pAppContext->pLoadSfc = 0; }
if ( ! pAppContext->pLoadSfc ) return FALSE;
RestoreInfo.dwEventType = BEGIN_NESTED_SYSTEM_CHANGE; RestoreInfo.dwRestorePtType = APPLICATION_INSTALL; RestoreInfo.llSequenceNumber = 0;
InstallLen = lstrlen(RestoreInfo.szDescription); NameLen = lstrlen(pwszApplicationName);
if ( InstallLen + NameLen >= MAX_DESC_W ) { lstrcpyn( &RestoreInfo.szDescription[InstallLen], pwszApplicationName, MAX_DESC_W - InstallLen - 1 ); RestoreInfo.szDescription[MAX_DESC_W - 1] = 0; } else { HRESULT hr; hr = StringCchCopy( &RestoreInfo.szDescription[InstallLen], MAX_DESC_W,pwszApplicationName ); if (FAILED(hr)) { return FALSE; } }
bStatus = (*gpfnSRSetRetorePointW)( &RestoreInfo, &SRStatus );
if ( bStatus ) pAppContext->SRSequence = SRStatus.llSequenceNumber;
return bStatus; }
void CheckLocalCall( IN handle_t hRpc ) { UINT Type; DWORD Status;
Status = I_RpcBindingInqTransportType( hRpc, &Type);
if ( (Status != RPC_S_OK) || (Type != TRANSPORT_TYPE_LPC) ) RpcRaiseException( ERROR_ACCESS_DENIED ); }
WCHAR* GetGpoNameFromGuid( IN PGROUP_POLICY_OBJECT pGpoList, IN GUID* pGpoGuid ) { PGROUP_POLICY_OBJECT pNextGpo; WCHAR wszTargetGuid[MAX_SZGUID_LEN]; WCHAR* pszPolicyName; pszPolicyName = NULL;
(void) GuidToString( *pGpoGuid, wszTargetGuid);
while (pGpoList) { pNextGpo = pGpoList->pNext; if ( lstrcmpi( pGpoList->szGPOName, wszTargetGuid) == 0 ) { pszPolicyName = pGpoList->lpDisplayName; break; }
pGpoList = pNextGpo; }
return pszPolicyName; }
DWORD GetPlatformCompatibleCOMClsCtx( DWORD Architecture, DWORD dwClsCtx ) { if ( (PROCESSOR_ARCHITECTURE_AMD64 == Architecture) || (PROCESSOR_ARCHITECTURE_IA64 == Architecture) ) { //
// On 64-bit, if we have any inproc server contexts, we need to
// ensure that we specifically ask for 64-bit inproc servers
//
if ( dwClsCtx & CLSCTX_INPROC ) { DWORD dwInproc64;
dwInproc64 = 0; if ( dwClsCtx & CLSCTX_INPROC_SERVER ) { dwInproc64 |= CLSCTX64_INPROC_SERVER; }
if ( dwClsCtx & CLSCTX_INPROC_HANDLER ) { dwInproc64 |= CLSCTX64_INPROC_HANDLER; }
//
// Now remove the standard inproc bits, which are interpreted
// as 32-bit inproc
//
dwClsCtx &= ~CLSCTX_INPROC;
//
// Add in the 64-bit inproc bits that we support
//
dwClsCtx |= dwInproc64; } } return dwClsCtx; }
void LogRsopInstallData( CManagedAppProcessor* pManApp, CAppInfo* pAppInfo ) { HRESULT hr;
if ( ! pManApp->GetRsopContext()->IsRsopEnabled() ) { return; }
hr = pManApp->GetRsopContext()->GetExclusiveLoggingAccess( NULL == pManApp->UserToken() );
//
// If the call above failed, rsop will be disabled so we have nothing to do
//
if ( FAILED(hr) ) { return; }
//
// First log the installed application
//
pManApp->AppList().WriteAppToRsopLog( pAppInfo );
//
// Now write all the removal entries
//
pManApp->AppList().WriteLog( CAppList::RSOP_FILTER_REMOVALSONLY );
//
// Since we have installed an app, the resultant set has changed, so
// update the RSoP version to ensure that we detect the change if
// we roam to another machine
//
(void) pManApp->GetRsopContext()->WriteCurrentRsopVersion( pManApp->AppmgmtKey() );
(void) pManApp->GetRsopContext()->ReleaseExclusiveLoggingAccess(); }
|