Source code

Revision control

Copy as Markdown

Other Tools

// Copyright 2022 The Chromium Authors.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <vector>
#include <windows.h>
#include <sddl.h>
#include "utils_win.h"
namespace content_analysis {
namespace sdk {
namespace internal {
std::string GetUserSID() {
std::string sid;
HANDLE handle;
if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &handle) &&
!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &handle)) {
return std::string();
}
DWORD length = 0;
std::vector<char> buffer;
if (!GetTokenInformation(handle, TokenUser, nullptr, 0, &length)) {
DWORD err = GetLastError();
if (err == ERROR_INSUFFICIENT_BUFFER) {
buffer.resize(length);
}
}
if (GetTokenInformation(handle, TokenUser, buffer.data(), buffer.size(),
&length)) {
TOKEN_USER* info = reinterpret_cast<TOKEN_USER*>(buffer.data());
char* sid_string;
if (ConvertSidToStringSidA(info->User.Sid, &sid_string)) {
sid = sid_string;
LocalFree(sid_string);
}
}
CloseHandle(handle);
return sid;
}
std::string BuildPipeName(const char* prefix,
const std::string& base,
bool user_specific) {
std::string pipename = prefix;
// If the agent is not user-specific, the assumption is that it runs with
// administrator privileges. Create the pipe in a location only available
// to administrators.
if (!user_specific)
pipename += "ProtectedPrefix\\Administrators\\";
pipename += base;
if (user_specific) {
std::string sid = GetUserSID();
if (sid.empty())
return std::string();
pipename += "." + sid;
}
return pipename;
}
std::string GetPipeNameForAgent(const std::string& base, bool user_specific) {
return BuildPipeName(kPipePrefixForAgent, base, user_specific);
}
std::string GetPipeNameForClient(const std::string& base, bool user_specific) {
return BuildPipeName(kPipePrefixForClient, base, user_specific);
}
DWORD CreatePipe(
const std::string& name,
bool user_specific,
bool is_first_pipe,
HANDLE* handle) {
DWORD err = ERROR_SUCCESS;
DWORD mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED;
// Create DACL for pipe to allow users on the local system to read and write
// to the pipe. The creator and owner as well as administrator always get
// full control of the pipe.
//
// If `user_specific` is true, a different agent instance is used for each
// OS user, so only allow the interactive logged on user to reads and write
// messages to the pipe. Otherwise only one agent instance used used for all
// OS users and all authenticated logged on users can reads and write
// messages.
//
// for a description of this string format.
constexpr char kDaclEveryone[] = "D:"
"(A;OICI;GA;;;CO)" // Allow full control to creator owner.
"(A;OICI;GA;;;BA)" // Allow full control to admins.
"(A;OICI;GRGW;;;WD)"; // Allow read and write to everyone.
constexpr char kDaclUserSpecific[] = "D:"
"(A;OICI;GA;;;CO)" // Allow full control to creator owner.
"(A;OICI;GA;;;BA)" // Allow full control to admins.
"(A;OICI;GRGW;;;IU)"; // Allow read and write to interactive user.
SECURITY_ATTRIBUTES sa;
memset(&sa, 0, sizeof(sa));
sa.nLength = sizeof(sa);
sa.bInheritHandle = FALSE;
if (!ConvertStringSecurityDescriptorToSecurityDescriptorA(
user_specific ? kDaclUserSpecific : kDaclEveryone, SDDL_REVISION_1,
&sa.lpSecurityDescriptor, /*outSdSize=*/nullptr)) {
err = GetLastError();
return err;
}
// When `is_first_pipe` is true, the agent expects there is no process that
// is currently listening on this pipe. If there is, CreateNamedPipeA()
// returns with ERROR_ACCESS_DENIED. This is used to detect if another
// process is listening for connections when there shouldn't be.
if (is_first_pipe) {
mode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
}
*handle = CreateNamedPipeA(name.c_str(), mode,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT |
PIPE_REJECT_REMOTE_CLIENTS, PIPE_UNLIMITED_INSTANCES, kBufferSize,
kBufferSize, 0, &sa);
if (*handle == INVALID_HANDLE_VALUE) {
err = GetLastError();
}
// Free the security descriptor as it is no longer needed once
// CreateNamedPipeA() returns.
LocalFree(sa.lpSecurityDescriptor);
return err;
}
bool GetProcessPath(unsigned long pid, std::string* binary_path) {
HANDLE hProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
if (hProc == nullptr) {
return false;
}
char path[MAX_PATH];
DWORD size = sizeof(path);
DWORD length = QueryFullProcessImageNameA(hProc, /*flags=*/0, path, &size);
CloseHandle(hProc);
if (length == 0) {
return false;
}
*binary_path = path;
return true;
}
ScopedOverlapped::ScopedOverlapped() {
memset(&overlapped_, 0, sizeof(overlapped_));
overlapped_.hEvent = CreateEvent(/*securityAttr=*/nullptr,
/*manualReset=*/TRUE,
/*initialState=*/FALSE,
/*name=*/nullptr);
}
ScopedOverlapped::~ScopedOverlapped() {
if (overlapped_.hEvent != nullptr) {
CloseHandle(overlapped_.hEvent);
}
}
} // internal
} // namespace sdk
} // namespace content_analysis