// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. #include "precomp.h" #include "RemoteMsiSession.h" // // Ensures that the request buffer is large enough to hold a request, // reallocating the buffer if necessary. // It will also reduce the buffer size if the previous allocation was very large. // static __success(return == 0) UINT EnsureBufSize(__deref_out_ecount(*pcchBuf) wchar_t** pszBuf, __deref_inout DWORD* pcchBuf, DWORD cchRequired) { // It will also reduce the buffer size if the previous allocation was very large. if (*pcchBuf < cchRequired || (LARGE_BUFFER_THRESHOLD/2 < *pcchBuf && cchRequired < *pcchBuf)) { if (*pszBuf != NULL) { SecureZeroMemory(*pszBuf, *pcchBuf); delete[] *pszBuf; } *pcchBuf = max(MIN_BUFFER_STRING_SIZE, cchRequired); *pszBuf = new wchar_t[*pcchBuf]; if (*pszBuf == NULL) { return ERROR_OUTOFMEMORY; } } return ERROR_SUCCESS; } typedef int (WINAPI *PMsiFunc_I_I)(int in1, __out int* out1); typedef int (WINAPI *PMsiFunc_II_I)(int in1, int in2, __out int* out1); typedef int (WINAPI *PMsiFunc_IS_I)(int in1, __in_z wchar_t* in2, __out int* out1); typedef int (WINAPI *PMsiFunc_ISI_I)(int in1, __in_z wchar_t* in2, int in3, __out int* out1); typedef int (WINAPI *PMsiFunc_ISII_I)(int in1, __in_z wchar_t* in2, int in3, int in4, __out int* out1); typedef int (WINAPI *PMsiFunc_IS_II)(int in1, __in_z wchar_t* in2, __out int* out1, __out int* out2); typedef MSIDBERROR (WINAPI *PMsiEFunc_I_S)(int in1, __out_ecount_full(*cchOut1) wchar_t* out1, __inout DWORD* cchOut1); typedef int (WINAPI *PMsiFunc_I_S)(int in1, __out_ecount_full(*cchOut1) wchar_t* out1, __inout DWORD* cchOut1); typedef int (WINAPI *PMsiFunc_II_S)(int in1, int in2, __out_ecount_full(*cchOut1) wchar_t* out1, __inout DWORD* cchOut1); typedef int (WINAPI *PMsiFunc_IS_S)(int in1, __in_z wchar_t* in2, __out_ecount_full(*cchOut1) wchar_t* out1, __inout DWORD* cchOut1); typedef int (WINAPI *PMsiFunc_ISII_SII)(int in1, __in_z wchar_t* in2, int in3, int in4, __out_ecount_full(*cchOut1) wchar_t* out1, __inout DWORD* cchOut1, __out int* out2, __out int* out3); UINT MsiFunc_I_I(PMsiFunc_I_I func, const RemoteMsiSession::RequestData* pReq, RemoteMsiSession::RequestData* pResp) { int in1 = pReq->fields[0].iValue; int out1; UINT ret = (UINT) func(in1, &out1); if (ret == 0) { pResp->fields[1].vt = VT_I4; pResp->fields[1].iValue = out1; } return ret; } UINT MsiFunc_II_I(PMsiFunc_II_I func, const RemoteMsiSession::RequestData* pReq, RemoteMsiSession::RequestData* pResp) { int in1 = pReq->fields[0].iValue; int in2 = pReq->fields[1].iValue; int out1; UINT ret = (UINT) func(in1, in2, &out1); if (ret == 0) { pResp->fields[1].vt = VT_I4; pResp->fields[1].iValue = out1; } return ret; } UINT MsiFunc_IS_I(PMsiFunc_IS_I func, const RemoteMsiSession::RequestData* pReq, RemoteMsiSession::RequestData* pResp) { int in1 = pReq->fields[0].iValue; wchar_t* in2 = pReq->fields[1].szValue; int out1; UINT ret = (UINT) func(in1, in2, &out1); if (ret == 0) { pResp->fields[1].vt = VT_I4; pResp->fields[1].iValue = out1; } return ret; } UINT MsiFunc_ISI_I(PMsiFunc_ISI_I func, const RemoteMsiSession::RequestData* pReq, RemoteMsiSession::RequestData* pResp) { int in1 = pReq->fields[0].iValue; wchar_t* in2 = pReq->fields[1].szValue; int in3 = pReq->fields[2].iValue; int out1; UINT ret = (UINT) func(in1, in2, in3, &out1); if (ret == 0) { pResp->fields[1].vt = VT_I4; pResp->fields[1].iValue = out1; } return ret; } UINT MsiFunc_ISII_I(PMsiFunc_ISII_I func, const RemoteMsiSession::RequestData* pReq, RemoteMsiSession::RequestData* pResp) { int in1 = pReq->fields[0].iValue; wchar_t* in2 = pReq->fields[1].szValue; int in3 = pReq->fields[2].iValue; int in4 = pReq->fields[3].iValue; int out1; UINT ret = (UINT) func(in1, in2, in3, in4, &out1); if (ret == 0) { pResp->fields[1].vt = VT_I4; pResp->fields[1].iValue = out1; } return ret; } UINT MsiFunc_IS_II(PMsiFunc_IS_II func, const RemoteMsiSession::RequestData* pReq, RemoteMsiSession::RequestData* pResp) { int in1 = pReq->fields[0].iValue; wchar_t* in2 = pReq->fields[1].szValue; int out1, out2; UINT ret = (UINT) func(in1, in2, &out1, &out2); if (ret == 0) { pResp->fields[1].vt = VT_I4; pResp->fields[1].iValue = out1; pResp->fields[2].vt = VT_I4; pResp->fields[2].iValue = out2; } return ret; } UINT MsiFunc_I_S(PMsiFunc_I_S func, const RemoteMsiSession::RequestData* pReq, RemoteMsiSession::RequestData* pResp, __deref_inout_ecount(cchBuf) wchar_t*& szBuf, __inout DWORD& cchBuf) { int in1 = pReq->fields[0].iValue; szBuf[0] = L'\0'; DWORD cchValue = cchBuf; UINT ret = (UINT) func(in1, szBuf, &cchValue); if (ret == ERROR_MORE_DATA) { ret = EnsureBufSize(&szBuf, &cchBuf, ++cchValue); if (ret == 0) { ret = (UINT) func(in1, szBuf, &cchValue); } } if (ret == 0) { pResp->fields[1].vt = VT_LPWSTR; pResp->fields[1].szValue = szBuf; } return ret; } MSIDBERROR MsiEFunc_I_S(PMsiEFunc_I_S func, const RemoteMsiSession::RequestData* pReq, RemoteMsiSession::RequestData* pResp, __deref_inout_ecount(cchBuf) wchar_t*& szBuf, __inout DWORD& cchBuf) { int in1 = pReq->fields[0].iValue; szBuf[0] = L'\0'; DWORD cchValue = cchBuf; MSIDBERROR ret = func(in1, szBuf, &cchValue); if (ret == MSIDBERROR_MOREDATA) { if (0 == EnsureBufSize(&szBuf, &cchBuf, ++cchValue)) { ret = func(in1, szBuf, &cchValue); } } if (ret != MSIDBERROR_MOREDATA) { pResp->fields[1].vt = VT_LPWSTR; pResp->fields[1].szValue = szBuf; } return ret; } UINT MsiFunc_II_S(PMsiFunc_II_S func, const RemoteMsiSession::RequestData* pReq, RemoteMsiSession::RequestData* pResp, __deref_inout_ecount(cchBuf) wchar_t*& szBuf, __inout DWORD& cchBuf) { int in1 = pReq->fields[0].iValue; int in2 = pReq->fields[1].iValue; szBuf[0] = L'\0'; DWORD cchValue = cchBuf; UINT ret = (UINT) func(in1, in2, szBuf, &cchValue); if (ret == ERROR_MORE_DATA) { ret = EnsureBufSize(&szBuf, &cchBuf, ++cchValue); if (ret == 0) { ret = (UINT) func(in1, in2, szBuf, &cchValue); } } if (ret == 0) { pResp->fields[1].vt = VT_LPWSTR; pResp->fields[1].szValue = szBuf; } return ret; } UINT MsiFunc_IS_S(PMsiFunc_IS_S func, const RemoteMsiSession::RequestData* pReq, RemoteMsiSession::RequestData* pResp, __deref_inout_ecount(cchBuf) wchar_t*& szBuf, __inout DWORD& cchBuf) { int in1 = pReq->fields[0].iValue; wchar_t* in2 = pReq->fields[1].szValue; szBuf[0] = L'\0'; DWORD cchValue = cchBuf; UINT ret = (UINT) func(in1, in2, szBuf, &cchValue); if (ret == ERROR_MORE_DATA) { ret = EnsureBufSize(&szBuf, &cchBuf, ++cchValue); if (ret == 0) { ret = (UINT) func(in1, in2, szBuf, &cchValue); } } if (ret == 0) { pResp->fields[1].vt = VT_LPWSTR; pResp->fields[1].szValue = szBuf; } return ret; } UINT MsiFunc_ISII_SII(PMsiFunc_ISII_SII func, const RemoteMsiSession::RequestData* pReq, RemoteMsiSession::RequestData* pResp, __deref_inout_ecount(cchBuf) wchar_t*& szBuf, __inout DWORD& cchBuf) { int in1 = pReq->fields[0].iValue; wchar_t* in2 = pReq->fields[1].szValue; int in3 = pReq->fields[2].iValue; int in4 = pReq->fields[3].iValue; szBuf[0] = L'\0'; DWORD cchValue = cchBuf; int out2, out3; UINT ret = (UINT) func(in1, in2, in3, in4, szBuf, &cchValue, &out2, &out3); if (ret == ERROR_MORE_DATA) { ret = EnsureBufSize(&szBuf, &cchBuf, ++cchValue); if (ret == 0) { ret = (UINT) func(in1, in2, in3, in4, szBuf, &cchValue, &out2, &out3); } } if (ret == 0) { pResp->fields[1].vt = VT_LPWSTR; pResp->fields[1].szValue = szBuf; pResp->fields[2].vt = VT_I4; pResp->fields[2].iValue = out2; pResp->fields[3].vt = VT_I4; pResp->fields[3].iValue = out3; } return ret; } void RemoteMsiSession::ProcessRequest(RequestId id, const RequestData* pReq, RequestData* pResp) { SecureZeroMemory(pResp, sizeof(RequestData)); UINT ret = EnsureBufSize(&m_pBufSend, &m_cbBufSend, 1024); if (0 == ret) { switch (id) { case RemoteMsiSession::EndSession: { this->ExitCode = pReq->fields[0].iValue; } break; case RemoteMsiSession::MsiCloseHandle: { MSIHANDLE h = (MSIHANDLE) pReq->fields[0].iValue; ret = ::MsiCloseHandle(h); } break; case RemoteMsiSession::MsiProcessMessage: { MSIHANDLE hInstall = (MSIHANDLE) pReq->fields[0].iValue; INSTALLMESSAGE eMessageType = (INSTALLMESSAGE) pReq->fields[1].iValue; MSIHANDLE hRecord = (MSIHANDLE) pReq->fields[2].iValue; ret = ::MsiProcessMessage(hInstall, eMessageType, hRecord); } break; case RemoteMsiSession::MsiGetProperty: { ret = MsiFunc_IS_S((PMsiFunc_IS_S) ::MsiGetProperty, pReq, pResp, m_pBufSend, m_cbBufSend); } break; case RemoteMsiSession::MsiSetProperty: { MSIHANDLE hInstall = (MSIHANDLE) pReq->fields[0].iValue; const wchar_t* szName = pReq->fields[1].szValue; const wchar_t* szValue = pReq->fields[2].szValue; ret = ::MsiSetProperty(hInstall, szName, szValue); } break; case RemoteMsiSession::MsiCreateRecord: { UINT cParams = pReq->fields[0].uiValue; ret = ::MsiCreateRecord(cParams); } break; case RemoteMsiSession::MsiRecordGetFieldCount: { MSIHANDLE hRecord = (MSIHANDLE) pReq->fields[0].iValue; ret = ::MsiRecordGetFieldCount(hRecord); } break; case RemoteMsiSession::MsiRecordGetInteger: { MSIHANDLE hRecord = (MSIHANDLE) pReq->fields[0].iValue; UINT iField = pReq->fields[1].uiValue; ret = ::MsiRecordGetInteger(hRecord, iField); } break; case RemoteMsiSession::MsiRecordSetInteger: { MSIHANDLE hRecord = (MSIHANDLE) pReq->fields[0].iValue; UINT iField = pReq->fields[1].uiValue; int iValue = pReq->fields[2].iValue; ret = ::MsiRecordSetInteger(hRecord, iField, iValue); } break; case RemoteMsiSession::MsiRecordGetString: { ret = MsiFunc_II_S((PMsiFunc_II_S) ::MsiRecordGetString, pReq, pResp, m_pBufSend, m_cbBufSend); } break; case RemoteMsiSession::MsiRecordSetString: { MSIHANDLE hRecord = (MSIHANDLE) pReq->fields[0].iValue; UINT iField = pReq->fields[1].uiValue; const wchar_t* szValue = pReq->fields[2].szValue; ret = ::MsiRecordSetString(hRecord, iField, szValue); } break; case RemoteMsiSession::MsiRecordClearData: { MSIHANDLE hRecord = (MSIHANDLE) pReq->fields[0].iValue; ret = ::MsiRecordClearData(hRecord); } break; case RemoteMsiSession::MsiRecordIsNull: { MSIHANDLE hRecord = (MSIHANDLE) pReq->fields[0].iValue; UINT iField = pReq->fields[1].uiValue; ret = ::MsiRecordIsNull(hRecord, iField); } break; case RemoteMsiSession::MsiFormatRecord: { ret = MsiFunc_II_S((PMsiFunc_II_S) ::MsiFormatRecord, pReq, pResp, m_pBufSend, m_cbBufSend); } break; case RemoteMsiSession::MsiGetActiveDatabase: { MSIHANDLE hInstall = (MSIHANDLE) pReq->fields[0].iValue; ret = (UINT) ::MsiGetActiveDatabase(hInstall); } break; case RemoteMsiSession::MsiDatabaseOpenView: { ret = MsiFunc_IS_I((PMsiFunc_IS_I) ::MsiDatabaseOpenView, pReq, pResp); } break; case RemoteMsiSession::MsiViewExecute: { MSIHANDLE hView = (MSIHANDLE) pReq->fields[0].iValue; MSIHANDLE hRecord = (MSIHANDLE) pReq->fields[1].iValue; ret = ::MsiViewExecute(hView, hRecord); } break; case RemoteMsiSession::MsiViewFetch: { ret = MsiFunc_I_I((PMsiFunc_I_I) ::MsiViewFetch, pReq, pResp); } break; case RemoteMsiSession::MsiViewModify: { MSIHANDLE hView = (MSIHANDLE) pReq->fields[0].iValue; MSIMODIFY eModifyMode = (MSIMODIFY) pReq->fields[1].iValue; MSIHANDLE hRecord = (MSIHANDLE) pReq->fields[2].iValue; ret = ::MsiViewModify(hView, eModifyMode, hRecord); } break; case RemoteMsiSession::MsiViewGetError: { ret = MsiEFunc_I_S((PMsiEFunc_I_S) ::MsiViewGetError, pReq, pResp, m_pBufSend, m_cbBufSend); } break; case RemoteMsiSession::MsiViewGetColumnInfo: { ret = MsiFunc_II_I((PMsiFunc_II_I) ::MsiViewGetColumnInfo, pReq, pResp); } break; case RemoteMsiSession::MsiDatabaseGetPrimaryKeys: { ret = MsiFunc_IS_I((PMsiFunc_IS_I) ::MsiDatabaseGetPrimaryKeys, pReq, pResp); } break; case RemoteMsiSession::MsiDatabaseIsTablePersistent: { MSIHANDLE hDb = (MSIHANDLE) pReq->fields[0].iValue; const wchar_t* szTable = pReq->fields[1].szValue; ret = ::MsiDatabaseIsTablePersistent(hDb, szTable); } break; case RemoteMsiSession::MsiDoAction: { MSIHANDLE hInstall = (MSIHANDLE) pReq->fields[0].iValue; const wchar_t* szAction = pReq->fields[1].szValue; ret = ::MsiDoAction(hInstall, szAction); } break; case RemoteMsiSession::MsiEnumComponentCosts: { ret = MsiFunc_ISII_SII((PMsiFunc_ISII_SII) ::MsiEnumComponentCosts, pReq, pResp, m_pBufSend, m_cbBufSend); } break; case RemoteMsiSession::MsiEvaluateCondition: { MSIHANDLE hInstall = (MSIHANDLE) pReq->fields[0].iValue; const wchar_t* szCondition = pReq->fields[1].szValue; ret = ::MsiEvaluateCondition(hInstall, szCondition); } break; case RemoteMsiSession::MsiGetComponentState: { ret = MsiFunc_IS_II((PMsiFunc_IS_II) ::MsiGetComponentState, pReq, pResp); } break; case RemoteMsiSession::MsiGetFeatureCost: { ret = MsiFunc_ISII_I((PMsiFunc_ISII_I) ::MsiGetFeatureCost, pReq, pResp); } break; case RemoteMsiSession::MsiGetFeatureState: { ret = MsiFunc_IS_II((PMsiFunc_IS_II) ::MsiGetFeatureState, pReq, pResp); } break; case RemoteMsiSession::MsiGetFeatureValidStates: { ret = MsiFunc_IS_I((PMsiFunc_IS_I) ::MsiGetFeatureValidStates, pReq, pResp); } break; case RemoteMsiSession::MsiGetLanguage: { MSIHANDLE hInstall = (MSIHANDLE) pReq->fields[0].iValue; ret = ::MsiGetLanguage(hInstall); } break; case RemoteMsiSession::MsiGetLastErrorRecord: { ret = ::MsiGetLastErrorRecord(); } break; case RemoteMsiSession::MsiGetMode: { MSIHANDLE hInstall = (MSIHANDLE) pReq->fields[0].iValue; MSIRUNMODE iRunMode = (MSIRUNMODE) pReq->fields[1].iValue; ret = ::MsiGetMode(hInstall, iRunMode); } break; case RemoteMsiSession::MsiGetSourcePath: { ret = MsiFunc_IS_S((PMsiFunc_IS_S) ::MsiGetSourcePath, pReq, pResp, m_pBufSend, m_cbBufSend); } break; case RemoteMsiSession::MsiGetSummaryInformation: { ret = MsiFunc_ISI_I((PMsiFunc_ISI_I) ::MsiGetSummaryInformation, pReq, pResp); } break; case RemoteMsiSession::MsiGetTargetPath: { ret = MsiFunc_IS_S((PMsiFunc_IS_S) ::MsiGetTargetPath, pReq, pResp, m_pBufSend, m_cbBufSend); } break; case RemoteMsiSession::MsiRecordDataSize: { MSIHANDLE hRecord = (MSIHANDLE) pReq->fields[0].iValue; UINT iField = pReq->fields[1].uiValue; ret = ::MsiRecordDataSize(hRecord, iField); } break; case RemoteMsiSession::MsiRecordReadStream: { MSIHANDLE hRecord = (MSIHANDLE) pReq->fields[0].iValue; UINT iField = pReq->fields[1].uiValue; DWORD cbRead = (DWORD) pReq->fields[2].uiValue; ret = EnsureBufSize(&m_pBufSend, &m_cbBufSend, (cbRead + 1) / 2); if (ret == 0) { ret = ::MsiRecordReadStream(hRecord, iField, (char*) m_pBufSend, &cbRead); if (ret == 0) { pResp->fields[1].vt = VT_STREAM; pResp->fields[1].szValue = m_pBufSend; pResp->fields[2].vt = VT_I4; pResp->fields[2].uiValue = (UINT) cbRead; } } } break; case RemoteMsiSession::MsiRecordSetStream: { MSIHANDLE hRecord = (MSIHANDLE) pReq->fields[0].iValue; UINT iField = pReq->fields[1].uiValue; const wchar_t* szFilePath = pReq->fields[2].szValue; ret = ::MsiRecordSetStream(hRecord, iField, szFilePath); } break; case RemoteMsiSession::MsiSequence: { MSIHANDLE hRecord = (MSIHANDLE) pReq->fields[0].iValue; const wchar_t* szTable = pReq->fields[1].szValue; UINT iSequenceMode = pReq->fields[2].uiValue; ret = ::MsiSequence(hRecord, szTable, iSequenceMode); } break; case RemoteMsiSession::MsiSetComponentState: { MSIHANDLE hInstall = (MSIHANDLE) pReq->fields[0].iValue; const wchar_t* szComponent = pReq->fields[1].szValue; INSTALLSTATE iState = (INSTALLSTATE) pReq->fields[2].iValue; ret = ::MsiSetComponentState(hInstall, szComponent, iState); } break; case RemoteMsiSession::MsiSetFeatureAttributes: { MSIHANDLE hInstall = (MSIHANDLE) pReq->fields[0].iValue; const wchar_t* szFeature = pReq->fields[1].szValue; DWORD dwAttrs = (DWORD) pReq->fields[2].uiValue; ret = ::MsiSetFeatureAttributes(hInstall, szFeature, dwAttrs); } break; case RemoteMsiSession::MsiSetFeatureState: { MSIHANDLE hInstall = (MSIHANDLE) pReq->fields[0].iValue; const wchar_t* szFeature = pReq->fields[1].szValue; INSTALLSTATE iState = (INSTALLSTATE) pReq->fields[2].iValue; ret = ::MsiSetFeatureState(hInstall, szFeature, iState); } break; case RemoteMsiSession::MsiSetInstallLevel: { MSIHANDLE hInstall = (MSIHANDLE) pReq->fields[0].iValue; int iInstallLevel = pReq->fields[1].iValue; ret = ::MsiSetInstallLevel(hInstall, iInstallLevel); } break; case RemoteMsiSession::MsiSetMode: { MSIHANDLE hInstall = (MSIHANDLE) pReq->fields[0].iValue; MSIRUNMODE iRunMode = (MSIRUNMODE) pReq->fields[1].uiValue; BOOL fState = (BOOL) pReq->fields[2].iValue; ret = ::MsiSetMode(hInstall, iRunMode, fState); } break; case RemoteMsiSession::MsiSetTargetPath: { MSIHANDLE hInstall = (MSIHANDLE) pReq->fields[0].iValue; const wchar_t* szFolder = pReq->fields[1].szValue; const wchar_t* szFolderPath = pReq->fields[2].szValue; ret = ::MsiSetTargetPath(hInstall, szFolder, szFolderPath); } break; case RemoteMsiSession::MsiSummaryInfoGetProperty: { MSIHANDLE hSummaryInfo = (MSIHANDLE) pReq->fields[0].iValue; UINT uiProperty = pReq->fields[1].uiValue; UINT uiDataType; int iValue; FILETIME ftValue; m_pBufSend[0] = L'\0'; DWORD cchValue = m_cbBufSend; ret = ::MsiSummaryInfoGetProperty(hSummaryInfo, uiProperty, &uiDataType, &iValue, &ftValue, m_pBufSend, &cchValue); if (ret == ERROR_MORE_DATA) { ret = EnsureBufSize(&m_pBufSend, &m_cbBufSend, ++cchValue); if (ret == 0) { ret = ::MsiSummaryInfoGetProperty(hSummaryInfo, uiProperty, &uiDataType, &iValue, &ftValue, m_pBufSend, &cchValue); } } if (ret == 0) { pResp->fields[1].vt = VT_UI4; pResp->fields[1].uiValue = uiDataType; switch (uiDataType) { case VT_I2: case VT_I4: pResp->fields[2].vt = VT_I4; pResp->fields[2].iValue = iValue; break; case VT_FILETIME: pResp->fields[2].vt = VT_UI4; pResp->fields[2].iValue = ftValue.dwHighDateTime; pResp->fields[3].vt = VT_UI4; pResp->fields[3].iValue = ftValue.dwLowDateTime; break; case VT_LPSTR: pResp->fields[2].vt = VT_LPWSTR; pResp->fields[2].szValue = m_pBufSend; break; } } } break; case RemoteMsiSession::MsiVerifyDiskSpace: { MSIHANDLE hInstall = (MSIHANDLE) pReq->fields[0].iValue; ret = ::MsiVerifyDiskSpace(hInstall); } break; default: { ret = ERROR_INVALID_FUNCTION; } break; } } pResp->fields[0].vt = VT_UI4; pResp->fields[0].uiValue = ret; }