stdex
Additional custom or not Standard C++ covered algorithms
Loading...
Searching...
No Matches
system.hpp
1/*
2 SPDX-License-Identifier: MIT
3 Copyright © 2023 Amebis
4*/
5
6#pragma once
7
8#include "compat.hpp"
9#ifdef _WIN32
10#include <windows.h>
11#include <oaidl.h>
12#include <tchar.h>
13#else
14#define _LARGEFILE64_SOURCE
15#include <grp.h>
16#include <pwd.h>
17#include <string.h>
18#include <sys/types.h>
19#include <unistd.h>
20#endif
21#include <regex>
22#include <stdexcept>
23#include <string>
24
25#if defined(_WIN32)
26#define PATH_SEPARATOR '\\'
27#define PATH_SEPARATOR_STR "\\"
28#else
29#define PATH_SEPARATOR '/'
30#define PATH_SEPARATOR_STR "/"
31#endif
32
33namespace stdex
34{
38#if defined(_WIN32)
39 using sys_handle = HANDLE;
40 const sys_handle invalid_handle = INVALID_HANDLE_VALUE;
41#else
42 using sys_handle = int;
43 const sys_handle invalid_handle = (sys_handle)-1;
44#endif
45
49#if defined(_WIN32)
50 inline DWORD sys_error() { return GetLastError(); }
51#else
52 inline int sys_error() { return errno; }
53#endif
54
58#if defined(_WIN32)
59 using schar_t = TCHAR;
60#else
61 using schar_t = char;
62#define _T(x) x
63#endif
64
69 using sys_char = schar_t;
70
74 using sstring = std::basic_string<stdex::schar_t>;
75
80 using sys_string = sstring;
81
85 using sregex = std::basic_regex<stdex::schar_t>;
86
91 {
92 public:
93 sys_object(_In_opt_ sys_handle h = invalid_handle) : m_h(h) {}
94
95 sys_object(_In_ const sys_object& other) : m_h(other.m_h != invalid_handle ? duplicate(other.m_h, false) : invalid_handle) {}
96
97 sys_object& operator =(_In_ const sys_object& other)
98 {
99 if (this != std::addressof(other)) {
100 if (m_h != invalid_handle)
101 close(m_h);
102 m_h = other.m_h != invalid_handle ? duplicate(other.m_h, false) : invalid_handle;
103 }
104 return *this;
105 }
106
107 sys_object(_Inout_ sys_object&& other) noexcept : m_h(other.m_h)
108 {
109 other.m_h = invalid_handle;
110 }
111
112 sys_object& operator =(_Inout_ sys_object&& other) noexcept
113 {
114 if (this != std::addressof(other)) {
115 if (m_h != invalid_handle)
116 close(m_h);
117 m_h = other.m_h;
118 other.m_h = invalid_handle;
119 }
120 return *this;
121 }
122
123 virtual ~sys_object() noexcept(false)
124 {
125 if (m_h != invalid_handle)
126 close(m_h);
127 }
128
132 virtual void close()
133 {
134 if (m_h != invalid_handle) {
135 close(m_h);
136 m_h = invalid_handle;
137 }
138 }
139
143 inline operator bool() const noexcept { return m_h != invalid_handle; }
144
148 inline sys_handle get() const noexcept { return m_h; }
149
150 protected:
154 static void close(_In_ sys_handle h)
155 {
156#ifdef _WIN32
157 if (CloseHandle(h) || GetLastError() == ERROR_INVALID_HANDLE)
158 return;
159 throw std::system_error(GetLastError(), std::system_category(), "CloseHandle failed");
160#else
161 if (::close(h) >= 0 || errno == EBADF)
162 return;
163 throw std::system_error(errno, std::system_category(), "close failed");
164#endif
165 }
166
170 static sys_handle duplicate(_In_ sys_handle h, _In_ bool inherit)
171 {
172 sys_handle h_new;
173#ifdef _WIN32
174 HANDLE process = GetCurrentProcess();
175 if (DuplicateHandle(process, h, process, &h_new, 0, inherit, DUPLICATE_SAME_ACCESS))
176 return h_new;
177 throw std::system_error(GetLastError(), std::system_category(), "DuplicateHandle failed");
178#else
179 _Unreferenced_(inherit);
180 if ((h_new = dup(h)) >= 0)
181 return h_new;
182 throw std::system_error(errno, std::system_category(), "dup failed");
183#endif
184 }
185
186 protected:
187 sys_handle m_h;
188 };
189
190#ifdef _WIN32
191 template <class T>
192 class safearray_accessor
193 {
194 public:
195 safearray_accessor(_In_ LPSAFEARRAY sa) : m_sa(sa)
196 {
197 HRESULT hr = SafeArrayAccessData(sa, reinterpret_cast<void HUGEP**>(&m_data));
198 if (FAILED(hr))
199 throw std::system_error(hr, std::system_category(), "SafeArrayAccessData failed");
200 }
201
202 ~safearray_accessor()
203 {
204 SafeArrayUnaccessData(m_sa);
205 }
206
207 T* data() const { return m_data; }
208
209 protected:
210 LPSAFEARRAY m_sa;
211 T* m_data;
212 };
213
217 struct SafeArrayDestroy_delete
218 {
222 void operator()(_In_ LPSAFEARRAY sa) const
223 {
224 SafeArrayDestroy(sa);
225 }
226 };
227
231 struct SysFreeString_delete
232 {
236 void operator()(_In_ BSTR sa) const
237 {
238 SysFreeString(sa);
239 }
240 };
241#endif
242
246#ifdef _WIN32
247 typedef uint16_t platform_id;
248#else
249 typedef const char* platform_id;
250
251 inline bool operator ==(_In_ const platform_id a, _In_ const platform_id b) { return a == b; }
252 inline bool operator !=(_In_ const platform_id a, _In_ const platform_id b) { return a != b; }
253 inline bool operator <(_In_ const platform_id a, _In_ const platform_id b) { return a == IMAGE_FILE_MACHINE_UNKNOWN && b != IMAGE_FILE_MACHINE_UNKNOWN || a != IMAGE_FILE_MACHINE_UNKNOWN && b != IMAGE_FILE_MACHINE_UNKNOWN && strcmp(a, b) < 0; }
254 inline bool operator <=(_In_ const platform_id a, _In_ const platform_id b) { return a == IMAGE_FILE_MACHINE_UNKNOWN || a != IMAGE_FILE_MACHINE_UNKNOWN && b != IMAGE_FILE_MACHINE_UNKNOWN && strcmp(a, b) <= 0; }
255 inline bool operator >(_In_ const platform_id a, _In_ const platform_id b) { return a != IMAGE_FILE_MACHINE_UNKNOWN && b == IMAGE_FILE_MACHINE_UNKNOWN || a != IMAGE_FILE_MACHINE_UNKNOWN && b != IMAGE_FILE_MACHINE_UNKNOWN && strcmp(a, b) > 0; }
256 inline bool operator >=(_In_ const platform_id a, _In_ const platform_id b) { return b == IMAGE_FILE_MACHINE_UNKNOWN || a != IMAGE_FILE_MACHINE_UNKNOWN && b != IMAGE_FILE_MACHINE_UNKNOWN && strcmp(a, b) >= 0; }
257#endif
258}
259
260#ifndef _WIN32
261constexpr stdex::platform_id IMAGE_FILE_MACHINE_UNKNOWN = nullptr;
262constexpr stdex::platform_id IMAGE_FILE_MACHINE_I386 = "i386";
263constexpr stdex::platform_id IMAGE_FILE_MACHINE_AMD64 = "x86_64";
264constexpr stdex::platform_id IMAGE_FILE_MACHINE_ARMNT = "arm";
265constexpr stdex::platform_id IMAGE_FILE_MACHINE_ARM64 = "aarch64";
266#endif
267
268namespace stdex
269{
273 const struct sys_info_t
274 {
278#if _M_IX86
279 static constexpr platform_id process_platform = IMAGE_FILE_MACHINE_I386;
280#elif _M_X64 // _M_ARM64EC is introducing as x64
281 static constexpr platform_id process_platform = IMAGE_FILE_MACHINE_AMD64;
282#elif _M_ARM
283 static constexpr platform_id process_platform = IMAGE_FILE_MACHINE_ARMNT;
284#elif _M_ARM64
285 static constexpr platform_id process_platform = IMAGE_FILE_MACHINE_ARM64;
286#elif __i386__
287 static constexpr platform_id process_platform = "i386";
288#elif __x86_64__
289 static constexpr platform_id process_platform = "x86_64";
290#elif __aarch64__
291 static constexpr platform_id process_platform = "aarch64";
292#else
293 #error Unknown platform
294#endif
295
299 platform_id os_platform;
300
301#ifdef _WIN32
305 bool wow64;
306#endif
307
312
316 bool admin;
317
322
323 sys_info_t() :
324 os_platform(IMAGE_FILE_MACHINE_UNKNOWN),
325 wow64(false),
327 admin(false),
328 elevated(false)
329 {
330#ifdef _WIN32
331 HMODULE kernel32_handle;
332 kernel32_handle = LoadLibrary(_T("kernel32.dll"));
333 _Assume_(kernel32_handle);
334 BOOL(WINAPI * IsWow64Process2)(HANDLE hProcess, USHORT * pProcessMachine, USHORT * pNativeMachine);
335 *reinterpret_cast<FARPROC*>(&IsWow64Process2) = GetProcAddress(kernel32_handle, "IsWow64Process2");
336 HANDLE process = GetCurrentProcess();
337 USHORT process_machine;
338#ifndef _WIN64
339 BOOL Wow64Process;
340#endif
341 if (IsWow64Process2 && IsWow64Process2(process, &process_machine, &os_platform)) {
342 wow64 = process_machine != IMAGE_FILE_MACHINE_UNKNOWN;
343 }
344#ifdef _WIN64
345 else {
346 os_platform = process_platform;
347 wow64 = false;
348 }
349#else
350 else if (IsWow64Process(process, &Wow64Process)) {
351 if (Wow64Process) {
352 os_platform = IMAGE_FILE_MACHINE_AMD64;
353 wow64 = true;
354 }
355 else {
356 os_platform = process_platform;
357 wow64 = false;
358 }
359 }
360#endif
361 FreeLibrary(kernel32_handle);
362#else
363 memset(&m_utsn, 0, sizeof(m_utsn));
364 if (uname(&m_utsn) != -1)
365 os_platform = reinterpret_cast<platform_id>(m_utsn.machine);
366#endif
367
368#ifdef _WIN32
369 HWINSTA hWinSta = GetProcessWindowStation();
370 if (hWinSta) {
371 TCHAR sName[MAX_PATH];
372 if (GetUserObjectInformation(hWinSta, UOI_NAME, sName, sizeof(sName), NULL)) {
373 sName[_countof(sName) - 1] = 0;
374 // Only "WinSta0" is interactive (Source: KB171890)
375 interactive_process = _tcsicmp(sName, _T("WinSta0")) == 0;
376 }
377 }
378#else
379 // TODO: Research interactive process vs service/agent/daemon on this platform.
380#endif
381
382#if defined(_WIN32)
383 {
384 HANDLE token_h;
385 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token_h)) {
386 sys_object token(token_h);
387
388 TOKEN_ELEVATION elevation;
389 DWORD size = sizeof(TOKEN_ELEVATION);
390 if (GetTokenInformation(token_h, TokenElevation, &elevation, sizeof(elevation), &size))
391 elevated = elevation.TokenIsElevated;
392
393 GetTokenInformation(token.get(), TokenGroups, NULL, 0, &size);
394 std::unique_ptr<TOKEN_GROUPS> groups((TOKEN_GROUPS*)new uint8_t[size]);
395 if (GetTokenInformation(token.get(), TokenGroups, (LPVOID)groups.get(), size, &size)) {
396 SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_AUTHORITY;
397 PSID sid_admins_h = NULL;
398 if (AllocateAndInitializeSid(&authority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &sid_admins_h)) {
399 struct SID_delete { void operator()(_In_ PSID p) const { FreeSid(p); } };
400 std::unique_ptr<void, SID_delete> sid_admins(sid_admins_h);
401 for (DWORD i = 0; i < groups->GroupCount; ++i)
402 if (EqualSid(sid_admins.get(), groups->Groups[i].Sid)) {
403 admin = true;
404 break;
405 }
406 }
407 }
408 }
409 }
410#elif defined(__APPLE__)
411 {
412 gid_t gids[NGROUPS + 1]; // A user cannot be member in more than NGROUPS groups, not counting the default group (hence the + 1)
413 for (int i = 0, n = getgroups(_countof(gids), gids); i < n; ++i) {
414 struct group* group = getgrgid(gids[i]);
415 if (!group) continue;
416 if (strcmp(group->gr_name, "admin") == 0) {
417 admin = true;
418 break;
419 }
420 }
421 }
422
423 elevated = geteuid() == 0;
424#else
425 // TODO: Set admin.
426 elevated = geteuid() == 0;
427#endif
428 }
429
430 protected:
431#ifndef _WIN32
432 struct utsname m_utsn;
433#endif
434 } sys_info;
435}
Operating system object (file, pipe, anything with an OS handle etc.)
Definition system.hpp:91
sys_handle get() const noexcept
Returns object handle.
Definition system.hpp:148
virtual void close()
Closes object.
Definition system.hpp:132
static sys_handle duplicate(sys_handle h, bool inherit)
Duplicates given object.
Definition system.hpp:170
static void close(sys_handle h)
Closes object.
Definition system.hpp:154
System information.
Definition system.hpp:274
bool admin
Is member of local group Administrators (Windows) or member of group wheel/sudoers (others)?
Definition system.hpp:316
bool elevated
Is elevated process (Windows) or running as root (others)?
Definition system.hpp:321
platform_id os_platform
The platform this process was compiled for.
Definition system.hpp:299
bool interactive_process
Is interactive process?
Definition system.hpp:311