1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012- OpenVPN Inc.
//
// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
//
#pragma once
// Get info about named pipe peer
#include <cstdlib> // defines std::abort()
#include <windows.h>
#include <sddl.h>
#include <aclapi.h>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/hexstr.hpp>
#include <openvpn/buffer/buffer.hpp>
#include <openvpn/win/winerr.hpp>
#include <openvpn/win/scoped_handle.hpp>
#include <openvpn/win/secattr.hpp>
namespace openvpn::Win {
struct NamedPipeImpersonate
{
OPENVPN_EXCEPTION(named_pipe_impersonate);
NamedPipeImpersonate(const HANDLE pipe)
{
if (!::ImpersonateNamedPipeClient(pipe))
{
const Win::LastError err;
OPENVPN_THROW(named_pipe_impersonate, "ImpersonateNamedPipeClient failed: " << err.message());
}
}
~NamedPipeImpersonate()
{
if (!::RevertToSelf())
{
OPENVPN_LOG("NamedPipeImpersonate: RevertToSelf failed, must abort");
std::abort();
}
}
};
struct NamedPipePeerInfo
{
OPENVPN_EXCEPTION(npinfo_error);
// Get process handle given PID.
static Win::ScopedHANDLE get_process(const ULONG pid, const bool limited)
{
// open process
Win::ScopedHANDLE proc(::OpenProcess(
limited ? (PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE) : PROCESS_ALL_ACCESS,
FALSE,
pid));
if (!proc.defined())
{
const Win::LastError err;
OPENVPN_THROW(npinfo_error, "OpenProcess failed: " << err.message());
}
return proc;
}
// Servers must call this method to modify their process
// access rights to grant clients the
// PROCESS_QUERY_LIMITED_INFORMATION right, so that clients
// can validate the server's exe path via get_exe_path().
static void allow_client_query()
{
SecurityAttributes sa(
"D:" // discretionary ACL
"(A;OICI;0x101000;;;S-1-1-0)" // grant PROCESS_QUERY_LIMITED_INFORMATION and SYNCHRONIZE access to Everyone
,
false,
"client query");
ACL *dacl;
BOOL bDaclPresent, bDaclDefaulted;
if (!::GetSecurityDescriptorDacl(sa.sa.lpSecurityDescriptor,
&bDaclPresent,
&dacl,
&bDaclDefaulted))
{
const Win::LastError err;
OPENVPN_THROW(npinfo_error, "allow_client_query: GetSecurityDescriptorDacl failed: " << err.message());
}
if (!bDaclPresent)
OPENVPN_THROW(npinfo_error, "allow_client_query: missing DACL");
const DWORD ssi_status = ::SetSecurityInfo(
::GetCurrentProcess(),
SE_KERNEL_OBJECT,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
dacl,
NULL);
if (ssi_status != ERROR_SUCCESS)
{
const Win::Error err(ssi_status);
OPENVPN_THROW(npinfo_error, "allow_client_query: SetSecurityInfo failed: " << err.message());
}
}
// Get PID of process at other end of named pipe
static ULONG get_pid(const HANDLE np_handle, const bool client)
{
ULONG pid = 0;
if (client)
{
if (!::GetNamedPipeClientProcessId(np_handle, &pid))
{
const Win::LastError err;
OPENVPN_THROW(npinfo_error, "GetNamedPipeClientProcessId failed: " << err.message());
}
}
else
{
if (!::GetNamedPipeServerProcessId(np_handle, &pid))
{
const Win::LastError err;
OPENVPN_THROW(npinfo_error, "GetNamedPipeServerProcessId failed: " << err.message());
}
}
return pid;
}
// Get exe path given process handle.
static std::wstring get_exe_path(const HANDLE proc)
{
// get exe path
const size_t exe_cap = 256;
wchar_t exe[exe_cap];
DWORD exe_size = exe_cap;
if (!::QueryFullProcessImageNameW(proc, 0, exe, &exe_size))
{
const Win::LastError err;
OPENVPN_THROW(npinfo_error, "QueryFullProcessImageNameW failed: " << err.message());
}
return std::wstring(exe, exe_size);
}
};
struct NamedPipePeerInfoCS : public NamedPipePeerInfo
{
NamedPipePeerInfoCS(const HANDLE handle, const bool client)
{
const ULONG pid = get_pid(handle, client);
proc = get_process(pid, !client);
exe_path = get_exe_path(proc());
}
Win::ScopedHANDLE proc;
std::wstring exe_path;
};
// Used by server to get info about clients
struct NamedPipePeerInfoClient : public NamedPipePeerInfoCS
{
NamedPipePeerInfoClient(const HANDLE handle)
: NamedPipePeerInfoCS(handle, true)
{
}
};
// Used by clients to get info about the server
struct NamedPipePeerInfoServer : public NamedPipePeerInfoCS
{
NamedPipePeerInfoServer(const HANDLE handle)
: NamedPipePeerInfoCS(handle, false)
{
}
};
} // namespace openvpn::Win
|