machine_id_win.cc (4095B)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <windows.h> 6 #include <sddl.h> // For ConvertSidToStringSidW. 7 8 #include <memory> 9 #include <string> 10 #include <vector> 11 12 #include "mozilla/ArrayUtils.h" 13 14 #include "rlz/lib/assert.h" 15 16 namespace rlz_lib { 17 18 namespace { 19 20 bool GetSystemVolumeSerialNumber(int* number) { 21 if (!number) 22 return false; 23 24 *number = 0; 25 26 // Find the system root path (e.g: C:\). 27 wchar_t system_path[MAX_PATH + 1]; 28 if (!GetSystemDirectoryW(system_path, MAX_PATH)) 29 return false; 30 31 wchar_t* first_slash = wcspbrk(system_path, L"\\/"); 32 if (first_slash != NULL) 33 *(first_slash + 1) = 0; 34 35 DWORD number_local = 0; 36 if (!GetVolumeInformationW(system_path, NULL, 0, &number_local, NULL, NULL, 37 NULL, 0)) 38 return false; 39 40 *number = (int)number_local; 41 return true; 42 } 43 44 bool GetComputerSid(const wchar_t* account_name, SID* sid, DWORD sid_size) { 45 static const DWORD kStartDomainLength = 128; // reasonable to start with 46 47 std::unique_ptr<wchar_t[]> domain_buffer(new wchar_t[kStartDomainLength]); 48 DWORD domain_size = kStartDomainLength; 49 DWORD sid_dword_size = sid_size; 50 SID_NAME_USE sid_name_use; 51 52 BOOL success = ::LookupAccountNameW(NULL, account_name, sid, 53 &sid_dword_size, domain_buffer.get(), 54 &domain_size, &sid_name_use); 55 if (!success && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { 56 // We could have gotten the insufficient buffer error because 57 // one or both of sid and szDomain was too small. Check for that 58 // here. 59 if (sid_dword_size > sid_size) 60 return false; 61 62 if (domain_size > kStartDomainLength) 63 domain_buffer.reset(new wchar_t[domain_size]); 64 65 success = ::LookupAccountNameW(NULL, account_name, sid, &sid_dword_size, 66 domain_buffer.get(), &domain_size, 67 &sid_name_use); 68 } 69 70 return success != FALSE; 71 } 72 73 std::vector<uint8_t> ConvertSidToBytes(SID* sid) { 74 std::wstring sid_string; 75 #if _WIN32_WINNT >= 0x500 76 wchar_t* sid_buffer = NULL; 77 if (ConvertSidToStringSidW(sid, &sid_buffer)) { 78 sid_string = sid_buffer; 79 LocalFree(sid_buffer); 80 } 81 #else 82 SID_IDENTIFIER_AUTHORITY* sia = ::GetSidIdentifierAuthority(sid); 83 84 if(sia->Value[0] || sia->Value[1]) { 85 base::SStringPrintf( 86 &sid_string, L"S-%d-0x%02hx%02hx%02hx%02hx%02hx%02hx", 87 SID_REVISION, (USHORT)sia->Value[0], (USHORT)sia->Value[1], 88 (USHORT)sia->Value[2], (USHORT)sia->Value[3], (USHORT)sia->Value[4], 89 (USHORT)sia->Value[5]); 90 } else { 91 ULONG authority = 0; 92 for (int i = 2; i < 6; ++i) { 93 authority <<= 8; 94 authority |= sia->Value[i]; 95 } 96 base::SStringPrintf(&sid_string, L"S-%d-%lu", SID_REVISION, authority); 97 } 98 99 int sub_auth_count = *::GetSidSubAuthorityCount(sid); 100 for(int i = 0; i < sub_auth_count; ++i) 101 base::StringAppendF(&sid_string, L"-%lu", *::GetSidSubAuthority(sid, i)); 102 #endif 103 104 // Get the contents of the string as a bunch of bytes. 105 return std::vector<uint8_t>( 106 reinterpret_cast<uint8_t*>(&sid_string[0]), 107 reinterpret_cast<uint8_t*>(&sid_string[sid_string.size()])); 108 } 109 110 } // namespace 111 112 bool GetRawMachineId(std::vector<uint8_t>* sid_bytes, int* volume_id) { 113 // Calculate the Windows SID. 114 115 wchar_t computer_name[MAX_COMPUTERNAME_LENGTH + 1] = {0}; 116 DWORD size = std::size(computer_name); 117 118 if (GetComputerNameW(computer_name, &size)) { 119 char sid_buffer[SECURITY_MAX_SID_SIZE]; 120 SID* sid = reinterpret_cast<SID*>(sid_buffer); 121 if (GetComputerSid(computer_name, sid, SECURITY_MAX_SID_SIZE)) { 122 *sid_bytes = ConvertSidToBytes(sid); 123 } 124 } 125 126 // Get the system drive volume serial number. 127 *volume_id = 0; 128 if (!GetSystemVolumeSerialNumber(volume_id)) { 129 ASSERT_STRING("GetMachineId: Failed to retrieve volume serial number"); 130 *volume_id = 0; 131 } 132 133 return true; 134 } 135 136 } // namespace rlz_lib