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.
2242 lines
65 KiB
2242 lines
65 KiB
//*************************************************************
|
|
//
|
|
// 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();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|