mirror of
https://github.com/OpenVPN/openvpn3.git
synced 2024-09-20 04:02:15 +02:00
win/impersonate: refactor impersonate logic
Extend existing Impersonate class and move there impersonate_as_system code from tunwin.hpp Signed-off-by: Lev Stipakov <lev@openvpn.net>
This commit is contained in:
parent
29a655147b
commit
5485de19a2
@ -59,6 +59,7 @@
|
||||
#include <openvpn/win/unicode.hpp>
|
||||
#include <openvpn/win/cmd.hpp>
|
||||
#include <openvpn/win/winerr.hpp>
|
||||
#include <openvpn/win/impersonate.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
namespace TunWin {
|
||||
@ -342,87 +343,6 @@ namespace openvpn {
|
||||
}
|
||||
};
|
||||
|
||||
inline HANDLE impersonate_as_system()
|
||||
{
|
||||
HANDLE thread_token, process_snapshot, winlogon_process, winlogon_token, duplicated_token, file_handle;
|
||||
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 INVALID_HANDLE_VALUE;
|
||||
if (!ImpersonateSelf(SecurityImpersonation))
|
||||
return INVALID_HANDLE_VALUE;
|
||||
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &thread_token))
|
||||
{
|
||||
RevertToSelf();
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (!AdjustTokenPrivileges(thread_token, FALSE, &privileges, sizeof(privileges), NULL, NULL))
|
||||
{
|
||||
CloseHandle(thread_token);
|
||||
RevertToSelf();
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
CloseHandle(thread_token);
|
||||
|
||||
process_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (process_snapshot == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
RevertToSelf();
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
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)
|
||||
{
|
||||
RevertToSelf();
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
winlogon_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
|
||||
if (!winlogon_process)
|
||||
{
|
||||
RevertToSelf();
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (!OpenProcessToken(winlogon_process, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &winlogon_token))
|
||||
{
|
||||
CloseHandle(winlogon_process);
|
||||
RevertToSelf();
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
CloseHandle(winlogon_process);
|
||||
|
||||
if (!DuplicateToken(winlogon_token, SecurityImpersonation, &duplicated_token))
|
||||
{
|
||||
CloseHandle(winlogon_token);
|
||||
RevertToSelf();
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
CloseHandle(winlogon_token);
|
||||
|
||||
if (!SetThreadToken(NULL, duplicated_token))
|
||||
{
|
||||
CloseHandle(duplicated_token);
|
||||
RevertToSelf();
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
CloseHandle(duplicated_token);
|
||||
}
|
||||
|
||||
// given a TAP GUID, form the pathname of the TAP device node
|
||||
inline std::string tap_path(const TapNameGuidPair& tap, bool wintun)
|
||||
{
|
||||
@ -446,19 +366,21 @@ namespace openvpn {
|
||||
const TapNameGuidPair& tap = *i;
|
||||
const std::string path = tap_path(tap, wintun);
|
||||
|
||||
// wintun device can be only opened under LocalSystem account
|
||||
if (wintun)
|
||||
impersonate_as_system();
|
||||
{
|
||||
// wintun device can be only opened under LocalSystem account
|
||||
std::unique_ptr<Win::Impersonate> imp;
|
||||
|
||||
hand.reset(::CreateFileA(path.c_str(),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0, /* was: FILE_SHARE_READ */
|
||||
0,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
|
||||
0));
|
||||
if (wintun)
|
||||
RevertToSelf();
|
||||
if (wintun)
|
||||
imp.reset(new Win::Impersonate(true));
|
||||
|
||||
hand.reset(::CreateFileA(path.c_str(),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0, /* was: FILE_SHARE_READ */
|
||||
0,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
|
||||
0));
|
||||
}
|
||||
|
||||
if (hand.defined())
|
||||
{
|
||||
|
@ -43,7 +43,7 @@ namespace openvpn {
|
||||
|
||||
void set_proxy(bool del) override
|
||||
{
|
||||
ImpersonateAsUser imp;
|
||||
Impersonate imp{false};
|
||||
|
||||
LONG status;
|
||||
RegKey hkcu;
|
||||
|
@ -29,19 +29,120 @@
|
||||
|
||||
namespace openvpn {
|
||||
namespace Win {
|
||||
class ImpersonateAsUser {
|
||||
|
||||
class Impersonate
|
||||
{
|
||||
public:
|
||||
ImpersonateAsUser() : local_system(is_local_system_())
|
||||
explicit Impersonate(bool as_local_system)
|
||||
: local_system_(is_local_system_())
|
||||
{
|
||||
if (local_system)
|
||||
OPENVPN_LOG("ImpersonateAsUser: running under SYSTEM account, need to impersonate");
|
||||
if (as_local_system)
|
||||
{
|
||||
if (local_system_)
|
||||
OPENVPN_LOG("ImpersonateAsSystem: running under SYSTEM account, no need to impersonate");
|
||||
else
|
||||
impersonate_as_local_system();
|
||||
}
|
||||
else
|
||||
{
|
||||
OPENVPN_LOG("ImpersonateAsUser: running under user account, no need to impersonate");
|
||||
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, file_handle;
|
||||
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);
|
||||
|
||||
DWORD sessId = WTSGetActiveConsoleSessionId();
|
||||
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;
|
||||
@ -76,23 +177,6 @@ namespace openvpn {
|
||||
OPENVPN_LOG("ImpersonateAsUser: impersonated as " << uname);
|
||||
}
|
||||
|
||||
~ImpersonateAsUser() {
|
||||
if (impersonated)
|
||||
{
|
||||
if (!RevertToSelf())
|
||||
{
|
||||
const Win::LastError err;
|
||||
OPENVPN_LOG("ImpersonateAsUser: RevertToSelf() failed: " << err.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_local_system() const
|
||||
{
|
||||
return local_system;
|
||||
}
|
||||
|
||||
private:
|
||||
// https://stackoverflow.com/a/4024388/227024
|
||||
BOOL is_local_system_() const
|
||||
{
|
||||
@ -129,8 +213,8 @@ namespace openvpn {
|
||||
return bSystem;
|
||||
}
|
||||
|
||||
bool local_system_ = false;
|
||||
bool impersonated = false;
|
||||
bool local_system = false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user