Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1261 lines
29 KiB

//
// Copyright (c) 1999-2001 Microsoft Corporation, All Rights Reserved
//
#include <precomp.h>
#include "msimethod.h"
#include "methods.h"
#include "msimeth_i.c"
IMsiMethodStatusSink * CMethods::m_pStatusSink = NULL;
bool CMethods::m_bCSReady = false;
CRITICAL_SECTION CMethods::m_cs;
UINT CMethods::m_uiMaxIndex = 0;
UINT CMethods::m_cConnections = 0;
CONNECTDATA* CMethods::m_paConnections = NULL;
bool g_bMsiPresent = true;
bool g_bMsiLoaded = false;
LPFNMSISETINTERNALUI g_fpMsiSetInternalUI = NULL;
LPFNMSISETEXTERNALUIW g_fpMsiSetExternalUIW = NULL;
LPFNMSIENABLELOGW g_fpMsiEnableLogW = NULL;
LPFNMSIINSTALLPRODUCTW g_fpMsiInstallProductW = NULL;
LPFNMSICONFIGUREPRODUCTW g_fpMsiConfigureProductW = NULL;
LPFNMSIREINSTALLPRODUCTW g_fpMsiReinstallProductW = NULL;
LPFNMSIAPPLYPATCHW g_fpMsiApplyPatchW = NULL;
LPFNMSICONFIGUREFEATUREW g_fpMsiConfigureFeatureW = NULL;
LPFNMSIREINSTALLFEATUREW g_fpMsiReinstallFeatureW = NULL;
CMethods::CMethods()
{
m_cRef=0;
InterlockedIncrement(&g_cObj);
m_dwCheckKeyPresentStatus = ERROR_SUCCESS;
}
CMethods::~CMethods()
{
InterlockedDecrement(&g_cObj);
}
STDMETHODIMP CMethods::QueryInterface(REFIID riid, void** ppv)
{
*ppv = NULL;
// Since we have multiple inheritance, it is necessary to cast the return type
if(riid == IID_IMsiProductMethods)
*ppv = (IMsiProductMethods *)this;
else if(riid == IID_IMsiSoftwareFeatureMethods)
*ppv = (IMsiSoftwareFeatureMethods *)this;
/*
else if(riid == IID_IConnectionPointContainer)
*ppv = (IConnectionPointContainer *)this;
else if(riid == IID_IConnectionPoint)
*ppv = (IConnectionPoint *)this;
*/
else if(riid == IID_IUnknown)
*ppv = (IMsiProductMethods *)this;
if(*ppv){
AddRef();
return NOERROR;
}else return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) CMethods::AddRef(void)
{
SetEvent(g_hMethodAdd);
return InterlockedIncrement((long *)&m_cRef);
}
STDMETHODIMP_(ULONG) CMethods::Release(void)
{
SetEvent(g_hMethodRelease);
ULONG nNewCount = InterlockedDecrement((long *)&m_cRef);
if(0 == nNewCount) delete this;
return nNewCount;
}
/*
HRESULT STDMETHODCALLTYPE CMethods::EnumConnectionPoints(
IEnumConnectionPoints __RPC_FAR *__RPC_FAR *ppEnum)
{ return E_NOTIMPL; }
HRESULT STDMETHODCALLTYPE CMethods::FindConnectionPoint(
REFIID riid,
IConnectionPoint __RPC_FAR *__RPC_FAR *ppCP)
{
*ppCP = NULL;
if(riid == IID_IMsiMethodStatusSink)
*ppCP = (IConnectionPoint *)this;
if(NULL != *ppCP){
this->AddRef();
return NOERROR;
}else return E_NOINTERFACE;
}
HRESULT STDMETHODCALLTYPE CMethods::GetConnectionInterface(
IID __RPC_FAR *pIID)
{
*pIID = IID_IMsiMethodStatusSink;
return S_OK;
}
HRESULT STDMETHODCALLTYPE CMethods::GetConnectionPointContainer(
IConnectionPointContainer __RPC_FAR *__RPC_FAR *ppCPC)
{
*ppCPC = (IConnectionPointContainer *)this;
return this->AddRef();
}
HRESULT STDMETHODCALLTYPE CMethods::Advise(
IUnknown __RPC_FAR *pUnkSink,
DWORD __RPC_FAR *pdwCookie)
{
HRESULT hr = S_OK;
UINT uiFreeSlot = 0;
IMsiMethodStatusSink* pISink = NULL;
if(FAILED(hr = pUnkSink->QueryInterface(IID_IMsiMethodStatusSink, (void **)&pISink)))
return hr;
// Store the specific sink interface in this connection point's
// array of live connections. First find a free slot (expand the
// array if needed).
hr = GetSlot(&uiFreeSlot);
if (SUCCEEDED(hr))
{
// Assign the new slot with the connection entry.
m_paConnections[uiFreeSlot].pUnk = pISink;
m_paConnections[uiFreeSlot].dwCookie = m_dwNextCookie;
// Assign the output Cookie value.
*pdwCookie = m_dwNextCookie;
// Increment the Cookie counter.
m_dwNextCookie++;
// Increment the number of live connections.
m_cConnections++;
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE CMethods::Unadvise(
DWORD dwCookie)
{
HRESULT hr = NOERROR;
UINT uiSlot;
if(0 != dwCookie){
if(SUCCEEDED(hr = FindSlot(dwCookie, &uiSlot))){
// Release the sink interface.
m_paConnections[uiSlot].pUnk->Release();
// Mark the array entry as empty.
m_paConnections[uiSlot].dwCookie = 0;
// Decrement the number of live connections.
m_cConnections--;
}
}else hr = E_INVALIDARG;
return hr;
}
HRESULT STDMETHODCALLTYPE CMethods::EnumConnections(
IEnumConnections __RPC_FAR *__RPC_FAR *ppEnum)
{ return E_NOTIMPL; }
*/
///////////////////////
//Product Mehtods
HRESULT STDMETHODCALLTYPE CMethods::Admin(
/* [string][in] */ LPCWSTR wszPackageLocation,
/* [string][in] */ LPCWSTR wszOptions,
/* [out] */ UINT __RPC_FAR *puiResult,
/* [in] */ int iThreadID)
{
HRESULT hr = S_OK;
if(CheckForMsiDll()){
InitStatic(&iThreadID);
EnterCriticalSection(&m_cs);
if(SUCCEEDED(hr = PrepareEnvironment())){
try{
*puiResult = g_fpMsiInstallProductW(wszPackageLocation, wszOptions);
}catch(...){
hr = RPC_E_SERVERFAULT;
}
ReleaseEnvironment();
}
LeaveCriticalSection(&m_cs);
}
return hr;
}
HRESULT STDMETHODCALLTYPE CMethods::Advertise(
/* [string][in] */ LPCWSTR wszPackageLocation,
/* [string][in] */ LPCWSTR wszOptions,
/* [out] */ UINT __RPC_FAR *puiResult,
/* [in] */ int iThreadID)
{
HRESULT hr = S_OK;
if(CheckForMsiDll()){
InitStatic(&iThreadID);
EnterCriticalSection(&m_cs);
if(SUCCEEDED(hr = PrepareEnvironment())){
try{
*puiResult = g_fpMsiInstallProductW(wszPackageLocation, wszOptions);
}catch(...){
hr = RPC_E_SERVERFAULT;
}
ReleaseEnvironment();
}
LeaveCriticalSection(&m_cs);
}
return hr;
}
HRESULT STDMETHODCALLTYPE CMethods::Configure(
/* [string][in] */ LPCWSTR wszProductCode,
/* [in] */ int iInstallLevel,
/* [in] */ int isInstallState,
/* [out] */ UINT __RPC_FAR *puiResult,
/* [in] */ int iThreadID)
{
HRESULT hr = S_OK;
if(CheckForMsiDll()){
InitStatic(&iThreadID);
EnterCriticalSection(&m_cs);
if(SUCCEEDED(hr = PrepareEnvironment())){
try{
*puiResult = g_fpMsiConfigureProductW(wszProductCode, iInstallLevel,
(INSTALLSTATE)isInstallState);
}catch(...){
hr = RPC_E_SERVERFAULT;
}
ReleaseEnvironment();
}
LeaveCriticalSection(&m_cs);
}
return hr;
}
HRESULT STDMETHODCALLTYPE CMethods::Install(
/* [string][in] */ LPCWSTR wszPackageLocation,
/* [string][in] */ LPCWSTR wszOptions,
/* [out] */ UINT __RPC_FAR *puiResult,
/* [in] */ int iThreadID)
{
HRESULT hr = S_OK;
if(CheckForMsiDll()){
InitStatic(&iThreadID);
EnterCriticalSection(&m_cs);
if(SUCCEEDED(hr = PrepareEnvironment())){
try{
*puiResult = g_fpMsiInstallProductW(wszPackageLocation, wszOptions);
}catch(...){
hr = RPC_E_SERVERFAULT;
}
ReleaseEnvironment();
}
LeaveCriticalSection(&m_cs);
}
return hr;
}
HRESULT STDMETHODCALLTYPE CMethods::Reinstall(
/* [string][in] */ LPCWSTR wszProductCode,
/* [in] */ DWORD dwReinstallMode,
/* [out] */ UINT __RPC_FAR *puiResult,
/* [in] */ int iThreadID)
{
HRESULT hr = S_OK;
if(CheckForMsiDll()){
InitStatic(&iThreadID);
EnterCriticalSection(&m_cs);
if(SUCCEEDED(hr = PrepareEnvironment())){
try{
*puiResult = g_fpMsiReinstallProductW(wszProductCode, dwReinstallMode);
}catch(...){
hr = RPC_E_SERVERFAULT;
}
ReleaseEnvironment();
}
LeaveCriticalSection(&m_cs);
}
return hr;
}
HRESULT STDMETHODCALLTYPE CMethods::Uninstall(
/* [string][in] */ LPCWSTR wszProductCode,
/* [out] */ UINT __RPC_FAR *puiResult,
/* [in] */ int iThreadID)
{
HRESULT hr = S_OK;
if(CheckForMsiDll()){
InitStatic(&iThreadID);
EnterCriticalSection(&m_cs);
if(SUCCEEDED(hr = PrepareEnvironment())){
try{
*puiResult = g_fpMsiConfigureProductW(wszProductCode, INSTALLLEVEL_DEFAULT,
INSTALLSTATE_ABSENT);
}catch(...){
hr = RPC_E_SERVERFAULT;
}
ReleaseEnvironment();
}
LeaveCriticalSection(&m_cs);
}
return hr;
}
HRESULT STDMETHODCALLTYPE CMethods::Upgrade(
/* [string][in] */ LPCWSTR wszPackageLocation,
/* [string][in] */ LPCWSTR wszOptions,
/* [out] */ UINT __RPC_FAR *puiResult,
/* [in] */ int iThreadID)
{
HRESULT hr = S_OK;
if(CheckForMsiDll()){
InitStatic(&iThreadID);
EnterCriticalSection(&m_cs);
if(SUCCEEDED(hr = PrepareEnvironment())){
try{
*puiResult = g_fpMsiApplyPatchW(wszPackageLocation, NULL, INSTALLTYPE_DEFAULT, wszOptions);
}catch(...){
hr = RPC_E_SERVERFAULT;
}
ReleaseEnvironment();
}
LeaveCriticalSection(&m_cs);
}
return hr;
}
///////////////////////
//SoftwareFeature Mehtods
HRESULT STDMETHODCALLTYPE CMethods::ConfigureSF(
/* [string][in] */ LPCWSTR wszProductCode,
/* [string][in] */ LPCWSTR wszFeature,
/* [in] */ int isInstallState,
/* [out] */ UINT __RPC_FAR *puiResult,
/* [in] */ int iThreadID)
{
HRESULT hr = S_OK;
if(CheckForMsiDll()){
InitStatic(&iThreadID);
EnterCriticalSection(&m_cs);
if(SUCCEEDED(hr = PrepareEnvironment())){
try{
*puiResult = g_fpMsiConfigureFeatureW(wszProductCode, wszFeature,
(INSTALLSTATE)isInstallState);
}catch(...){
hr = RPC_E_SERVERFAULT;
}
ReleaseEnvironment();
}
LeaveCriticalSection(&m_cs);
}
return hr;
}
HRESULT STDMETHODCALLTYPE CMethods::ReinstallSF(
/* [string][in] */ LPCWSTR wszProductCode,
/* [string][in] */ LPCWSTR wszFeature,
/* [in] */ DWORD dwReinstallMode,
/* [out] */ UINT __RPC_FAR *puiResult,
/* [in] */ int iThreadID)
{
HRESULT hr = S_OK;
if(CheckForMsiDll()){
InitStatic(&iThreadID);
EnterCriticalSection(&m_cs);
if(SUCCEEDED(hr = PrepareEnvironment())){
try{
*puiResult = g_fpMsiReinstallFeatureW(wszProductCode, wszFeature, dwReinstallMode);
}catch(...){
hr = RPC_E_SERVERFAULT;
}
ReleaseEnvironment();
}
LeaveCriticalSection(&m_cs);
}
return hr;
}
HRESULT CMethods::InitStatic(int *piThreadID)
{
HRESULT hr = S_OK;
//Initialize the critical section object
if(!m_bCSReady){
InitializeCriticalSection(&m_cs);
m_bCSReady = true;
CONNECTDATA* paConns;
// Build the initial dynamic array for connections.
paConns = new CONNECTDATA[10];
if(NULL != paConns){
// Zero the array.
memset(paConns, 0, 10 * sizeof(CONNECTDATA));
// Rig this connection point object so that it will use the
// new internal array of connections.
m_uiMaxIndex = 10;
m_paConnections = paConns;
m_dwNextCookie = 0;
m_cConnections = 0;
}else hr = E_OUTOFMEMORY;
}
g_fpMsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
g_fpMsiSetExternalUIW(this->EventHandler, (INSTALLLOGMODE_PROGRESS | INSTALLLOGMODE_ACTIONDATA
| INSTALLLOGMODE_INFO | INSTALLLOGMODE_WARNING | INSTALLLOGMODE_ACTIONSTART),
(void *)piThreadID);
g_fpMsiEnableLogW((INSTALLLOGMODE_ACTIONDATA | INSTALLLOGMODE_INFO | INSTALLLOGMODE_FATALEXIT |
INSTALLLOGMODE_ERROR | INSTALLLOGMODE_WARNING | INSTALLLOGMODE_USER |
INSTALLLOGMODE_RESOLVESOURCE | INSTALLLOGMODE_OUTOFDISKSPACE | INSTALLLOGMODE_COMMONDATA |
INSTALLLOGMODE_ACTIONSTART), NULL, TRUE);
return hr;
}
HRESULT CMethods::GetSlot(UINT* puiFreeSlot)
{
HRESULT hr = NOERROR;
BOOL bOpen = FALSE;
UINT i;
CONNECTDATA* paConns;
// Zero the output variable.
*puiFreeSlot = 0;
// Loop to find an empty slot.
for(i=0; i<m_uiMaxIndex; i++){
if(m_paConnections[i].dwCookie == 0){
// We found an open empty slot.
*puiFreeSlot = i;
bOpen = TRUE;
break;
}
}
if(!bOpen){
// We didn't find an existing open slot in the array--it's full.
// Expand the array by ALLOC_CONNECTIONS entries and assign the
// appropriate output index.
paConns = new CONNECTDATA[m_uiMaxIndex + 10];
if(NULL != paConns){
// Copy the content of the old full array to the new larger array.
for(i=0; i<m_uiMaxIndex; i++){
paConns[i].pUnk = m_paConnections[i].pUnk;
paConns[i].dwCookie = m_paConnections[i].dwCookie;
}
// Zero (ie mark as empty) the expanded portion of the new array.
for(i=m_uiMaxIndex; i<m_uiMaxIndex+10; i++){
paConns[i].pUnk = NULL;
paConns[i].dwCookie = 0;
}
// New larger array is ready--delete the old array.
delete [] m_paConnections;
// Rig the connection point to use the new larger array.
m_paConnections = paConns;
// Assign the output free slot as first entry in new expanded area.
*puiFreeSlot = m_uiMaxIndex;
// Calculate the new max index.
m_uiMaxIndex += 10;
}else hr = E_OUTOFMEMORY;
}
return hr;
}
HRESULT CMethods::FindSlot(
DWORD dwCookie,
UINT* puiSlot)
{
HRESULT hr = CONNECT_E_NOCONNECTION;
UINT i;
// Loop to find the Cookie.
for(i=0; i<m_uiMaxIndex; i++){
if(dwCookie == m_paConnections[i].dwCookie){
// If a cookie match is found, assign the output slot index.
*puiSlot = i;
hr = NOERROR;
break;
}
}
return hr;
}
DWORD CMethods::GetAccount(HANDLE TokenHandle, WCHAR *wcDomain, WCHAR *wcUser)
{
DWORD dwStatus = S_OK;
TOKEN_USER *tTokenUser = NULL;
DWORD dwReturnLength = 0;
TOKEN_INFORMATION_CLASS tTokenInformationClass = TokenUser;
if(!GetTokenInformation(TokenHandle, tTokenInformationClass, NULL, 0, &dwReturnLength) &&
GetLastError () == ERROR_INSUFFICIENT_BUFFER){
tTokenUser = (TOKEN_USER*) new UCHAR[dwReturnLength];
if(TokenUser){
try{
if(GetTokenInformation(TokenHandle, tTokenInformationClass,
(void *)tTokenUser, dwReturnLength, &dwReturnLength)){
DWORD dwUserSize = BUFF_SIZE;
DWORD dwDomainSize = BUFF_SIZE;
SID_NAME_USE Use;
if(!LookupAccountSidW(NULL, tTokenUser->User.Sid, wcUser, &dwUserSize,
wcDomain, &dwDomainSize, &Use)){
dwStatus = GetLastError();
}
}else dwStatus = GetLastError();
}catch(...){
delete [] (UCHAR *)tTokenUser;
throw;
}
delete [] (UCHAR *)tTokenUser;
}else{
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
}
}else dwStatus = GetLastError();
return dwStatus ;
}
DWORD CMethods::GetSid(HANDLE TokenHandle, WCHAR *wcSID)
{
DWORD dwStatus = S_OK ;
TOKEN_USER *tTokenUser = NULL ;
DWORD dwReturnLength = 0 ;
TOKEN_INFORMATION_CLASS tTokenInformationClass = TokenUser ;
if(!GetTokenInformation(TokenHandle, tTokenInformationClass, NULL, 0, &dwReturnLength) &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER){
tTokenUser = (TOKEN_USER *) new UCHAR[dwReturnLength] ;
if(TokenUser){
try{
if(GetTokenInformation(TokenHandle, tTokenInformationClass, (void *)tTokenUser,
dwReturnLength, &dwReturnLength)){
// Initialize m_strSid - human readable form of our SID
SID_IDENTIFIER_AUTHORITY *psia = ::GetSidIdentifierAuthority(tTokenUser->User.Sid);
// We assume that only last byte is used (authorities between 0 and 15).
// Correct this if needed.
// ASSERT(psia->Value[0] == psia->Value[1] == psia->Value[2] == psia->Value[3]
// == psia->Value[4] == 0);
DWORD dwTopAuthority = psia->Value[5];
WCHAR bstrtTempSid[BUFF_SIZE];
wcscpy(bstrtTempSid, L"S-1-");
WCHAR wstrAuth[32];
ZeroMemory(wstrAuth, 32);
_itow(dwTopAuthority, wstrAuth, 10);
wcscat(bstrtTempSid, wstrAuth);
int iSubAuthorityCount = *(GetSidSubAuthorityCount(tTokenUser->User.Sid));
for(int i = 0; i < iSubAuthorityCount; i++){
DWORD dwSubAuthority = *(GetSidSubAuthority( tTokenUser->User.Sid, i ));
ZeroMemory(wstrAuth, wcslen(wstrAuth));
_itow(dwSubAuthority, wstrAuth,10);
wcscat(bstrtTempSid, L"-");
wcscat(bstrtTempSid, wstrAuth);
}
// Now allocate the passed in wstr:
WCHAR* wstrtemp = NULL;
try{
wstrtemp = (WCHAR*) new WCHAR[wcslen(bstrtTempSid) + 1];
if(wstrtemp!=NULL){
ZeroMemory(wstrtemp, wcslen(bstrtTempSid) + 1);
wcscpy(wstrtemp, (WCHAR*)bstrtTempSid);
}
wcSID = wstrtemp;
}catch(...){
if(wstrtemp!=NULL){
delete wstrtemp;
wstrtemp = NULL;
}
throw;
}
}else dwStatus = GetLastError();
}catch(...){
delete [] (UCHAR *)tTokenUser;
throw ;
}
delete [] (UCHAR *)tTokenUser;
}else throw CHeap_Exception(CHeap_Exception::E_ALLOCATION_ERROR);
}else dwStatus = GetLastError();
return dwStatus ;
}
DWORD CMethods::LoadHive(LPWSTR pszUserName, LPWSTR pszKeyName)
{
DWORD i, dwSIDSize, dwDomainNameSize, dwRetCode, dwSubAuthorities ;
char SIDBuffer[_MAX_PATH];
WCHAR szDomainName[_MAX_PATH], szSID[_MAX_PATH], szTemp[_MAX_PATH] ;
SID *pSID = (SID *) SIDBuffer ;
PSID_IDENTIFIER_AUTHORITY pSIA ;
SID_NAME_USE AccountType ;
WCHAR wcTemp[BUFF_SIZE];
CRegistry Reg ;
// Set the necessary privs
//========================
dwRetCode = AcquirePrivilege();
if(dwRetCode != ERROR_SUCCESS)
{
return dwRetCode;
}
// Look up the user's account info
//================================
dwSIDSize = strlen(SIDBuffer) ;
dwDomainNameSize = wcslen(szDomainName) ;
int iLookup;
{
// CreateMutexAsProcess createMutexAsProcess(SECURITYAPIMUTEXNAME);
iLookup = LookupAccountNameW(NULL, pszUserName, pSID, &dwSIDSize,
szDomainName, &dwDomainNameSize, &AccountType);
}
if(!iLookup){
RestorePrivilege();
CoImpersonateClient();
return ERROR_BAD_USERNAME ;
}
// Translate the SID into text (a la PSS article Q131320)
//=======================================================
pSIA = GetSidIdentifierAuthority(pSID) ;
dwSubAuthorities = *GetSidSubAuthorityCount(pSID) ;
dwSIDSize = wprintf(szSID, TEXT("S-%lu-"), (DWORD) SID_REVISION) ;
if((pSIA->Value[0] != 0) || (pSIA->Value[1] != 0)){
dwSIDSize += swprintf(szSID + wcslen(szSID), L"0x%02hx%02hx%02hx%02hx%02hx%02hx",
(USHORT) pSIA->Value[0],
(USHORT) pSIA->Value[1],
(USHORT) pSIA->Value[2],
(USHORT) pSIA->Value[3],
(USHORT) pSIA->Value[4],
(USHORT) pSIA->Value[5]) ;
}else{
dwSIDSize += swprintf(szSID + wcslen(szSID), L"%lu",
(ULONG)(pSIA->Value[5] ) +
(ULONG)(pSIA->Value[4] << 8) +
(ULONG)(pSIA->Value[3] << 16) +
(ULONG)(pSIA->Value[2] << 24));
}
for(i = 0 ; i < dwSubAuthorities ; i++){
dwSIDSize += swprintf(szSID + dwSIDSize, L"-%lu",
*GetSidSubAuthority(pSID, i)) ;
}
// See if the key already exists
//==============================
dwRetCode = Reg.Open(HKEY_USERS, szSID, KEY_READ) ;
// We need to keep a handle open. See m_hKey below, so we'll let the destructor close this.
// Reg.Close();
if(dwRetCode != ERROR_SUCCESS){
// Try to locate user's registry hive
//===================================
swprintf(szTemp, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\%s", szSID) ;
dwRetCode = Reg.Open(HKEY_LOCAL_MACHINE, szTemp, KEY_READ);
if(dwRetCode == ERROR_SUCCESS){
CHString chsTemp(wcTemp);
dwRetCode = Reg.GetCurrentKeyValue(L"ProfileImagePath", chsTemp);
Reg.Close();
if(dwRetCode == ERROR_SUCCESS){
// NT 4 doesn't include the file name in the registry
//===================================================
if(!IsLessThan4()){
wcscat(wcTemp, L"\\NTUSER.DAT");
}
ExpandEnvironmentStringsW(wcTemp, szTemp, sizeof(szTemp) / sizeof(TCHAR)) ;
// Try it three times, another process may have the file open
bool bTryTryAgain = false;
int nTries = 0;
do{
// need to serialize access, using "write" because RegLoadKey wants exclusive access
// even though it is a read operation
EnterCriticalSection(&m_cs);
dwRetCode = (DWORD) RegLoadKeyW(HKEY_USERS, szSID, szTemp) ;
LeaveCriticalSection(&m_cs);
if((dwRetCode == ERROR_SHARING_VIOLATION)
&& (++nTries < 11)){
Sleep(20 * nTries);
bTryTryAgain = true;
}else{
bTryTryAgain = false;
}
}while (bTryTryAgain);
// if we still can't get in, tell somebody.
// if (dwRetCode == ERROR_SHARING_VIOLATION)
// LogErrorMessage(_T("Sharing violation on NTUSER.DAT (Load)"));
}
}
}
if(dwRetCode == ERROR_SUCCESS){
wcscpy(pszKeyName, szSID) ;
LONG lRetVal;
WCHAR wcKey[BUFF_SIZE];
wcscpy(wcKey, szSID);
wcscat(wcKey, L"\\Software");
lRetVal = RegOpenKeyExW(HKEY_USERS, wcKey, 0, KEY_QUERY_VALUE, &m_hKey);
// ASSERT_BREAK(lRetVal == ERROR_SUCCESS);
}
// Restore original privilege level & end self-impersonation
//==========================================================
RestorePrivilege() ;
return dwRetCode ;
}
DWORD CMethods::UnloadHive(LPCWSTR pszKeyName)
{
DWORD dwRetCode = ERROR_SUCCESS;
if(m_hKey != NULL){
RegCloseKey(m_hKey);
m_hKey = NULL;
}
dwRetCode = AcquirePrivilege();
if(dwRetCode == ERROR_SUCCESS){
EnterCriticalSection(&m_cs);
dwRetCode = RegUnLoadKeyW(HKEY_USERS, pszKeyName) ;
LeaveCriticalSection(&m_cs);
RestorePrivilege() ;
}
return dwRetCode ;
}
DWORD CMethods::AcquirePrivilege()
{
// are you calling in twice? Shouldn't.
// at worst, it would cause a leak, so I'm going with it anyway.
// ASSERT_BREAK(m_pOriginalPriv == NULL);
BOOL bRetCode = FALSE;
HANDLE hToken = INVALID_HANDLE_VALUE ;
TOKEN_PRIVILEGES TPriv ;
LUID LUID ;
// Validate the platform
//======================
// Try getting the thread token. If it fails the first time it's
// because we're a system thread and we don't yet have a thread
// token, so just impersonate self and try again.
if (OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES |
TOKEN_QUERY, FALSE, &hToken))
{
try{
GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &m_dwSize);
if (m_dwSize > 0){
// This is cleaned in the destructor, so no try/catch required
m_pOriginalPriv = (TOKEN_PRIVILEGES*) new BYTE[m_dwSize];
if (m_pOriginalPriv == NULL){
throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
}
}
if(m_pOriginalPriv && GetTokenInformation(hToken, TokenPrivileges, m_pOriginalPriv, m_dwSize, &m_dwSize)){
// DEADLOCK ON NT! it's actually an NT bug, but we have to protect ourselves
// CreateMutexAsProcess createMutexAsProcess(SECURITYAPIMUTEXNAME);
bRetCode = LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &LUID);
if(bRetCode){
TPriv.PrivilegeCount = 1 ;
TPriv.Privileges[0].Luid = LUID ;
TPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
bRetCode = AdjustTokenPrivileges(hToken, FALSE, &TPriv,
sizeof(TOKEN_PRIVILEGES), NULL, NULL);
}
bRetCode = LookupPrivilegeValue(NULL, SE_BACKUP_NAME, &LUID);
if(bRetCode){
TPriv.PrivilegeCount = 1 ;
TPriv.Privileges[0].Luid = LUID ;
TPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
bRetCode = AdjustTokenPrivileges(hToken, FALSE, &TPriv,
sizeof(TOKEN_PRIVILEGES), NULL, NULL) ;
}
}
}catch(...){
CloseHandle(hToken);
throw ;
}
CloseHandle(hToken);
}
if(!bRetCode){
return GetLastError();
}
return ERROR_SUCCESS ;
}
void CMethods::RestorePrivilege()
{
// ASSERT_BREAK(m_pOriginalPriv != NULL);
if (m_pOriginalPriv != NULL){
HANDLE hToken;
try{
if (OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, TRUE, &hToken)){
AdjustTokenPrivileges(hToken, FALSE, m_pOriginalPriv, m_dwSize, NULL, NULL);
CloseHandle(hToken) ;
}
}catch(...){
delete m_pOriginalPriv;
m_pOriginalPriv = NULL;
m_dwSize = 0;
throw;
}
delete m_pOriginalPriv;
m_pOriginalPriv = NULL;
m_dwSize = 0;
}
}
HRESULT CMethods::PrepareEnvironment()
{
// PROCESS_INFORMATION piMethods;
STARTUPINFO siMethods;
ZeroMemory(&siMethods, sizeof(siMethods));
siMethods.cb = sizeof(siMethods);
try{
HANDLE hClientToken = INVALID_HANDLE_VALUE;
//Get thread token
if(!OpenThreadToken(GetCurrentThread(), (TOKEN_DUPLICATE |TOKEN_QUERY |
TOKEN_ASSIGN_PRIMARY), TRUE, &hClientToken)){
return GetLastError();
}
//Prepare registry
DWORD dwStatus = ERROR_SUCCESS;
WCHAR wcDomain[BUFF_SIZE];
WCHAR wcUser[BUFF_SIZE];
if((dwStatus = GetAccount(hClientToken, wcDomain, wcUser)) != 0)
return GetLastError();
WCHAR wcAccount[BUFF_SIZE];
wcscpy(wcAccount, wcDomain);
wcscat(wcAccount, L"\\");
wcscat(wcAccount, wcUser);
WCHAR wcSID[BUFF_SIZE];
if((dwStatus = GetSid(hClientToken, wcSID)) == ERROR_SUCCESS){
CRegistry Reg ;
//check if SID already present under HKEY_USER ...
m_dwCheckKeyPresentStatus = Reg.Open(HKEY_USERS, wcSID, KEY_READ);
Reg.Close() ;
if(m_dwCheckKeyPresentStatus != ERROR_SUCCESS)
dwStatus = LoadHive(wcAccount, m_wcKeyName);
}
if(dwStatus != ERROR_SUCCESS){
dwStatus = GetLastError();
}
///////////////
}catch(...){
throw;
}
return S_OK;
}
HRESULT CMethods::ReleaseEnvironment()
{
//remove the key if it wasn't there b4....
if(m_dwCheckKeyPresentStatus != ERROR_SUCCESS){
UnloadHive(m_wcKeyName);
}
return S_OK;
}
int WINAPI CMethods::EventHandler(LPVOID pvContext, UINT iMessageType, LPCWSTR szMessage)
{
// Loop to find the Cookie.
/* for(UINT i = 0; i < m_cConnections; i++){
IMsiMethodStatusSink * pStatus = (IMsiMethodStatusSink *)m_paConnections[i].pUnk;
if(pStatus) pStatus->Indicate((int *)pvContext,iMessageType, szMessage);
}
*/
if(g_bPipe){
int *piContext = (int*)(pvContext);
WCHAR wcMessage[1000];
WCHAR wcTmp[100];
wcscpy(wcMessage, _itow(*piContext, wcTmp, 10));
wcscat(wcMessage, L"~");
wcscat(wcMessage, _itow(iMessageType, wcTmp, 10));
wcscat(wcMessage, L"~");
wcscat(wcMessage, szMessage);
wcscat(wcMessage, L"\n");
DWORD dwWritten = 0;
//synchronized pipe access
// WaitForSingleObject(g_hMutex, INFINITE);
WriteFile(g_hPipe, wcMessage, (wcslen(wcMessage) * 2), &dwWritten, NULL);
// ReleaseMutex(g_hMutex);
}
return 0;
}
//Ensure msi.dll and functions are loaded if present on system
bool CMethods::CheckForMsiDll()
{
if(!g_bMsiLoaded){
//synchronize us with the perf counters
HANDLE hMutex = OpenMutex(SYNCHRONIZE, FALSE, WBEMPERFORMANCEDATAMUTEX);
if(hMutex) WaitForSingleObject(hMutex, INFINITE);
HINSTANCE hiMsiDll = LoadLibraryW(L"msi.dll");
if(!hiMsiDll){
hiMsiDll = LoadLibraryA("msi.dll");
if(!hiMsiDll){
char cBuf[MAX_PATH] = { '\0' };
if ( GetSystemDirectoryA(cBuf, MAX_PATH) != 0 )
{
if ( ( strlen ( cBuf ) + strlen ( "\\msi.dll" ) + 1 ) < MAX_PATH )
{
strcat(cBuf, "\\msi.dll");
hiMsiDll = LoadLibraryA(cBuf);
}
}
}
}
if(hiMsiDll){
//Load the function pointers
g_fpMsiSetInternalUI = (LPFNMSISETINTERNALUI)GetProcAddress(hiMsiDll, "MsiSetInternalUI");
g_fpMsiSetExternalUIW = (LPFNMSISETEXTERNALUIW)GetProcAddress(hiMsiDll, "MsiSetExternalUIW");
g_fpMsiEnableLogW = (LPFNMSIENABLELOGW)GetProcAddress(hiMsiDll, "MsiEnableLogW");
g_fpMsiInstallProductW = (LPFNMSIINSTALLPRODUCTW)GetProcAddress(hiMsiDll, "MsiInstallProductW");
g_fpMsiConfigureProductW = (LPFNMSICONFIGUREPRODUCTW)GetProcAddress(hiMsiDll, "MsiConfigureProductW");
g_fpMsiReinstallProductW = (LPFNMSIREINSTALLPRODUCTW)GetProcAddress(hiMsiDll, "MsiReinstallProductW");
g_fpMsiApplyPatchW = (LPFNMSIAPPLYPATCHW)GetProcAddress(hiMsiDll, "MsiApplyPatchW");
g_fpMsiConfigureFeatureW = (LPFNMSICONFIGUREFEATUREW)GetProcAddress(hiMsiDll, "MsiConfigureFeatureW");
g_fpMsiReinstallFeatureW = (LPFNMSIREINSTALLFEATUREW)GetProcAddress(hiMsiDll, "MsiReinstallFeatureW");
// Did we get all the pointers we need?
if(g_fpMsiSetInternalUI && g_fpMsiSetExternalUIW && g_fpMsiEnableLogW &&
g_fpMsiInstallProductW && g_fpMsiConfigureProductW && g_fpMsiReinstallProductW &&
g_fpMsiApplyPatchW && g_fpMsiConfigureFeatureW && g_fpMsiReinstallFeatureW){
g_bMsiLoaded = true;
}
}else{
g_bMsiPresent = false;
}
if(hMutex){
ReleaseMutex(hMutex);
CloseHandle(hMutex);
}
}
return g_bMsiLoaded;
}