stdex
Additional custom or not Standard C++ covered algorithms
Loading...
Searching...
No Matches
sys_info.hpp
1/*
2 SPDX-License-Identifier: MIT
3 Copyright © 2023-2024 Amebis
4*/
5
6#pragma once
7
8#include "assert.hpp"
9#include "compat.hpp"
10#include "string.hpp"
11#include "system.hpp"
12#if defined(_WIN32)
13#include "windows.h"
14#include <stdlib.h>
15#include <tchar.h>
16#else
17#include <sys/utsname.h>
18#endif
19#include <map>
20#include <memory>
21
22#if defined(__GNUC__)
23#pragma GCC diagnostic push
24#pragma GCC diagnostic ignored "-Wexit-time-destructors"
25#endif
26
27namespace stdex
28{
32 enum class platform_id : uint16_t {
33#ifdef _WIN32
34 unknown = IMAGE_FILE_MACHINE_UNKNOWN,
35 i386 = IMAGE_FILE_MACHINE_I386,
36 x86_64 = IMAGE_FILE_MACHINE_AMD64,
37 arm = IMAGE_FILE_MACHINE_ARMNT,
38 aarch64 = IMAGE_FILE_MACHINE_ARM64,
39#else
40 unknown = 0,
41 i386 = 0x014c,
42 x86_64 = 0x8664,
43 arm = 0x01c4,
44 aarch64 = 0xaa64,
45#endif
46 };
47
55 inline platform_id platform_from_name(_In_z_ const char* name)
56 {
57 struct platform_less {
58 bool operator()(_In_z_ const char* a, _In_z_ const char* b) const
59 {
60 return stricmp(a, b) < 0;
61 }
62 };
63 static const std::map<const char*, platform_id, platform_less> platforms = {
64 { "aarch64", platform_id::aarch64 },
65 { "arm", platform_id::arm },
66 { "i386", platform_id::i386 },
67 { "x86_64", platform_id::x86_64 },
68 };
69 if (auto el = platforms.find(name); el != platforms.end())
70 return el->second;
71 return platform_id::unknown;
72 }
73
77 inline const struct sys_info_t
78 {
82#if _M_IX86 || __i386__
83 static constexpr platform_id process_platform = platform_id::i386;
84#elif _M_X64 /* _M_ARM64EC is introducing as x64 */ || __x86_64__
85 static constexpr platform_id process_platform = platform_id::x86_64;
86#elif _M_ARM || __arm__
87 static constexpr platform_id process_platform = platform_id::arm;
88#elif _M_ARM64 || __aarch64__
89 static constexpr platform_id process_platform = platform_id::aarch64;
90#else
91 #error Unknown platform
92#endif
93
97 platform_id os_platform;
98
99#ifdef _WIN32
103 bool wow64;
104#endif
105
110
114 bool admin;
115
120
124 sstring username;
125
126 sys_info_t() :
127 os_platform(platform_id::unknown),
128#ifdef _WIN32
129 wow64(false),
130#endif
132 admin(false),
133 elevated(false)
134 {
135#ifdef _WIN32
136 HMODULE kernel32_handle;
137 kernel32_handle = LoadLibrary(_T("kernel32.dll"));
138 stdex_assert(kernel32_handle);
139 BOOL(WINAPI * IsWow64Process2)(HANDLE hProcess, USHORT * pProcessMachine, USHORT * pNativeMachine);
140 *reinterpret_cast<FARPROC*>(&IsWow64Process2) = GetProcAddress(kernel32_handle, "IsWow64Process2");
141 HANDLE process = GetCurrentProcess();
142 USHORT process_machine;
143#ifndef _WIN64
144 BOOL Wow64Process;
145#endif
146 if (IsWow64Process2 && IsWow64Process2(process, &process_machine, reinterpret_cast<USHORT*>(&os_platform))) {
147 wow64 = process_machine != IMAGE_FILE_MACHINE_UNKNOWN;
148 }
149#ifdef _WIN64
150 else {
151 os_platform = process_platform;
152 wow64 = false;
153 }
154#else
155 else if (IsWow64Process(process, &Wow64Process)) {
156 if (Wow64Process) {
157 os_platform = platform_id::x86_64;
158 wow64 = true;
159 }
160 else {
161 os_platform = process_platform;
162 wow64 = false;
163 }
164 }
165#endif
166 FreeLibrary(kernel32_handle);
167#else
168 memset(&m_utsn, 0, sizeof(m_utsn));
169 if (uname(&m_utsn) != -1)
170 os_platform = platform_from_name(m_utsn.machine);
171#endif
172
173#ifdef _WIN32
174 HWINSTA hWinSta = GetProcessWindowStation();
175 if (hWinSta) {
176 TCHAR sName[MAX_PATH];
177 if (GetUserObjectInformation(hWinSta, UOI_NAME, sName, sizeof(sName), NULL)) {
178 sName[_countof(sName) - 1] = 0;
179 // Only "WinSta0" is interactive (Source: KB171890)
180 interactive_process = _tcsicmp(sName, _T("WinSta0")) == 0;
181 }
182 }
183#else
184 // TODO: Research interactive process vs service/agent/daemon on this platform.
185#endif
186
187#if defined(_WIN32)
188 {
189 HANDLE token_h;
190 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token_h)) {
191 sys_object token(token_h);
192
193 TOKEN_ELEVATION elevation;
194 DWORD size = sizeof(TOKEN_ELEVATION);
195 if (GetTokenInformation(token_h, TokenElevation, &elevation, sizeof(elevation), &size))
196 elevated = elevation.TokenIsElevated;
197
198 GetTokenInformation(token.get(), TokenGroups, NULL, 0, &size);
199 std::unique_ptr<TOKEN_GROUPS> groups((TOKEN_GROUPS*)new uint8_t[size]);
200 if (GetTokenInformation(token.get(), TokenGroups, (LPVOID)groups.get(), size, &size)) {
201 SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_AUTHORITY;
202 PSID sid_admins_h = NULL;
203 if (AllocateAndInitializeSid(&authority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &sid_admins_h)) {
204 struct SID_delete { void operator()(_In_ PSID p) const { FreeSid(p); } };
205 std::unique_ptr<void, SID_delete> sid_admins(sid_admins_h);
206 for (DWORD i = 0; i < groups->GroupCount; ++i)
207 if (EqualSid(sid_admins.get(), groups->Groups[i].Sid)) {
208 admin = true;
209 break;
210 }
211 }
212 }
213 }
214 }
215#elif defined(__APPLE__)
216 {
217 gid_t gids[NGROUPS_MAX];
218 for (int i = 0, n = getgroups(NGROUPS_MAX, gids); i < n; ++i) {
219 struct group* group = getgrgid(gids[i]);
220 if (!group) continue;
221 if (strcmp(group->gr_name, "admin") == 0) {
222 admin = true;
223 break;
224 }
225 }
226 }
227
228 elevated = geteuid() == 0;
229#else
230 // TODO: Set admin.
231 elevated = geteuid() == 0;
232#endif
233
234#ifdef _WIN32
235 {
236 TCHAR szStackBuffer[0x100];
237 ULONG ulSize = _countof(szStackBuffer);
238 if (GetUserNameEx(NameFormat, szStackBuffer, &ulSize))
239 username.assign(szStackBuffer, ulSize);
240 if (GetLastError() == ERROR_MORE_DATA) {
241 // Allocate buffer on heap and retry.
242 username.resize(ulSize - 1);
243 if (!GetUserNameEx(NameFormat, &username[0], &ulSize))
244 username.clear();
245 }
246 }
247#else
248 {
249 struct passwd *pw = getpwuid(geteuid());
250 if (pw && pw->pw_name)
251 username = pw->pw_name;
252 }
253#endif
254 }
255
259 static bool is_screen_reader()
260 {
261#ifdef _WIN32
262 BOOL b;
263 return SystemParametersInfo(SPI_GETSCREENREADER, 0, &b, 0) && b;
264#else
265 return false;
266#endif
267 }
268
269 protected:
270#ifndef _WIN32
271 struct utsname m_utsn;
272#endif
273 } sys_info;
274}
275
276#if defined(__GNUC__)
277#pragma GCC diagnostic pop
278#endif
Operating system object base class.
Definition system.hpp:142
T get() const noexcept
Returns object handle.
Definition system.hpp:199
System information.
Definition sys_info.hpp:78
bool admin
Is member of local group Administrators (Windows) or member of group wheel/sudoers (others)?
Definition sys_info.hpp:114
bool elevated
Is elevated process (Windows) or running as root (others)?
Definition sys_info.hpp:119
platform_id os_platform
The platform this process was compiled for.
Definition sys_info.hpp:97
static bool is_screen_reader()
Is screen reader currently active?
Definition sys_info.hpp:259
sstring username
Currently signed in user.
Definition sys_info.hpp:124
bool interactive_process
Is interactive process?
Definition sys_info.hpp:109