mirror of
https://github.com/OpenVPN/openvpn3.git
synced 2024-09-19 11:42:15 +02:00
Make all C++ source code files have LF (Unix) line endings
For consistency. Some of the Windows-specific files, but not all of them, had CRLF file endings. Signed-off-by: Frank Lichtenheld <frank@lichtenheld.com>
This commit is contained in:
parent
f544e04df7
commit
b8ae379dd5
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.hpp eol=lf
|
||||
*.cpp eol=lf
|
@ -1,92 +1,92 @@
|
||||
// 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-2022 OpenVPN Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License Version 3
|
||||
// as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
// Client tun setup base class for Windows
|
||||
|
||||
#ifndef OPENVPN_TUN_WIN_CLIENT_SETUPBASE_H
|
||||
#define OPENVPN_TUN_WIN_CLIENT_SETUPBASE_H
|
||||
|
||||
#include <windows.h> // for HANDLE
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <openvpn/io/io.hpp>
|
||||
|
||||
#include <openvpn/common/destruct.hpp>
|
||||
#include <openvpn/common/stop.hpp>
|
||||
#include <openvpn/tun/builder/capture.hpp>
|
||||
|
||||
#include <openvpn/tun/win/ringbuffer.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace TunWin {
|
||||
struct SetupBase : public DestructorBase
|
||||
{
|
||||
typedef RCPtr<SetupBase> Ptr;
|
||||
|
||||
OPENVPN_EXCEPTION(tun_win_setup);
|
||||
|
||||
virtual HANDLE get_handle(std::ostream &os) = 0;
|
||||
|
||||
// clang-format off
|
||||
virtual HANDLE establish(const TunBuilderCapture &pull,
|
||||
const std::wstring &openvpn_app_path,
|
||||
Stop *stop,
|
||||
std::ostream &os,
|
||||
RingBuffer::Ptr rings) = 0;
|
||||
// clang-format on
|
||||
|
||||
virtual bool l2_ready(const TunBuilderCapture &pull) = 0;
|
||||
|
||||
// clang-format off
|
||||
virtual void l2_finish(const TunBuilderCapture &pull,
|
||||
Stop *stop,
|
||||
std::ostream &os) = 0;
|
||||
// clang-format on
|
||||
|
||||
virtual void confirm()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void set_service_fail_handler(std::function<void()> &&handler)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Util::TapNameGuidPair get_adapter_state() = 0;
|
||||
|
||||
virtual void set_adapter_state(const Util::TapNameGuidPair &state) = 0;
|
||||
};
|
||||
|
||||
struct SetupFactory : public RC<thread_unsafe_refcount>
|
||||
{
|
||||
typedef RCPtr<SetupFactory> Ptr;
|
||||
|
||||
// clang-format off
|
||||
virtual SetupBase::Ptr new_setup_obj(openvpn_io::io_context &io_context,
|
||||
const TunWin::Type tun_type,
|
||||
bool allow_local_dns_resolvers) = 0;
|
||||
// clang-format on
|
||||
};
|
||||
} // namespace TunWin
|
||||
} // namespace openvpn
|
||||
|
||||
#endif
|
||||
// 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-2022 OpenVPN Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License Version 3
|
||||
// as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
// Client tun setup base class for Windows
|
||||
|
||||
#ifndef OPENVPN_TUN_WIN_CLIENT_SETUPBASE_H
|
||||
#define OPENVPN_TUN_WIN_CLIENT_SETUPBASE_H
|
||||
|
||||
#include <windows.h> // for HANDLE
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <openvpn/io/io.hpp>
|
||||
|
||||
#include <openvpn/common/destruct.hpp>
|
||||
#include <openvpn/common/stop.hpp>
|
||||
#include <openvpn/tun/builder/capture.hpp>
|
||||
|
||||
#include <openvpn/tun/win/ringbuffer.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace TunWin {
|
||||
struct SetupBase : public DestructorBase
|
||||
{
|
||||
typedef RCPtr<SetupBase> Ptr;
|
||||
|
||||
OPENVPN_EXCEPTION(tun_win_setup);
|
||||
|
||||
virtual HANDLE get_handle(std::ostream &os) = 0;
|
||||
|
||||
// clang-format off
|
||||
virtual HANDLE establish(const TunBuilderCapture &pull,
|
||||
const std::wstring &openvpn_app_path,
|
||||
Stop *stop,
|
||||
std::ostream &os,
|
||||
RingBuffer::Ptr rings) = 0;
|
||||
// clang-format on
|
||||
|
||||
virtual bool l2_ready(const TunBuilderCapture &pull) = 0;
|
||||
|
||||
// clang-format off
|
||||
virtual void l2_finish(const TunBuilderCapture &pull,
|
||||
Stop *stop,
|
||||
std::ostream &os) = 0;
|
||||
// clang-format on
|
||||
|
||||
virtual void confirm()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void set_service_fail_handler(std::function<void()> &&handler)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Util::TapNameGuidPair get_adapter_state() = 0;
|
||||
|
||||
virtual void set_adapter_state(const Util::TapNameGuidPair &state) = 0;
|
||||
};
|
||||
|
||||
struct SetupFactory : public RC<thread_unsafe_refcount>
|
||||
{
|
||||
typedef RCPtr<SetupFactory> Ptr;
|
||||
|
||||
// clang-format off
|
||||
virtual SetupBase::Ptr new_setup_obj(openvpn_io::io_context &io_context,
|
||||
const TunWin::Type tun_type,
|
||||
bool allow_local_dns_resolvers) = 0;
|
||||
// clang-format on
|
||||
};
|
||||
} // namespace TunWin
|
||||
} // namespace openvpn
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,197 +1,197 @@
|
||||
// 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-2022 OpenVPN Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License Version 3
|
||||
// as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
// Name Resolution Policy Table (NRPT) utilities for Windows
|
||||
|
||||
#ifndef OPENVPN_TUN_WIN_NRPT_H
|
||||
#define OPENVPN_TUN_WIN_NRPT_H
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include <openvpn/common/exception.hpp>
|
||||
#include <openvpn/common/string.hpp>
|
||||
#include <openvpn/common/wstring.hpp>
|
||||
#include <openvpn/common/action.hpp>
|
||||
#include <openvpn/win/reg.hpp>
|
||||
#include <openvpn/win/winerr.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace TunWin {
|
||||
|
||||
// NRPT rules described here: https://msdn.microsoft.com/en-us/library/ff957356.aspx
|
||||
class NRPT
|
||||
{
|
||||
public:
|
||||
OPENVPN_EXCEPTION(nrpt_error);
|
||||
|
||||
static void create_rule(const std::vector<std::string> names, const std::vector<std::string> dns_servers)
|
||||
{
|
||||
Win::RegKey key;
|
||||
|
||||
for (size_t i = 0; i < names.size(); ++i)
|
||||
{
|
||||
// open/create the key
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << dnsPolicyConfig() << "\\" << policyPrefix() << "-" << i;
|
||||
auto key_name = ss.str();
|
||||
|
||||
const LONG status = ::RegCreateKeyA(HKEY_LOCAL_MACHINE, key_name.c_str(), key.ref());
|
||||
check_reg_error<nrpt_error>(status, key_name);
|
||||
}
|
||||
|
||||
// Name
|
||||
{
|
||||
std::wstring name(wstring::from_utf8(names[i]));
|
||||
name += L'\0';
|
||||
const LONG status = ::RegSetValueExW(key(),
|
||||
L"Name",
|
||||
0,
|
||||
REG_MULTI_SZ,
|
||||
(const BYTE *)name.c_str(),
|
||||
(name.length() + 1) * 2);
|
||||
check_reg_error<nrpt_error>(status, "Name");
|
||||
}
|
||||
|
||||
// GenericDNSServers
|
||||
{
|
||||
const std::wstring dns_servers_joined = wstring::from_utf8(string::join(dns_servers, ";"));
|
||||
const LONG status = ::RegSetValueExW(key(),
|
||||
L"GenericDNSServers",
|
||||
0,
|
||||
REG_SZ,
|
||||
(const BYTE *)dns_servers_joined.c_str(),
|
||||
(dns_servers_joined.length() + 1) * 2);
|
||||
check_reg_error<nrpt_error>(status, "GenericDNSServers");
|
||||
}
|
||||
|
||||
// ConfigOptions
|
||||
{
|
||||
const DWORD value = 0x8; // Only the Generic DNS server option (that is, the option defined in section 2.2.2.13) is specified.
|
||||
const LONG status = ::RegSetValueExW(key(),
|
||||
L"ConfigOptions",
|
||||
0,
|
||||
REG_DWORD,
|
||||
(const BYTE *)&value,
|
||||
sizeof(value));
|
||||
check_reg_error<nrpt_error>(status, "ConfigOptions");
|
||||
}
|
||||
|
||||
// Version
|
||||
{
|
||||
const DWORD value = 0x2;
|
||||
const LONG status = ::RegSetValueExW(key(),
|
||||
L"Version",
|
||||
0,
|
||||
REG_DWORD,
|
||||
(const BYTE *)&value,
|
||||
sizeof(value));
|
||||
check_reg_error<nrpt_error>(status, "Version");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool delete_rule()
|
||||
{
|
||||
Win::RegKeyEnumerator keys(HKEY_LOCAL_MACHINE, dnsPolicyConfig());
|
||||
|
||||
for (const auto &key : keys)
|
||||
{
|
||||
// remove only own policies
|
||||
if (key.find(policyPrefix()) == std::string::npos)
|
||||
continue;
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << dnsPolicyConfig() << "\\" << key;
|
||||
auto path = ss.str();
|
||||
::RegDeleteTreeA(HKEY_LOCAL_MACHINE, path.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
static const char *dnsPolicyConfig()
|
||||
{
|
||||
static const char subkey[] = "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig";
|
||||
return subkey;
|
||||
}
|
||||
|
||||
static const char *policyPrefix()
|
||||
{
|
||||
static const char prefix[] = "OpenVPNDNSRouting";
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public:
|
||||
class ActionCreate : public Action
|
||||
{
|
||||
public:
|
||||
ActionCreate(const std::vector<std::string> &names_arg,
|
||||
const std::vector<std::string> &dns_servers_arg)
|
||||
: names(names_arg),
|
||||
dns_servers(dns_servers_arg)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void execute(std::ostream &log) override
|
||||
{
|
||||
log << to_string() << std::endl;
|
||||
create_rule(names, dns_servers);
|
||||
}
|
||||
|
||||
virtual std::string to_string() const override
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "NRPT::ActionCreate"
|
||||
<< " names=[" << string::join(names, ",") << "]"
|
||||
<< " dns_servers=[" << string::join(dns_servers, ",") << "]";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
private:
|
||||
const std::vector<std::string> names;
|
||||
const std::vector<std::string> dns_servers;
|
||||
};
|
||||
|
||||
class ActionDelete : public Action
|
||||
{
|
||||
public:
|
||||
virtual void execute(std::ostream &log) override
|
||||
{
|
||||
log << to_string() << std::endl;
|
||||
delete_rule();
|
||||
}
|
||||
|
||||
virtual std::string to_string() const override
|
||||
{
|
||||
return "NRPT::ActionDelete";
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace TunWin
|
||||
} // namespace openvpn
|
||||
|
||||
#endif
|
||||
// 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-2022 OpenVPN Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License Version 3
|
||||
// as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
// Name Resolution Policy Table (NRPT) utilities for Windows
|
||||
|
||||
#ifndef OPENVPN_TUN_WIN_NRPT_H
|
||||
#define OPENVPN_TUN_WIN_NRPT_H
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include <openvpn/common/exception.hpp>
|
||||
#include <openvpn/common/string.hpp>
|
||||
#include <openvpn/common/wstring.hpp>
|
||||
#include <openvpn/common/action.hpp>
|
||||
#include <openvpn/win/reg.hpp>
|
||||
#include <openvpn/win/winerr.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace TunWin {
|
||||
|
||||
// NRPT rules described here: https://msdn.microsoft.com/en-us/library/ff957356.aspx
|
||||
class NRPT
|
||||
{
|
||||
public:
|
||||
OPENVPN_EXCEPTION(nrpt_error);
|
||||
|
||||
static void create_rule(const std::vector<std::string> names, const std::vector<std::string> dns_servers)
|
||||
{
|
||||
Win::RegKey key;
|
||||
|
||||
for (size_t i = 0; i < names.size(); ++i)
|
||||
{
|
||||
// open/create the key
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << dnsPolicyConfig() << "\\" << policyPrefix() << "-" << i;
|
||||
auto key_name = ss.str();
|
||||
|
||||
const LONG status = ::RegCreateKeyA(HKEY_LOCAL_MACHINE, key_name.c_str(), key.ref());
|
||||
check_reg_error<nrpt_error>(status, key_name);
|
||||
}
|
||||
|
||||
// Name
|
||||
{
|
||||
std::wstring name(wstring::from_utf8(names[i]));
|
||||
name += L'\0';
|
||||
const LONG status = ::RegSetValueExW(key(),
|
||||
L"Name",
|
||||
0,
|
||||
REG_MULTI_SZ,
|
||||
(const BYTE *)name.c_str(),
|
||||
(name.length() + 1) * 2);
|
||||
check_reg_error<nrpt_error>(status, "Name");
|
||||
}
|
||||
|
||||
// GenericDNSServers
|
||||
{
|
||||
const std::wstring dns_servers_joined = wstring::from_utf8(string::join(dns_servers, ";"));
|
||||
const LONG status = ::RegSetValueExW(key(),
|
||||
L"GenericDNSServers",
|
||||
0,
|
||||
REG_SZ,
|
||||
(const BYTE *)dns_servers_joined.c_str(),
|
||||
(dns_servers_joined.length() + 1) * 2);
|
||||
check_reg_error<nrpt_error>(status, "GenericDNSServers");
|
||||
}
|
||||
|
||||
// ConfigOptions
|
||||
{
|
||||
const DWORD value = 0x8; // Only the Generic DNS server option (that is, the option defined in section 2.2.2.13) is specified.
|
||||
const LONG status = ::RegSetValueExW(key(),
|
||||
L"ConfigOptions",
|
||||
0,
|
||||
REG_DWORD,
|
||||
(const BYTE *)&value,
|
||||
sizeof(value));
|
||||
check_reg_error<nrpt_error>(status, "ConfigOptions");
|
||||
}
|
||||
|
||||
// Version
|
||||
{
|
||||
const DWORD value = 0x2;
|
||||
const LONG status = ::RegSetValueExW(key(),
|
||||
L"Version",
|
||||
0,
|
||||
REG_DWORD,
|
||||
(const BYTE *)&value,
|
||||
sizeof(value));
|
||||
check_reg_error<nrpt_error>(status, "Version");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool delete_rule()
|
||||
{
|
||||
Win::RegKeyEnumerator keys(HKEY_LOCAL_MACHINE, dnsPolicyConfig());
|
||||
|
||||
for (const auto &key : keys)
|
||||
{
|
||||
// remove only own policies
|
||||
if (key.find(policyPrefix()) == std::string::npos)
|
||||
continue;
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << dnsPolicyConfig() << "\\" << key;
|
||||
auto path = ss.str();
|
||||
::RegDeleteTreeA(HKEY_LOCAL_MACHINE, path.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
static const char *dnsPolicyConfig()
|
||||
{
|
||||
static const char subkey[] = "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig";
|
||||
return subkey;
|
||||
}
|
||||
|
||||
static const char *policyPrefix()
|
||||
{
|
||||
static const char prefix[] = "OpenVPNDNSRouting";
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public:
|
||||
class ActionCreate : public Action
|
||||
{
|
||||
public:
|
||||
ActionCreate(const std::vector<std::string> &names_arg,
|
||||
const std::vector<std::string> &dns_servers_arg)
|
||||
: names(names_arg),
|
||||
dns_servers(dns_servers_arg)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void execute(std::ostream &log) override
|
||||
{
|
||||
log << to_string() << std::endl;
|
||||
create_rule(names, dns_servers);
|
||||
}
|
||||
|
||||
virtual std::string to_string() const override
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "NRPT::ActionCreate"
|
||||
<< " names=[" << string::join(names, ",") << "]"
|
||||
<< " dns_servers=[" << string::join(dns_servers, ",") << "]";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
private:
|
||||
const std::vector<std::string> names;
|
||||
const std::vector<std::string> dns_servers;
|
||||
};
|
||||
|
||||
class ActionDelete : public Action
|
||||
{
|
||||
public:
|
||||
virtual void execute(std::ostream &log) override
|
||||
{
|
||||
log << to_string() << std::endl;
|
||||
delete_rule();
|
||||
}
|
||||
|
||||
virtual std::string to_string() const override
|
||||
{
|
||||
return "NRPT::ActionDelete";
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace TunWin
|
||||
} // namespace openvpn
|
||||
|
||||
#endif
|
||||
|
@ -1,185 +1,185 @@
|
||||
// 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-2022 OpenVPN Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License Version 3
|
||||
// as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
// proxy settings for Windows
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wininet.h>
|
||||
|
||||
#include <openvpn/win/impersonate.hpp>
|
||||
#include <openvpn/tun/proxy.hpp>
|
||||
#include <openvpn/win/reg.hpp>
|
||||
|
||||
using namespace openvpn::Win;
|
||||
|
||||
namespace openvpn {
|
||||
namespace TunWin {
|
||||
class WinProxySettings : public ProxySettings
|
||||
{
|
||||
public:
|
||||
typedef RCPtr<WinProxySettings> Ptr;
|
||||
|
||||
WinProxySettings(const TunBuilderCapture::ProxyAutoConfigURL &config_arg)
|
||||
: ProxySettings(config_arg)
|
||||
{
|
||||
}
|
||||
|
||||
void set_proxy(bool del) override
|
||||
{
|
||||
Impersonate imp{false};
|
||||
|
||||
LONG status;
|
||||
RegKey hkcu;
|
||||
RegKey key;
|
||||
|
||||
status = ::RegOpenCurrentUser(KEY_QUERY_VALUE | KEY_SET_VALUE, hkcu.ref());
|
||||
check_reg_error<proxy_error>(status, "RegOpenCurrentUser");
|
||||
|
||||
status = ::RegCreateKeyExA(hkcu(), key_name, 0, NULL, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, NULL, key.ref(), NULL);
|
||||
check_reg_error<proxy_error>(status, key_name);
|
||||
|
||||
if (!del)
|
||||
{
|
||||
save_key(key, "AutoConfigURL", config.url, true);
|
||||
save_key(key, "ProxyEnable", "0", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
restore_key(key, "AutoConfigURL", true);
|
||||
restore_key(key, "ProxyEnable", false);
|
||||
}
|
||||
|
||||
// WinInet API cannot be called from service, even via impersonation
|
||||
if (!imp.is_local_system())
|
||||
{
|
||||
OPENVPN_LOG("Refresh proxy settings");
|
||||
|
||||
InternetSetOptionA(NULL, INTERNET_OPTION_SETTINGS_CHANGED, NULL, 0);
|
||||
InternetSetOptionA(NULL, INTERNET_OPTION_REFRESH, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void restore_key(Win::RegKey ®key, const std::string &key, bool str)
|
||||
{
|
||||
LONG status;
|
||||
char prev_val_str[1024] = {0}; // should be enough to fit proxy URL
|
||||
DWORD prev_val_dword;
|
||||
DWORD prev_buf_size = str ? sizeof(prev_val_str) : sizeof(prev_val_dword);
|
||||
bool del = false;
|
||||
Win::RegKey hkcu;
|
||||
|
||||
status = ::RegOpenCurrentUser(KEY_QUERY_VALUE | KEY_SET_VALUE, hkcu.ref());
|
||||
check_reg_error<proxy_error>(status, "RegOpenCurrentUser");
|
||||
|
||||
// get previous value
|
||||
std::string prev_key_name = sname + key;
|
||||
status = ::RegGetValueA(hkcu(),
|
||||
key_name,
|
||||
prev_key_name.c_str(),
|
||||
str ? RRF_RT_REG_SZ : RRF_RT_REG_DWORD,
|
||||
NULL,
|
||||
str ? (PVOID)prev_val_str : (PVOID)&prev_val_dword,
|
||||
&prev_buf_size);
|
||||
check_reg_error<proxy_error>(status, prev_key_name);
|
||||
|
||||
RegDeleteValueA(regkey(), prev_key_name.c_str());
|
||||
|
||||
// check if previous value needs to be deleted
|
||||
if (str)
|
||||
del = strcmp(delete_value_str, prev_val_str) == 0;
|
||||
else
|
||||
del = prev_val_dword == delete_value_dword;
|
||||
|
||||
if (del)
|
||||
::RegDeleteValueA(regkey(), key.c_str());
|
||||
else
|
||||
::RegSetValueExA(regkey(),
|
||||
key.c_str(),
|
||||
0,
|
||||
str ? REG_SZ : REG_DWORD,
|
||||
str ? (const BYTE *)prev_val_str : (CONST BYTE *)&prev_val_dword,
|
||||
str ? strlen(prev_val_str) + 1 : sizeof(prev_val_dword));
|
||||
}
|
||||
|
||||
void save_key(Win::RegKey ®key, const std::string &key, const std::string &value, bool str)
|
||||
{
|
||||
LONG status;
|
||||
char prev_val_str[1024] = {0}; // should be enought to fit proxy URL
|
||||
DWORD prev_val_dword;
|
||||
DWORD prev_buf_size = str ? sizeof(prev_val_str) : sizeof(prev_val_dword);
|
||||
Win::RegKey hkcu;
|
||||
|
||||
status = ::RegOpenCurrentUser(KEY_QUERY_VALUE | KEY_SET_VALUE, hkcu.ref());
|
||||
check_reg_error<proxy_error>(status, "RegOpenCurrentUser");
|
||||
|
||||
// get original value
|
||||
status = ::RegGetValueA(hkcu(),
|
||||
key_name,
|
||||
key.c_str(),
|
||||
str ? RRF_RT_REG_SZ : RRF_RT_REG_DWORD,
|
||||
NULL,
|
||||
str ? (PVOID)prev_val_str : (PVOID)&prev_val_dword,
|
||||
&prev_buf_size);
|
||||
switch (status)
|
||||
{
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
// mark that original value doesn't exist
|
||||
strcpy(prev_val_str, delete_value_str);
|
||||
prev_val_dword = delete_value_dword;
|
||||
case ERROR_SUCCESS:
|
||||
break;
|
||||
default:
|
||||
check_reg_error<proxy_error>(status, key);
|
||||
break;
|
||||
}
|
||||
|
||||
// save original value
|
||||
std::string prev_key_name = sname + key;
|
||||
status = ::RegSetValueExA(regkey(),
|
||||
prev_key_name.c_str(),
|
||||
0,
|
||||
str ? REG_SZ : REG_DWORD,
|
||||
str ? (const BYTE *)prev_val_str : (CONST BYTE *)&prev_val_dword,
|
||||
str ? strlen(prev_val_str) + 1 : sizeof(DWORD));
|
||||
check_reg_error<proxy_error>(status, prev_key_name);
|
||||
|
||||
// save new value
|
||||
DWORD val_dword = 0;
|
||||
if (!str)
|
||||
val_dword = std::atol(value.c_str());
|
||||
status = ::RegSetValueExA(regkey(),
|
||||
key.c_str(),
|
||||
0,
|
||||
str ? REG_SZ : REG_DWORD,
|
||||
str ? (const BYTE *)value.c_str() : (CONST BYTE *)&val_dword,
|
||||
str ? value.length() + 1 : sizeof(val_dword));
|
||||
check_reg_error<proxy_error>(status, key);
|
||||
}
|
||||
|
||||
const char *key_name = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
|
||||
const char *delete_value_str = "DeleteValue";
|
||||
const DWORD delete_value_dword = 0xCAFEBABE;
|
||||
};
|
||||
} // namespace TunWin
|
||||
} // namespace openvpn
|
||||
// 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-2022 OpenVPN Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License Version 3
|
||||
// as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
// proxy settings for Windows
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wininet.h>
|
||||
|
||||
#include <openvpn/win/impersonate.hpp>
|
||||
#include <openvpn/tun/proxy.hpp>
|
||||
#include <openvpn/win/reg.hpp>
|
||||
|
||||
using namespace openvpn::Win;
|
||||
|
||||
namespace openvpn {
|
||||
namespace TunWin {
|
||||
class WinProxySettings : public ProxySettings
|
||||
{
|
||||
public:
|
||||
typedef RCPtr<WinProxySettings> Ptr;
|
||||
|
||||
WinProxySettings(const TunBuilderCapture::ProxyAutoConfigURL &config_arg)
|
||||
: ProxySettings(config_arg)
|
||||
{
|
||||
}
|
||||
|
||||
void set_proxy(bool del) override
|
||||
{
|
||||
Impersonate imp{false};
|
||||
|
||||
LONG status;
|
||||
RegKey hkcu;
|
||||
RegKey key;
|
||||
|
||||
status = ::RegOpenCurrentUser(KEY_QUERY_VALUE | KEY_SET_VALUE, hkcu.ref());
|
||||
check_reg_error<proxy_error>(status, "RegOpenCurrentUser");
|
||||
|
||||
status = ::RegCreateKeyExA(hkcu(), key_name, 0, NULL, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, NULL, key.ref(), NULL);
|
||||
check_reg_error<proxy_error>(status, key_name);
|
||||
|
||||
if (!del)
|
||||
{
|
||||
save_key(key, "AutoConfigURL", config.url, true);
|
||||
save_key(key, "ProxyEnable", "0", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
restore_key(key, "AutoConfigURL", true);
|
||||
restore_key(key, "ProxyEnable", false);
|
||||
}
|
||||
|
||||
// WinInet API cannot be called from service, even via impersonation
|
||||
if (!imp.is_local_system())
|
||||
{
|
||||
OPENVPN_LOG("Refresh proxy settings");
|
||||
|
||||
InternetSetOptionA(NULL, INTERNET_OPTION_SETTINGS_CHANGED, NULL, 0);
|
||||
InternetSetOptionA(NULL, INTERNET_OPTION_REFRESH, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void restore_key(Win::RegKey ®key, const std::string &key, bool str)
|
||||
{
|
||||
LONG status;
|
||||
char prev_val_str[1024] = {0}; // should be enough to fit proxy URL
|
||||
DWORD prev_val_dword;
|
||||
DWORD prev_buf_size = str ? sizeof(prev_val_str) : sizeof(prev_val_dword);
|
||||
bool del = false;
|
||||
Win::RegKey hkcu;
|
||||
|
||||
status = ::RegOpenCurrentUser(KEY_QUERY_VALUE | KEY_SET_VALUE, hkcu.ref());
|
||||
check_reg_error<proxy_error>(status, "RegOpenCurrentUser");
|
||||
|
||||
// get previous value
|
||||
std::string prev_key_name = sname + key;
|
||||
status = ::RegGetValueA(hkcu(),
|
||||
key_name,
|
||||
prev_key_name.c_str(),
|
||||
str ? RRF_RT_REG_SZ : RRF_RT_REG_DWORD,
|
||||
NULL,
|
||||
str ? (PVOID)prev_val_str : (PVOID)&prev_val_dword,
|
||||
&prev_buf_size);
|
||||
check_reg_error<proxy_error>(status, prev_key_name);
|
||||
|
||||
RegDeleteValueA(regkey(), prev_key_name.c_str());
|
||||
|
||||
// check if previous value needs to be deleted
|
||||
if (str)
|
||||
del = strcmp(delete_value_str, prev_val_str) == 0;
|
||||
else
|
||||
del = prev_val_dword == delete_value_dword;
|
||||
|
||||
if (del)
|
||||
::RegDeleteValueA(regkey(), key.c_str());
|
||||
else
|
||||
::RegSetValueExA(regkey(),
|
||||
key.c_str(),
|
||||
0,
|
||||
str ? REG_SZ : REG_DWORD,
|
||||
str ? (const BYTE *)prev_val_str : (CONST BYTE *)&prev_val_dword,
|
||||
str ? strlen(prev_val_str) + 1 : sizeof(prev_val_dword));
|
||||
}
|
||||
|
||||
void save_key(Win::RegKey ®key, const std::string &key, const std::string &value, bool str)
|
||||
{
|
||||
LONG status;
|
||||
char prev_val_str[1024] = {0}; // should be enought to fit proxy URL
|
||||
DWORD prev_val_dword;
|
||||
DWORD prev_buf_size = str ? sizeof(prev_val_str) : sizeof(prev_val_dword);
|
||||
Win::RegKey hkcu;
|
||||
|
||||
status = ::RegOpenCurrentUser(KEY_QUERY_VALUE | KEY_SET_VALUE, hkcu.ref());
|
||||
check_reg_error<proxy_error>(status, "RegOpenCurrentUser");
|
||||
|
||||
// get original value
|
||||
status = ::RegGetValueA(hkcu(),
|
||||
key_name,
|
||||
key.c_str(),
|
||||
str ? RRF_RT_REG_SZ : RRF_RT_REG_DWORD,
|
||||
NULL,
|
||||
str ? (PVOID)prev_val_str : (PVOID)&prev_val_dword,
|
||||
&prev_buf_size);
|
||||
switch (status)
|
||||
{
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
// mark that original value doesn't exist
|
||||
strcpy(prev_val_str, delete_value_str);
|
||||
prev_val_dword = delete_value_dword;
|
||||
case ERROR_SUCCESS:
|
||||
break;
|
||||
default:
|
||||
check_reg_error<proxy_error>(status, key);
|
||||
break;
|
||||
}
|
||||
|
||||
// save original value
|
||||
std::string prev_key_name = sname + key;
|
||||
status = ::RegSetValueExA(regkey(),
|
||||
prev_key_name.c_str(),
|
||||
0,
|
||||
str ? REG_SZ : REG_DWORD,
|
||||
str ? (const BYTE *)prev_val_str : (CONST BYTE *)&prev_val_dword,
|
||||
str ? strlen(prev_val_str) + 1 : sizeof(DWORD));
|
||||
check_reg_error<proxy_error>(status, prev_key_name);
|
||||
|
||||
// save new value
|
||||
DWORD val_dword = 0;
|
||||
if (!str)
|
||||
val_dword = std::atol(value.c_str());
|
||||
status = ::RegSetValueExA(regkey(),
|
||||
key.c_str(),
|
||||
0,
|
||||
str ? REG_SZ : REG_DWORD,
|
||||
str ? (const BYTE *)value.c_str() : (CONST BYTE *)&val_dword,
|
||||
str ? value.length() + 1 : sizeof(val_dword));
|
||||
check_reg_error<proxy_error>(status, key);
|
||||
}
|
||||
|
||||
const char *key_name = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
|
||||
const char *delete_value_str = "DeleteValue";
|
||||
const DWORD delete_value_dword = 0xCAFEBABE;
|
||||
};
|
||||
} // namespace TunWin
|
||||
} // namespace openvpn
|
||||
|
@ -1,220 +1,220 @@
|
||||
// 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-2022 OpenVPN Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License Version 3
|
||||
// as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <lmcons.h>
|
||||
#include <wtsapi32.h>
|
||||
|
||||
#include <openvpn/win/winerr.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace Win {
|
||||
|
||||
class Impersonate
|
||||
{
|
||||
public:
|
||||
explicit Impersonate(bool as_local_system)
|
||||
: local_system_(is_local_system_())
|
||||
{
|
||||
if (as_local_system)
|
||||
{
|
||||
if (local_system_)
|
||||
OPENVPN_LOG("ImpersonateAsSystem: running under SYSTEM account, no need to impersonate");
|
||||
else
|
||||
impersonate_as_local_system();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (local_system_)
|
||||
impersonate_as_user();
|
||||
else
|
||||
OPENVPN_LOG("ImpersonateAsUser: running under user account, no need to impersonate");
|
||||
}
|
||||
}
|
||||
|
||||
~Impersonate()
|
||||
{
|
||||
if (impersonated)
|
||||
{
|
||||
if (!RevertToSelf())
|
||||
{
|
||||
const Win::LastError err;
|
||||
OPENVPN_LOG("Impersonate: RevertToSelf() failed: " << err.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_local_system() const
|
||||
{
|
||||
return local_system_;
|
||||
}
|
||||
|
||||
private:
|
||||
void impersonate_as_local_system()
|
||||
{
|
||||
HANDLE thread_token, process_snapshot, winlogon_process, winlogon_token, duplicated_token;
|
||||
PROCESSENTRY32 entry = {};
|
||||
entry.dwSize = sizeof(PROCESSENTRY32);
|
||||
BOOL ret;
|
||||
DWORD pid = 0;
|
||||
TOKEN_PRIVILEGES privileges = {};
|
||||
privileges.PrivilegeCount = 1;
|
||||
privileges.Privileges->Attributes = SE_PRIVILEGE_ENABLED;
|
||||
|
||||
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &privileges.Privileges[0].Luid))
|
||||
return;
|
||||
|
||||
if (!ImpersonateSelf(SecurityImpersonation))
|
||||
return;
|
||||
|
||||
impersonated = true;
|
||||
|
||||
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &thread_token))
|
||||
return;
|
||||
if (!AdjustTokenPrivileges(thread_token, FALSE, &privileges, sizeof(privileges), NULL, NULL))
|
||||
{
|
||||
CloseHandle(thread_token);
|
||||
return;
|
||||
}
|
||||
CloseHandle(thread_token);
|
||||
|
||||
process_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (process_snapshot == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
|
||||
for (ret = Process32First(process_snapshot, &entry); ret; ret = Process32Next(process_snapshot, &entry))
|
||||
{
|
||||
if (!_stricmp(entry.szExeFile, "winlogon.exe"))
|
||||
{
|
||||
pid = entry.th32ProcessID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CloseHandle(process_snapshot);
|
||||
if (!pid)
|
||||
return;
|
||||
|
||||
winlogon_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
|
||||
if (!winlogon_process)
|
||||
return;
|
||||
|
||||
if (!OpenProcessToken(winlogon_process, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &winlogon_token))
|
||||
{
|
||||
CloseHandle(winlogon_process);
|
||||
return;
|
||||
}
|
||||
CloseHandle(winlogon_process);
|
||||
|
||||
if (!DuplicateToken(winlogon_token, SecurityImpersonation, &duplicated_token))
|
||||
{
|
||||
CloseHandle(winlogon_token);
|
||||
return;
|
||||
}
|
||||
CloseHandle(winlogon_token);
|
||||
|
||||
if (!SetThreadToken(NULL, duplicated_token))
|
||||
{
|
||||
CloseHandle(duplicated_token);
|
||||
return;
|
||||
}
|
||||
CloseHandle(duplicated_token);
|
||||
}
|
||||
|
||||
void impersonate_as_user()
|
||||
{
|
||||
DWORD sessId = WTSGetActiveConsoleSessionId();
|
||||
if (sessId == 0xFFFFFFFF)
|
||||
{
|
||||
const Win::LastError err;
|
||||
OPENVPN_LOG("ImpersonateAsUser: WTSGetActiveConsoleSessionId() failed: " << err.message());
|
||||
return;
|
||||
}
|
||||
|
||||
HANDLE hToken;
|
||||
if (!WTSQueryUserToken(sessId, &hToken))
|
||||
{
|
||||
const Win::LastError err;
|
||||
OPENVPN_LOG("ImpersonateAsUser: WTSQueryUserToken() failed: " << err.message());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ImpersonateLoggedOnUser(hToken))
|
||||
{
|
||||
CloseHandle(hToken);
|
||||
|
||||
const Win::LastError err;
|
||||
OPENVPN_LOG("ImpersonateAsUser: ImpersonateLoggedOnUser() failed: " << err.message());
|
||||
return;
|
||||
}
|
||||
|
||||
CloseHandle(hToken);
|
||||
|
||||
impersonated = true;
|
||||
|
||||
char uname[UNLEN + 1];
|
||||
DWORD len = UNLEN + 1;
|
||||
GetUserNameA(uname, &len);
|
||||
OPENVPN_LOG("ImpersonateAsUser: impersonated as " << uname);
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/4024388/227024
|
||||
BOOL is_local_system_() const
|
||||
{
|
||||
HANDLE hToken;
|
||||
UCHAR bTokenUser[sizeof(TOKEN_USER) + 8 + 4 * SID_MAX_SUB_AUTHORITIES];
|
||||
PTOKEN_USER pTokenUser = (PTOKEN_USER)bTokenUser;
|
||||
ULONG cbTokenUser;
|
||||
SID_IDENTIFIER_AUTHORITY siaNT = SECURITY_NT_AUTHORITY;
|
||||
PSID pSystemSid;
|
||||
BOOL bSystem;
|
||||
|
||||
// open process token
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
|
||||
return FALSE;
|
||||
|
||||
// retrieve user SID
|
||||
if (!GetTokenInformation(hToken, TokenUser, pTokenUser, sizeof(bTokenUser), &cbTokenUser))
|
||||
{
|
||||
CloseHandle(hToken);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CloseHandle(hToken);
|
||||
|
||||
// allocate LocalSystem well-known SID
|
||||
if (!AllocateAndInitializeSid(&siaNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pSystemSid))
|
||||
return FALSE;
|
||||
|
||||
// compare the user SID from the token with the LocalSystem SID
|
||||
bSystem = EqualSid(pTokenUser->User.Sid, pSystemSid);
|
||||
|
||||
FreeSid(pSystemSid);
|
||||
|
||||
return bSystem;
|
||||
}
|
||||
|
||||
bool local_system_ = false;
|
||||
bool impersonated = false;
|
||||
};
|
||||
} // namespace Win
|
||||
} // namespace openvpn
|
||||
// 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-2022 OpenVPN Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License Version 3
|
||||
// as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <lmcons.h>
|
||||
#include <wtsapi32.h>
|
||||
|
||||
#include <openvpn/win/winerr.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace Win {
|
||||
|
||||
class Impersonate
|
||||
{
|
||||
public:
|
||||
explicit Impersonate(bool as_local_system)
|
||||
: local_system_(is_local_system_())
|
||||
{
|
||||
if (as_local_system)
|
||||
{
|
||||
if (local_system_)
|
||||
OPENVPN_LOG("ImpersonateAsSystem: running under SYSTEM account, no need to impersonate");
|
||||
else
|
||||
impersonate_as_local_system();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (local_system_)
|
||||
impersonate_as_user();
|
||||
else
|
||||
OPENVPN_LOG("ImpersonateAsUser: running under user account, no need to impersonate");
|
||||
}
|
||||
}
|
||||
|
||||
~Impersonate()
|
||||
{
|
||||
if (impersonated)
|
||||
{
|
||||
if (!RevertToSelf())
|
||||
{
|
||||
const Win::LastError err;
|
||||
OPENVPN_LOG("Impersonate: RevertToSelf() failed: " << err.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_local_system() const
|
||||
{
|
||||
return local_system_;
|
||||
}
|
||||
|
||||
private:
|
||||
void impersonate_as_local_system()
|
||||
{
|
||||
HANDLE thread_token, process_snapshot, winlogon_process, winlogon_token, duplicated_token;
|
||||
PROCESSENTRY32 entry = {};
|
||||
entry.dwSize = sizeof(PROCESSENTRY32);
|
||||
BOOL ret;
|
||||
DWORD pid = 0;
|
||||
TOKEN_PRIVILEGES privileges = {};
|
||||
privileges.PrivilegeCount = 1;
|
||||
privileges.Privileges->Attributes = SE_PRIVILEGE_ENABLED;
|
||||
|
||||
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &privileges.Privileges[0].Luid))
|
||||
return;
|
||||
|
||||
if (!ImpersonateSelf(SecurityImpersonation))
|
||||
return;
|
||||
|
||||
impersonated = true;
|
||||
|
||||
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &thread_token))
|
||||
return;
|
||||
if (!AdjustTokenPrivileges(thread_token, FALSE, &privileges, sizeof(privileges), NULL, NULL))
|
||||
{
|
||||
CloseHandle(thread_token);
|
||||
return;
|
||||
}
|
||||
CloseHandle(thread_token);
|
||||
|
||||
process_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (process_snapshot == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
|
||||
for (ret = Process32First(process_snapshot, &entry); ret; ret = Process32Next(process_snapshot, &entry))
|
||||
{
|
||||
if (!_stricmp(entry.szExeFile, "winlogon.exe"))
|
||||
{
|
||||
pid = entry.th32ProcessID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CloseHandle(process_snapshot);
|
||||
if (!pid)
|
||||
return;
|
||||
|
||||
winlogon_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
|
||||
if (!winlogon_process)
|
||||
return;
|
||||
|
||||
if (!OpenProcessToken(winlogon_process, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &winlogon_token))
|
||||
{
|
||||
CloseHandle(winlogon_process);
|
||||
return;
|
||||
}
|
||||
CloseHandle(winlogon_process);
|
||||
|
||||
if (!DuplicateToken(winlogon_token, SecurityImpersonation, &duplicated_token))
|
||||
{
|
||||
CloseHandle(winlogon_token);
|
||||
return;
|
||||
}
|
||||
CloseHandle(winlogon_token);
|
||||
|
||||
if (!SetThreadToken(NULL, duplicated_token))
|
||||
{
|
||||
CloseHandle(duplicated_token);
|
||||
return;
|
||||
}
|
||||
CloseHandle(duplicated_token);
|
||||
}
|
||||
|
||||
void impersonate_as_user()
|
||||
{
|
||||
DWORD sessId = WTSGetActiveConsoleSessionId();
|
||||
if (sessId == 0xFFFFFFFF)
|
||||
{
|
||||
const Win::LastError err;
|
||||
OPENVPN_LOG("ImpersonateAsUser: WTSGetActiveConsoleSessionId() failed: " << err.message());
|
||||
return;
|
||||
}
|
||||
|
||||
HANDLE hToken;
|
||||
if (!WTSQueryUserToken(sessId, &hToken))
|
||||
{
|
||||
const Win::LastError err;
|
||||
OPENVPN_LOG("ImpersonateAsUser: WTSQueryUserToken() failed: " << err.message());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ImpersonateLoggedOnUser(hToken))
|
||||
{
|
||||
CloseHandle(hToken);
|
||||
|
||||
const Win::LastError err;
|
||||
OPENVPN_LOG("ImpersonateAsUser: ImpersonateLoggedOnUser() failed: " << err.message());
|
||||
return;
|
||||
}
|
||||
|
||||
CloseHandle(hToken);
|
||||
|
||||
impersonated = true;
|
||||
|
||||
char uname[UNLEN + 1];
|
||||
DWORD len = UNLEN + 1;
|
||||
GetUserNameA(uname, &len);
|
||||
OPENVPN_LOG("ImpersonateAsUser: impersonated as " << uname);
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/4024388/227024
|
||||
BOOL is_local_system_() const
|
||||
{
|
||||
HANDLE hToken;
|
||||
UCHAR bTokenUser[sizeof(TOKEN_USER) + 8 + 4 * SID_MAX_SUB_AUTHORITIES];
|
||||
PTOKEN_USER pTokenUser = (PTOKEN_USER)bTokenUser;
|
||||
ULONG cbTokenUser;
|
||||
SID_IDENTIFIER_AUTHORITY siaNT = SECURITY_NT_AUTHORITY;
|
||||
PSID pSystemSid;
|
||||
BOOL bSystem;
|
||||
|
||||
// open process token
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
|
||||
return FALSE;
|
||||
|
||||
// retrieve user SID
|
||||
if (!GetTokenInformation(hToken, TokenUser, pTokenUser, sizeof(bTokenUser), &cbTokenUser))
|
||||
{
|
||||
CloseHandle(hToken);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CloseHandle(hToken);
|
||||
|
||||
// allocate LocalSystem well-known SID
|
||||
if (!AllocateAndInitializeSid(&siaNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pSystemSid))
|
||||
return FALSE;
|
||||
|
||||
// compare the user SID from the token with the LocalSystem SID
|
||||
bSystem = EqualSid(pTokenUser->User.Sid, pSystemSid);
|
||||
|
||||
FreeSid(pSystemSid);
|
||||
|
||||
return bSystem;
|
||||
}
|
||||
|
||||
bool local_system_ = false;
|
||||
bool impersonated = false;
|
||||
};
|
||||
} // namespace Win
|
||||
} // namespace openvpn
|
||||
|
@ -1,130 +1,130 @@
|
||||
// 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-2022 OpenVPN Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License Version 3
|
||||
// as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// registry utilities for Windows
|
||||
|
||||
#ifndef OPENVPN_WIN_REG_H
|
||||
#define OPENVPN_WIN_REG_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <openvpn/win/winerr.hpp>
|
||||
#include <openvpn/common/size.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace Win {
|
||||
|
||||
template <typename E>
|
||||
static void check_reg_error(DWORD status, const std::string &key)
|
||||
{
|
||||
if (status != ERROR_SUCCESS)
|
||||
{
|
||||
const Win::Error err(status);
|
||||
OPENVPN_THROW(E, "registry key " << key << " error: " << err.message());
|
||||
}
|
||||
}
|
||||
|
||||
// HKEY wrapper
|
||||
class RegKey
|
||||
{
|
||||
RegKey(const RegKey &) = delete;
|
||||
RegKey &operator=(const RegKey &) = delete;
|
||||
|
||||
public:
|
||||
RegKey()
|
||||
: key(nullptr)
|
||||
{
|
||||
}
|
||||
bool defined() const
|
||||
{
|
||||
return key != nullptr && key != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
HKEY *ref()
|
||||
{
|
||||
return &key;
|
||||
}
|
||||
HKEY operator()()
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
~RegKey()
|
||||
{
|
||||
if (defined())
|
||||
::RegCloseKey(key);
|
||||
}
|
||||
|
||||
private:
|
||||
HKEY key;
|
||||
};
|
||||
|
||||
class RegKeyEnumerator : public std::vector<std::string>
|
||||
{
|
||||
public:
|
||||
RegKeyEnumerator(HKEY hkey, const std::string &path)
|
||||
{
|
||||
RegKey regKey;
|
||||
auto status = ::RegOpenKeyExA(hkey,
|
||||
path.c_str(),
|
||||
0,
|
||||
KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
|
||||
regKey.ref());
|
||||
if (status != ERROR_SUCCESS)
|
||||
return;
|
||||
|
||||
DWORD subkeys_num;
|
||||
status = ::RegQueryInfoKeyA(regKey(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
NULL,
|
||||
&subkeys_num,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
|
||||
if (status != ERROR_SUCCESS)
|
||||
return;
|
||||
|
||||
const int MAX_KEY_LENGTH = 255;
|
||||
for (DWORD i = 0; i < subkeys_num; ++i)
|
||||
{
|
||||
DWORD subkey_size = MAX_KEY_LENGTH;
|
||||
char subkey[MAX_KEY_LENGTH];
|
||||
status = ::RegEnumKeyExA(regKey(),
|
||||
i,
|
||||
subkey,
|
||||
&subkey_size,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
if (status == ERROR_SUCCESS)
|
||||
push_back(subkey);
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace Win
|
||||
} // namespace openvpn
|
||||
|
||||
#endif
|
||||
// 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-2022 OpenVPN Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License Version 3
|
||||
// as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// registry utilities for Windows
|
||||
|
||||
#ifndef OPENVPN_WIN_REG_H
|
||||
#define OPENVPN_WIN_REG_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <openvpn/win/winerr.hpp>
|
||||
#include <openvpn/common/size.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace Win {
|
||||
|
||||
template <typename E>
|
||||
static void check_reg_error(DWORD status, const std::string &key)
|
||||
{
|
||||
if (status != ERROR_SUCCESS)
|
||||
{
|
||||
const Win::Error err(status);
|
||||
OPENVPN_THROW(E, "registry key " << key << " error: " << err.message());
|
||||
}
|
||||
}
|
||||
|
||||
// HKEY wrapper
|
||||
class RegKey
|
||||
{
|
||||
RegKey(const RegKey &) = delete;
|
||||
RegKey &operator=(const RegKey &) = delete;
|
||||
|
||||
public:
|
||||
RegKey()
|
||||
: key(nullptr)
|
||||
{
|
||||
}
|
||||
bool defined() const
|
||||
{
|
||||
return key != nullptr && key != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
HKEY *ref()
|
||||
{
|
||||
return &key;
|
||||
}
|
||||
HKEY operator()()
|
||||
{
|
||||
return key;
|
||||
}
|
||||
|
||||
~RegKey()
|
||||
{
|
||||
if (defined())
|
||||
::RegCloseKey(key);
|
||||
}
|
||||
|
||||
private:
|
||||
HKEY key;
|
||||
};
|
||||
|
||||
class RegKeyEnumerator : public std::vector<std::string>
|
||||
{
|
||||
public:
|
||||
RegKeyEnumerator(HKEY hkey, const std::string &path)
|
||||
{
|
||||
RegKey regKey;
|
||||
auto status = ::RegOpenKeyExA(hkey,
|
||||
path.c_str(),
|
||||
0,
|
||||
KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
|
||||
regKey.ref());
|
||||
if (status != ERROR_SUCCESS)
|
||||
return;
|
||||
|
||||
DWORD subkeys_num;
|
||||
status = ::RegQueryInfoKeyA(regKey(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
NULL,
|
||||
&subkeys_num,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
|
||||
if (status != ERROR_SUCCESS)
|
||||
return;
|
||||
|
||||
const int MAX_KEY_LENGTH = 255;
|
||||
for (DWORD i = 0; i < subkeys_num; ++i)
|
||||
{
|
||||
DWORD subkey_size = MAX_KEY_LENGTH;
|
||||
char subkey[MAX_KEY_LENGTH];
|
||||
status = ::RegEnumKeyExA(regKey(),
|
||||
i,
|
||||
subkey,
|
||||
&subkey_size,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
if (status == ERROR_SUCCESS)
|
||||
push_back(subkey);
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace Win
|
||||
} // namespace openvpn
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user