From 95a5a8f9efef02ddcec5b3f69be99a00d71a802a Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Sun, 16 Dec 2018 21:19:24 -0600 Subject: Import implementation of IisCA from old repo's scasched/scaexec. --- src/ca/scawebsvcext.cpp | 343 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 343 insertions(+) create mode 100644 src/ca/scawebsvcext.cpp (limited to 'src/ca/scawebsvcext.cpp') diff --git a/src/ca/scawebsvcext.cpp b/src/ca/scawebsvcext.cpp new file mode 100644 index 00000000..369e951b --- /dev/null +++ b/src/ca/scawebsvcext.cpp @@ -0,0 +1,343 @@ +// 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" + +// sql queries +enum eWebSvcExtQuery { ldqComponent=1 , ldqFile, ldqDescription, ldqGroup, ldqAttributes, ldqInstalled, ldqAction }; + + +LPCWSTR vcsWebSvcExtRoot = L"/LM/W3SVC"; + +// prototypes for private helper functions +static HRESULT AddWebSvcExtToList( + __in SCA_WEBSVCEXT** ppsWseList + ); + +//static HRESULT ScaCheckWebSvcExtValue( +// __in IMSAdminBase* piMetabase, +// __in DWORD dwMDIdentifier +// ); + +static HRESULT ScaWebSvcExtInstall( + __in LPWSTR *pwzWebSvcExtList, + __in DWORD_PTR *pcchWebSvcExtList, + __in SCA_WEBSVCEXT* psWseList + ); + +static HRESULT ScaWebSvcExtUninstall( + __in LPWSTR *pwzWebSvcExtList, + __in const DWORD *pcchWebSvcExtList, + __in SCA_WEBSVCEXT* psWseList + ); + +// functions + +HRESULT __stdcall ScaWebSvcExtRead( + __in SCA_WEBSVCEXT** ppsWseList, + __inout LPWSTR *ppwzCustomActionData + ) +{ + Assert(ppsWseList); + + HRESULT hr = S_OK; + MSIHANDLE hRec; + LPWSTR pwzData = NULL; + INSTALLSTATE isInstalled = INSTALLSTATE_UNKNOWN; + INSTALLSTATE isAction = INSTALLSTATE_UNKNOWN; + SCA_WEBSVCEXT* psWebSvcExt = NULL; + WCA_WRAPQUERY_HANDLE hWrapQuery = NULL; + + hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData); + ExitOnFailure(hr, "Failed to unwrap query for ScaWebSvcExtRead"); + + if (0 == WcaGetQueryRecords(hWrapQuery)) + { + WcaLog(LOGMSG_VERBOSE, "Skipping ScaWebSvcExtRead() because IIsWebServiceExtension data not present"); + ExitFunction1(hr = S_FALSE); + } + + // loop through all the web service extensions + while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec))) + { + // Get the Component first. If the Component is not being modified during + // this transaction, skip processing this whole record. + hr = WcaGetRecordString(hRec, ldqComponent, &pwzData); + ExitOnFailure(hr, "Failed to get Component for WebSvcExt"); + + hr = WcaGetRecordInteger(hRec, ldqInstalled, (int *)&isInstalled); + ExitOnFailure(hr, "Failed to get Component installed state for WebSvcExt"); + + hr = WcaGetRecordInteger(hRec, ldqAction, (int *)&isAction); + ExitOnFailure(hr, "Failed to get Component action state for WebSvcExt"); + + if (!WcaIsInstalling(isInstalled, isAction) && + !WcaIsReInstalling(isInstalled, isAction) && + !WcaIsUninstalling(isInstalled, isAction)) + { + continue; // skip this record. + } + + hr = AddWebSvcExtToList(ppsWseList); + ExitOnFailure(hr, "failed to add element to web svc ext list"); + + psWebSvcExt = *ppsWseList; + Assert(psWebSvcExt); + + psWebSvcExt->isInstalled = isInstalled; + psWebSvcExt->isAction = isAction; + + hr = WcaGetRecordString(hRec, ldqFile, &pwzData); + ExitOnFailure(hr, "Failed to get File for WebSvcExt"); + hr = ::StringCchCopyW(psWebSvcExt->wzFile, countof(psWebSvcExt->wzFile), pwzData); + ExitOnFailure(hr, "Failed to copy File for WebSvcExt"); + + hr = WcaGetRecordString(hRec, ldqDescription, &pwzData); + ExitOnFailure(hr, "Failed to get Description for WebSvcExt"); + hr = ::StringCchCopyW(psWebSvcExt->wzDescription, countof(psWebSvcExt->wzDescription), pwzData); + ExitOnFailure(hr, "Failed to copy Description for WebSvcExt"); + + hr = WcaGetRecordString(hRec, ldqGroup, &pwzData); + ExitOnFailure(hr, "Failed to get Group for WebSvcExt"); + hr = ::StringCchCopyW(psWebSvcExt->wzGroup, countof(psWebSvcExt->wzGroup), pwzData); + ExitOnFailure(hr, "Failed to copy Group for WebSvcExt"); + + hr = WcaGetRecordInteger(hRec, ldqAttributes, &psWebSvcExt->iAttributes); + ExitOnFailure(hr, "Failed to get Attributes for WebSvcExt"); + } + + if (E_NOMOREITEMS == hr) + hr = S_OK; + ExitOnFailure(hr, "Failure while processing WebSvcExt"); + +LExit: + WcaFinishUnwrapQuery(hWrapQuery); + + ReleaseStr(pwzData); + + return hr; +} + + +// Commit does both install and uninstall +HRESULT __stdcall ScaWebSvcExtCommit( + __in IMSAdminBase* piMetabase, + __in SCA_WEBSVCEXT* psWseList + ) +{ + Assert(piMetabase); + + HRESULT hr = S_OK; + METADATA_RECORD mr; + + LPWSTR wzWebSvcExtList = NULL; + DWORD cbWebSvcExtList = 0; + DWORD_PTR cchWebSvcExtList = 0; + + if (!psWseList) + { + WcaLog(LOGMSG_VERBOSE, "Skipping ScaWebSvcExtCommit() because there are no web service extensions in the list"); + ExitFunction(); + } + + // Get current set of web service extensions. + ::ZeroMemory(&mr, sizeof(mr)); + mr.dwMDIdentifier = MD_WEB_SVC_EXT_RESTRICTION_LIST; + mr.dwMDAttributes = 0; + mr.dwMDUserType = IIS_MD_UT_SERVER; + mr.dwMDDataType = ALL_METADATA; + mr.pbMDData = NULL; + mr.dwMDDataLen = 0; + + hr = piMetabase->GetData(METADATA_MASTER_ROOT_HANDLE, vcsWebSvcExtRoot, &mr, &cbWebSvcExtList); + if (MD_ERROR_DATA_NOT_FOUND == hr) + { + WcaLog(LOGMSG_VERBOSE, "Skipping ScaWebSvcExtCommit() because WebSvcExtRestrictionList value is not present"); + ExitFunction1(hr = S_FALSE); + } + else if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr) + { + // cchWebSvcExtList is returned in bytes. Convert to WCHAR size to call StrAlloc + cchWebSvcExtList = cbWebSvcExtList / sizeof(WCHAR); + hr = StrAlloc(&wzWebSvcExtList, cchWebSvcExtList); + ExitOnFailure(hr, "Failed allocating space for web service extensions"); + } + else + { + ExitOnFailure(hr, "Failed retrieving web service extensions"); + } + + mr.pbMDData = (unsigned char*)wzWebSvcExtList; + mr.dwMDDataLen = cbWebSvcExtList; + + hr = piMetabase->GetData(METADATA_MASTER_ROOT_HANDLE, vcsWebSvcExtRoot, &mr, &cbWebSvcExtList); + ExitOnFailure(hr, "Failed retrieving web service extensions"); + + // Make changes to local copy of metabase + while (psWseList) + { + if (WcaIsInstalling(psWseList->isInstalled, psWseList->isAction)) + { + hr = ScaWebSvcExtInstall(&wzWebSvcExtList, &cchWebSvcExtList, psWseList); + ExitOnFailure(hr, "Failed to install Web Service extension"); + } + else if (WcaIsUninstalling(psWseList->isInstalled, psWseList->isAction)) + { + hr = ScaWebSvcExtUninstall(&wzWebSvcExtList, (DWORD *)&cchWebSvcExtList, psWseList); + ExitOnFailure(hr, "Failed to uninstall Web Service extension"); + } + + psWseList = psWseList->psWseNext; + } + + // Write Metabase + hr = ScaWriteMetabaseValue(piMetabase, vcsWebSvcExtRoot, NULL, MD_WEB_SVC_EXT_RESTRICTION_LIST, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, wzWebSvcExtList); + ExitOnFailure(hr, "Failed to write WebServiceExtensions: '%ls'", wzWebSvcExtList); + +LExit: + ReleaseStr(wzWebSvcExtList); + + return hr; +} + + +static HRESULT ScaWebSvcExtInstall( + __in LPWSTR *ppwzWebSvcExtList, + __in DWORD_PTR *pcchWebSvcExtList, + __in SCA_WEBSVCEXT* psWseList + ) +{ + Assert( ppwzWebSvcExtList && pcchWebSvcExtList && psWseList); + Assert(*ppwzWebSvcExtList); + + HRESULT hr = S_OK; + + LPWSTR pwzWebSvcExt = NULL; + int iAllow; + int iUiDeletable; + + BOOL fAlreadyExists = FALSE; + DWORD_PTR dwIndex = 0xFFFFFFFF; + LPCWSTR wzFoundString = NULL; + + // Check if it's already in there + hr = MultiSzFindSubstring(*ppwzWebSvcExtList, psWseList->wzFile, &dwIndex, &wzFoundString); + ExitOnFailure(hr, "failed to search for string:%ls in web service extension MULTISZ", psWseList->wzFile); + + if (S_FALSE != hr && NULL != wcsstr(wzFoundString, psWseList->wzGroup) && NULL != wcsstr(wzFoundString, psWseList->wzDescription)) + { + fAlreadyExists = TRUE; + } + + // Construct the single string in the format required for the WebSvc Ext list in metabase + iAllow = (psWseList->iAttributes & 1); + iUiDeletable = ((psWseList->iAttributes >> 1) & 1); + hr = StrAllocFormatted(&pwzWebSvcExt, L"%d,%s,%d,%s,%s", iAllow, psWseList->wzFile, iUiDeletable, psWseList->wzGroup, psWseList->wzDescription); + ExitOnFailure(hr, "Failure allocating space for web service extensions"); + + if (fAlreadyExists) + { + hr = MultiSzReplaceString(ppwzWebSvcExtList, dwIndex, pwzWebSvcExt); + ExitOnFailure(hr, "failed to update web service extension string: %ls", pwzWebSvcExt); + } + else + { + hr = MultiSzPrepend(ppwzWebSvcExtList, pcchWebSvcExtList, pwzWebSvcExt); + ExitOnFailure(hr, "failed to prepend web service extension string: %ls", pwzWebSvcExt); + } + +LExit: + ReleaseStr(pwzWebSvcExt); + + return hr; +} + + +static HRESULT ScaWebSvcExtUninstall( + __in LPWSTR *ppwzWebSvcExtList, + __in const DWORD* /*pcchWebSvcExtList*/, + __in SCA_WEBSVCEXT* psWseList + ) +{ + Assert(ppwzWebSvcExtList && *ppwzWebSvcExtList && psWseList); + Assert(*ppwzWebSvcExtList); + + HRESULT hr = S_OK; + DWORD_PTR dwIndex = 0xFFFFFFFF; + LPCWSTR wzFoundString = NULL; + + // Find the string to remove + hr = MultiSzFindSubstring(*ppwzWebSvcExtList, psWseList->wzFile, &dwIndex, &wzFoundString); + ExitOnFailure(hr, "failed to search for string:%ls in web service extension MULTISZ", psWseList->wzFile); + + // If we found a match (ignoring the Allow and Deletable flags) + if (S_FALSE != hr && NULL != wcsstr(wzFoundString, psWseList->wzGroup) && NULL != wcsstr(wzFoundString, psWseList->wzDescription)) + { + hr = MultiSzRemoveString(ppwzWebSvcExtList, dwIndex); + ExitOnFailure(hr, "failed to remove string: %d from web service extension MULTISZ", dwIndex); + } + +LExit: + return hr; +} + + +//static HRESULT ScaCheckWebSvcExtValue( +// __in IMSAdminBase* piMetabase, +// __in DWORD dwMDIdentifier +// ) +//{ +// if (!piMetabase) +// { +// return E_INVALIDARG; +// } +// +// HRESULT hr = S_OK; +// METADATA_RECORD mr = { 0 }; +// DWORD cch = 0; +// +// mr.dwMDIdentifier = dwMDIdentifier; +// mr.dwMDUserType = IIS_MD_UT_SERVER; +// +// hr = piMetabase->GetData(METADATA_MASTER_ROOT_HANDLE, vcsWebSvcExtRoot, &mr, &cch); +// if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr) +// { +// hr = S_OK; +// } +// else if (MD_ERROR_DATA_NOT_FOUND == hr) +// { +// hr = S_FALSE; +// } +// +// return hr; +//} + + +void ScaWebSvcExtFreeList( + __in SCA_WEBSVCEXT* psWseList + ) +{ + SCA_WEBSVCEXT* psWseDelete = psWseList; + while (psWseList) + { + psWseDelete = psWseList; + psWseList = psWseList->psWseNext; + MemFree(psWseDelete); + } +} + + +static HRESULT AddWebSvcExtToList( + __in SCA_WEBSVCEXT** ppsWseList + ) +{ + HRESULT hr = S_OK; + + SCA_WEBSVCEXT* psWse = static_cast(MemAlloc(sizeof(SCA_WEBSVCEXT), TRUE)); + ExitOnNull(psWse, hr, E_OUTOFMEMORY, "failed to allocate element for web svc ext list"); + + psWse->psWseNext = *ppsWseList; + *ppsWseList = psWse; + +LExit: + return hr; +} -- cgit v1.2.3-55-g6feb