0
0
mirror of https://github.com/OpenVPN/openvpn3.git synced 2024-09-19 19:52: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:
Frank Lichtenheld 2023-04-20 13:40:44 +02:00
parent f544e04df7
commit b8ae379dd5
7 changed files with 1818 additions and 1816 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
*.hpp eol=lf
*.cpp eol=lf

View File

@ -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

View File

@ -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

View File

@ -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 &regkey, 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 &regkey, 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 &regkey, 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 &regkey, 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

View File

@ -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

View File

@ -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