]> cygwin.com Git - cygwin-apps/setup.git/blame - win32.cc
Added dpiAwareness element to manifest
[cygwin-apps/setup.git] / win32.cc
CommitLineData
5072c0bb
BD
1/*
2 * Copyright (c) 2007 Brian Dessent
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by Brian Dessent <brian@dessent.net>
13 *
14 */
15
5072c0bb 16#include "win32.h"
2e0aaec9 17#include <memory>
b41c2908 18#include <malloc.h>
5072c0bb 19#include "LogFile.h"
d29a864d 20#include "resource.h"
2801c09c 21#include "ini.h"
89cc2408 22#include <sys/stat.h>
20f237b4 23#include "String++.h"
5072c0bb 24
be617b59
CV
25NTSecurity nt_sec;
26
7d0ffe17
CV
27#define ALL_INHERIT_ACE (CONTAINER_INHERIT_ACE \
28 | OBJECT_INHERIT_ACE \
29 | INHERIT_ONLY_ACE)
30#define NO_INHERIT_ACE (0)
31
26922cd2
CV
32PSECURITY_DESCRIPTOR
33NTSecurity::GetPosixPerms (const char *fname, PSID owner_sid, PSID group_sid,
34 mode_t mode, SECURITY_DESCRIPTOR &out_sd, acl_t &acl)
be617b59 35{
26922cd2 36 DWORD u_attribute, g_attribute, o_attribute;
89cc2408 37 DWORD offset = 0;
b41c2908 38
be617b59
CV
39 /* Initialize out SD */
40 if (!InitializeSecurityDescriptor (&out_sd, SECURITY_DESCRIPTOR_REVISION))
157dc2b8 41 Log (LOG_TIMESTAMP) << "InitializeSecurityDescriptor(" << fname
b41c2908 42 << ") failed: " << GetLastError () << endLog;
1e029da2 43 out_sd.Control |= SE_DACL_PROTECTED;
5072c0bb 44
be617b59 45 /* Initialize ACL and fill with almost POSIX-like permissions.
b41c2908
CV
46 Note that the current user always requires write permissions, otherwise
47 creating files in directories with restricted permissions fails. */
be617b59 48 if (!InitializeAcl (&acl.acl , sizeof acl, ACL_REVISION))
157dc2b8 49 Log (LOG_TIMESTAMP) << "InitializeAcl(" << fname << ") failed: "
be617b59 50 << GetLastError () << endLog;
89cc2408 51 /* USER */
26922cd2
CV
52 /* Default user to current user. */
53 if (!owner_sid)
54 owner_sid = ownerSID.user.User.Sid;
89cc2408 55 u_attribute = STANDARD_RIGHTS_ALL | FILE_GENERIC_READ | FILE_GENERIC_WRITE;
b41c2908 56 if (mode & 0100) // S_IXUSR
89cc2408 57 u_attribute |= FILE_GENERIC_EXECUTE;
b41c2908 58 if ((mode & 0300) == 0300) // S_IWUSR | S_IXUSR
89cc2408 59 u_attribute |= FILE_DELETE_CHILD;
7d0ffe17
CV
60 if (!AddAccessAllowedAceEx (&acl.acl, ACL_REVISION, NO_INHERIT_ACE,
61 u_attribute, owner_sid))
62 Log (LOG_TIMESTAMP) << "AddAccessAllowedAceEx(" << fname
b41c2908 63 << ", owner) failed: " << GetLastError () << endLog;
89cc2408
CV
64 else
65 offset++;
66 /* GROUP */
26922cd2
CV
67 /* Default group to current primary group. */
68 if (!group_sid)
69 group_sid = groupSID;
89cc2408 70 g_attribute = STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES;
b41c2908 71 if (mode & 0040) // S_IRGRP
89cc2408 72 g_attribute |= FILE_GENERIC_READ;
b41c2908 73 if (mode & 0020) // S_IWGRP
89cc2408 74 g_attribute |= FILE_GENERIC_WRITE;
b41c2908 75 if (mode & 0010) // S_IXGRP
89cc2408 76 g_attribute |= FILE_GENERIC_EXECUTE;
b41c2908 77 if ((mode & 01030) == 00030) // S_IWGRP | S_IXGRP, !S_ISVTX
89cc2408 78 g_attribute |= FILE_DELETE_CHILD;
7d0ffe17
CV
79 if (!AddAccessAllowedAceEx (&acl.acl, ACL_REVISION, NO_INHERIT_ACE,
80 g_attribute, group_sid))
81 Log (LOG_TIMESTAMP) << "AddAccessAllowedAceEx(" << fname
b41c2908 82 << ", group) failed: " << GetLastError () << endLog;
89cc2408
CV
83 else
84 offset++;
85 /* OTHER */
86 o_attribute = STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES;
b41c2908 87 if (mode & 0004) // S_IROTH
89cc2408 88 o_attribute |= FILE_GENERIC_READ;
b41c2908 89 if (mode & 0002) // S_IWOTH
89cc2408 90 o_attribute |= FILE_GENERIC_WRITE;
b41c2908 91 if (mode & 0001) // S_IXOTH
89cc2408 92 o_attribute |= FILE_GENERIC_EXECUTE;
b41c2908 93 if ((mode & 01003) == 00003) // S_IWOTH | S_IXOTH, !S_ISVTX
89cc2408 94 o_attribute |= FILE_DELETE_CHILD;
7d0ffe17
CV
95 if (!AddAccessAllowedAceEx (&acl.acl, ACL_REVISION, NO_INHERIT_ACE,
96 o_attribute, everyOneSID.theSID ()))
97 Log (LOG_TIMESTAMP) << "AddAccessAllowedAceEx(" << fname
b41c2908 98 << ", everyone) failed: " << GetLastError () << endLog;
89cc2408
CV
99 else
100 offset++;
be617b59
CV
101 if (mode & 07000) /* At least one of S_ISUID, S_ISGID, S_ISVTX */
102 {
89cc2408 103 DWORD attribute = 0;
be617b59
CV
104 if (mode & 04000) // S_ISUID
105 attribute |= FILE_APPEND_DATA;
106 if (mode & 02000) // S_ISGID
107 attribute |= FILE_WRITE_DATA;
108 if (mode & 01000) // S_ISVTX
109 attribute |= FILE_READ_DATA;
7d0ffe17
CV
110 if (!AddAccessAllowedAceEx (&acl.acl, ACL_REVISION, NO_INHERIT_ACE,
111 attribute, nullSID.theSID ()))
112 Log (LOG_TIMESTAMP) << "AddAccessAllowedAceEx(" << fname
be617b59 113 << ", null) failed: " << GetLastError () << endLog;
89cc2408
CV
114 else
115 offset++;
116 }
117 /* For directories, we also add inherit-only ACEs for CREATOR OWNER,
118 CREATOR GROUP, and EVERYONE (aka OTHER). */
119 if (mode & S_IFDIR)
120 {
d285d991
CV
121 if (mode & 01000) // S_ISVTX
122 {
123 /* Don't allow default write permissions for group and other
124 in a S_ISVTX dir. */
125 /* GROUP */
126 g_attribute = STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES;
127 if (mode & 0040) // S_IRGRP
128 g_attribute |= FILE_GENERIC_READ;
129 if (mode & 0010) // S_IXGRP
130 g_attribute |= FILE_GENERIC_EXECUTE;
131 /* OTHER */
132 o_attribute = STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES;
133 if (mode & 0004) // S_IROTH
134 o_attribute |= FILE_GENERIC_READ;
135 if (mode & 0001) // S_IXOTH
136 o_attribute |= FILE_GENERIC_EXECUTE;
137 }
7d0ffe17
CV
138 if (!AddAccessAllowedAceEx (&acl.acl, ACL_REVISION, ALL_INHERIT_ACE,
139 u_attribute, cr_ownerSID.theSID ()))
140 Log (LOG_TIMESTAMP) << "AddAccessAllowedAceEx(" << fname
89cc2408
CV
141 << ", creator owner) failed: "
142 << GetLastError () << endLog;
143 else
7d0ffe17
CV
144 offset++;
145 if (!AddAccessAllowedAceEx (&acl.acl, ACL_REVISION, ALL_INHERIT_ACE,
146 g_attribute, cr_groupSID.theSID ()))
147 Log (LOG_TIMESTAMP) << "AddAccessAllowedAceEx(" << fname
89cc2408
CV
148 << ", creator group) failed: "
149 << GetLastError () << endLog;
150 else
7d0ffe17
CV
151 offset++;
152 if (!AddAccessAllowedAceEx (&acl.acl, ACL_REVISION, ALL_INHERIT_ACE,
153 o_attribute, everyOneSID.theSID ()))
154 Log (LOG_TIMESTAMP) << "AddAccessAllowedAceEx(" << fname
89cc2408
CV
155 << ", everyone inherit) failed: "
156 << GetLastError () << endLog;
157 else
7d0ffe17 158 offset++;
be617b59 159 }
b41c2908
CV
160
161 /* Set SD's DACL to just created ACL. */
be617b59 162 if (!SetSecurityDescriptorDacl (&out_sd, TRUE, &acl.acl, FALSE))
157dc2b8 163 Log (LOG_TIMESTAMP) << "SetSecurityDescriptorDacl(" << fname
b41c2908 164 << ") failed: " << GetLastError () << endLog;
26922cd2
CV
165 return &out_sd;
166}
167
5072c0bb
BD
168void
169NTSecurity::NoteFailedAPI (const std::string &api)
170{
157dc2b8 171 Log (LOG_TIMESTAMP) << api << "() failed: " << GetLastError () << endLog;
5072c0bb
BD
172}
173
174void
be617b59 175NTSecurity::initialiseWellKnownSIDs ()
5072c0bb 176{
be617b59
CV
177 SID_IDENTIFIER_AUTHORITY n_sid_auth = { SECURITY_NULL_SID_AUTHORITY };
178 /* Get the SID for "NULL" S-1-0-0 */
179 if (!AllocateAndInitializeSid (&n_sid_auth, 1, SECURITY_NULL_RID,
180 0, 0, 0, 0, 0, 0, 0, &nullSID.theSID ()))
be617b59 181 return;
be617b59
CV
182 SID_IDENTIFIER_AUTHORITY e_sid_auth = { SECURITY_WORLD_SID_AUTHORITY };
183 /* Get the SID for "Everyone" S-1-1-0 */
184 if (!AllocateAndInitializeSid (&e_sid_auth, 1, SECURITY_WORLD_RID,
185 0, 0, 0, 0, 0, 0, 0, &everyOneSID.theSID ()))
be617b59 186 return;
be617b59
CV
187 SID_IDENTIFIER_AUTHORITY nt_sid_auth = { SECURITY_NT_AUTHORITY };
188 /* Get the SID for "Administrators" S-1-5-32-544 */
157dc2b8 189 if (!AllocateAndInitializeSid (&nt_sid_auth, 2, SECURITY_BUILTIN_DOMAIN_RID,
be617b59
CV
190 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
191 &administratorsSID.theSID ()))
be617b59 192 return;
be617b59 193 /* Get the SID for "Users" S-1-5-32-545 */
157dc2b8 194 if (!AllocateAndInitializeSid (&nt_sid_auth, 2, SECURITY_BUILTIN_DOMAIN_RID,
be617b59
CV
195 DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0,
196 &usersSID.theSID ()))
be617b59 197 return;
89cc2408
CV
198 SID_IDENTIFIER_AUTHORITY c_sid_auth = { SECURITY_CREATOR_SID_AUTHORITY };
199 /* Get the SID for "CREATOR OWNER" S-1-3-0 */
157dc2b8 200 if (!AllocateAndInitializeSid (&c_sid_auth, 1, SECURITY_CREATOR_OWNER_RID,
26922cd2 201 0, 0, 0, 0, 0, 0, 0, &cr_ownerSID.theSID ()))
89cc2408 202 return;
89cc2408 203 /* Get the SID for "CREATOR GROUP" S-1-3-1 */
157dc2b8 204 if (!AllocateAndInitializeSid (&c_sid_auth, 1, SECURITY_CREATOR_GROUP_RID,
26922cd2 205 0, 0, 0, 0, 0, 0, 0, &cr_groupSID.theSID ()))
89cc2408 206 return;
be617b59 207 wellKnownSIDsinitialized (true);
5072c0bb
BD
208}
209
210void
211NTSecurity::setDefaultDACL ()
212{
157dc2b8 213 /* To assure that the created files have a useful ACL, the
5072c0bb
BD
214 default DACL in the process token is set to full access to
215 everyone. This applies to files and subdirectories created
216 in directories which don't propagate permissions to child
157dc2b8 217 objects.
5072c0bb 218 To assure that the files group is meaningful, a token primary
be617b59
CV
219 group of None is changed to Users or Administrators.
220 This is the fallback if real POSIX permissions don't
221 work for some reason. */
5072c0bb
BD
222
223 /* Create a buffer which has enough room to contain the TOKEN_DEFAULT_DACL
224 structure plus an ACL with one ACE. */
225 size_t bufferSize = sizeof (ACL) + sizeof (ACCESS_ALLOWED_ACE)
226 + GetLengthSid (everyOneSID.theSID ()) - sizeof (DWORD);
227
1c6add37 228 std::unique_ptr<char[]> buf (new char[bufferSize]);
5072c0bb
BD
229
230 /* First initialize the TOKEN_DEFAULT_DACL structure. */
231 PACL dacl = (PACL) buf.get ();
232
233 /* Initialize the ACL for containing one ACE. */
234 if (!InitializeAcl (dacl, bufferSize, ACL_REVISION))
235 {
236 NoteFailedAPI ("InitializeAcl");
5072c0bb
BD
237 return;
238 }
239
240 /* Create the ACE which grants full access to "Everyone" and store it
241 in dacl. */
7d0ffe17
CV
242 if (!AddAccessAllowedAceEx (dacl, ACL_REVISION, NO_INHERIT_ACE,
243 GENERIC_ALL, everyOneSID.theSID ()))
5072c0bb 244 {
7d0ffe17 245 NoteFailedAPI ("AddAccessAllowedAceEx");
5072c0bb
BD
246 return;
247 }
248
249 /* Set the default DACL to the above computed ACL. */
157dc2b8 250 if (!SetTokenInformation (token.theHANDLE(), TokenDefaultDacl, &dacl,
5072c0bb 251 bufferSize))
be617b59 252 NoteFailedAPI ("SetTokenInformation");
5072c0bb
BD
253}
254
255void
be617b59 256NTSecurity::setBackupPrivileges ()
5072c0bb 257{
b41c2908
CV
258 LUID backup, restore;
259 if (!LookupPrivilegeValue (NULL, SE_BACKUP_NAME, &backup))
260 NoteFailedAPI ("LookupPrivilegeValue");
261 else if (!LookupPrivilegeValue (NULL, SE_RESTORE_NAME, &restore))
262 NoteFailedAPI ("LookupPrivilegeValue");
263 else
264 {
265 PTOKEN_PRIVILEGES new_privs;
266
267 new_privs = (PTOKEN_PRIVILEGES) alloca (sizeof (TOKEN_PRIVILEGES)
268 + sizeof (LUID_AND_ATTRIBUTES));
269 new_privs->PrivilegeCount = 2;
270 new_privs->Privileges[0].Luid = backup;
271 new_privs->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
272 new_privs->Privileges[1].Luid = restore;
273 new_privs->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
274 if (!AdjustTokenPrivileges (token.theHANDLE (), FALSE, new_privs,
275 0, NULL, NULL))
276 NoteFailedAPI ("AdjustTokenPrivileges");
277 else if (GetLastError () == ERROR_NOT_ALL_ASSIGNED)
157dc2b8
AG
278 Log (LOG_TIMESTAMP) << "User has NO backup/restore rights" << endLog;
279 else
280 Log (LOG_TIMESTAMP) << "User has backup/restore rights" << endLog;
b41c2908 281 }
be617b59
CV
282}
283
770e3aed
CV
284void
285NTSecurity::resetPrimaryGroup ()
d29a864d
CV
286{
287 if (primaryGroupSID.pgrp.PrimaryGroup)
288 {
157dc2b8 289 Log (LOG_TIMESTAMP) << "Changing gid back to original" << endLog;
d29a864d
CV
290 if (!SetTokenInformation (token.theHANDLE (), TokenPrimaryGroup,
291 &primaryGroupSID, sizeof primaryGroupSID))
292 NoteFailedAPI ("SetTokenInformation");
293 }
294}
295
296void
297NTSecurity::setAdminGroup ()
770e3aed
CV
298{
299 TOKEN_PRIMARY_GROUP tpg;
300
d29a864d 301 tpg.PrimaryGroup = administratorsSID.theSID ();
157dc2b8 302 Log (LOG_TIMESTAMP) << "Changing gid to Administrators" << endLog;
d29a864d
CV
303 if (!SetTokenInformation (token.theHANDLE (), TokenPrimaryGroup,
304 &tpg, sizeof tpg))
770e3aed 305 NoteFailedAPI ("SetTokenInformation");
26922cd2
CV
306 else
307 groupSID = administratorsSID.theSID ();
770e3aed
CV
308}
309
be617b59 310void
78e83185 311NTSecurity::setDefaultSecurity ()
be617b59 312{
be617b59
CV
313 /* Get the processes access token. */
314 if (!OpenProcessToken (GetCurrentProcess (),
315 TOKEN_READ | TOKEN_ADJUST_DEFAULT
316 | TOKEN_ADJUST_PRIVILEGES, &token.theHANDLE ()))
317 {
318 NoteFailedAPI ("OpenProcessToken");
319 return;
320 }
321
322 /* Set backup and restore privileges if available. */
323 setBackupPrivileges ();
b41c2908 324
449640c4 325 /* Log if symlink creation privilege is available. */
7850e958 326 if (!hasSymlinkCreationRights())
449640c4
JT
327 Log (LOG_TIMESTAMP) << "User has NO symlink creation right" << endLog;
328 else
329 Log (LOG_TIMESTAMP) << "User has symlink creation right" << endLog;
330
be617b59
CV
331 /* If initializing the well-known SIDs didn't work, we're finished here. */
332 if (!wellKnownSIDsinitialized ())
5072c0bb
BD
333 return;
334
be617b59
CV
335 /* Set the default DACL to all permissions for everyone as a fallback. */
336 setDefaultDACL ();
337
5072c0bb 338 /* Get the user */
157dc2b8 339 if (!GetTokenInformation (token.theHANDLE (), TokenUser, &ownerSID,
26922cd2 340 sizeof ownerSID, &size))
5072c0bb 341 {
d29a864d 342 NoteFailedAPI ("GetTokenInformation(user)");
5072c0bb
BD
343 return;
344 }
345 /* Make it the owner */
26922cd2 346 TOKEN_OWNER owner = { ownerSID.user.User.Sid };
157dc2b8 347 if (!SetTokenInformation (token.theHANDLE (), TokenOwner, &owner,
d29a864d 348 sizeof owner))
5072c0bb 349 {
d29a864d 350 NoteFailedAPI ("SetTokenInformation(owner)");
5072c0bb
BD
351 return;
352 }
3d427dc9 353 /* Get original primary group */
770e3aed 354 if (!GetTokenInformation (token.theHANDLE (), TokenPrimaryGroup,
d29a864d 355 &primaryGroupSID, sizeof primaryGroupSID, &size))
770e3aed 356 {
d29a864d
CV
357 NoteFailedAPI("GetTokenInformation(pgrp)");
358 primaryGroupSID.pgrp.PrimaryGroup = (PSID) NULL;
770e3aed 359 }
26922cd2 360 groupSID = primaryGroupSID.pgrp.PrimaryGroup;
5072c0bb
BD
361}
362
aa09dcbb
CV
363bool
364NTSecurity::isRunAsAdmin ()
365{
366 BOOL is_run_as_admin = FALSE;
367 if (!CheckTokenMembership(NULL, administratorsSID.theSID (), &is_run_as_admin))
507e5b52 368 NoteFailedAPI("CheckTokenMembership(administratorsSID)");
aa09dcbb
CV
369 return (is_run_as_admin == TRUE);
370}
371
449640c4
JT
372bool
373NTSecurity::hasSymlinkCreationRights ()
374{
375 LUID symlink;
376 if (!LookupPrivilegeValue (NULL, SE_CREATE_SYMBOLIC_LINK_NAME, &symlink))
377 {
378 NoteFailedAPI ("LookupPrivilegeValue");
379 return FALSE;
380 }
381
382 DWORD size;
383 GetTokenInformation (token.theHANDLE (), TokenPrivileges, NULL, 0, &size);
384 /* Will fail ERROR_INSUFFICIENT_BUFFER, but updates size */
385
386 TOKEN_PRIVILEGES *privileges = (TOKEN_PRIVILEGES *)alloca(size);
387 if (!GetTokenInformation (token.theHANDLE (), TokenPrivileges, privileges,
388 size, &size))
389 {
390 NoteFailedAPI ("GetTokenInformation(privileges)");
391 return FALSE;
392 }
393
394 unsigned int i;
395 for (i = 0; i < privileges->PrivilegeCount; i++)
396 {
397 if (memcmp(&privileges->Privileges[i].Luid, &symlink, sizeof(LUID)) == 0)
398 {
beaffbbd 399 return TRUE;
449640c4
JT
400 }
401 }
402
403 return FALSE;
404}
aa09dcbb 405
5072c0bb
BD
406VersionInfo::VersionInfo ()
407{
408 v.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
409 if (GetVersionEx (&v) == 0)
410 {
157dc2b8 411 Log (LOG_PLAIN) << "GetVersionEx () failed: " << GetLastError ()
5072c0bb 412 << endLog;
157dc2b8 413
5072c0bb
BD
414 /* If GetVersionEx fails we really should bail with an error of some kind,
415 but for now just assume we're on NT and continue. */
416 v.dwPlatformId = VER_PLATFORM_WIN32_NT;
417 }
418}
419
420/* This is the Construct on First Use idiom to avoid static initialization
421 order problems. */
422VersionInfo& GetVer ()
423{
424 static VersionInfo *vi = new VersionInfo ();
425 return *vi;
426}
e73fb694
JT
427
428/* Identify native machine arch if we are running under WoW */
429USHORT
430WowNativeMachine ()
431{
e73fb694
JT
432 typedef BOOL (WINAPI *PFNISWOW64PROCESS2)(HANDLE, USHORT *, USHORT *);
433 PFNISWOW64PROCESS2 pfnIsWow64Process2 = (PFNISWOW64PROCESS2)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process2");
434
435 typedef BOOL (WINAPI *PFNISWOW64PROCESS)(HANDLE, PBOOL);
436 PFNISWOW64PROCESS pfnIsWow64Process = (PFNISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process");
437
438 USHORT processMachine, nativeMachine;
439 if ((pfnIsWow64Process2) &&
440 (pfnIsWow64Process2(GetCurrentProcess(), &processMachine, &nativeMachine)))
441 return nativeMachine;
442 else if (pfnIsWow64Process) {
70fc13d3 443#ifdef _X86_
e73fb694
JT
444 BOOL bIsWow64 = FALSE;
445 if (pfnIsWow64Process(GetCurrentProcess(), &bIsWow64))
446 return bIsWow64 ? IMAGE_FILE_MACHINE_AMD64 : IMAGE_FILE_MACHINE_I386;
70fc13d3 447#endif
e73fb694 448 }
70fc13d3 449
4936dbca
JT
450#ifdef __x86_64__
451 return IMAGE_FILE_MACHINE_AMD64;
452#else
e73fb694
JT
453 return IMAGE_FILE_MACHINE_I386;
454#endif
455}
a2362bc5 456
fd571d50
JT
457/* Identify machine arch for the current process */
458USHORT
459WindowsProcessMachine ()
460{
461#if defined(__x86_64__)
462 USHORT processMachine = IMAGE_FILE_MACHINE_AMD64;
463#elif defined(__i386__)
464 USHORT processMachine = IMAGE_FILE_MACHINE_I386;
465#elif defined(__aarch64__)
466 USHORT processMachine = IMAGE_FILE_MACHINE_ARM64;
467#else
468 #error "Unknown architecture"
469#endif
470 return processMachine;
471}
472
473/* Convert a machine arch identifier to a string */
474const std::string
475machine_name(USHORT machine)
476{
477 switch (machine)
478 {
479 case IMAGE_FILE_MACHINE_I386:
480 return "x86";
481 break;
482 case IMAGE_FILE_MACHINE_AMD64:
483 return "x86_64";
484 break;
485 case IMAGE_FILE_MACHINE_ARM64:
486 return "ARM64";
487 break;
488 default:
489 std::stringstream machine_desc;
490 machine_desc << std::hex << machine;
491 return machine_desc.str();
492 }
493}
494
477a6ff5
JT
495const std::wstring
496LoadStringWEx(UINT uID, UINT langId)
497{
498 HINSTANCE hInstance = GetModuleHandle(NULL);
499
500 // Convert the string ID into a bundle number
501 LPCSTR bundle = MAKEINTRESOURCE(uID / 16 + 1);
502 HRSRC hRes = ::FindResourceEx(hInstance, RT_STRING, bundle, langId);
503 if (hRes)
504 {
505 HGLOBAL h = ::LoadResource(hInstance, hRes);
506 if (h)
507 {
508 HGLOBAL hGlob = ::LockResource(h);
509
510 // walk string bundle
511 wchar_t *buf = (wchar_t *)hGlob;
512 for (unsigned int i = 0; i < (uID & 15); i++)
513 {
514 buf += 1 + (UINT)*buf;
515 }
516
517 int len = *buf;
518 return std::wstring(buf + 1, len);
519 }
520 }
521 // N.B.: Due to the way string bundles are encoded, there's no difference
522 // between an absent string resource whose bundle is present, and a string
523 // resource containing the null string.
524 return L"";
525}
526
a2362bc5
JT
527const std::wstring
528LoadStringW(unsigned int uID)
529{
530 wchar_t *buf;
531
532 int len = ::LoadStringW(GetModuleHandle(NULL), uID, (LPWSTR)&buf, 0);
533 if (len > 0)
534 return std::wstring(buf, len);
535
7409282c
JT
536 // if empty or absent, fallback to the untranslated string
537 return LoadStringWEx(uID, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
a2362bc5 538}
b60d80c6 539
20f237b4
JT
540const std::string
541LoadStringUtf8(unsigned int uID)
542{
543 return wstring_to_string(LoadStringW(uID));
544}
545
b60d80c6
JT
546bool
547is_developer_mode(void)
548{
549 HKEY hKey;
550 LSTATUS err = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AppModelUnlock", 0, KEY_READ, &hKey);
551 if (err != ERROR_SUCCESS)
552 return false;
553
554 DWORD value;
555 DWORD size = sizeof(DWORD);
556 err = RegQueryValueExW(hKey, L"AllowDevelopmentWithoutDevLicense", NULL, NULL, reinterpret_cast<LPBYTE>(&value), &size);
557 RegCloseKey(hKey);
558 if (err != ERROR_SUCCESS)
559 return false;
560
561 return value != 0;
562}
This page took 0.196383 seconds and 6 git commands to generate.