0
0
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:
Lev Stipakov 2019-06-05 09:42:20 +03:00
parent 29a655147b
commit 5485de19a2
3 changed files with 124 additions and 118 deletions

View File

@ -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())
{

View File

@ -43,7 +43,7 @@ namespace openvpn {
void set_proxy(bool del) override
{
ImpersonateAsUser imp;
Impersonate imp{false};
LONG status;
RegKey hkcu;

View File

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