// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. #pragma once #include "precomp.hxx" class ENVIRONMENT_VAR_HELPERS { public: static VOID CopyToMultiSz( ENVIRONMENT_VAR_ENTRY * pEntry, PVOID pvData ) { STRU strTemp; MULTISZ *pMultiSz = static_cast(pvData); DBG_ASSERT(pMultiSz); DBG_ASSERT(pEntry); strTemp.Copy(pEntry->QueryName()); strTemp.Append(pEntry->QueryValue()); pMultiSz->Append(strTemp.QueryStr()); } static VOID CopyToTable( ENVIRONMENT_VAR_ENTRY * pEntry, PVOID pvData ) { // best effort copy, ignore the failure ENVIRONMENT_VAR_ENTRY * pNewEntry = new ENVIRONMENT_VAR_ENTRY(); if (pNewEntry != NULL) { pNewEntry->Initialize(pEntry->QueryName(), pEntry->QueryValue()); ENVIRONMENT_VAR_HASH *pHash = static_cast(pvData); DBG_ASSERT(pHash); pHash->InsertRecord(pNewEntry); // Need to dereference as InsertRecord references it now pNewEntry->Dereference(); } } static VOID AppendEnvironmentVariables ( ENVIRONMENT_VAR_ENTRY * pEntry, PVOID pvData ) { HRESULT hr = S_OK; DWORD dwResult = 0; DWORD dwError = 0; STRU struNameBuffer; STACK_STRU(struValueBuffer, 300); BOOL fFound = FALSE; HRESULT* pHr = static_cast(pvData); // pEntry->QueryName includes the trailing =, remove it before calling stru if (FAILED(hr = struNameBuffer.Copy(pEntry->QueryName()))) { goto Finished; } dwResult = struNameBuffer.LastIndexOf(L'='); if (dwResult != -1) { struNameBuffer.QueryStr()[dwResult] = L'\0'; if (FAILED(hr = struNameBuffer.SyncWithBuffer())) { goto Finished; } } dwResult = GetEnvironmentVariable(struNameBuffer.QueryStr(), struValueBuffer.QueryStr(), struValueBuffer.QuerySizeCCH()); if (dwResult == 0) { dwError = GetLastError(); // Windows API (e.g., CreateProcess) allows variable with empty string value // in such case dwResult will be 0 and dwError will also be 0 // As UI and CMD does not allow empty value, ignore this environment var if (dwError != ERROR_ENVVAR_NOT_FOUND && dwError != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(dwError); goto Finished; } } else if (dwResult > struValueBuffer.QuerySizeCCH()) { // have to increase the buffer and try get environment var again struValueBuffer.Reset(); struValueBuffer.Resize(dwResult + (DWORD)wcslen(pEntry->QueryValue()) + 2); // for null char and semicolon dwResult = GetEnvironmentVariable(struNameBuffer.QueryStr(), struValueBuffer.QueryStr(), struValueBuffer.QuerySizeCCH()); if (struValueBuffer.IsEmpty()) { hr = E_UNEXPECTED; goto Finished; } fFound = TRUE; } else { fFound = TRUE; } if (FAILED(hr = struValueBuffer.SyncWithBuffer())) { goto Finished; } if (fFound) { if (FAILED(hr = struValueBuffer.Append(L";"))) { goto Finished; } } if (FAILED(hr = struValueBuffer.Append(pEntry->QueryValue()))) { goto Finished; } if (FAILED(hr = pEntry->Initialize(pEntry->QueryName(), struValueBuffer.QueryStr()))) { goto Finished; } Finished: if (FAILED(hr)) { *pHr = hr; } return; } static VOID SetEnvironmentVariables ( ENVIRONMENT_VAR_ENTRY * pEntry, PVOID pvData ) { UNREFERENCED_PARAMETER(pvData); HRESULT hr = S_OK; DWORD dwResult = 0; STRU struNameBuffer; HRESULT* pHr = static_cast(pvData); // pEntry->QueryName includes the trailing =, remove it before calling SetEnvironmentVariable. if (FAILED(hr = struNameBuffer.Copy(pEntry->QueryName()))) { goto Finished; } dwResult = struNameBuffer.LastIndexOf(L'='); if (dwResult != -1) { struNameBuffer.QueryStr()[dwResult] = L'\0'; if (FAILED(hr = struNameBuffer.SyncWithBuffer())) { goto Finished; } } dwResult = SetEnvironmentVariable(struNameBuffer.QueryStr(), pEntry->QueryValue()); if (dwResult == 0) { hr = HRESULT_FROM_WIN32(GetLastError()); } Finished: if (FAILED(hr)) { *pHr = hr; } return; } static HRESULT InitEnvironmentVariablesTable ( _In_ ENVIRONMENT_VAR_HASH* pInEnvironmentVarTable, _In_ BOOL fWindowsAuthEnabled, _In_ BOOL fBasicAuthEnabled, _In_ BOOL fAnonymousAuthEnabled, _Out_ ENVIRONMENT_VAR_HASH** ppEnvironmentVarTable ) { HRESULT hr = S_OK; BOOL fFound = FALSE; DWORD dwResult, dwError; STRU strIisAuthEnvValue; STACK_STRU(strStartupAssemblyEnv, 1024); ENVIRONMENT_VAR_ENTRY* pHostingEntry = NULL; ENVIRONMENT_VAR_ENTRY* pIISAuthEntry = NULL; ENVIRONMENT_VAR_HASH* pEnvironmentVarTable = NULL; pEnvironmentVarTable = new ENVIRONMENT_VAR_HASH(); if (pEnvironmentVarTable == NULL) { hr = E_OUTOFMEMORY; goto Finished; } // // few environment variables expected, small bucket size for hash table // if (FAILED(hr = pEnvironmentVarTable->Initialize(37 /*prime*/))) { goto Finished; } // copy the envirable hash table (from configuration) to a temp one as we may need to remove elements pInEnvironmentVarTable->Apply(ENVIRONMENT_VAR_HELPERS::CopyToTable, pEnvironmentVarTable); if (pEnvironmentVarTable->Count() != pInEnvironmentVarTable->Count()) { // hash table copy failed hr = E_UNEXPECTED; goto Finished; } pEnvironmentVarTable->FindKey((PWSTR)ASPNETCORE_IIS_AUTH_ENV_STR, &pIISAuthEntry); if (pIISAuthEntry != NULL) { // user defined ASPNETCORE_IIS_HTTPAUTH in configuration, wipe it off pIISAuthEntry->Dereference(); pEnvironmentVarTable->DeleteKey((PWSTR)ASPNETCORE_IIS_AUTH_ENV_STR); } if (fWindowsAuthEnabled) { strIisAuthEnvValue.Copy(ASPNETCORE_IIS_AUTH_WINDOWS); } if (fBasicAuthEnabled) { strIisAuthEnvValue.Append(ASPNETCORE_IIS_AUTH_BASIC); } if (fAnonymousAuthEnabled) { strIisAuthEnvValue.Append(ASPNETCORE_IIS_AUTH_ANONYMOUS); } if (strIisAuthEnvValue.IsEmpty()) { strIisAuthEnvValue.Copy(ASPNETCORE_IIS_AUTH_NONE); } pIISAuthEntry = new ENVIRONMENT_VAR_ENTRY(); if (pIISAuthEntry == NULL) { hr = E_OUTOFMEMORY; goto Finished; } if (FAILED(hr = pIISAuthEntry->Initialize(ASPNETCORE_IIS_AUTH_ENV_STR, strIisAuthEnvValue.QueryStr())) || FAILED(hr = pEnvironmentVarTable->InsertRecord(pIISAuthEntry))) { goto Finished; } // Compiler is complaining about conversion between PCWSTR and PWSTR here. // Explictly casting. pEnvironmentVarTable->FindKey((PWSTR)HOSTING_STARTUP_ASSEMBLIES_NAME, &pHostingEntry); if (pHostingEntry != NULL) { // user defined ASPNETCORE_HOSTINGSTARTUPASSEMBLIES in configuration // the value will be used in OutputEnvironmentVariables. Do nothing here pHostingEntry->Dereference(); pHostingEntry = NULL; goto Skipped; } //check whether ASPNETCORE_HOSTINGSTARTUPASSEMBLIES is defined in system dwResult = GetEnvironmentVariable(HOSTING_STARTUP_ASSEMBLIES_ENV_STR, strStartupAssemblyEnv.QueryStr(), strStartupAssemblyEnv.QuerySizeCCH()); if (dwResult == 0) { dwError = GetLastError(); // Windows API (e.g., CreateProcess) allows variable with empty string value // in such case dwResult will be 0 and dwError will also be 0 // As UI and CMD does not allow empty value, ignore this environment var if (dwError != ERROR_ENVVAR_NOT_FOUND && dwError != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(dwError); goto Finished; } } else if (dwResult > strStartupAssemblyEnv.QuerySizeCCH()) { // have to increase the buffer and try get environment var again strStartupAssemblyEnv.Reset(); strStartupAssemblyEnv.Resize(dwResult + (DWORD)wcslen(HOSTING_STARTUP_ASSEMBLIES_VALUE) + 1); dwResult = GetEnvironmentVariable(HOSTING_STARTUP_ASSEMBLIES_ENV_STR, strStartupAssemblyEnv.QueryStr(), strStartupAssemblyEnv.QuerySizeCCH()); if (strStartupAssemblyEnv.IsEmpty()) { hr = E_UNEXPECTED; goto Finished; } fFound = TRUE; } else { fFound = TRUE; } strStartupAssemblyEnv.SyncWithBuffer(); if (fFound) { strStartupAssemblyEnv.Append(L";"); } strStartupAssemblyEnv.Append(HOSTING_STARTUP_ASSEMBLIES_VALUE); // the environment variable was not defined, create it and add to hashtable pHostingEntry = new ENVIRONMENT_VAR_ENTRY(); if (pHostingEntry == NULL) { hr = E_OUTOFMEMORY; goto Finished; } if (FAILED(hr = pHostingEntry->Initialize(HOSTING_STARTUP_ASSEMBLIES_NAME, strStartupAssemblyEnv.QueryStr())) || FAILED(hr = pEnvironmentVarTable->InsertRecord(pHostingEntry))) { goto Finished; } Skipped: *ppEnvironmentVarTable = pEnvironmentVarTable; pEnvironmentVarTable = NULL; Finished: if (pHostingEntry != NULL) { pHostingEntry->Dereference(); pHostingEntry = NULL; } if (pIISAuthEntry != NULL) { pIISAuthEntry->Dereference(); pIISAuthEntry = NULL; } if (pEnvironmentVarTable != NULL) { pEnvironmentVarTable->Clear(); delete pEnvironmentVarTable; pEnvironmentVarTable = NULL; } return hr; } static HRESULT AddWebsocketEnabledToEnvironmentVariables ( _Inout_ ENVIRONMENT_VAR_HASH* pInEnvironmentVarTable, _In_ BOOL fWebsocketsEnabled ) { HRESULT hr = S_OK; ENVIRONMENT_VAR_ENTRY* pIISWebsocketEntry = NULL; STACK_STRU(strIISWebsocketEnvValue, 40); // We only need to set the WEBSOCKET_SUPPORTED environment variable for out of process pInEnvironmentVarTable->FindKey((PWSTR)ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED_ENV_STR, &pIISWebsocketEntry); if (pIISWebsocketEntry != NULL) { // user defined ASPNETCORE_IIS_WEBSOCKETS in configuration, wipe it off pIISWebsocketEntry->Dereference(); pInEnvironmentVarTable->DeleteKey((PWSTR)ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED_ENV_STR); } // Set either true or false for the WebsocketEnvValue. if (fWebsocketsEnabled) { if (FAILED(hr = strIISWebsocketEnvValue.Copy(L"true"))) { goto Finished; } } else { if (FAILED(hr = strIISWebsocketEnvValue.Copy(L"false"))) { goto Finished; } } pIISWebsocketEntry = new ENVIRONMENT_VAR_ENTRY(); if (pIISWebsocketEntry == NULL) { hr = E_OUTOFMEMORY; goto Finished; } if (FAILED(hr = pIISWebsocketEntry->Initialize(ASPNETCORE_IIS_WEBSOCKETS_SUPPORTED_ENV_STR, strIISWebsocketEnvValue.QueryStr())) || FAILED(hr = pInEnvironmentVarTable->InsertRecord(pIISWebsocketEntry))) { goto Finished; } Finished: return hr; } public: ENVIRONMENT_VAR_HELPERS(); ~ENVIRONMENT_VAR_HELPERS(); };