2013-01-24 21:30:11 +00:00
|
|
|
/*
|
|
|
|
* Rufus: The Reliable USB Formatting Utility
|
|
|
|
* Standard Windows function calls
|
2021-04-09 11:36:30 +00:00
|
|
|
* Copyright © 2013-2021 Pete Batard <pete@akeo.ie>
|
2013-01-24 21:30:11 +00:00
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
#ifdef _CRTDBG_MAP_ALLOC
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <crtdbg.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <windows.h>
|
|
|
|
#include <sddl.h>
|
2019-03-12 14:20:19 +00:00
|
|
|
#include <gpedit.h>
|
2013-01-24 21:30:11 +00:00
|
|
|
|
|
|
|
#include "rufus.h"
|
2016-03-03 17:24:54 +00:00
|
|
|
#include "missing.h"
|
2013-10-15 21:58:27 +00:00
|
|
|
#include "resource.h"
|
2016-02-20 22:52:32 +00:00
|
|
|
#include "msapi_utf8.h"
|
2013-10-15 21:58:27 +00:00
|
|
|
#include "localization.h"
|
2013-01-24 21:30:11 +00:00
|
|
|
|
2016-02-20 22:52:32 +00:00
|
|
|
#include "settings.h"
|
|
|
|
|
2013-11-05 02:16:49 +00:00
|
|
|
int nWindowsVersion = WINDOWS_UNDEFINED;
|
2017-04-19 10:30:24 +00:00
|
|
|
int nWindowsBuildNumber = -1;
|
2013-11-05 02:16:49 +00:00
|
|
|
char WindowsVersionStr[128] = "Windows ";
|
2013-01-24 21:30:11 +00:00
|
|
|
|
2014-05-17 23:37:01 +00:00
|
|
|
/*
|
|
|
|
* Hash table functions - modified From glibc 2.3.2:
|
|
|
|
* [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
|
|
|
|
* [Knuth] The Art of Computer Programming, part 3 (6.4)
|
|
|
|
*/
|
|
|
|
|
2015-12-30 14:27:52 +00:00
|
|
|
/*
|
2014-05-17 23:37:01 +00:00
|
|
|
* For the used double hash method the table size has to be a prime. To
|
|
|
|
* correct the user given table size we need a prime test. This trivial
|
|
|
|
* algorithm is adequate because the code is called only during init and
|
|
|
|
* the number is likely to be small
|
|
|
|
*/
|
|
|
|
static uint32_t isprime(uint32_t number)
|
|
|
|
{
|
|
|
|
// no even number will be passed
|
|
|
|
uint32_t divider = 3;
|
|
|
|
|
|
|
|
while((divider * divider < number) && (number % divider != 0))
|
|
|
|
divider += 2;
|
|
|
|
|
|
|
|
return (number % divider != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Before using the hash table we must allocate memory for it.
|
|
|
|
* We allocate one element more as the found prime number says.
|
|
|
|
* This is done for more effective indexing as explained in the
|
|
|
|
* comment for the hash function.
|
|
|
|
*/
|
|
|
|
BOOL htab_create(uint32_t nel, htab_table* htab)
|
|
|
|
{
|
|
|
|
if (htab == NULL) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (htab->table != NULL) {
|
|
|
|
uprintf("warning: htab_create() was called with a non empty table");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Change nel to the first prime number not smaller as nel.
|
|
|
|
nel |= 1;
|
|
|
|
while(!isprime(nel))
|
|
|
|
nel += 2;
|
|
|
|
|
|
|
|
htab->size = nel;
|
|
|
|
htab->filled = 0;
|
|
|
|
|
|
|
|
// allocate memory and zero out.
|
|
|
|
htab->table = (htab_entry*)calloc(htab->size + 1, sizeof(htab_entry));
|
|
|
|
if (htab->table == NULL) {
|
|
|
|
uprintf("could not allocate space for hash table\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* After using the hash table it has to be destroyed. */
|
|
|
|
void htab_destroy(htab_table* htab)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if ((htab == NULL) || (htab->table == NULL)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<htab->size+1; i++) {
|
|
|
|
if (htab->table[i].used) {
|
|
|
|
safe_free(htab->table[i].str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
htab->filled = 0; htab->size = 0;
|
|
|
|
safe_free(htab->table);
|
|
|
|
htab->table = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is the search function. It uses double hashing with open addressing.
|
|
|
|
* We use a trick to speed up the lookup. The table is created with one
|
|
|
|
* more element available. This enables us to use the index zero special.
|
|
|
|
* This index will never be used because we store the first hash index in
|
|
|
|
* the field used where zero means not used. Every other value means used.
|
|
|
|
* The used field can be used as a first fast comparison for equality of
|
|
|
|
* the stored and the parameter value. This helps to prevent unnecessary
|
|
|
|
* expensive calls of strcmp.
|
|
|
|
*/
|
|
|
|
uint32_t htab_hash(char* str, htab_table* htab)
|
|
|
|
{
|
|
|
|
uint32_t hval, hval2;
|
|
|
|
uint32_t idx;
|
|
|
|
uint32_t r = 0;
|
|
|
|
int c;
|
|
|
|
char* sz = str;
|
|
|
|
|
|
|
|
if ((htab == NULL) || (htab->table == NULL) || (str == NULL)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute main hash value using sdbm's algorithm (empirically
|
|
|
|
// shown to produce half the collisions as djb2's).
|
|
|
|
// See http://www.cse.yorku.ca/~oz/hash.html
|
|
|
|
while ((c = *sz++) != 0)
|
|
|
|
r = c + (r << 6) + (r << 16) - r;
|
|
|
|
if (r == 0)
|
|
|
|
++r;
|
|
|
|
|
|
|
|
// compute table hash: simply take the modulus
|
|
|
|
hval = r % htab->size;
|
|
|
|
if (hval == 0)
|
|
|
|
++hval;
|
|
|
|
|
|
|
|
// Try the first index
|
|
|
|
idx = hval;
|
|
|
|
|
|
|
|
if (htab->table[idx].used) {
|
|
|
|
if ( (htab->table[idx].used == hval)
|
|
|
|
&& (safe_strcmp(str, htab->table[idx].str) == 0) ) {
|
|
|
|
// existing hash
|
|
|
|
return idx;
|
|
|
|
}
|
2015-05-28 17:47:53 +00:00
|
|
|
// uprintf("hash collision ('%s' vs '%s')\n", str, htab->table[idx].str);
|
2014-05-17 23:37:01 +00:00
|
|
|
|
|
|
|
// Second hash function, as suggested in [Knuth]
|
|
|
|
hval2 = 1 + hval % (htab->size - 2);
|
|
|
|
|
|
|
|
do {
|
|
|
|
// Because size is prime this guarantees to step through all available indexes
|
|
|
|
if (idx <= hval2) {
|
|
|
|
idx = ((uint32_t)htab->size) + idx - hval2;
|
|
|
|
} else {
|
|
|
|
idx -= hval2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we visited all entries leave the loop unsuccessfully
|
|
|
|
if (idx == hval) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If entry is found use it.
|
|
|
|
if ( (htab->table[idx].used == hval)
|
|
|
|
&& (safe_strcmp(str, htab->table[idx].str) == 0) ) {
|
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (htab->table[idx].used);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not found => New entry
|
|
|
|
|
|
|
|
// If the table is full return an error
|
|
|
|
if (htab->filled >= htab->size) {
|
|
|
|
uprintf("hash table is full (%d entries)", htab->size);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
safe_free(htab->table[idx].str);
|
|
|
|
htab->table[idx].used = hval;
|
|
|
|
htab->table[idx].str = (char*) malloc(safe_strlen(str)+1);
|
|
|
|
if (htab->table[idx].str == NULL) {
|
|
|
|
uprintf("could not duplicate string for hash table\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
memcpy(htab->table[idx].str, str, safe_strlen(str)+1);
|
|
|
|
++htab->filled;
|
|
|
|
|
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
2013-11-23 00:46:06 +00:00
|
|
|
BOOL is_x64(void)
|
2013-01-24 21:30:11 +00:00
|
|
|
{
|
2013-11-05 02:16:49 +00:00
|
|
|
BOOL ret = FALSE;
|
2014-05-18 23:56:17 +00:00
|
|
|
PF_TYPE_DECL(WINAPI, BOOL, IsWow64Process, (HANDLE, PBOOL));
|
2013-11-05 02:16:49 +00:00
|
|
|
// Detect if we're running a 32 or 64 bit system
|
|
|
|
if (sizeof(uintptr_t) < 8) {
|
2014-05-12 21:44:10 +00:00
|
|
|
PF_INIT(IsWow64Process, Kernel32);
|
|
|
|
if (pfIsWow64Process != NULL) {
|
|
|
|
(*pfIsWow64Process)(GetCurrentProcess(), &ret);
|
2013-11-05 02:16:49 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ret = TRUE;
|
|
|
|
}
|
|
|
|
return ret;
|
2013-01-24 21:30:11 +00:00
|
|
|
}
|
|
|
|
|
2018-10-22 16:42:40 +00:00
|
|
|
int GetCpuArch(void)
|
|
|
|
{
|
|
|
|
SYSTEM_INFO info = { 0 };
|
|
|
|
GetNativeSystemInfo(&info);
|
|
|
|
switch (info.wProcessorArchitecture) {
|
|
|
|
case PROCESSOR_ARCHITECTURE_AMD64:
|
|
|
|
return CPU_ARCH_X86_64;
|
|
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
|
|
return CPU_ARCH_X86_64;
|
2019-09-06 10:32:37 +00:00
|
|
|
case PROCESSOR_ARCHITECTURE_ARM64:
|
2018-10-22 16:42:40 +00:00
|
|
|
return CPU_ARCH_ARM_64;
|
|
|
|
case PROCESSOR_ARCHITECTURE_ARM:
|
|
|
|
return CPU_ARCH_ARM_32;
|
|
|
|
default:
|
|
|
|
return CPU_ARCH_UNDEFINED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-05 02:16:49 +00:00
|
|
|
// From smartmontools os_win32.cpp
|
|
|
|
void GetWindowsVersion(void)
|
2013-06-25 21:50:22 +00:00
|
|
|
{
|
2013-11-05 02:16:49 +00:00
|
|
|
OSVERSIONINFOEXA vi, vi2;
|
|
|
|
const char* w = 0;
|
|
|
|
const char* w64 = "32 bit";
|
2019-01-31 13:50:03 +00:00
|
|
|
char *vptr;
|
2013-11-05 02:16:49 +00:00
|
|
|
size_t vlen;
|
|
|
|
unsigned major, minor;
|
|
|
|
ULONGLONG major_equal, minor_equal;
|
|
|
|
BOOL ws;
|
|
|
|
|
|
|
|
nWindowsVersion = WINDOWS_UNDEFINED;
|
2017-08-10 18:43:04 +00:00
|
|
|
static_strcpy(WindowsVersionStr, "Windows Undefined");
|
2013-11-05 02:16:49 +00:00
|
|
|
|
|
|
|
memset(&vi, 0, sizeof(vi));
|
|
|
|
vi.dwOSVersionInfoSize = sizeof(vi);
|
|
|
|
if (!GetVersionExA((OSVERSIONINFOA *)&vi)) {
|
|
|
|
memset(&vi, 0, sizeof(vi));
|
|
|
|
vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
|
|
|
|
if (!GetVersionExA((OSVERSIONINFOA *)&vi))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
|
|
|
|
|
|
|
|
if (vi.dwMajorVersion > 6 || (vi.dwMajorVersion == 6 && vi.dwMinorVersion >= 2)) {
|
|
|
|
// Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the actual OS version
|
|
|
|
// See: http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
|
2015-01-28 01:06:51 +00:00
|
|
|
// And starting with Windows 10 Preview 2, Windows enforces the use of the application/supportedOS
|
|
|
|
// manifest in order for VerSetConditionMask() to report the ACTUAL OS major and minor...
|
2013-11-05 02:16:49 +00:00
|
|
|
|
|
|
|
major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);
|
|
|
|
for (major = vi.dwMajorVersion; major <= 9; major++) {
|
|
|
|
memset(&vi2, 0, sizeof(vi2));
|
|
|
|
vi2.dwOSVersionInfoSize = sizeof(vi2); vi2.dwMajorVersion = major;
|
|
|
|
if (!VerifyVersionInfoA(&vi2, VER_MAJORVERSION, major_equal))
|
|
|
|
continue;
|
|
|
|
if (vi.dwMajorVersion < major) {
|
|
|
|
vi.dwMajorVersion = major; vi.dwMinorVersion = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL);
|
|
|
|
for (minor = vi.dwMinorVersion; minor <= 9; minor++) {
|
|
|
|
memset(&vi2, 0, sizeof(vi2)); vi2.dwOSVersionInfoSize = sizeof(vi2);
|
|
|
|
vi2.dwMinorVersion = minor;
|
|
|
|
if (!VerifyVersionInfoA(&vi2, VER_MINORVERSION, minor_equal))
|
|
|
|
continue;
|
|
|
|
vi.dwMinorVersion = minor;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vi.dwMajorVersion <= 0xf && vi.dwMinorVersion <= 0xf) {
|
|
|
|
ws = (vi.wProductType <= VER_NT_WORKSTATION);
|
|
|
|
nWindowsVersion = vi.dwMajorVersion << 4 | vi.dwMinorVersion;
|
|
|
|
switch (nWindowsVersion) {
|
|
|
|
case 0x51: w = "XP";
|
|
|
|
break;
|
2017-09-15 11:40:33 +00:00
|
|
|
case 0x52: w = (!GetSystemMetrics(89)?"Server 2003":"Server 2003_R2");
|
2013-11-05 02:16:49 +00:00
|
|
|
break;
|
2017-09-15 11:40:33 +00:00
|
|
|
case 0x60: w = (ws?"Vista":"Server 2008");
|
2013-11-05 02:16:49 +00:00
|
|
|
break;
|
2017-09-15 11:40:33 +00:00
|
|
|
case 0x61: w = (ws?"7":"Server 2008_R2");
|
2013-11-05 02:16:49 +00:00
|
|
|
break;
|
2017-09-15 11:40:33 +00:00
|
|
|
case 0x62: w = (ws?"8":"Server 2012");
|
2013-11-05 02:16:49 +00:00
|
|
|
break;
|
2017-09-15 11:40:33 +00:00
|
|
|
case 0x63: w = (ws?"8.1":"Server 2012_R2");
|
2013-11-05 02:16:49 +00:00
|
|
|
break;
|
2015-01-28 01:06:51 +00:00
|
|
|
case 0x64: w = (ws?"10 (Preview 1)":"Server 10 (Preview 1)");
|
|
|
|
break;
|
|
|
|
// Starting with Windows 10 Preview 2, the major is the same as the public-facing version
|
2017-09-15 11:40:33 +00:00
|
|
|
case 0xA0: w = (ws?"10":"Server 2016");
|
2014-02-22 00:34:52 +00:00
|
|
|
break;
|
2013-11-05 02:16:49 +00:00
|
|
|
default:
|
2015-05-02 13:41:46 +00:00
|
|
|
if (nWindowsVersion < 0x51)
|
2014-02-22 00:34:52 +00:00
|
|
|
nWindowsVersion = WINDOWS_UNSUPPORTED;
|
|
|
|
else
|
2014-11-08 00:23:50 +00:00
|
|
|
w = "11 or later";
|
2013-11-05 02:16:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_x64())
|
|
|
|
w64 = "64-bit";
|
|
|
|
|
|
|
|
vptr = &WindowsVersionStr[sizeof("Windows ") - 1];
|
|
|
|
vlen = sizeof(WindowsVersionStr) - sizeof("Windows ") - 1;
|
|
|
|
if (!w)
|
|
|
|
safe_sprintf(vptr, vlen, "%s %u.%u %s", (vi.dwPlatformId==VER_PLATFORM_WIN32_NT?"NT":"??"),
|
|
|
|
(unsigned)vi.dwMajorVersion, (unsigned)vi.dwMinorVersion, w64);
|
|
|
|
else if (vi.wServicePackMinor)
|
|
|
|
safe_sprintf(vptr, vlen, "%s SP%u.%u %s", w, vi.wServicePackMajor, vi.wServicePackMinor, w64);
|
|
|
|
else if (vi.wServicePackMajor)
|
|
|
|
safe_sprintf(vptr, vlen, "%s SP%u %s", w, vi.wServicePackMajor, w64);
|
|
|
|
else
|
|
|
|
safe_sprintf(vptr, vlen, "%s %s", w, w64);
|
2015-09-30 22:08:07 +00:00
|
|
|
|
2019-11-14 22:43:24 +00:00
|
|
|
// Add the build number (including UBR if available) for Windows 8.0 and later
|
2019-01-30 17:15:25 +00:00
|
|
|
nWindowsBuildNumber = vi.dwBuildNumber;
|
2015-09-30 22:08:07 +00:00
|
|
|
if (nWindowsVersion >= 0x62) {
|
2019-11-14 22:43:24 +00:00
|
|
|
int nUbr = ReadRegistryKey32(REGKEY_HKLM, "Software\\Microsoft\\Windows NT\\CurrentVersion\\UBR");
|
2019-01-30 17:15:25 +00:00
|
|
|
vptr = &WindowsVersionStr[safe_strlen(WindowsVersionStr)];
|
|
|
|
vlen = sizeof(WindowsVersionStr) - safe_strlen(WindowsVersionStr) - 1;
|
2019-11-14 22:43:24 +00:00
|
|
|
if (nUbr > 0)
|
|
|
|
safe_sprintf(vptr, vlen, " (Build %d.%d)", nWindowsBuildNumber, nUbr);
|
|
|
|
else
|
|
|
|
safe_sprintf(vptr, vlen, " (Build %d)", nWindowsBuildNumber);
|
2015-09-30 22:08:07 +00:00
|
|
|
}
|
2013-06-25 21:50:22 +00:00
|
|
|
}
|
|
|
|
|
2013-01-24 21:30:11 +00:00
|
|
|
/*
|
|
|
|
* String array manipulation
|
|
|
|
*/
|
2014-05-17 23:37:01 +00:00
|
|
|
void StrArrayCreate(StrArray* arr, uint32_t initial_size)
|
2013-01-24 21:30:11 +00:00
|
|
|
{
|
|
|
|
if (arr == NULL) return;
|
|
|
|
arr->Max = initial_size; arr->Index = 0;
|
2014-01-22 01:28:25 +00:00
|
|
|
arr->String = (char**)calloc(arr->Max, sizeof(char*));
|
|
|
|
if (arr->String == NULL)
|
2013-01-24 21:30:11 +00:00
|
|
|
uprintf("Could not allocate string array\n");
|
|
|
|
}
|
|
|
|
|
2016-12-13 14:21:51 +00:00
|
|
|
int32_t StrArrayAdd(StrArray* arr, const char* str, BOOL duplicate)
|
2013-01-24 21:30:11 +00:00
|
|
|
{
|
|
|
|
char** old_table;
|
2016-12-13 14:21:51 +00:00
|
|
|
if ((arr == NULL) || (arr->String == NULL) || (str == NULL))
|
2014-05-17 23:37:01 +00:00
|
|
|
return -1;
|
2013-01-24 21:30:11 +00:00
|
|
|
if (arr->Index == arr->Max) {
|
|
|
|
arr->Max *= 2;
|
2014-01-22 01:28:25 +00:00
|
|
|
old_table = arr->String;
|
|
|
|
arr->String = (char**)realloc(arr->String, arr->Max*sizeof(char*));
|
|
|
|
if (arr->String == NULL) {
|
2013-01-24 21:30:11 +00:00
|
|
|
free(old_table);
|
|
|
|
uprintf("Could not reallocate string array\n");
|
2014-05-17 23:37:01 +00:00
|
|
|
return -1;
|
2013-01-24 21:30:11 +00:00
|
|
|
}
|
|
|
|
}
|
2016-12-13 14:21:51 +00:00
|
|
|
arr->String[arr->Index] = (duplicate)?safe_strdup(str):(char*)str;
|
2014-05-17 23:37:01 +00:00
|
|
|
if (arr->String[arr->Index] == NULL) {
|
2013-01-24 21:30:11 +00:00
|
|
|
uprintf("Could not store string in array\n");
|
2014-05-17 23:37:01 +00:00
|
|
|
return -1;
|
2013-01-24 21:30:11 +00:00
|
|
|
}
|
2014-05-17 23:37:01 +00:00
|
|
|
return arr->Index++;
|
2013-01-24 21:30:11 +00:00
|
|
|
}
|
|
|
|
|
2018-03-22 23:14:20 +00:00
|
|
|
int32_t StrArrayFind(StrArray* arr, const char* str)
|
|
|
|
{
|
|
|
|
uint32_t i;
|
|
|
|
if ((str == NULL) || (arr == NULL) || (arr->String == NULL))
|
|
|
|
return -1;
|
|
|
|
for (i = 0; i<arr->Index; i++) {
|
|
|
|
if (strcmp(arr->String[i], str) == 0)
|
|
|
|
return (int32_t)i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-01-24 21:30:11 +00:00
|
|
|
void StrArrayClear(StrArray* arr)
|
|
|
|
{
|
2018-03-22 23:14:20 +00:00
|
|
|
uint32_t i;
|
2014-01-22 01:28:25 +00:00
|
|
|
if ((arr == NULL) || (arr->String == NULL))
|
2013-01-24 21:30:11 +00:00
|
|
|
return;
|
|
|
|
for (i=0; i<arr->Index; i++) {
|
2014-01-22 01:28:25 +00:00
|
|
|
safe_free(arr->String[i]);
|
2013-01-24 21:30:11 +00:00
|
|
|
}
|
|
|
|
arr->Index = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void StrArrayDestroy(StrArray* arr)
|
|
|
|
{
|
|
|
|
StrArrayClear(arr);
|
|
|
|
if (arr != NULL)
|
2014-01-22 01:28:25 +00:00
|
|
|
safe_free(arr->String);
|
2013-01-24 21:30:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Retrieve the SID of the current user. The returned PSID must be freed by the caller using LocalFree()
|
|
|
|
*/
|
|
|
|
static PSID GetSID(void) {
|
|
|
|
TOKEN_USER* tu = NULL;
|
|
|
|
DWORD len;
|
|
|
|
HANDLE token;
|
|
|
|
PSID ret = NULL;
|
|
|
|
char* psid_string = NULL;
|
|
|
|
|
|
|
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
|
|
|
|
uprintf("OpenProcessToken failed: %s\n", WindowsErrorString());
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!GetTokenInformation(token, TokenUser, tu, 0, &len)) {
|
|
|
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
|
|
|
uprintf("GetTokenInformation (pre) failed: %s\n", WindowsErrorString());
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
tu = (TOKEN_USER*)calloc(1, len);
|
|
|
|
}
|
|
|
|
if (tu == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (GetTokenInformation(token, TokenUser, tu, len, &len)) {
|
|
|
|
/*
|
|
|
|
* now of course, the interesting thing is that if you return tu->User.Sid
|
|
|
|
* but free tu, the PSID pointer becomes invalid after a while.
|
|
|
|
* The workaround? Convert to string then back to PSID
|
|
|
|
*/
|
|
|
|
if (!ConvertSidToStringSidA(tu->User.Sid, &psid_string)) {
|
|
|
|
uprintf("Unable to convert SID to string: %s\n", WindowsErrorString());
|
|
|
|
ret = NULL;
|
|
|
|
} else {
|
|
|
|
if (!ConvertStringSidToSidA(psid_string, &ret)) {
|
|
|
|
uprintf("Unable to convert string back to SID: %s\n", WindowsErrorString());
|
|
|
|
ret = NULL;
|
|
|
|
}
|
|
|
|
// MUST use LocalFree()
|
|
|
|
LocalFree(psid_string);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ret = NULL;
|
|
|
|
uprintf("GetTokenInformation (real) failed: %s\n", WindowsErrorString());
|
|
|
|
}
|
|
|
|
free(tu);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* read or write I/O to a file
|
|
|
|
* buffer is allocated by the procedure. path is UTF-8
|
|
|
|
*/
|
|
|
|
BOOL FileIO(BOOL save, char* path, char** buffer, DWORD* size)
|
|
|
|
{
|
2018-03-26 17:58:22 +00:00
|
|
|
SECURITY_ATTRIBUTES s_attr, *sa = NULL;
|
2013-01-24 21:30:11 +00:00
|
|
|
SECURITY_DESCRIPTOR s_desc;
|
|
|
|
PSID sid = NULL;
|
|
|
|
HANDLE handle;
|
|
|
|
BOOL r;
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
|
|
// Change the owner from admin to regular user
|
|
|
|
sid = GetSID();
|
|
|
|
if ( (sid != NULL)
|
|
|
|
&& InitializeSecurityDescriptor(&s_desc, SECURITY_DESCRIPTOR_REVISION)
|
|
|
|
&& SetSecurityDescriptorOwner(&s_desc, sid, FALSE) ) {
|
|
|
|
s_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
|
|
s_attr.bInheritHandle = FALSE;
|
|
|
|
s_attr.lpSecurityDescriptor = &s_desc;
|
2018-03-26 17:58:22 +00:00
|
|
|
sa = &s_attr;
|
2013-01-24 21:30:11 +00:00
|
|
|
} else {
|
|
|
|
uprintf("Could not set security descriptor: %s\n", WindowsErrorString());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!save) {
|
|
|
|
*buffer = NULL;
|
|
|
|
}
|
|
|
|
handle = CreateFileU(path, save?GENERIC_WRITE:GENERIC_READ, FILE_SHARE_READ,
|
2018-03-26 17:58:22 +00:00
|
|
|
sa, save?CREATE_ALWAYS:OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
2013-01-24 21:30:11 +00:00
|
|
|
|
|
|
|
if (handle == INVALID_HANDLE_VALUE) {
|
|
|
|
uprintf("Could not %s file '%s'\n", save?"create":"open", path);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (save) {
|
|
|
|
r = WriteFile(handle, *buffer, *size, size, NULL);
|
|
|
|
} else {
|
|
|
|
*size = GetFileSize(handle, NULL);
|
|
|
|
*buffer = (char*)malloc(*size);
|
|
|
|
if (*buffer == NULL) {
|
|
|
|
uprintf("Could not allocate buffer for reading file\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
r = ReadFile(handle, *buffer, *size, size, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!r) {
|
|
|
|
uprintf("I/O Error: %s\n", WindowsErrorString());
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2018-06-08 15:29:41 +00:00
|
|
|
PrintInfoDebug(0, save?MSG_216:MSG_215, path);
|
2013-01-24 21:30:11 +00:00
|
|
|
ret = TRUE;
|
|
|
|
|
|
|
|
out:
|
|
|
|
CloseHandle(handle);
|
|
|
|
if (!ret) {
|
|
|
|
// Only leave a buffer allocated if successful
|
|
|
|
*size = 0;
|
|
|
|
if (!save) {
|
|
|
|
safe_free(*buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-02-19 12:41:13 +00:00
|
|
|
/*
|
|
|
|
* Get a resource from the RC. If needed that resource can be duplicated.
|
|
|
|
* If duplicate is true and len is non-zero, the a zeroed buffer of 'len'
|
|
|
|
* size is allocated for the resource. Else the buffer is allocate for
|
|
|
|
* the resource size.
|
|
|
|
*/
|
2013-01-25 01:38:10 +00:00
|
|
|
unsigned char* GetResource(HMODULE module, char* name, char* type, const char* desc, DWORD* len, BOOL duplicate)
|
|
|
|
{
|
|
|
|
HGLOBAL res_handle;
|
|
|
|
HRSRC res;
|
2020-02-19 12:41:13 +00:00
|
|
|
DWORD res_len;
|
2013-01-25 01:38:10 +00:00
|
|
|
unsigned char* p = NULL;
|
|
|
|
|
|
|
|
res = FindResourceA(module, name, type);
|
|
|
|
if (res == NULL) {
|
2015-07-03 22:42:45 +00:00
|
|
|
uprintf("Could not locate resource '%s': %s\n", desc, WindowsErrorString());
|
2013-01-25 01:38:10 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
res_handle = LoadResource(module, res);
|
|
|
|
if (res_handle == NULL) {
|
2015-07-03 22:42:45 +00:00
|
|
|
uprintf("Could not load resource '%s': %s\n", desc, WindowsErrorString());
|
2013-01-25 01:38:10 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2020-02-19 12:41:13 +00:00
|
|
|
res_len = SizeofResource(module, res);
|
2013-01-25 01:38:10 +00:00
|
|
|
|
|
|
|
if (duplicate) {
|
2020-02-19 12:41:13 +00:00
|
|
|
if (*len == 0)
|
|
|
|
*len = res_len;
|
|
|
|
p = (unsigned char*)calloc(*len, 1);
|
2013-01-25 01:38:10 +00:00
|
|
|
if (p == NULL) {
|
2020-02-19 12:41:13 +00:00
|
|
|
uprintf("Could not allocate resource '%s'\n", desc);
|
2013-01-25 01:38:10 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2020-02-19 19:51:32 +00:00
|
|
|
memcpy(p, LockResource(res_handle), min(res_len, *len));
|
|
|
|
if (res_len > *len)
|
|
|
|
uprintf("WARNING: Resource '%s' was truncated by %d bytes!\n", desc, res_len - *len);
|
2013-01-25 01:38:10 +00:00
|
|
|
} else {
|
|
|
|
p = (unsigned char*)LockResource(res_handle);
|
|
|
|
}
|
2020-02-19 12:41:13 +00:00
|
|
|
*len = res_len;
|
2013-01-25 01:38:10 +00:00
|
|
|
|
|
|
|
out:
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2014-12-20 00:22:00 +00:00
|
|
|
DWORD GetResourceSize(HMODULE module, char* name, char* type, const char* desc)
|
|
|
|
{
|
|
|
|
DWORD len = 0;
|
|
|
|
return (GetResource(module, name, type, desc, &len, FALSE) == NULL)?0:len;
|
|
|
|
}
|
2013-01-25 01:38:10 +00:00
|
|
|
|
2015-01-16 01:51:24 +00:00
|
|
|
// Run a console command, with optional redirection of stdout and stderr to our log
|
|
|
|
DWORD RunCommand(const char* cmd, const char* dir, BOOL log)
|
|
|
|
{
|
2015-06-25 18:51:42 +00:00
|
|
|
DWORD ret, dwRead, dwAvail, dwPipeSize = 4096;
|
2015-01-16 01:51:24 +00:00
|
|
|
STARTUPINFOA si = {0};
|
|
|
|
PROCESS_INFORMATION pi = {0};
|
2019-01-30 00:21:50 +00:00
|
|
|
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
|
2015-01-16 01:51:24 +00:00
|
|
|
HANDLE hOutputRead = INVALID_HANDLE_VALUE, hOutputWrite = INVALID_HANDLE_VALUE;
|
2015-06-25 18:51:42 +00:00
|
|
|
static char* output;
|
2015-01-16 01:51:24 +00:00
|
|
|
|
|
|
|
si.cb = sizeof(si);
|
|
|
|
if (log) {
|
2015-08-22 22:23:08 +00:00
|
|
|
// NB: The size of a pipe is a suggestion, NOT an absolute guarantee
|
2015-06-25 18:51:42 +00:00
|
|
|
// This means that you may get a pipe of 4K even if you requested 1K
|
2019-01-30 00:21:50 +00:00
|
|
|
if (!CreatePipe(&hOutputRead, &hOutputWrite, &sa, dwPipeSize)) {
|
2015-01-16 01:51:24 +00:00
|
|
|
ret = GetLastError();
|
|
|
|
uprintf("Could not set commandline pipe: %s", WindowsErrorString());
|
|
|
|
goto out;
|
|
|
|
}
|
[net] add Windows retail ISO downloads
* This is accomplished through Fido (https://github.com/pbatard/Fido), a *SIGNED*
PowerShell script, that is downloaded from GitHub and that resides in memory for
the duration of a session.
* The reason we use a downloaded PS script, rather than an embedded on, is because:
- Microsoft have regularly been changing the deal with regards to how retail ISOs
can be downloaded, and not for the better, so we can't simply embed a static
means of downloading ISOs and expect that to work forever.
- By using an external script, we can immediately respond to whatever new means of
*ANNOYING* their legitimate users Microsoft will come up with next, as well as
make sure that, the minute a new retail version of Windows becomes available, it
also becomes available for download in Rufus.
* Note that if you are concerned about downloading a remote PS script that is being
run at the same level as an elevated application, you should understand that:
- Only scripts downloaded from GitHub, from an account that is protected with 2FA,
are allowed to run (i.e. someone would first have to steal a *physical* 2FA key
to be in a position to upload a malicious script).
- On top of this, only scripts that are signed with a separate private key (RSA +
AES-256), that is itself also protected with a strong unique password which only
a single person knows (and must manually enter each time they want to make a new
version of the script available for download), are allowed to run.
The above means that there's about as much chance for someone to manage to upload
a malicious script on the GitHub servers, that Rufus would allow to run, as there
is for someone to upload a malicious version of Rufus itself.
Still, if you are paranoid and have concerns that, even as you can validate from
its source that Rufus does not attempt to execute any remote script unless a user
actively selected and clicked the DOWNLOAD button, you can also completely disable
the remote script download feature, if you just set the update check to disabled
(which, by the way, Rufus *EXPLICITLY* asks you to choose whether you want to
enable or not, the very first time you run the application).
* Also remove _unlinkU() which duplicates what DeleteFileU() already does.
2019-03-02 23:28:56 +00:00
|
|
|
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES | STARTF_PREVENTPINNING | STARTF_TITLEISAPPID;
|
2015-01-16 01:51:24 +00:00
|
|
|
si.wShowWindow = SW_HIDE;
|
2019-01-30 00:21:50 +00:00
|
|
|
si.hStdOutput = hOutputWrite;
|
|
|
|
si.hStdError = hOutputWrite;
|
2015-01-16 01:51:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!CreateProcessU(NULL, cmd, NULL, NULL, TRUE,
|
|
|
|
NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, dir, &si, &pi)) {
|
|
|
|
ret = GetLastError();
|
2015-06-24 19:00:20 +00:00
|
|
|
uprintf("Unable to launch command '%s': %s", cmd, WindowsErrorString());
|
2015-01-16 01:51:24 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (log) {
|
|
|
|
while (1) {
|
2015-02-13 19:51:30 +00:00
|
|
|
// coverity[string_null]
|
2015-06-25 18:51:42 +00:00
|
|
|
if (PeekNamedPipe(hOutputRead, NULL, dwPipeSize, NULL, &dwAvail, NULL)) {
|
|
|
|
if (dwAvail != 0) {
|
|
|
|
output = malloc(dwAvail + 1);
|
|
|
|
if ((output != NULL) && (ReadFile(hOutputRead, output, dwAvail, &dwRead, NULL)) && (dwRead != 0)) {
|
|
|
|
output[dwAvail] = 0;
|
|
|
|
// coverity[tainted_string]
|
|
|
|
uprintf(output);
|
|
|
|
}
|
|
|
|
free(output);
|
2015-01-16 01:51:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (WaitForSingleObject(pi.hProcess, 0) == WAIT_OBJECT_0)
|
|
|
|
break;
|
|
|
|
Sleep(100);
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!GetExitCodeProcess(pi.hProcess, &ret))
|
|
|
|
ret = GetLastError();
|
|
|
|
CloseHandle(pi.hProcess);
|
|
|
|
CloseHandle(pi.hThread);
|
|
|
|
|
|
|
|
out:
|
2019-01-30 00:21:50 +00:00
|
|
|
safe_closehandle(hOutputWrite);
|
2015-01-16 01:51:24 +00:00
|
|
|
safe_closehandle(hOutputRead);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-01-20 21:50:24 +00:00
|
|
|
BOOL CompareGUID(const GUID *guid1, const GUID *guid2) {
|
|
|
|
if ((guid1 != NULL) && (guid2 != NULL)) {
|
|
|
|
return (memcmp(guid1, guid2, sizeof(GUID)) == 0);
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2015-12-30 14:27:52 +00:00
|
|
|
static BOOL CALLBACK EnumFontFamExProc(const LOGFONTA *lpelfe,
|
|
|
|
const TEXTMETRICA *lpntme, DWORD FontType, LPARAM lParam)
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2018-03-22 23:14:20 +00:00
|
|
|
BOOL IsFontAvailable(const char* font_name)
|
|
|
|
{
|
|
|
|
BOOL r;
|
2015-12-30 14:27:52 +00:00
|
|
|
LOGFONTA lf = { 0 };
|
|
|
|
HDC hDC = GetDC(hMainDialog);
|
|
|
|
|
2017-10-27 09:29:03 +00:00
|
|
|
if (font_name == NULL) {
|
2018-03-22 23:14:20 +00:00
|
|
|
safe_release_dc(hMainDialog, hDC);
|
2015-12-30 14:27:52 +00:00
|
|
|
return FALSE;
|
2017-10-27 09:29:03 +00:00
|
|
|
}
|
2015-12-30 14:27:52 +00:00
|
|
|
|
|
|
|
lf.lfCharSet = DEFAULT_CHARSET;
|
|
|
|
safe_strcpy(lf.lfFaceName, LF_FACESIZE, font_name);
|
|
|
|
|
2018-03-22 23:14:20 +00:00
|
|
|
r = EnumFontFamiliesExA(hDC, &lf, EnumFontFamExProc, 0, 0);
|
|
|
|
safe_release_dc(hMainDialog, hDC);
|
|
|
|
return r;
|
2015-12-30 14:27:52 +00:00
|
|
|
}
|
|
|
|
|
2013-01-24 21:30:11 +00:00
|
|
|
/*
|
|
|
|
* Set or restore a Local Group Policy DWORD key indexed by szPath/SzPolicy
|
|
|
|
*/
|
2014-11-01 22:08:20 +00:00
|
|
|
// I've seen rare cases where pLGPO->lpVtbl->Save(...) gets stuck, which prevents the
|
|
|
|
// application from launching altogether. To alleviate this, use a thread that we can
|
|
|
|
// terminate if needed...
|
|
|
|
typedef struct {
|
|
|
|
BOOL bRestore;
|
|
|
|
BOOL* bExistingKey;
|
|
|
|
const char* szPath;
|
|
|
|
const char* szPolicy;
|
|
|
|
DWORD dwValue;
|
|
|
|
} SetLGP_Params;
|
|
|
|
|
|
|
|
DWORD WINAPI SetLGPThread(LPVOID param)
|
2013-01-24 21:30:11 +00:00
|
|
|
{
|
2014-11-01 22:08:20 +00:00
|
|
|
SetLGP_Params* p = (SetLGP_Params*)param;
|
2013-01-24 21:30:11 +00:00
|
|
|
LONG r;
|
|
|
|
DWORD disp, regtype, val=0, val_size=sizeof(DWORD);
|
|
|
|
HRESULT hr;
|
|
|
|
IGroupPolicyObject* pLGPO;
|
|
|
|
// Along with global 'existing_key', this static value is used to restore initial state
|
|
|
|
static DWORD original_val;
|
|
|
|
HKEY path_key = NULL, policy_key = NULL;
|
2019-03-12 14:20:19 +00:00
|
|
|
// MSVC is finicky about these ones even if you link against gpedit.lib => redefine them
|
2015-12-30 14:27:52 +00:00
|
|
|
const IID my_IID_IGroupPolicyObject =
|
2015-01-20 21:50:24 +00:00
|
|
|
{ 0xea502723L, 0xa23d, 0x11d1, { 0xa7, 0xd3, 0x0, 0x0, 0xf8, 0x75, 0x71, 0xe3 } };
|
2015-12-30 14:27:52 +00:00
|
|
|
const IID my_CLSID_GroupPolicyObject =
|
2015-01-20 21:50:24 +00:00
|
|
|
{ 0xea502722L, 0xa23d, 0x11d1, { 0xa7, 0xd3, 0x0, 0x0, 0xf8, 0x75, 0x71, 0xe3 } };
|
2013-01-24 21:30:11 +00:00
|
|
|
GUID ext_guid = REGISTRY_EXTENSION_GUID;
|
|
|
|
// Can be anything really
|
2015-01-20 21:50:24 +00:00
|
|
|
GUID snap_guid = { 0x3D271CFCL, 0x2BC6, 0x4AC2, {0xB6, 0x33, 0x3B, 0xDF, 0xF5, 0xBD, 0xAB, 0x2A} };
|
2013-01-24 21:30:11 +00:00
|
|
|
|
2014-11-01 22:08:20 +00:00
|
|
|
// Reinitialize COM since it's not shared between threads
|
2021-04-09 11:36:30 +00:00
|
|
|
IGNORE_RETVAL(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE));
|
2014-11-01 22:08:20 +00:00
|
|
|
|
2013-01-24 21:30:11 +00:00
|
|
|
// We need an IGroupPolicyObject instance to set a Local Group Policy
|
|
|
|
hr = CoCreateInstance(&my_CLSID_GroupPolicyObject, NULL, CLSCTX_INPROC_SERVER, &my_IID_IGroupPolicyObject, (LPVOID*)&pLGPO);
|
|
|
|
if (FAILED(hr)) {
|
2017-04-27 22:06:42 +00:00
|
|
|
ubprintf("SetLGP: CoCreateInstance failed; hr = %lx", hr);
|
2013-01-24 21:30:11 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
hr = pLGPO->lpVtbl->OpenLocalMachineGPO(pLGPO, GPO_OPEN_LOAD_REGISTRY);
|
|
|
|
if (FAILED(hr)) {
|
2017-04-27 22:06:42 +00:00
|
|
|
ubprintf("SetLGP: OpenLocalMachineGPO failed - error %lx", hr);
|
2013-01-24 21:30:11 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
hr = pLGPO->lpVtbl->GetRegistryKey(pLGPO, GPO_SECTION_MACHINE, &path_key);
|
|
|
|
if (FAILED(hr)) {
|
2017-04-27 22:06:42 +00:00
|
|
|
ubprintf("SetLGP: GetRegistryKey failed - error %lx", hr);
|
2013-01-24 21:30:11 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2014-11-01 22:08:20 +00:00
|
|
|
r = RegCreateKeyExA(path_key, p->szPath, 0, NULL, 0, KEY_SET_VALUE | KEY_QUERY_VALUE,
|
2013-01-24 21:30:11 +00:00
|
|
|
NULL, &policy_key, &disp);
|
|
|
|
if (r != ERROR_SUCCESS) {
|
2017-04-27 22:06:42 +00:00
|
|
|
ubprintf("SetLGP: Failed to open LGPO path %s - error %lx", p->szPath, hr);
|
2015-01-23 02:26:41 +00:00
|
|
|
policy_key = NULL;
|
2013-01-24 21:30:11 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2014-11-01 22:08:20 +00:00
|
|
|
if ((disp == REG_OPENED_EXISTING_KEY) && (!p->bRestore) && (!(*(p->bExistingKey)))) {
|
2013-01-24 21:30:11 +00:00
|
|
|
// backup existing value for restore
|
2014-11-01 22:08:20 +00:00
|
|
|
*(p->bExistingKey) = TRUE;
|
2013-01-24 21:30:11 +00:00
|
|
|
regtype = REG_DWORD;
|
2014-11-01 22:08:20 +00:00
|
|
|
r = RegQueryValueExA(policy_key, p->szPolicy, NULL, ®type, (LPBYTE)&original_val, &val_size);
|
2013-01-24 21:30:11 +00:00
|
|
|
if (r == ERROR_FILE_NOT_FOUND) {
|
|
|
|
// The Key exists but not its value, which is OK
|
2014-11-01 22:08:20 +00:00
|
|
|
*(p->bExistingKey) = FALSE;
|
2013-01-24 21:30:11 +00:00
|
|
|
} else if (r != ERROR_SUCCESS) {
|
2017-04-27 22:06:42 +00:00
|
|
|
ubprintf("SetLGP: Failed to read original %s policy value - error %lx", p->szPolicy, r);
|
2013-01-24 21:30:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-01 22:08:20 +00:00
|
|
|
if ((!p->bRestore) || (*(p->bExistingKey))) {
|
|
|
|
val = (p->bRestore)?original_val:p->dwValue;
|
|
|
|
r = RegSetValueExA(policy_key, p->szPolicy, 0, REG_DWORD, (BYTE*)&val, sizeof(val));
|
2013-01-24 21:30:11 +00:00
|
|
|
} else {
|
2014-11-01 22:08:20 +00:00
|
|
|
r = RegDeleteValueA(policy_key, p->szPolicy);
|
2013-01-24 21:30:11 +00:00
|
|
|
}
|
|
|
|
if (r != ERROR_SUCCESS) {
|
2017-04-27 22:06:42 +00:00
|
|
|
ubprintf("SetLGP: RegSetValueEx / RegDeleteValue failed - error %lx", r);
|
2013-01-24 21:30:11 +00:00
|
|
|
}
|
|
|
|
RegCloseKey(policy_key);
|
|
|
|
policy_key = NULL;
|
|
|
|
|
|
|
|
// Apply policy
|
2014-11-01 22:08:20 +00:00
|
|
|
hr = pLGPO->lpVtbl->Save(pLGPO, TRUE, (p->bRestore)?FALSE:TRUE, &ext_guid, &snap_guid);
|
2014-10-29 19:16:29 +00:00
|
|
|
if (hr != S_OK) {
|
2017-04-27 22:06:42 +00:00
|
|
|
ubprintf("SetLGP: Unable to apply %s policy - error %lx", p->szPolicy, hr);
|
2013-01-24 21:30:11 +00:00
|
|
|
goto error;
|
|
|
|
} else {
|
2014-11-01 22:08:20 +00:00
|
|
|
if ((!p->bRestore) || (*(p->bExistingKey))) {
|
2017-04-27 22:06:42 +00:00
|
|
|
ubprintf("SetLGP: Successfully %s %s policy to 0x%08lX", (p->bRestore)?"restored":"set", p->szPolicy, val);
|
2013-01-24 21:30:11 +00:00
|
|
|
} else {
|
2017-04-25 19:25:50 +00:00
|
|
|
ubprintf("SetLGP: Successfully removed %s policy key", p->szPolicy);
|
2013-01-24 21:30:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RegCloseKey(path_key);
|
|
|
|
pLGPO->lpVtbl->Release(pLGPO);
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
error:
|
2017-04-25 13:32:19 +00:00
|
|
|
if (path_key != NULL)
|
|
|
|
RegCloseKey(path_key);
|
|
|
|
if (pLGPO != NULL)
|
|
|
|
pLGPO->lpVtbl->Release(pLGPO);
|
2021-04-09 11:36:30 +00:00
|
|
|
CoUninitialize();
|
2013-01-24 21:30:11 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2014-11-01 22:08:20 +00:00
|
|
|
|
|
|
|
BOOL SetLGP(BOOL bRestore, BOOL* bExistingKey, const char* szPath, const char* szPolicy, DWORD dwValue)
|
|
|
|
{
|
|
|
|
SetLGP_Params params = {bRestore, bExistingKey, szPath, szPolicy, dwValue};
|
|
|
|
DWORD r = FALSE;
|
2015-02-11 23:22:18 +00:00
|
|
|
HANDLE thread_id;
|
|
|
|
|
|
|
|
if (ReadSettingBool(SETTING_DISABLE_LGP)) {
|
2017-04-25 19:25:50 +00:00
|
|
|
ubprintf("LPG handling disabled, per settings");
|
2015-02-11 23:22:18 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
thread_id = CreateThread(NULL, 0, SetLGPThread, (LPVOID)¶ms, 0, NULL);
|
2014-11-01 22:08:20 +00:00
|
|
|
if (thread_id == NULL) {
|
2017-04-25 19:25:50 +00:00
|
|
|
ubprintf("SetLGP: Unable to start thread");
|
2014-11-01 22:08:20 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2017-04-25 13:32:19 +00:00
|
|
|
if (WaitForSingleObject(thread_id, 5000) != WAIT_OBJECT_0) {
|
2017-04-25 19:25:50 +00:00
|
|
|
ubprintf("SetLGP: Killing stuck thread!");
|
2014-11-01 22:08:20 +00:00
|
|
|
TerminateThread(thread_id, 0);
|
|
|
|
CloseHandle(thread_id);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2015-01-23 02:26:41 +00:00
|
|
|
if (!GetExitCodeThread(thread_id, &r))
|
|
|
|
return FALSE;
|
2014-11-01 22:08:20 +00:00
|
|
|
return (BOOL) r;
|
|
|
|
}
|
2016-03-03 17:24:54 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This call tries to evenly balance the affinities for an array of
|
|
|
|
* num_threads, according to the number of cores at our disposal...
|
|
|
|
*/
|
|
|
|
BOOL SetThreadAffinity(DWORD_PTR* thread_affinity, size_t num_threads)
|
|
|
|
{
|
2016-03-04 16:34:50 +00:00
|
|
|
size_t i, j, pc;
|
2016-03-03 17:24:54 +00:00
|
|
|
DWORD_PTR affinity, dummy;
|
|
|
|
|
|
|
|
memset(thread_affinity, 0, num_threads * sizeof(DWORD_PTR));
|
|
|
|
if (!GetProcessAffinityMask(GetCurrentProcess(), &affinity, &dummy))
|
|
|
|
return FALSE;
|
|
|
|
uuprintf("\r\nThread affinities:");
|
|
|
|
uuprintf(" avail:\t%s", printbitslz(affinity));
|
|
|
|
|
|
|
|
// If we don't have enough virtual cores to evenly spread our load forget it
|
|
|
|
pc = popcnt64(affinity);
|
|
|
|
if (pc < num_threads)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
// Spread the affinity as evenly as we can
|
|
|
|
thread_affinity[num_threads - 1] = affinity;
|
|
|
|
for (i = 0; i < num_threads - 1; i++) {
|
|
|
|
for (j = 0; j < pc / num_threads; j++) {
|
|
|
|
thread_affinity[i] |= affinity & (-1LL * affinity);
|
|
|
|
affinity ^= affinity & (-1LL * affinity);
|
|
|
|
}
|
|
|
|
uuprintf(" thr_%d:\t%s", i, printbitslz(thread_affinity[i]));
|
|
|
|
thread_affinity[num_threads - 1] ^= thread_affinity[i];
|
|
|
|
}
|
|
|
|
uuprintf(" thr_%d:\t%s", i, printbitslz(thread_affinity[i]));
|
|
|
|
return TRUE;
|
|
|
|
}
|
2016-07-09 15:20:58 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns true if:
|
|
|
|
* 1. The OS supports UAC, UAC is on, and the current process runs elevated, or
|
|
|
|
* 2. The OS doesn't support UAC or UAC is off, and the process is being run by a member of the admin group
|
|
|
|
*/
|
|
|
|
BOOL IsCurrentProcessElevated(void)
|
|
|
|
{
|
|
|
|
BOOL r = FALSE;
|
|
|
|
DWORD size;
|
|
|
|
HANDLE token = INVALID_HANDLE_VALUE;
|
|
|
|
TOKEN_ELEVATION te;
|
|
|
|
SID_IDENTIFIER_AUTHORITY auth = { SECURITY_NT_AUTHORITY };
|
|
|
|
PSID psid;
|
|
|
|
|
|
|
|
if (ReadRegistryKey32(REGKEY_HKLM, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\EnableLUA") == 1) {
|
|
|
|
uprintf("Note: UAC is active");
|
|
|
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
|
|
|
|
uprintf("Could not get current process token: %s", WindowsErrorString());
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (!GetTokenInformation(token, TokenElevation, &te, sizeof(te), &size)) {
|
|
|
|
uprintf("Could not get token information: %s", WindowsErrorString());
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
r = (te.TokenIsElevated != 0);
|
2017-04-25 13:32:19 +00:00
|
|
|
} else {
|
2016-07-09 15:20:58 +00:00
|
|
|
uprintf("Note: UAC is either disabled or not available");
|
|
|
|
if (!AllocateAndInitializeSid(&auth, 2, SECURITY_BUILTIN_DOMAIN_RID,
|
|
|
|
DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psid))
|
|
|
|
goto out;
|
|
|
|
if (!CheckTokenMembership(NULL, psid, &r))
|
|
|
|
r = FALSE;
|
|
|
|
FreeSid(psid);
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
safe_closehandle(token);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* GetCurrentMUI(void)
|
|
|
|
{
|
|
|
|
static char mui_str[LOCALE_NAME_MAX_LENGTH];
|
|
|
|
wchar_t wmui_str[LOCALE_NAME_MAX_LENGTH];
|
|
|
|
|
2017-11-13 14:29:48 +00:00
|
|
|
if (LCIDToLocaleName(GetUserDefaultUILanguage(), wmui_str, LOCALE_NAME_MAX_LENGTH, 0) > 0) {
|
2016-07-09 15:20:58 +00:00
|
|
|
wchar_to_utf8_no_alloc(wmui_str, mui_str, LOCALE_NAME_MAX_LENGTH);
|
|
|
|
} else {
|
2017-08-10 18:43:04 +00:00
|
|
|
static_strcpy(mui_str, "en-US");
|
2016-07-09 15:20:58 +00:00
|
|
|
}
|
|
|
|
return mui_str;
|
|
|
|
}
|