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