OpenVPN 3 Core Library
Loading...
Searching...
No Matches
impersonate.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12#pragma once
13
14#include <windows.h>
15#include <lmcons.h>
16#include <wtsapi32.h>
17
19
20namespace openvpn::Win {
21
23{
24 public:
25 explicit Impersonate(bool as_local_system)
27 {
28 if (as_local_system)
29 {
30 if (local_system_)
31 OPENVPN_LOG("ImpersonateAsSystem: running under SYSTEM account, no need to impersonate");
32 else
34 }
35 else
36 {
37 if (local_system_)
39 else
40 OPENVPN_LOG("ImpersonateAsUser: running under user account, no need to impersonate");
41 }
42 }
43
45 {
46 if (impersonated)
47 {
48 if (!RevertToSelf())
49 {
50 const Win::LastError err;
51 OPENVPN_LOG("Impersonate: RevertToSelf() failed: " << err.message());
52 }
53 }
54 }
55
56 bool is_local_system() const
57 {
58 return local_system_;
59 }
60
61 private:
63 {
64 HANDLE thread_token, process_snapshot, winlogon_process, winlogon_token, duplicated_token;
65 PROCESSENTRY32 entry = {};
66 entry.dwSize = sizeof(PROCESSENTRY32);
67 BOOL ret;
68 DWORD pid = 0;
69 TOKEN_PRIVILEGES privileges = {};
70 privileges.PrivilegeCount = 1;
71 privileges.Privileges->Attributes = SE_PRIVILEGE_ENABLED;
72
73 if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &privileges.Privileges[0].Luid))
74 return;
75
76 if (!ImpersonateSelf(SecurityImpersonation))
77 return;
78
79 impersonated = true;
80
81 if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &thread_token))
82 return;
83 if (!AdjustTokenPrivileges(thread_token, FALSE, &privileges, sizeof(privileges), NULL, NULL))
84 {
85 CloseHandle(thread_token);
86 return;
87 }
88 CloseHandle(thread_token);
89
90 process_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
91 if (process_snapshot == INVALID_HANDLE_VALUE)
92 return;
93
94 for (ret = Process32First(process_snapshot, &entry); ret; ret = Process32Next(process_snapshot, &entry))
95 {
96 if (!_stricmp(entry.szExeFile, "winlogon.exe"))
97 {
98 pid = entry.th32ProcessID;
99 break;
100 }
101 }
102 CloseHandle(process_snapshot);
103 if (!pid)
104 return;
105
106 winlogon_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
107 if (!winlogon_process)
108 return;
109
110 if (!OpenProcessToken(winlogon_process, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &winlogon_token))
111 {
112 CloseHandle(winlogon_process);
113 return;
114 }
115 CloseHandle(winlogon_process);
116
117 if (!DuplicateToken(winlogon_token, SecurityImpersonation, &duplicated_token))
118 {
119 CloseHandle(winlogon_token);
120 return;
121 }
122 CloseHandle(winlogon_token);
123
124 if (!SetThreadToken(NULL, duplicated_token))
125 {
126 CloseHandle(duplicated_token);
127 return;
128 }
129 CloseHandle(duplicated_token);
130 }
131
133 {
134 DWORD sessId = WTSGetActiveConsoleSessionId();
135 if (sessId == 0xFFFFFFFF)
136 {
137 const Win::LastError err;
138 OPENVPN_LOG("ImpersonateAsUser: WTSGetActiveConsoleSessionId() failed: " << err.message());
139 return;
140 }
141
142 HANDLE hToken;
143 if (!WTSQueryUserToken(sessId, &hToken))
144 {
145 const Win::LastError err;
146 OPENVPN_LOG("ImpersonateAsUser: WTSQueryUserToken() failed: " << err.message());
147 return;
148 }
149
150 if (!ImpersonateLoggedOnUser(hToken))
151 {
152 CloseHandle(hToken);
153
154 const Win::LastError err;
155 OPENVPN_LOG("ImpersonateAsUser: ImpersonateLoggedOnUser() failed: " << err.message());
156 return;
157 }
158
159 CloseHandle(hToken);
160
161 impersonated = true;
162
163 char uname[UNLEN + 1];
164 DWORD len = UNLEN + 1;
165 GetUserNameA(uname, &len);
166 OPENVPN_LOG("ImpersonateAsUser: impersonated as " << uname);
167 }
168
169 // https://stackoverflow.com/a/4024388/227024
170 BOOL is_local_system_() const
171 {
172 HANDLE hToken;
173 UCHAR bTokenUser[sizeof(TOKEN_USER) + 8 + 4 * SID_MAX_SUB_AUTHORITIES];
174 PTOKEN_USER pTokenUser = (PTOKEN_USER)bTokenUser;
175 ULONG cbTokenUser;
176 SID_IDENTIFIER_AUTHORITY siaNT = SECURITY_NT_AUTHORITY;
177 PSID pSystemSid;
178 BOOL bSystem;
179
180 // open process token
181 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
182 return FALSE;
183
184 // retrieve user SID
185 if (!GetTokenInformation(hToken, TokenUser, pTokenUser, sizeof(bTokenUser), &cbTokenUser))
186 {
187 CloseHandle(hToken);
188 return FALSE;
189 }
190
191 CloseHandle(hToken);
192
193 // allocate LocalSystem well-known SID
194 if (!AllocateAndInitializeSid(&siaNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pSystemSid))
195 return FALSE;
196
197 // compare the user SID from the token with the LocalSystem SID
198 bSystem = EqualSid(pTokenUser->User.Sid, pSystemSid);
199
200 FreeSid(pSystemSid);
201
202 return bSystem;
203 }
204
205 bool local_system_ = false;
206 bool impersonated = false;
207};
208} // namespace openvpn::Win
Impersonate(bool as_local_system)
#define OPENVPN_LOG(args)
std::string ret