diff options
| author | zousar <[email protected]> | 2021-11-29 23:28:28 -0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-11-29 23:28:28 -0700 |
| commit | 93ed87e6f3c73bfb3c1a0fb8c3805173d3b5c039 (patch) | |
| tree | 649e53df1162e843646cb07f1e9c98476089ae24 | |
| parent | Merge pull request #28 from EpicGames/non-elevated-asio (diff) | |
| parent | Address review feedback and fix issue when deploying. (diff) | |
| download | zen-93ed87e6f3c73bfb3c1a0fb8c3805173d3b5c039.tar.xz zen-93ed87e6f3c73bfb3c1a0fb8c3805173d3b5c039.zip | |
Merge pull request #30 from EpicGames/non-elevated-asio
Get zenserver running non-elevated
| -rw-r--r-- | zenhttp/httpsys.cpp | 88 | ||||
| -rw-r--r-- | zenhttp/httpsys.h | 20 | ||||
| -rw-r--r-- | zenserver/config.cpp | 33 | ||||
| -rw-r--r-- | zenserver/xmake.lua | 1 | ||||
| -rw-r--r-- | zenserver/zenserver.vcxproj | 2 | ||||
| -rw-r--r-- | zenutil/zenserverprocess.cpp | 22 |
6 files changed, 125 insertions, 41 deletions
diff --git a/zenhttp/httpsys.cpp b/zenhttp/httpsys.cpp index 15d7a9700..e9472e3b8 100644 --- a/zenhttp/httpsys.cpp +++ b/zenhttp/httpsys.cpp @@ -748,15 +748,20 @@ HttpSysServer::~HttpSysServer() } void -HttpSysServer::Initialize(const wchar_t* UrlPath) +HttpSysServer::InitializeServer(int BasePort) { + using namespace std::literals; + + WideStringBuilder<64> WildcardUrlPath; + WildcardUrlPath << u8"http://*:"sv << int64_t(BasePort) << u8"/"sv; + m_IsOk = false; ULONG Result = HttpCreateServerSession(HTTPAPI_VERSION_2, &m_HttpSessionId, 0); if (Result != NO_ERROR) { - ZEN_ERROR("Failed to create server session for '{}': {:#x}", WideToUtf8(UrlPath), Result); + ZEN_ERROR("Failed to create server session for '{}': {:#x}", WideToUtf8(WildcardUrlPath), Result); return; } @@ -765,18 +770,44 @@ HttpSysServer::Initialize(const wchar_t* UrlPath) if (Result != NO_ERROR) { - ZEN_ERROR("Failed to create URL group for '{}': {:#x}", WideToUtf8(UrlPath), Result); + ZEN_ERROR("Failed to create URL group for '{}': {:#x}", WideToUtf8(WildcardUrlPath), Result); return; } - m_BaseUri = UrlPath; + Result = HttpAddUrlToUrlGroup(m_HttpUrlGroupId, WildcardUrlPath.c_str(), HTTP_URL_CONTEXT(0), 0); - Result = HttpAddUrlToUrlGroup(m_HttpUrlGroupId, UrlPath, HTTP_URL_CONTEXT(0), 0); + m_BaseUris.clear(); + if (Result == NO_ERROR) + { + m_BaseUris.push_back(WildcardUrlPath.c_str()); + } + else + { + // If we can't register the wildcard path, we fall back to local paths + // This local paths allow requests originating locally to function, but will not allow + // remote origin requests to function. This can be remedied by using netsh + // during an install process to grant permissions to route public access to the appropriate + // port for the current user. eg: + // netsh http add urlacl url=http://*:1337/ user=<some_user> - if (Result != NO_ERROR) + const std::u8string_view Hosts[] = { u8"[::1]"sv, u8"localhost"sv, u8"127.0.0.1"sv }; + + for (const std::u8string_view Host : Hosts) + { + WideStringBuilder<64> LocalUrlPath; + LocalUrlPath << u8"http://"sv << Host << u8":"sv << int64_t(BasePort) << u8"/"sv; + + if (HttpAddUrlToUrlGroup(m_HttpUrlGroupId, LocalUrlPath.c_str(), HTTP_URL_CONTEXT(0), 0) == NO_ERROR) + { + m_BaseUris.push_back(LocalUrlPath.c_str()); + } + } + } + + if (m_BaseUris.empty()) { - ZEN_ERROR("Failed to add base URL to URL group for '{}': {:#x}", WideToUtf8(UrlPath), Result); + ZEN_ERROR("Failed to add base URL to URL group for '{}': {:#x}", WideToUtf8(WildcardUrlPath), Result); return; } @@ -791,7 +822,7 @@ HttpSysServer::Initialize(const wchar_t* UrlPath) if (Result != NO_ERROR) { - ZEN_ERROR("Failed to create request queue for '{}': {:#x}", WideToUtf8(UrlPath), Result); + ZEN_ERROR("Failed to create request queue for '{}': {:#x}", WideToUtf8(m_BaseUris.front()), Result); return; } @@ -803,7 +834,7 @@ HttpSysServer::Initialize(const wchar_t* UrlPath) if (Result != NO_ERROR) { - ZEN_ERROR("Failed to set server binding property for '{}': {:#x}", WideToUtf8(UrlPath), Result); + ZEN_ERROR("Failed to set server binding property for '{}': {:#x}", WideToUtf8(m_BaseUris.front()), Result); return; } @@ -815,13 +846,13 @@ HttpSysServer::Initialize(const wchar_t* UrlPath) if (ErrorCode) { - ZEN_ERROR("Failed to create IOCP for '{}': {}", WideToUtf8(UrlPath), ErrorCode.message()); + ZEN_ERROR("Failed to create IOCP for '{}': {}", WideToUtf8(m_BaseUris.front()), ErrorCode.message()); } else { m_IsOk = true; - ZEN_INFO("Started http.sys server at '{}'", WideToUtf8(UrlPath)); + ZEN_INFO("Started http.sys server at '{}'", WideToUtf8(m_BaseUris.front())); } } @@ -952,15 +983,18 @@ HttpSysServer::RegisterService(const char* UrlPath, HttpService& Service) // Convert to wide string - std::wstring Url16 = m_BaseUri + PathUtf16; + for (const std::wstring& BaseUri : m_BaseUris) + { + std::wstring Url16 = BaseUri + PathUtf16; - ULONG Result = HttpAddUrlToUrlGroup(m_HttpUrlGroupId, Url16.c_str(), HTTP_URL_CONTEXT(&Service), 0 /* Reserved */); + ULONG Result = HttpAddUrlToUrlGroup(m_HttpUrlGroupId, Url16.c_str(), HTTP_URL_CONTEXT(&Service), 0 /* Reserved */); - if (Result != NO_ERROR) - { - ZEN_ERROR("HttpAddUrlToUrlGroup failed with result: '{}'", GetSystemErrorAsString(Result)); + if (Result != NO_ERROR) + { + ZEN_ERROR("HttpAddUrlToUrlGroup failed with result: '{}'", GetSystemErrorAsString(Result)); - return; + return; + } } } @@ -978,13 +1012,16 @@ HttpSysServer::UnregisterService(const char* UrlPath, HttpService& Service) // Convert to wide string - std::wstring Url16 = m_BaseUri + PathUtf16; + for (const std::wstring& BaseUri : m_BaseUris) + { + std::wstring Url16 = BaseUri + PathUtf16; - ULONG Result = HttpRemoveUrlFromUrlGroup(m_HttpUrlGroupId, Url16.c_str(), 0); + ULONG Result = HttpRemoveUrlFromUrlGroup(m_HttpUrlGroupId, Url16.c_str(), 0); - if (Result != NO_ERROR) - { - ZEN_ERROR("HttpRemoveUrlFromUrlGroup failed with result: '{}'", GetSystemErrorAsString(Result)); + if (Result != NO_ERROR) + { + ZEN_ERROR("HttpRemoveUrlFromUrlGroup failed with result: '{}'", GetSystemErrorAsString(Result)); + } } } @@ -1570,12 +1607,7 @@ InitialRequestHandler::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesT void HttpSysServer::Initialize(int BasePort) { - using namespace std::literals; - - WideStringBuilder<64> BaseUri; - BaseUri << u8"http://*:"sv << int64_t(BasePort) << u8"/"sv; - - Initialize(BaseUri.c_str()); + InitializeServer(BasePort); StartServer(); } diff --git a/zenhttp/httpsys.h b/zenhttp/httpsys.h index 46ba122cc..7df8fba8f 100644 --- a/zenhttp/httpsys.h +++ b/zenhttp/httpsys.h @@ -52,7 +52,7 @@ public: inline bool IsAsyncResponseEnabled() const { return m_IsAsyncResponseEnabled; } private: - void Initialize(const wchar_t* UrlPath); + void InitializeServer(int BasePort); void Cleanup(); void StartServer(); @@ -75,15 +75,15 @@ private: WinIoThreadPool m_ThreadPool; WorkerThreadPool m_AsyncWorkPool; - std::wstring m_BaseUri; // http://*:nnnn/ - HTTP_SERVER_SESSION_ID m_HttpSessionId = 0; - HTTP_URL_GROUP_ID m_HttpUrlGroupId = 0; - HANDLE m_RequestQueueHandle = 0; - std::atomic_int32_t m_PendingRequests{0}; - std::atomic<int32_t> m_IsShuttingDown{0}; - int32_t m_MinPendingRequests = 16; - int32_t m_MaxPendingRequests = 128; - Event m_ShutdownEvent; + std::vector<std::wstring> m_BaseUris; // eg: http://*:nnnn/ + HTTP_SERVER_SESSION_ID m_HttpSessionId = 0; + HTTP_URL_GROUP_ID m_HttpUrlGroupId = 0; + HANDLE m_RequestQueueHandle = 0; + std::atomic_int32_t m_PendingRequests{0}; + std::atomic_int32_t m_IsShuttingDown{0}; + int32_t m_MinPendingRequests = 16; + int32_t m_MaxPendingRequests = 128; + Event m_ShutdownEvent; }; } // namespace zen diff --git a/zenserver/config.cpp b/zenserver/config.cpp index 1e847ce3d..0a812b5a2 100644 --- a/zenserver/config.cpp +++ b/zenserver/config.cpp @@ -45,6 +45,39 @@ PickDefaultStateDirectory() return myDocumentsDir; } + int CandidateDriveLetterOffset = -1; + ULARGE_INTEGER CandidateDriveSize; + CandidateDriveSize.QuadPart = 0L; + DWORD LogicalDrives = GetLogicalDrives(); + char CandidateDriveName[] = "A:\\"; + for (int DriveLetterOffset = 0; DriveLetterOffset < 32; ++DriveLetterOffset) + { + if ((LogicalDrives & (1 << DriveLetterOffset)) != 0) + { + CandidateDriveName[0] = (char)('A' + DriveLetterOffset); + if (GetDriveTypeA(CandidateDriveName) == DRIVE_FIXED) + { + ULARGE_INTEGER FreeBytesAvailableToCaller; + ULARGE_INTEGER TotalNumberOfBytes; + if (0 != GetDiskFreeSpaceExA(CandidateDriveName, &FreeBytesAvailableToCaller, &TotalNumberOfBytes, nullptr)) + { + if ((FreeBytesAvailableToCaller.QuadPart > 0) && (TotalNumberOfBytes.QuadPart > CandidateDriveSize.QuadPart)) + { + CandidateDriveLetterOffset = DriveLetterOffset; + CandidateDriveSize = TotalNumberOfBytes; + } + } + } + } + } + + if (CandidateDriveLetterOffset >= 0) + { + char RootZenFolderName[] = "A:\\zen"; + RootZenFolderName[0] = (char)('A' + CandidateDriveLetterOffset); + return RootZenFolderName; + } + return L""; } diff --git a/zenserver/xmake.lua b/zenserver/xmake.lua index bba9b6ba5..bffb5d9d2 100644 --- a/zenserver/xmake.lua +++ b/zenserver/xmake.lua @@ -12,7 +12,6 @@ target("zenserver") if is_plat("windows") then add_ldflags("/subsystem:console,5.02") add_ldflags("/MANIFEST:EMBED") - add_ldflags("/MANIFESTUAC:level='requireAdministrator'") add_ldflags("/LTCG") else del_files("windows/**") diff --git a/zenserver/zenserver.vcxproj b/zenserver/zenserver.vcxproj index 935979cc3..056d431cb 100644 --- a/zenserver/zenserver.vcxproj +++ b/zenserver/zenserver.vcxproj @@ -82,7 +82,6 @@ <EnableCOMDATFolding>true</EnableCOMDATFolding> <OptimizeReferences>true</OptimizeReferences> <GenerateDebugInformation>true</GenerateDebugInformation> - <UACExecutionLevel>RequireAdministrator</UACExecutionLevel> <DelayLoadDLLs>projectedfslib.dll;shell32.dll</DelayLoadDLLs> </Link> </ItemDefinitionGroup> @@ -99,7 +98,6 @@ <Link> <SubSystem>Console</SubSystem> <GenerateDebugInformation>true</GenerateDebugInformation> - <UACExecutionLevel>RequireAdministrator</UACExecutionLevel> <DelayLoadDLLs>projectedfslib.dll;shell32.dll</DelayLoadDLLs> </Link> </ItemDefinitionGroup> diff --git a/zenutil/zenserverprocess.cpp b/zenutil/zenserverprocess.cpp index d064f962a..e366a917f 100644 --- a/zenutil/zenserverprocess.cpp +++ b/zenutil/zenserverprocess.cpp @@ -89,11 +89,19 @@ ZenServerState::Initialize() { // TODO: there's a small chance of a race here, this logic could be tightened up with a mutex to // ensure only a single process at a time creates the mapping + // TODO: the fallback to Local instead of Global has a flaw where if you start a non-elevated instance + // first then start an elevated instance second you'll have the first instance with a local + // mapping and the second instance with a global mapping. This kind of elevated/non-elevated + // shouldn't be common, but handling for it should be improved in the future. if (HANDLE hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, L"Global\\ZenMap")) { m_hMapFile = hMap; } + else if (HANDLE hLocalMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, L"Local\\ZenMap")) + { + m_hMapFile = hLocalMap; + } else { // Security attributes to enable any user to access state @@ -108,6 +116,16 @@ ZenServerState::Initialize() if (hMap == NULL) { + hMap = CreateFileMapping(INVALID_HANDLE_VALUE, // use paging file + Attrs.Attributes(), // allow anyone to access + PAGE_READWRITE, // read/write access + 0, // maximum object size (high-order DWORD) + m_MaxEntryCount * sizeof(ZenServerEntry), // maximum object size (low-order DWORD) + L"Local\\ZenMap"); // name of mapping object + } + + if (hMap == NULL) + { ThrowLastError("Could not open or create file mapping object for Zen server state"); } @@ -136,6 +154,10 @@ ZenServerState::InitializeReadOnly() { m_hMapFile = hMap; } + else if (HANDLE hLocalMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, L"Local\\ZenMap")) + { + m_hMapFile = hLocalMap; + } else { return false; |