tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

utils_win.cc (5481B)


      1 // Copyright 2022 The Chromium Authors.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <vector>
      6 
      7 #include <windows.h>
      8 #include <sddl.h>
      9 
     10 #include "utils_win.h"
     11 
     12 namespace content_analysis {
     13 namespace sdk {
     14 namespace internal {
     15 
     16 std::string GetUserSID() {
     17  std::string sid;
     18 
     19  HANDLE handle;
     20  if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &handle) &&
     21    !OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &handle)) {
     22    return std::string();
     23  }
     24 
     25  DWORD length = 0;
     26  std::vector<char> buffer;
     27  if (!GetTokenInformation(handle, TokenUser, nullptr, 0, &length)) {
     28    DWORD err = GetLastError();
     29    if (err == ERROR_INSUFFICIENT_BUFFER) {
     30      buffer.resize(length);
     31    }
     32  }
     33  if (GetTokenInformation(handle, TokenUser, buffer.data(), buffer.size(),
     34    &length)) {
     35    TOKEN_USER* info = reinterpret_cast<TOKEN_USER*>(buffer.data());
     36    char* sid_string;
     37    if (ConvertSidToStringSidA(info->User.Sid, &sid_string)) {
     38      sid = sid_string;
     39      LocalFree(sid_string);
     40    }
     41  }
     42 
     43  CloseHandle(handle);
     44  return sid;
     45 }
     46 
     47 std::string BuildPipeName(const char* prefix,
     48                          const std::string& base,
     49                          bool user_specific) {
     50  std::string pipename = prefix;
     51 
     52  // If the agent is not user-specific, the assumption is that it runs with
     53  // administrator privileges.  Create the pipe in a location only available
     54  // to administrators.
     55  if (!user_specific)
     56    pipename += "ProtectedPrefix\\Administrators\\";
     57 
     58  pipename += base;
     59 
     60  if (user_specific) {
     61    std::string sid = GetUserSID();
     62    if (sid.empty())
     63      return std::string();
     64 
     65    pipename += "." + sid;
     66  }
     67 
     68  return pipename;
     69 }
     70 
     71 std::string GetPipeNameForAgent(const std::string& base, bool user_specific) {
     72  return BuildPipeName(kPipePrefixForAgent, base, user_specific);
     73 }
     74 
     75 std::string GetPipeNameForClient(const std::string& base, bool user_specific) {
     76  return BuildPipeName(kPipePrefixForClient, base, user_specific);
     77 }
     78 
     79 DWORD CreatePipe(
     80    const std::string& name,
     81    bool user_specific,
     82    bool is_first_pipe,
     83    HANDLE* handle) {
     84  DWORD err = ERROR_SUCCESS;
     85  DWORD mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED;
     86 
     87  // Create DACL for pipe to allow users on the local system to read and write
     88  // to the pipe.  The creator and owner as well as administrator always get
     89  // full control of the pipe.
     90  //
     91  // If `user_specific` is true, a different agent instance is used for each
     92  // OS user, so only allow the interactive logged on user to reads and write
     93  // messages to the pipe.  Otherwise only one agent instance used used for all
     94  // OS users and all authenticated logged on users can reads and write
     95  // messages.
     96  //
     97  // See https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-definition-language
     98  // for a description of this string format.
     99  constexpr char kDaclEveryone[] = "D:"
    100      "(A;OICI;GA;;;CO)"     // Allow full control to creator owner.
    101      "(A;OICI;GA;;;BA)"     // Allow full control to admins.
    102      "(A;OICI;GRGW;;;WD)";  // Allow read and write to everyone.
    103  constexpr char kDaclUserSpecific[] = "D:"
    104      "(A;OICI;GA;;;CO)"     // Allow full control to creator owner.
    105      "(A;OICI;GA;;;BA)"     // Allow full control to admins.
    106      "(A;OICI;GRGW;;;IU)";  // Allow read and write to interactive user.
    107  SECURITY_ATTRIBUTES sa;
    108  memset(&sa, 0, sizeof(sa));
    109  sa.nLength = sizeof(sa);
    110  sa.bInheritHandle = FALSE;
    111  if (!ConvertStringSecurityDescriptorToSecurityDescriptorA(
    112      user_specific ? kDaclUserSpecific : kDaclEveryone, SDDL_REVISION_1,
    113      &sa.lpSecurityDescriptor, /*outSdSize=*/nullptr)) {
    114    err = GetLastError();
    115    return err;
    116  }
    117 
    118  // When `is_first_pipe` is true, the agent expects there is no process that
    119  // is currently listening on this pipe.  If there is, CreateNamedPipeA()
    120  // returns with ERROR_ACCESS_DENIED.  This is used to detect if another
    121  // process is listening for connections when there shouldn't be.
    122  if (is_first_pipe) {
    123    mode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
    124  }
    125  *handle = CreateNamedPipeA(name.c_str(), mode,
    126    PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT |
    127    PIPE_REJECT_REMOTE_CLIENTS, PIPE_UNLIMITED_INSTANCES, kBufferSize,
    128    kBufferSize, 0, &sa);
    129  if (*handle == INVALID_HANDLE_VALUE) {
    130    err = GetLastError();
    131  }
    132 
    133  // Free the security descriptor as it is no longer needed once
    134  // CreateNamedPipeA() returns.
    135  LocalFree(sa.lpSecurityDescriptor);
    136 
    137  return err;
    138 }
    139 
    140 bool GetProcessPath(unsigned long pid, std::string* binary_path) {
    141  HANDLE hProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
    142  if (hProc == nullptr) {
    143    return false;
    144  }
    145  
    146  char path[MAX_PATH];
    147  DWORD size = sizeof(path);
    148  DWORD length = QueryFullProcessImageNameA(hProc, /*flags=*/0, path, &size);
    149  CloseHandle(hProc);
    150  if (length == 0) {
    151    return false;
    152  }
    153 
    154  *binary_path = path;
    155  return true;
    156 }
    157 
    158 ScopedOverlapped::ScopedOverlapped() {
    159  memset(&overlapped_, 0, sizeof(overlapped_));
    160  overlapped_.hEvent = CreateEvent(/*securityAttr=*/nullptr,
    161                                   /*manualReset=*/TRUE,
    162                                   /*initialState=*/FALSE,
    163                                   /*name=*/nullptr);
    164 }
    165 
    166 ScopedOverlapped::~ScopedOverlapped() {
    167  if (overlapped_.hEvent != nullptr) {
    168    CloseHandle(overlapped_.hEvent);
    169  }
    170 }
    171 
    172 }  // internal
    173 }  // namespace sdk
    174 }  // namespace content_analysis