I could have used CryptStringToBinaryA for the hex->bin conversion, but that would add another import to wineboot.
This patch was created by me on request from Alexandr Oleynikov of the Lutris project back in September of 2020.
From: Torge Matthies tmatthies@codeweavers.com
Uses a hash of the systemd or dbus machine-id to generate a stable product id. If neither file is found (e.g. on macOS), it will use all zeroes for the hash input.
Signed-off-by: Torge Matthies tmatthies@codeweavers.com --- loader/wine.inf.in | 2 - programs/wineboot/wineboot.c | 146 +++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 2 deletions(-)
diff --git a/loader/wine.inf.in b/loader/wine.inf.in index e7b435ed0f0..14a58c9f380 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -343,7 +343,6 @@ HKCU,%CurrentVersion%\Run,,16 HKCU,%CurrentVersionNT%\Winlogon,,16 HKLM,%CurrentVersion%,"CommonFilesDir",,"%16427%" HKLM,%CurrentVersion%,"FirstInstallDateTime",1,21,81,7c,23 -HKLM,%CurrentVersion%,"ProductId",,"12345-oem-0000001-54321" HKLM,%CurrentVersion%,"ProgramFilesDir",,"%16422%" HKLM,%CurrentVersion%,"ProgramFilesPath",0x20000,"%%ProgramFiles%%" HKLM,%CurrentVersion%,"RegisteredOrganization",2,"" @@ -368,7 +367,6 @@ HKLM,%CurrentVersion%\Shell Extensions\Approved,,16 HKLM,%CurrentVersion%\Time Zones,"SymbolicLinkValue",0x60000,"\Registry\Machine%CurrentVersionNT%\Time Zones" HKLM,%CurrentVersion%\Uninstall,,16 HKLM,%CurrentVersionNT%,"InstallDate",0x10003,1273299354 -HKLM,%CurrentVersionNT%,"ProductId",,"12345-oem-0000001-54321" HKLM,%CurrentVersionNT%,"RegisteredOrganization",2,"" HKLM,%CurrentVersionNT%,"RegisteredOwner",2,"" HKLM,%CurrentVersionNT%,"SystemRoot",,"%10%" diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c index 4de20705224..0f860dcf86d 100644 --- a/programs/wineboot/wineboot.c +++ b/programs/wineboot/wineboot.c @@ -71,6 +71,7 @@ #include <wine/svcctl.h> #include <wine/asm.h> #include <wine/debug.h> +#include <bcrypt.h>
#include <shlobj.h> #include <shobjidl.h> @@ -748,6 +749,150 @@ static void create_hardware_registry_keys(void) HeapFree( GetProcessHeap(), 0, power_info ); }
+static unsigned char decode_hex( char c ) +{ + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + else if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + return 0xFF; +} + +static void get_machineid( BYTE *buf ) +{ + static const char sd_machineid_path[] = "\??\unix\/etc/machine-id"; + static const char dbus_machineid_path[] = "\??\unix\/var/lib/dbus/machine-id"; + HANDLE file; + char buffer[34]; + BOOL status; + DWORD bytes_read; + int i; + + memset( buf, 0, 16 ); + + file = CreateFileA( sd_machineid_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL ); + if (file == INVALID_HANDLE_VALUE) + file = CreateFileA( dbus_machineid_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL ); + if (file == INVALID_HANDLE_VALUE) + { + WARN( "Could not open machine id file: error %lu\n", GetLastError() ); + return; + } + status = ReadFile( file, buffer, sizeof(buffer), &bytes_read, NULL ); + CloseHandle( file ); + if (!status) + { + WARN( "Could not read machine id file: error %lu\n", GetLastError() ); + return; + } + if (!(bytes_read == 32 || (bytes_read == 33 && buffer[32] == '\n'))) + { + WARN( "Wrong machine id file size\n" ); + return; + } + + for (i = 0; i < 16; i++) + { + unsigned char high_nibble, low_nibble; + high_nibble = decode_hex( buffer[i * 2] ); + low_nibble = decode_hex( buffer[i * 2 + 1] ); + if (high_nibble == 0xFF || low_nibble == 0xFF) + { + WARN( "Failed to decode machine id byte %d\n", i ); + memset( buf, 0, i ); + return; + } + buf[i] = (high_nibble << 4) | low_nibble; + } +} + +#define MACHINEID_HASH_ALG BCRYPT_SHA1_ALGORITHM +#define MACHINEID_HASH_ALG_SIZE 20 + +static void get_machineid_hash( BYTE *buf ) +{ + static const char salt[8] = "WINESALT"; + BYTE input[16 + sizeof(salt)]; + BCRYPT_ALG_HANDLE alg; + NTSTATUS status; + BYTE hash[MACHINEID_HASH_ALG_SIZE]; + int i; + + memset( buf, 0, 8 ); + + get_machineid( input ); + memcpy( &input[sizeof(input) - sizeof(salt)], salt, sizeof(salt) ); + + status = BCryptOpenAlgorithmProvider( &alg, MACHINEID_HASH_ALG, NULL, 0 ); + if (!status) + { + status = BCryptHash( alg, NULL, 0, input, sizeof(input), hash, sizeof(hash) ); + BCryptCloseAlgorithmProvider( alg, 0 ); + } + if (status) + { + WARN( "Couldn't hash machine id: error %lx\n", status ); + return; + } + + for (i = 8; i < ARRAY_SIZE(hash); i++) + hash[i % 8] ^= hash[i]; + memcpy( buf, hash, 8 ); + return; +} + +static void get_productid( WCHAR *buf ) +{ + BYTE machineid[8]; + DWORD mid_lodword, mid_hidword; + unsigned int c, e; + unsigned int tmp, check_digit; + + get_machineid_hash( machineid ); + mid_lodword = (machineid[3] << 24U) | (machineid[2] << 16U) | (machineid[1] << 8U) | machineid[0]; + mid_hidword = (machineid[7] << 24U) | (machineid[6] << 16U) | (machineid[5] << 8U) | machineid[4]; + c = (unsigned int)(mid_lodword * 999999ULL / 0xFFFFFFFF); + e = (unsigned int)(mid_hidword * 999ULL / 0xFFFFFFFF); + + tmp = c; + check_digit = tmp % 10; + tmp = tmp / 10; + check_digit += tmp % 10; + tmp = tmp / 10; + check_digit += tmp % 10; + tmp = tmp / 10; + check_digit += tmp % 10; + tmp = tmp / 10; + check_digit += tmp % 10; + tmp = tmp / 10; + check_digit += tmp; + check_digit = 7 - check_digit % 7; + + swprintf( buf, 24, L"55034-OEM-%06u%u-00%03u", c, check_digit, e ); +} + +/* create the volatile software registry keys */ +static void create_software_registry_keys(void) +{ + WCHAR productid[24]; + HKEY key; + + get_productid( productid ); + + if (!RegCreateKeyW( HKEY_LOCAL_MACHINE, L"Software\Microsoft\Windows NT\CurrentVersion", &key )) + { + set_reg_value( key, L"ProductId", productid ); + RegCloseKey( key ); + } + + if (!RegCreateKeyW( HKEY_LOCAL_MACHINE, L"Software\Microsoft\Windows\CurrentVersion", &key )) + { + set_reg_value( key, L"ProductId", productid ); + RegCloseKey( key ); + } +}
/* create the DynData registry keys */ static void create_dynamic_registry_keys(void) @@ -1697,6 +1842,7 @@ int __cdecl main( int argc, char *argv[] )
create_user_shared_data(); create_hardware_registry_keys(); + create_software_registry_keys(); create_dynamic_registry_keys(); create_environment_registry_keys(); create_computer_name_keys();
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=121821
Your paranoid android.
=== debian11 (build log) ===
/home/winetest/tools/testbot/var/wine-win32/../wine/programs/wineboot/wineboot.c:828: undefined reference to `BCryptOpenAlgorithmProvider@16' /usr/bin/i686-w64-mingw32-ld: /home/winetest/tools/testbot/var/wine-win32/../wine/programs/wineboot/wineboot.c:831: undefined reference to `BCryptHash@28' /usr/bin/i686-w64-mingw32-ld: /home/winetest/tools/testbot/var/wine-win32/../wine/programs/wineboot/wineboot.c:832: undefined reference to `BCryptCloseAlgorithmProvider@8' collect2: error: ld returned 1 exit status Task: The win32 Wine build failed
=== debian11 (build log) ===
/home/winetest/tools/testbot/var/wine-wow64/../wine/programs/wineboot/wineboot.c:828: undefined reference to `BCryptOpenAlgorithmProvider' /usr/bin/x86_64-w64-mingw32-ld: /home/winetest/tools/testbot/var/wine-wow64/../wine/programs/wineboot/wineboot.c:831: undefined reference to `BCryptHash' /usr/bin/x86_64-w64-mingw32-ld: /home/winetest/tools/testbot/var/wine-wow64/../wine/programs/wineboot/wineboot.c:832: undefined reference to `BCryptCloseAlgorithmProvider' collect2: error: ld returned 1 exit status Task: The wow64 Wine build failed