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/scaapppool.cpp | 594 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 594 insertions(+) create mode 100644 src/ca/scaapppool.cpp (limited to 'src/ca/scaapppool.cpp') diff --git a/src/ca/scaapppool.cpp b/src/ca/scaapppool.cpp new file mode 100644 index 00000000..781c55ca --- /dev/null +++ b/src/ca/scaapppool.cpp @@ -0,0 +1,594 @@ +// 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" + +/*------------------------------------------------------------------ +AppPool table: + +Column Type Nullable Example Value +AppPool s72 No TestPool +Name s72 No "TestPool" +Component_ s72 No ComponentName +Attributes i2 No 8 (APATTR_OTHERUSER) +User_ s72 Yes UserKey +RecycleMinutes i2 Yes 500 +RecycleRequests i2 Yes 5000 +RecycleTimes s72 Yes "1:45,13:30,22:00" +IdleTimeout i2 Yes 15 +QueueLimit i2 Yes 500 +CPUMon s72 Yes "65,500,1" (65% CPU usage, 500 minutes, Shutdown Action) +MaxProc i2 Yes 5 +ManagedRuntimeVersion s72 Yes "v2.0" +ManagedPipelineMode s72 Yes "Integrated" + +Notes: +RecycleTimes is a comma delimeted list of times. CPUMon is a +comma delimeted list of the following format: +,,. The values for +Action are 1 (Shutdown) and 0 (No Action). + +------------------------------------------------------------------*/ + +enum eAppPoolQuery { apqAppPool = 1, apqName, apqComponent, apqAttributes, apqUser, apqRecycleMinutes, apqRecycleRequests, apqRecycleTimes, apqVirtualMemory, apqPrivateMemory, apqIdleTimeout, apqQueueLimit, apqCpuMon, apqMaxProc, apqManagedRuntimeVersion, apqManagedPipelineMode, apqInstalled, apqAction }; + +enum eComponentAttrQuery { caqComponent = 1, caqAttributes }; + +// prototypes +static HRESULT AppPoolExists( + __in IMSAdminBase* piMetabase, + __in LPCWSTR wzAppPool + ); + +// functions + +void ScaAppPoolFreeList( + __in SCA_APPPOOL* psapList + ) +{ + SCA_APPPOOL* psapDelete = psapList; + while (psapList) + { + psapDelete = psapList; + psapList = psapList->psapNext; + + MemFree(psapDelete); + } +} + + +HRESULT ScaAppPoolRead( + __inout SCA_APPPOOL** ppsapList, + __in WCA_WRAPQUERY_HANDLE hUserQuery, + __inout LPWSTR *ppwzCustomActionData + ) +{ + Assert(ppsapList); + + HRESULT hr = S_OK; + + MSIHANDLE hRec, hRecComp; + LPWSTR pwzData = NULL; + SCA_APPPOOL* psap = NULL; + WCA_WRAPQUERY_HANDLE hAppPoolQuery = NULL; + WCA_WRAPQUERY_HANDLE hComponentQuery = NULL; + + hr = WcaBeginUnwrapQuery(&hAppPoolQuery, ppwzCustomActionData); + ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead"); + + if (0 == WcaGetQueryRecords(hAppPoolQuery)) + { + WcaLog(LOGMSG_VERBOSE, "Skipping ScaAppPoolRead() - required table not present"); + ExitFunction1(hr = S_FALSE); + } + + hr = WcaBeginUnwrapQuery(&hComponentQuery, ppwzCustomActionData); + ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead"); + + // loop through all the AppPools + while (S_OK == (hr = WcaFetchWrappedRecord(hAppPoolQuery, &hRec))) + { + // Add this record's information into the list of things to process. + hr = AddAppPoolToList(ppsapList); + ExitOnFailure(hr, "failed to add app pool to app pool list"); + + psap = *ppsapList; + + hr = WcaGetRecordString(hRec, apqComponent, &pwzData); + ExitOnFailure(hr, "failed to get AppPool.Component"); + + if (pwzData && *pwzData) + { + psap->fHasComponent = TRUE; + + hr = ::StringCchCopyW(psap->wzComponent, countof(psap->wzComponent), pwzData); + ExitOnFailure(hr, "failed to copy component name: %ls", pwzData); + + hr = WcaGetRecordInteger(hRec, apqInstalled, (int *)&psap->isInstalled); + ExitOnFailure(hr, "Failed to get Component installed state for app pool"); + + hr = WcaGetRecordInteger(hRec, apqAction, (int *)&psap->isAction); + ExitOnFailure(hr, "Failed to get Component action state for app pool"); + + WcaFetchWrappedReset(hComponentQuery); + hr = WcaFetchWrappedRecordWhereString(hComponentQuery, caqComponent, psap->wzComponent, &hRecComp); + ExitOnFailure(hr, "Failed to fetch Component.Attributes for Component '%ls'", psap->wzComponent); + + hr = WcaGetRecordInteger(hRecComp, caqAttributes, &psap->iCompAttributes); + ExitOnFailure(hr, "failed to get Component.Attributes"); + } + + hr = WcaGetRecordString(hRec, apqAppPool, &pwzData); + ExitOnFailure(hr, "failed to get AppPool.AppPool"); + hr = ::StringCchCopyW(psap->wzAppPool, countof(psap->wzAppPool), pwzData); + ExitOnFailure(hr, "failed to copy AppPool name: %ls", pwzData); + + hr = WcaGetRecordString(hRec, apqName, &pwzData); + ExitOnFailure(hr, "failed to get AppPool.Name"); + hr = ::StringCchCopyW(psap->wzName, countof(psap->wzName), pwzData); + ExitOnFailure(hr, "failed to copy app pool name: %ls", pwzData); + hr = ::StringCchPrintfW(psap->wzKey, countof(psap->wzKey), L"/LM/W3SVC/AppPools/%s", pwzData); + ExitOnFailure(hr, "failed to format app pool key name"); + + hr = WcaGetRecordInteger(hRec, apqAttributes, &psap->iAttributes); + ExitOnFailure(hr, "failed to get AppPool.Attributes"); + + hr = WcaGetRecordString(hRec, apqUser, &pwzData); + ExitOnFailure(hr, "failed to get AppPool.User"); + hr = ScaGetUserDeferred(pwzData, hUserQuery, &psap->suUser); + ExitOnFailure(hr, "failed to get user: %ls", pwzData); + + hr = WcaGetRecordInteger(hRec, apqRecycleRequests, &psap->iRecycleRequests); + ExitOnFailure(hr, "failed to get AppPool.RecycleRequests"); + + hr = WcaGetRecordInteger(hRec, apqRecycleMinutes, &psap->iRecycleMinutes); + ExitOnFailure(hr, "failed to get AppPool.Minutes"); + + hr = WcaGetRecordString(hRec, apqRecycleTimes, &pwzData); + ExitOnFailure(hr, "failed to get AppPool.RecycleTimes"); + hr = ::StringCchCopyW(psap->wzRecycleTimes, countof(psap->wzRecycleTimes), pwzData); + ExitOnFailure(hr, "failed to copy recycle value: %ls", pwzData); + + hr = WcaGetRecordInteger(hRec, apqVirtualMemory, &psap->iVirtualMemory); + ExitOnFailure(hr, "failed to get AppPool.VirtualMemory"); + + hr = WcaGetRecordInteger(hRec, apqPrivateMemory, &psap->iPrivateMemory); + ExitOnFailure(hr, "failed to get AppPool.PrivateMemory"); + + hr = WcaGetRecordInteger(hRec, apqIdleTimeout, &psap->iIdleTimeout); + ExitOnFailure(hr, "failed to get AppPool.IdleTimeout"); + + hr = WcaGetRecordInteger(hRec, apqQueueLimit, &psap->iQueueLimit); + ExitOnFailure(hr, "failed to get AppPool.QueueLimit"); + + hr = WcaGetRecordString(hRec, apqCpuMon, &pwzData); + ExitOnFailure(hr, "failed to get AppPool.CPUMon"); + hr = ::StringCchCopyW(psap->wzCpuMon, countof(psap->wzCpuMon), pwzData); + ExitOnFailure(hr, "failed to copy cpu monitor value: %ls", pwzData); + + hr = WcaGetRecordInteger(hRec, apqMaxProc, &psap->iMaxProcesses); + ExitOnFailure(hr, "failed to get AppPool.MaxProc"); + + hr = WcaGetRecordString(hRec, apqManagedRuntimeVersion, &pwzData); + ExitOnFailure(hr, "failed to get AppPool.ManagedRuntimeVersion"); + hr = ::StringCchCopyW(psap->wzManagedRuntimeVersion, countof(psap->wzManagedRuntimeVersion), pwzData); + ExitOnFailure(hr, "failed to copy ManagedRuntimeVersion value: %ls", pwzData); + + hr = WcaGetRecordString(hRec, apqManagedPipelineMode, &pwzData); + ExitOnFailure(hr, "failed to get AppPool.ManagedPipelineMode"); + hr = ::StringCchCopyW(psap->wzManagedPipelineMode, countof(psap->wzManagedPipelineMode), pwzData); + ExitOnFailure(hr, "failed to copy ManagedPipelineMode value: %ls", pwzData); + + } + + if (E_NOMOREITEMS == hr) + { + hr = S_OK; + } + ExitOnFailure(hr, "failure while processing AppPools"); + +LExit: + WcaFinishUnwrapQuery(hAppPoolQuery); + WcaFinishUnwrapQuery(hComponentQuery); + + ReleaseStr(pwzData); + return hr; +} + + +HRESULT ScaFindAppPool( + __in IMSAdminBase* piMetabase, + __in LPCWSTR wzAppPool, + __out_ecount(cchName) LPWSTR wzName, + __in DWORD cchName, + __in SCA_APPPOOL *psapList + ) +{ + Assert(piMetabase && wzAppPool && *wzAppPool && wzName && *wzName); + + HRESULT hr = S_OK; + + // check memory first + SCA_APPPOOL* psap = psapList; + for (; psap; psap = psap->psapNext) + { + if (0 == lstrcmpW(psap->wzAppPool, wzAppPool)) + { + break; + } + } + ExitOnNull(psap, hr, HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Could not find the app pool: %ls", wzAppPool); + + // copy the web app pool name + hr = ::StringCchCopyW(wzName, cchName, psap->wzName); + ExitOnFailure(hr, "failed to copy app pool name while finding app pool: %ls", psap->wzName); + + // if it's not being installed now, check if it exists already + if (!psap->fHasComponent) + { + hr = AppPoolExists(piMetabase, psap->wzName); + ExitOnFailure(hr, "failed to check for existence of app pool: %ls", psap->wzName); + } + +LExit: + return hr; +} + + +static HRESULT AppPoolExists( + __in IMSAdminBase* piMetabase, + __in LPCWSTR wzAppPool + ) +{ + Assert(piMetabase && wzAppPool && *wzAppPool); + + HRESULT hr = S_OK; + WCHAR wzSubKey[METADATA_MAX_NAME_LEN]; + + for (DWORD dwIndex = 0; SUCCEEDED(hr); ++dwIndex) + { + hr = piMetabase->EnumKeys(METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC/AppPools", wzSubKey, dwIndex); + if (SUCCEEDED(hr) && 0 == lstrcmpW(wzSubKey, wzAppPool)) + { + hr = S_OK; + break; + } + } + + if (E_NOMOREITEMS == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) + { + hr = S_FALSE; + } + + return hr; +} + + +HRESULT ScaAppPoolInstall( + __in IMSAdminBase* piMetabase, + __in SCA_APPPOOL* psapList + ) +{ + Assert(piMetabase); + + HRESULT hr = S_OK; + + for (SCA_APPPOOL* psap = psapList; psap; psap = psap->psapNext) + { + // if we are installing the app pool + if (psap->fHasComponent && WcaIsInstalling(psap->isInstalled, psap->isAction)) + { + hr = ScaWriteAppPool(piMetabase, psap); + ExitOnFailure(hr, "failed to write AppPool '%ls' to metabase", psap->wzAppPool); + } + } + +LExit: + return hr; +} + + +HRESULT ScaAppPoolUninstall( + __in IMSAdminBase* piMetabase, + __in SCA_APPPOOL* psapList + ) +{ + Assert(piMetabase); + + HRESULT hr = S_OK; + + for (SCA_APPPOOL* psap = psapList; psap; psap = psap->psapNext) + { + // if we are uninstalling the app pool + if (psap->fHasComponent && WcaIsUninstalling(psap->isInstalled, psap->isAction)) + { + hr = ScaRemoveAppPool(piMetabase, psap); + ExitOnFailure(hr, "Failed to remove AppPool '%ls' from metabase", psap->wzAppPool); + } + } + +LExit: + return hr; +} + + +HRESULT ScaWriteAppPool( + __in IMSAdminBase* piMetabase, + __in SCA_APPPOOL* psap + ) +{ + Assert(piMetabase && psap); + + HRESULT hr = S_OK; + DWORD dwIdentity = 0xFFFFFFFF; + BOOL fExists = FALSE; + LPWSTR pwzValue = NULL; + LPWSTR wz = NULL; + + hr = AppPoolExists(piMetabase, psap->wzName); + ExitOnFailure(hr, "failed to check if app pool already exists"); + if (S_FALSE == hr) + { + // didn't find the AppPool key, so we need to create it + hr = ScaCreateMetabaseKey(piMetabase, psap->wzKey, L""); + ExitOnFailure(hr, "failed to create AppPool key: %ls", psap->wzKey); + + // mark it as an AppPool + hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsApplicationPool"); + ExitOnFailure(hr, "failed to mark key as AppPool key: %ls", psap->wzKey); + + // TODO: Make this an Attribute? + // set autostart value + hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_AUTO_START, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)1); + ExitOnFailure(hr, "failed to mark key as AppPool key: %ls", psap->wzKey); + } + else + { + fExists = TRUE; + } + + // + // Set the AppPool Recycling Tab + // + if (MSI_NULL_INTEGER != psap->iRecycleMinutes) + { + hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_TIME, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iRecycleMinutes)); + ExitOnFailure(hr, "failed to set periodic restart time"); + } + + if (MSI_NULL_INTEGER != psap->iRecycleRequests) + { + hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_REQUEST_COUNT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iRecycleRequests)); + ExitOnFailure(hr, "failed to set periodic restart request count"); + } + + if (*psap->wzRecycleTimes) + { + // Add another NULL' onto pwz since it's a 'MULTISZ' + hr = StrAllocString(&pwzValue, psap->wzRecycleTimes, 0); + ExitOnFailure(hr, "failed to allocate string for MULTISZ"); + hr = StrAllocConcat(&pwzValue, L"\0", 1); + ExitOnFailure(hr, "failed to add second null to RecycleTime multisz"); + + // Replace the commas with NULLs + wz = pwzValue; + while (NULL != (wz = wcschr(wz, L','))) + { + *wz = L'\0'; + ++wz; + } + + hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_SCHEDULE, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, (LPVOID)pwzValue); + ExitOnFailure(hr, "failed to set periodic restart schedule"); + } + + if (MSI_NULL_INTEGER != psap->iVirtualMemory) + { + hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_MEMORY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iVirtualMemory)); + ExitOnFailure(hr, "failed to set periodic restart memory count"); + } + + if (MSI_NULL_INTEGER != psap->iPrivateMemory) + { + hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_PRIVATE_MEMORY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iPrivateMemory)); + ExitOnFailure(hr, "failed to set periodic restart private memory count"); + } + + + // + // Set AppPool Performance Tab + // + if (MSI_NULL_INTEGER != psap->iIdleTimeout) + { + hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_IDLE_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iIdleTimeout)); + ExitOnFailure(hr, "failed to set idle timeout value"); + } + + if (MSI_NULL_INTEGER != psap->iQueueLimit) + { + hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_UL_APPPOOL_QUEUE_LENGTH, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iQueueLimit)); + ExitOnFailure(hr, "failed to set request queue limit value"); + } + + if (*psap->wzCpuMon) + { + hr = StrAllocString(&pwzValue, psap->wzCpuMon, 0); + ExitOnFailure(hr, "failed to allocate CPUMonitor string"); + + DWORD dwPercent = 0; + DWORD dwRefreshMinutes = 0; + DWORD dwAction = 0; + + dwPercent = wcstoul(pwzValue, &wz, 10); + if (100 < dwPercent) + { + ExitOnFailure(hr = E_INVALIDARG, "invalid maximum cpu percentage value: %d", dwPercent); + } + if (wz && L',' == *wz) + { + ++wz; + dwRefreshMinutes = wcstoul(wz, &wz, 10); + if (wz && L',' == *wz) + { + ++wz; + dwAction = wcstoul(wz, &wz, 10); + } + } + + if (dwPercent) + { + hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_CPU_LIMIT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)(dwPercent * 1000))); + ExitOnFailure(hr, "failed to set CPU percentage max"); + } + if (dwRefreshMinutes) + { + hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_CPU_RESET_INTERVAL, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwRefreshMinutes)); + ExitOnFailure(hr, "failed to set refresh CPU minutes"); + } + if (dwAction) + { + // 0 = No Action + // 1 = Shutdown + hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_CPU_ACTION, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwAction)); + ExitOnFailure(hr, "failed to set CPU action"); + } + } + + if (MSI_NULL_INTEGER != psap->iMaxProcesses) + { + hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_MAX_PROCESS_COUNT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iMaxProcesses)); + ExitOnFailure(hr, "failed to set web garden maximum worker processes"); + } + + // TODO: Health Tab if anyone wants it? + + // + // Set the AppPool Identity tab + // + if (psap->iAttributes & APATTR_NETSERVICE) + { + dwIdentity = MD_APPPOOL_IDENTITY_TYPE_NETWORKSERVICE; + } + else if (psap->iAttributes & APATTR_LOCSERVICE) + { + dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSERVICE; + } + else if (psap->iAttributes & APATTR_LOCSYSTEM) + { + dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSYSTEM; + } + else if (psap->iAttributes & APATTR_OTHERUSER) + { + if (!*psap->suUser.wzDomain || CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzDomain, -1, L".", -1)) + { + if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"NetworkService", -1)) + { + dwIdentity = MD_APPPOOL_IDENTITY_TYPE_NETWORKSERVICE; + } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"LocalService", -1)) + { + dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSERVICE; + } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"LocalSystem", -1)) + { + dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSYSTEM; + } + else + { + dwIdentity = MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER; + } + } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzDomain, -1, L"NT AUTHORITY", -1)) + { + if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"NETWORK SERVICE", -1)) + { + dwIdentity = MD_APPPOOL_IDENTITY_TYPE_NETWORKSERVICE; + } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"SERVICE", -1)) + { + dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSERVICE; + } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"SYSTEM", -1)) + { + dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSYSTEM; + } + else + { + dwIdentity = MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER; + } + } + else + { + dwIdentity = MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER; + } + } + + if (-1 != dwIdentity) + { + hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_IDENTITY_TYPE, METADATA_INHERIT , IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwIdentity)); + ExitOnFailure(hr, "failed to set app pool identity"); + + if (MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER == dwIdentity) + { + if (*psap->suUser.wzDomain) + { + hr = StrAllocFormatted(&pwzValue, L"%s\\%s", psap->suUser.wzDomain, psap->suUser.wzName); + ExitOnFailure(hr, "failed to format user name: %ls domain: %ls", psap->suUser.wzName, psap->suUser.wzDomain); + } + else + { + hr = StrAllocFormatted(&pwzValue, L"%s", psap->suUser.wzName); + ExitOnFailure(hr, "failed to format user name: %ls", psap->suUser.wzName); + } + + hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_WAM_USER_NAME, METADATA_INHERIT , IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)pwzValue); + ExitOnFailure(hr, "failed to set app pool identity name"); + + hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_WAM_PWD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)psap->suUser.wzPassword); + ExitOnFailure(hr, "failed to set app pool identity password"); + } + } + +LExit: + ReleaseStr(pwzValue); + + return hr; +} + + +HRESULT ScaRemoveAppPool( + __in IMSAdminBase* piMetabase, + __in SCA_APPPOOL* psap + ) +{ + Assert(piMetabase && psap); + + HRESULT hr = S_OK; + + // simply remove the root key and everything else is pulled at the same time + if (0 != lstrlenW(psap->wzKey)) + { + hr = ScaDeleteMetabaseKey(piMetabase, psap->wzKey, L""); + ExitOnFailure(hr, "failed to delete AppPool key: %ls", psap->wzKey); + } + + // TODO: Maybe check to make sure any web sites that are using this AppPool are put back in the 'DefaultAppPool' + +LExit: + return hr; +} + + +HRESULT AddAppPoolToList( + __in SCA_APPPOOL** ppsapList + ) +{ + HRESULT hr = S_OK; + SCA_APPPOOL* psap = static_cast(MemAlloc(sizeof(SCA_APPPOOL), TRUE)); + ExitOnNull(psap, hr, E_OUTOFMEMORY, "failed to allocate memory for new element in app pool list"); + + psap->psapNext = *ppsapList; + *ppsapList = psap; + +LExit: + return hr; +} -- cgit v1.2.3-55-g6feb