| 1 | // 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. |
| 2 | |
| 3 | #include "precomp.h" |
| 4 | |
| 5 | /*------------------------------------------------------------------ |
| 6 | AppPool table: |
| 7 | |
| 8 | Column Type Nullable Example Value |
| 9 | AppPool s72 No TestPool |
| 10 | Name s72 No "TestPool" |
| 11 | Component_ s72 No ComponentName |
| 12 | Attributes i2 No 8 (APATTR_OTHERUSER) |
| 13 | User_ s72 Yes UserKey |
| 14 | RecycleMinutes i2 Yes 500 |
| 15 | RecycleRequests i2 Yes 5000 |
| 16 | RecycleTimes s72 Yes "1:45,13:30,22:00" |
| 17 | IdleTimeout i2 Yes 15 |
| 18 | QueueLimit i2 Yes 500 |
| 19 | CPUMon s72 Yes "65,500,1" (65% CPU usage, 500 minutes, Shutdown Action) |
| 20 | MaxProc i2 Yes 5 |
| 21 | ManagedRuntimeVersion s72 Yes "v2.0" |
| 22 | ManagedPipelineMode s72 Yes "Integrated" |
| 23 | |
| 24 | Notes: |
| 25 | RecycleTimes is a comma delimeted list of times. CPUMon is a |
| 26 | comma delimeted list of the following format: |
| 27 | <percent CPU usage>,<refress minutes>,<Action>. The values for |
| 28 | Action are 1 (Shutdown) and 0 (No Action). |
| 29 | |
| 30 | ------------------------------------------------------------------*/ |
| 31 | |
| 32 | enum eAppPoolQuery { apqAppPool = 1, apqName, apqComponent, apqAttributes, apqUser, apqRecycleMinutes, apqRecycleRequests, apqRecycleTimes, apqVirtualMemory, apqPrivateMemory, apqIdleTimeout, apqQueueLimit, apqCpuMon, apqMaxProc, apqManagedRuntimeVersion, apqManagedPipelineMode, apqInstalled, apqAction }; |
| 33 | |
| 34 | enum eComponentAttrQuery { caqComponent = 1, caqAttributes }; |
| 35 | |
| 36 | // prototypes |
| 37 | static HRESULT AppPoolExists( |
| 38 | __in IMSAdminBase* piMetabase, |
| 39 | __in LPCWSTR wzAppPool |
| 40 | ); |
| 41 | |
| 42 | // functions |
| 43 | |
| 44 | void ScaAppPoolFreeList( |
| 45 | __in SCA_APPPOOL* psapList |
| 46 | ) |
| 47 | { |
| 48 | SCA_APPPOOL* psapDelete = psapList; |
| 49 | while (psapList) |
| 50 | { |
| 51 | psapDelete = psapList; |
| 52 | psapList = psapList->psapNext; |
| 53 | |
| 54 | MemFree(psapDelete); |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | |
| 59 | HRESULT ScaAppPoolRead( |
| 60 | __inout SCA_APPPOOL** ppsapList, |
| 61 | __in WCA_WRAPQUERY_HANDLE hUserQuery, |
| 62 | __inout LPWSTR *ppwzCustomActionData |
| 63 | ) |
| 64 | { |
| 65 | Assert(ppsapList); |
| 66 | |
| 67 | HRESULT hr = S_OK; |
| 68 | |
| 69 | MSIHANDLE hRec, hRecComp; |
| 70 | LPWSTR pwzData = NULL; |
| 71 | SCA_APPPOOL* psap = NULL; |
| 72 | WCA_WRAPQUERY_HANDLE hAppPoolQuery = NULL; |
| 73 | WCA_WRAPQUERY_HANDLE hComponentQuery = NULL; |
| 74 | |
| 75 | hr = WcaBeginUnwrapQuery(&hAppPoolQuery, ppwzCustomActionData); |
| 76 | ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead"); |
| 77 | |
| 78 | if (0 == WcaGetQueryRecords(hAppPoolQuery)) |
| 79 | { |
| 80 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaAppPoolRead() - required table not present"); |
| 81 | ExitFunction1(hr = S_FALSE); |
| 82 | } |
| 83 | |
| 84 | hr = WcaBeginUnwrapQuery(&hComponentQuery, ppwzCustomActionData); |
| 85 | ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead"); |
| 86 | |
| 87 | // loop through all the AppPools |
| 88 | while (S_OK == (hr = WcaFetchWrappedRecord(hAppPoolQuery, &hRec))) |
| 89 | { |
| 90 | // Add this record's information into the list of things to process. |
| 91 | hr = AddAppPoolToList(ppsapList); |
| 92 | ExitOnFailure(hr, "failed to add app pool to app pool list"); |
| 93 | |
| 94 | psap = *ppsapList; |
| 95 | |
| 96 | hr = WcaGetRecordString(hRec, apqComponent, &pwzData); |
| 97 | ExitOnFailure(hr, "failed to get AppPool.Component"); |
| 98 | |
| 99 | if (pwzData && *pwzData) |
| 100 | { |
| 101 | psap->fHasComponent = TRUE; |
| 102 | |
| 103 | hr = ::StringCchCopyW(psap->wzComponent, countof(psap->wzComponent), pwzData); |
| 104 | ExitOnFailure(hr, "failed to copy component name: %ls", pwzData); |
| 105 | |
| 106 | hr = WcaGetRecordInteger(hRec, apqInstalled, (int *)&psap->isInstalled); |
| 107 | ExitOnFailure(hr, "Failed to get Component installed state for app pool"); |
| 108 | |
| 109 | hr = WcaGetRecordInteger(hRec, apqAction, (int *)&psap->isAction); |
| 110 | ExitOnFailure(hr, "Failed to get Component action state for app pool"); |
| 111 | |
| 112 | WcaFetchWrappedReset(hComponentQuery); |
| 113 | hr = WcaFetchWrappedRecordWhereString(hComponentQuery, caqComponent, psap->wzComponent, &hRecComp); |
| 114 | ExitOnFailure(hr, "Failed to fetch Component.Attributes for Component '%ls'", psap->wzComponent); |
| 115 | |
| 116 | hr = WcaGetRecordInteger(hRecComp, caqAttributes, &psap->iCompAttributes); |
| 117 | ExitOnFailure(hr, "failed to get Component.Attributes"); |
| 118 | } |
| 119 | |
| 120 | hr = WcaGetRecordString(hRec, apqAppPool, &pwzData); |
| 121 | ExitOnFailure(hr, "failed to get AppPool.AppPool"); |
| 122 | hr = ::StringCchCopyW(psap->wzAppPool, countof(psap->wzAppPool), pwzData); |
| 123 | ExitOnFailure(hr, "failed to copy AppPool name: %ls", pwzData); |
| 124 | |
| 125 | hr = WcaGetRecordString(hRec, apqName, &pwzData); |
| 126 | ExitOnFailure(hr, "failed to get AppPool.Name"); |
| 127 | hr = ::StringCchCopyW(psap->wzName, countof(psap->wzName), pwzData); |
| 128 | ExitOnFailure(hr, "failed to copy app pool name: %ls", pwzData); |
| 129 | hr = ::StringCchPrintfW(psap->wzKey, countof(psap->wzKey), L"/LM/W3SVC/AppPools/%s", pwzData); |
| 130 | ExitOnFailure(hr, "failed to format app pool key name"); |
| 131 | |
| 132 | hr = WcaGetRecordInteger(hRec, apqAttributes, &psap->iAttributes); |
| 133 | ExitOnFailure(hr, "failed to get AppPool.Attributes"); |
| 134 | |
| 135 | hr = WcaGetRecordString(hRec, apqUser, &pwzData); |
| 136 | ExitOnFailure(hr, "failed to get AppPool.User"); |
| 137 | hr = ScaGetUserDeferred(pwzData, hUserQuery, &psap->suUser); |
| 138 | ExitOnFailure(hr, "failed to get user: %ls", pwzData); |
| 139 | |
| 140 | hr = WcaGetRecordInteger(hRec, apqRecycleRequests, &psap->iRecycleRequests); |
| 141 | ExitOnFailure(hr, "failed to get AppPool.RecycleRequests"); |
| 142 | |
| 143 | hr = WcaGetRecordInteger(hRec, apqRecycleMinutes, &psap->iRecycleMinutes); |
| 144 | ExitOnFailure(hr, "failed to get AppPool.Minutes"); |
| 145 | |
| 146 | hr = WcaGetRecordString(hRec, apqRecycleTimes, &pwzData); |
| 147 | ExitOnFailure(hr, "failed to get AppPool.RecycleTimes"); |
| 148 | hr = ::StringCchCopyW(psap->wzRecycleTimes, countof(psap->wzRecycleTimes), pwzData); |
| 149 | ExitOnFailure(hr, "failed to copy recycle value: %ls", pwzData); |
| 150 | |
| 151 | hr = WcaGetRecordInteger(hRec, apqVirtualMemory, &psap->iVirtualMemory); |
| 152 | ExitOnFailure(hr, "failed to get AppPool.VirtualMemory"); |
| 153 | |
| 154 | hr = WcaGetRecordInteger(hRec, apqPrivateMemory, &psap->iPrivateMemory); |
| 155 | ExitOnFailure(hr, "failed to get AppPool.PrivateMemory"); |
| 156 | |
| 157 | hr = WcaGetRecordInteger(hRec, apqIdleTimeout, &psap->iIdleTimeout); |
| 158 | ExitOnFailure(hr, "failed to get AppPool.IdleTimeout"); |
| 159 | |
| 160 | hr = WcaGetRecordInteger(hRec, apqQueueLimit, &psap->iQueueLimit); |
| 161 | ExitOnFailure(hr, "failed to get AppPool.QueueLimit"); |
| 162 | |
| 163 | hr = WcaGetRecordString(hRec, apqCpuMon, &pwzData); |
| 164 | ExitOnFailure(hr, "failed to get AppPool.CPUMon"); |
| 165 | hr = ::StringCchCopyW(psap->wzCpuMon, countof(psap->wzCpuMon), pwzData); |
| 166 | ExitOnFailure(hr, "failed to copy cpu monitor value: %ls", pwzData); |
| 167 | |
| 168 | hr = WcaGetRecordInteger(hRec, apqMaxProc, &psap->iMaxProcesses); |
| 169 | ExitOnFailure(hr, "failed to get AppPool.MaxProc"); |
| 170 | |
| 171 | hr = WcaGetRecordString(hRec, apqManagedRuntimeVersion, &pwzData); |
| 172 | ExitOnFailure(hr, "failed to get AppPool.ManagedRuntimeVersion"); |
| 173 | hr = ::StringCchCopyW(psap->wzManagedRuntimeVersion, countof(psap->wzManagedRuntimeVersion), pwzData); |
| 174 | ExitOnFailure(hr, "failed to copy ManagedRuntimeVersion value: %ls", pwzData); |
| 175 | |
| 176 | hr = WcaGetRecordString(hRec, apqManagedPipelineMode, &pwzData); |
| 177 | ExitOnFailure(hr, "failed to get AppPool.ManagedPipelineMode"); |
| 178 | hr = ::StringCchCopyW(psap->wzManagedPipelineMode, countof(psap->wzManagedPipelineMode), pwzData); |
| 179 | ExitOnFailure(hr, "failed to copy ManagedPipelineMode value: %ls", pwzData); |
| 180 | |
| 181 | } |
| 182 | |
| 183 | if (E_NOMOREITEMS == hr) |
| 184 | { |
| 185 | hr = S_OK; |
| 186 | } |
| 187 | ExitOnFailure(hr, "failure while processing AppPools"); |
| 188 | |
| 189 | LExit: |
| 190 | WcaFinishUnwrapQuery(hAppPoolQuery); |
| 191 | WcaFinishUnwrapQuery(hComponentQuery); |
| 192 | |
| 193 | ReleaseStr(pwzData); |
| 194 | return hr; |
| 195 | } |
| 196 | |
| 197 | |
| 198 | HRESULT ScaFindAppPool( |
| 199 | __in IMSAdminBase* piMetabase, |
| 200 | __in LPCWSTR wzAppPool, |
| 201 | __out_ecount(cchName) LPWSTR wzName, |
| 202 | __in DWORD cchName, |
| 203 | __in SCA_APPPOOL *psapList |
| 204 | ) |
| 205 | { |
| 206 | Assert(piMetabase && wzAppPool && *wzAppPool && wzName && *wzName); |
| 207 | |
| 208 | HRESULT hr = S_OK; |
| 209 | |
| 210 | // check memory first |
| 211 | SCA_APPPOOL* psap = psapList; |
| 212 | for (; psap; psap = psap->psapNext) |
| 213 | { |
| 214 | if (0 == lstrcmpW(psap->wzAppPool, wzAppPool)) |
| 215 | { |
| 216 | break; |
| 217 | } |
| 218 | } |
| 219 | ExitOnNull(psap, hr, HRESULT_FROM_WIN32(ERROR_NOT_FOUND), "Could not find the app pool: %ls", wzAppPool); |
| 220 | |
| 221 | // copy the web app pool name |
| 222 | hr = ::StringCchCopyW(wzName, cchName, psap->wzName); |
| 223 | ExitOnFailure(hr, "failed to copy app pool name while finding app pool: %ls", psap->wzName); |
| 224 | |
| 225 | // if it's not being installed now, check if it exists already |
| 226 | if (!psap->fHasComponent) |
| 227 | { |
| 228 | hr = AppPoolExists(piMetabase, psap->wzName); |
| 229 | ExitOnFailure(hr, "failed to check for existence of app pool: %ls", psap->wzName); |
| 230 | } |
| 231 | |
| 232 | LExit: |
| 233 | return hr; |
| 234 | } |
| 235 | |
| 236 | |
| 237 | static HRESULT AppPoolExists( |
| 238 | __in IMSAdminBase* piMetabase, |
| 239 | __in LPCWSTR wzAppPool |
| 240 | ) |
| 241 | { |
| 242 | Assert(piMetabase && wzAppPool && *wzAppPool); |
| 243 | |
| 244 | HRESULT hr = S_OK; |
| 245 | WCHAR wzSubKey[METADATA_MAX_NAME_LEN]; |
| 246 | |
| 247 | for (DWORD dwIndex = 0; SUCCEEDED(hr); ++dwIndex) |
| 248 | { |
| 249 | hr = piMetabase->EnumKeys(METADATA_MASTER_ROOT_HANDLE, L"/LM/W3SVC/AppPools", wzSubKey, dwIndex); |
| 250 | if (SUCCEEDED(hr) && 0 == lstrcmpW(wzSubKey, wzAppPool)) |
| 251 | { |
| 252 | hr = S_OK; |
| 253 | break; |
| 254 | } |
| 255 | } |
| 256 | |
| 257 | if (E_NOMOREITEMS == hr || HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) |
| 258 | { |
| 259 | hr = S_FALSE; |
| 260 | } |
| 261 | |
| 262 | return hr; |
| 263 | } |
| 264 | |
| 265 | |
| 266 | HRESULT ScaAppPoolInstall( |
| 267 | __in IMSAdminBase* piMetabase, |
| 268 | __in SCA_APPPOOL* psapList |
| 269 | ) |
| 270 | { |
| 271 | Assert(piMetabase); |
| 272 | |
| 273 | HRESULT hr = S_OK; |
| 274 | |
| 275 | for (SCA_APPPOOL* psap = psapList; psap; psap = psap->psapNext) |
| 276 | { |
| 277 | // if we are installing the app pool |
| 278 | if (psap->fHasComponent && WcaIsInstalling(psap->isInstalled, psap->isAction)) |
| 279 | { |
| 280 | hr = ScaWriteAppPool(piMetabase, psap); |
| 281 | ExitOnFailure(hr, "failed to write AppPool '%ls' to metabase", psap->wzAppPool); |
| 282 | } |
| 283 | } |
| 284 | |
| 285 | LExit: |
| 286 | return hr; |
| 287 | } |
| 288 | |
| 289 | |
| 290 | HRESULT ScaAppPoolUninstall( |
| 291 | __in IMSAdminBase* piMetabase, |
| 292 | __in SCA_APPPOOL* psapList |
| 293 | ) |
| 294 | { |
| 295 | Assert(piMetabase); |
| 296 | |
| 297 | HRESULT hr = S_OK; |
| 298 | |
| 299 | for (SCA_APPPOOL* psap = psapList; psap; psap = psap->psapNext) |
| 300 | { |
| 301 | // if we are uninstalling the app pool |
| 302 | if (psap->fHasComponent && WcaIsUninstalling(psap->isInstalled, psap->isAction)) |
| 303 | { |
| 304 | hr = ScaRemoveAppPool(piMetabase, psap); |
| 305 | ExitOnFailure(hr, "Failed to remove AppPool '%ls' from metabase", psap->wzAppPool); |
| 306 | } |
| 307 | } |
| 308 | |
| 309 | LExit: |
| 310 | return hr; |
| 311 | } |
| 312 | |
| 313 | |
| 314 | HRESULT ScaWriteAppPool( |
| 315 | __in IMSAdminBase* piMetabase, |
| 316 | __in SCA_APPPOOL* psap |
| 317 | ) |
| 318 | { |
| 319 | Assert(piMetabase && psap); |
| 320 | |
| 321 | HRESULT hr = S_OK; |
| 322 | DWORD dwIdentity = 0xFFFFFFFF; |
| 323 | BOOL fExists = FALSE; |
| 324 | LPWSTR pwzValue = NULL; |
| 325 | LPWSTR wz = NULL; |
| 326 | |
| 327 | hr = AppPoolExists(piMetabase, psap->wzName); |
| 328 | ExitOnFailure(hr, "failed to check if app pool already exists"); |
| 329 | if (S_FALSE == hr) |
| 330 | { |
| 331 | // didn't find the AppPool key, so we need to create it |
| 332 | hr = ScaCreateMetabaseKey(piMetabase, psap->wzKey, L""); |
| 333 | ExitOnFailure(hr, "failed to create AppPool key: %ls", psap->wzKey); |
| 334 | |
| 335 | // mark it as an AppPool |
| 336 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, (LPVOID)L"IIsApplicationPool"); |
| 337 | ExitOnFailure(hr, "failed to mark key as AppPool key: %ls", psap->wzKey); |
| 338 | |
| 339 | // TODO: Make this an Attribute? |
| 340 | // set autostart value |
| 341 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_AUTO_START, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)1); |
| 342 | ExitOnFailure(hr, "failed to mark key as AppPool key: %ls", psap->wzKey); |
| 343 | } |
| 344 | else |
| 345 | { |
| 346 | fExists = TRUE; |
| 347 | } |
| 348 | |
| 349 | // |
| 350 | // Set the AppPool Recycling Tab |
| 351 | // |
| 352 | if (MSI_NULL_INTEGER != psap->iRecycleMinutes) |
| 353 | { |
| 354 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_TIME, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iRecycleMinutes)); |
| 355 | ExitOnFailure(hr, "failed to set periodic restart time"); |
| 356 | } |
| 357 | |
| 358 | if (MSI_NULL_INTEGER != psap->iRecycleRequests) |
| 359 | { |
| 360 | 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)); |
| 361 | ExitOnFailure(hr, "failed to set periodic restart request count"); |
| 362 | } |
| 363 | |
| 364 | if (*psap->wzRecycleTimes) |
| 365 | { |
| 366 | // Add another NULL' onto pwz since it's a 'MULTISZ' |
| 367 | hr = StrAllocString(&pwzValue, psap->wzRecycleTimes, 0); |
| 368 | ExitOnFailure(hr, "failed to allocate string for MULTISZ"); |
| 369 | hr = StrAllocConcat(&pwzValue, L"\0", 1); |
| 370 | ExitOnFailure(hr, "failed to add second null to RecycleTime multisz"); |
| 371 | |
| 372 | // Replace the commas with NULLs |
| 373 | wz = pwzValue; |
| 374 | while (NULL != (wz = wcschr(wz, L','))) |
| 375 | { |
| 376 | *wz = L'\0'; |
| 377 | ++wz; |
| 378 | } |
| 379 | |
| 380 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_SCHEDULE, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, (LPVOID)pwzValue); |
| 381 | ExitOnFailure(hr, "failed to set periodic restart schedule"); |
| 382 | } |
| 383 | |
| 384 | if (MSI_NULL_INTEGER != psap->iVirtualMemory) |
| 385 | { |
| 386 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_PERIODIC_RESTART_MEMORY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iVirtualMemory)); |
| 387 | ExitOnFailure(hr, "failed to set periodic restart memory count"); |
| 388 | } |
| 389 | |
| 390 | if (MSI_NULL_INTEGER != psap->iPrivateMemory) |
| 391 | { |
| 392 | 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)); |
| 393 | ExitOnFailure(hr, "failed to set periodic restart private memory count"); |
| 394 | } |
| 395 | |
| 396 | |
| 397 | // |
| 398 | // Set AppPool Performance Tab |
| 399 | // |
| 400 | if (MSI_NULL_INTEGER != psap->iIdleTimeout) |
| 401 | { |
| 402 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_IDLE_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iIdleTimeout)); |
| 403 | ExitOnFailure(hr, "failed to set idle timeout value"); |
| 404 | } |
| 405 | |
| 406 | if (MSI_NULL_INTEGER != psap->iQueueLimit) |
| 407 | { |
| 408 | 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)); |
| 409 | ExitOnFailure(hr, "failed to set request queue limit value"); |
| 410 | } |
| 411 | |
| 412 | if (*psap->wzCpuMon) |
| 413 | { |
| 414 | hr = StrAllocString(&pwzValue, psap->wzCpuMon, 0); |
| 415 | ExitOnFailure(hr, "failed to allocate CPUMonitor string"); |
| 416 | |
| 417 | DWORD dwPercent = 0; |
| 418 | DWORD dwRefreshMinutes = 0; |
| 419 | DWORD dwAction = 0; |
| 420 | |
| 421 | dwPercent = wcstoul(pwzValue, &wz, 10); |
| 422 | if (100 < dwPercent) |
| 423 | { |
| 424 | ExitOnFailure(hr = E_INVALIDARG, "invalid maximum cpu percentage value: %d", dwPercent); |
| 425 | } |
| 426 | if (wz && L',' == *wz) |
| 427 | { |
| 428 | ++wz; |
| 429 | dwRefreshMinutes = wcstoul(wz, &wz, 10); |
| 430 | if (wz && L',' == *wz) |
| 431 | { |
| 432 | ++wz; |
| 433 | dwAction = wcstoul(wz, &wz, 10); |
| 434 | } |
| 435 | } |
| 436 | |
| 437 | if (dwPercent) |
| 438 | { |
| 439 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_CPU_LIMIT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)(dwPercent * 1000))); |
| 440 | ExitOnFailure(hr, "failed to set CPU percentage max"); |
| 441 | } |
| 442 | if (dwRefreshMinutes) |
| 443 | { |
| 444 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_CPU_RESET_INTERVAL, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwRefreshMinutes)); |
| 445 | ExitOnFailure(hr, "failed to set refresh CPU minutes"); |
| 446 | } |
| 447 | if (dwAction) |
| 448 | { |
| 449 | // 0 = No Action |
| 450 | // 1 = Shutdown |
| 451 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_CPU_ACTION, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwAction)); |
| 452 | ExitOnFailure(hr, "failed to set CPU action"); |
| 453 | } |
| 454 | } |
| 455 | |
| 456 | if (MSI_NULL_INTEGER != psap->iMaxProcesses) |
| 457 | { |
| 458 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_MAX_PROCESS_COUNT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)psap->iMaxProcesses)); |
| 459 | ExitOnFailure(hr, "failed to set web garden maximum worker processes"); |
| 460 | } |
| 461 | |
| 462 | // TODO: Health Tab if anyone wants it? |
| 463 | |
| 464 | // |
| 465 | // Set the AppPool Identity tab |
| 466 | // |
| 467 | if (psap->iAttributes & APATTR_NETSERVICE) |
| 468 | { |
| 469 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_NETWORKSERVICE; |
| 470 | } |
| 471 | else if (psap->iAttributes & APATTR_LOCSERVICE) |
| 472 | { |
| 473 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSERVICE; |
| 474 | } |
| 475 | else if (psap->iAttributes & APATTR_LOCSYSTEM) |
| 476 | { |
| 477 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSYSTEM; |
| 478 | } |
| 479 | else if (psap->iAttributes & APATTR_OTHERUSER) |
| 480 | { |
| 481 | if (!*psap->suUser.wzDomain || CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzDomain, -1, L".", -1)) |
| 482 | { |
| 483 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"NetworkService", -1)) |
| 484 | { |
| 485 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_NETWORKSERVICE; |
| 486 | } |
| 487 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"LocalService", -1)) |
| 488 | { |
| 489 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSERVICE; |
| 490 | } |
| 491 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"LocalSystem", -1)) |
| 492 | { |
| 493 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSYSTEM; |
| 494 | } |
| 495 | else |
| 496 | { |
| 497 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER; |
| 498 | } |
| 499 | } |
| 500 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzDomain, -1, L"NT AUTHORITY", -1)) |
| 501 | { |
| 502 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"NETWORK SERVICE", -1)) |
| 503 | { |
| 504 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_NETWORKSERVICE; |
| 505 | } |
| 506 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"SERVICE", -1)) |
| 507 | { |
| 508 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSERVICE; |
| 509 | } |
| 510 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, psap->suUser.wzName, -1, L"SYSTEM", -1)) |
| 511 | { |
| 512 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_LOCALSYSTEM; |
| 513 | } |
| 514 | else |
| 515 | { |
| 516 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER; |
| 517 | } |
| 518 | } |
| 519 | else |
| 520 | { |
| 521 | dwIdentity = MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER; |
| 522 | } |
| 523 | } |
| 524 | |
| 525 | if (-1 != dwIdentity) |
| 526 | { |
| 527 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_APPPOOL_IDENTITY_TYPE, METADATA_INHERIT , IIS_MD_UT_SERVER, DWORD_METADATA, (LPVOID)((DWORD_PTR)dwIdentity)); |
| 528 | ExitOnFailure(hr, "failed to set app pool identity"); |
| 529 | |
| 530 | if (MD_APPPOOL_IDENTITY_TYPE_SPECIFICUSER == dwIdentity) |
| 531 | { |
| 532 | if (*psap->suUser.wzDomain) |
| 533 | { |
| 534 | hr = StrAllocFormatted(&pwzValue, L"%s\\%s", psap->suUser.wzDomain, psap->suUser.wzName); |
| 535 | ExitOnFailure(hr, "failed to format user name: %ls domain: %ls", psap->suUser.wzName, psap->suUser.wzDomain); |
| 536 | } |
| 537 | else |
| 538 | { |
| 539 | hr = StrAllocFormatted(&pwzValue, L"%s", psap->suUser.wzName); |
| 540 | ExitOnFailure(hr, "failed to format user name: %ls", psap->suUser.wzName); |
| 541 | } |
| 542 | |
| 543 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_WAM_USER_NAME, METADATA_INHERIT , IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)pwzValue); |
| 544 | ExitOnFailure(hr, "failed to set app pool identity name"); |
| 545 | |
| 546 | hr = ScaWriteMetabaseValue(piMetabase, psap->wzKey, NULL, MD_WAM_PWD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, (LPVOID)psap->suUser.wzPassword); |
| 547 | ExitOnFailure(hr, "failed to set app pool identity password"); |
| 548 | } |
| 549 | } |
| 550 | |
| 551 | LExit: |
| 552 | ReleaseStr(pwzValue); |
| 553 | |
| 554 | return hr; |
| 555 | } |
| 556 | |
| 557 | |
| 558 | HRESULT ScaRemoveAppPool( |
| 559 | __in IMSAdminBase* piMetabase, |
| 560 | __in SCA_APPPOOL* psap |
| 561 | ) |
| 562 | { |
| 563 | Assert(piMetabase && psap); |
| 564 | |
| 565 | HRESULT hr = S_OK; |
| 566 | |
| 567 | // simply remove the root key and everything else is pulled at the same time |
| 568 | if (0 != lstrlenW(psap->wzKey)) |
| 569 | { |
| 570 | hr = ScaDeleteMetabaseKey(piMetabase, psap->wzKey, L""); |
| 571 | ExitOnFailure(hr, "failed to delete AppPool key: %ls", psap->wzKey); |
| 572 | } |
| 573 | |
| 574 | // TODO: Maybe check to make sure any web sites that are using this AppPool are put back in the 'DefaultAppPool' |
| 575 | |
| 576 | LExit: |
| 577 | return hr; |
| 578 | } |
| 579 | |
| 580 | |
| 581 | HRESULT AddAppPoolToList( |
| 582 | __in SCA_APPPOOL** ppsapList |
| 583 | ) |
| 584 | { |
| 585 | HRESULT hr = S_OK; |
| 586 | SCA_APPPOOL* psap = static_cast<SCA_APPPOOL*>(MemAlloc(sizeof(SCA_APPPOOL), TRUE)); |
| 587 | ExitOnNull(psap, hr, E_OUTOFMEMORY, "failed to allocate memory for new element in app pool list"); |
| 588 | |
| 589 | psap->psapNext = *ppsapList; |
| 590 | *ppsapList = psap; |
| 591 | |
| 592 | LExit: |
| 593 | return hr; |
| 594 | } |