fakekms/cpp/fakekms_win.cc (69 lines of code) (raw):

// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #define WIN32_LEAN_AND_MEAN #include <windows.h> #include "absl/cleanup/cleanup.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "fakekms/cpp/fakekms.h" namespace fakekms { namespace { class WindowsServer : public Server { public: static absl::StatusOr<std::unique_ptr<WindowsServer>> New( std::string_view flags); WindowsServer(std::string listen_addr, HANDLE process_handle) : Server(listen_addr), process_handle_(process_handle) {} ~WindowsServer() { CHECK(TerminateProcess(process_handle_, 0)); CHECK(CloseHandle(process_handle_)); } private: HANDLE process_handle_; }; absl::Status Win32ErrorToStatus(std::string_view message) { char* error_text = nullptr; DWORD error_code = GetLastError(); FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), error_text, 0, nullptr); return absl::InternalError( absl::StrFormat("%s: code %d: %s", message, error_code, error_text)); } } // namespace absl::StatusOr<std::unique_ptr<Server>> Server::New() { // https://docs.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output SECURITY_ATTRIBUTES security_attrs{ sizeof(SECURITY_ATTRIBUTES), // nLength nullptr, // lpSecurityDescriptor true, // bInheritHandle }; HANDLE out_read, out_write; if (!CreatePipe(&out_read, &out_write, &security_attrs, 0)) { return Win32ErrorToStatus("error creating output pipe"); } absl::Cleanup c = [&] { CHECK(CloseHandle(out_read)); CHECK(CloseHandle(out_write)); }; STARTUPINFOA startup_info; ZeroMemory(&startup_info, sizeof(STARTUPINFOA)); startup_info.cb = sizeof(STARTUPINFOA); startup_info.hStdOutput = out_write; startup_info.dwFlags = STARTF_USESTDHANDLES; PROCESS_INFORMATION process_info; std::string bin_path = BinaryLocation(".exe"); if (!CreateProcessA(bin_path.c_str(), const_cast<char*>(bin_path.c_str()), nullptr, nullptr, true, CREATE_NO_WINDOW, nullptr, nullptr, &startup_info, &process_info)) { return Win32ErrorToStatus("error creating fakekms process"); } CHECK(CloseHandle(process_info.hThread)); // we don't use this handle const size_t kBufferSize = 4096; // should be enough to hold the listen addr char buf[kBufferSize]; DWORD len; if (!ReadFile(out_read, buf, kBufferSize, &len, nullptr)) { return Win32ErrorToStatus("error reading listen address"); } std::string address(buf, len); return std::make_unique<WindowsServer>(address, process_info.hProcess); } } // namespace fakekms