// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include // For ConvertSidToStringSidW. #include #include #include #include "mozilla/ArrayUtils.h" #include "rlz/lib/assert.h" namespace rlz_lib { namespace { bool GetSystemVolumeSerialNumber(int* number) { if (!number) return false; *number = 0; // Find the system root path (e.g: C:\). wchar_t system_path[MAX_PATH + 1]; if (!GetSystemDirectoryW(system_path, MAX_PATH)) return false; wchar_t* first_slash = wcspbrk(system_path, L"\\/"); if (first_slash != NULL) *(first_slash + 1) = 0; DWORD number_local = 0; if (!GetVolumeInformationW(system_path, NULL, 0, &number_local, NULL, NULL, NULL, 0)) return false; *number = (int)number_local; return true; } bool GetComputerSid(const wchar_t* account_name, SID* sid, DWORD sid_size) { static const DWORD kStartDomainLength = 128; // reasonable to start with std::unique_ptr domain_buffer(new wchar_t[kStartDomainLength]); DWORD domain_size = kStartDomainLength; DWORD sid_dword_size = sid_size; SID_NAME_USE sid_name_use; BOOL success = ::LookupAccountNameW(NULL, account_name, sid, &sid_dword_size, domain_buffer.get(), &domain_size, &sid_name_use); if (!success && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { // We could have gotten the insufficient buffer error because // one or both of sid and szDomain was too small. Check for that // here. if (sid_dword_size > sid_size) return false; if (domain_size > kStartDomainLength) domain_buffer.reset(new wchar_t[domain_size]); success = ::LookupAccountNameW(NULL, account_name, sid, &sid_dword_size, domain_buffer.get(), &domain_size, &sid_name_use); } return success != FALSE; } std::vector ConvertSidToBytes(SID* sid) { std::wstring sid_string; #if _WIN32_WINNT >= 0x500 wchar_t* sid_buffer = NULL; if (ConvertSidToStringSidW(sid, &sid_buffer)) { sid_string = sid_buffer; LocalFree(sid_buffer); } #else SID_IDENTIFIER_AUTHORITY* sia = ::GetSidIdentifierAuthority(sid); if(sia->Value[0] || sia->Value[1]) { base::SStringPrintf( &sid_string, L"S-%d-0x%02hx%02hx%02hx%02hx%02hx%02hx", SID_REVISION, (USHORT)sia->Value[0], (USHORT)sia->Value[1], (USHORT)sia->Value[2], (USHORT)sia->Value[3], (USHORT)sia->Value[4], (USHORT)sia->Value[5]); } else { ULONG authority = 0; for (int i = 2; i < 6; ++i) { authority <<= 8; authority |= sia->Value[i]; } base::SStringPrintf(&sid_string, L"S-%d-%lu", SID_REVISION, authority); } int sub_auth_count = *::GetSidSubAuthorityCount(sid); for(int i = 0; i < sub_auth_count; ++i) base::StringAppendF(&sid_string, L"-%lu", *::GetSidSubAuthority(sid, i)); #endif // Get the contents of the string as a bunch of bytes. return std::vector( reinterpret_cast(&sid_string[0]), reinterpret_cast(&sid_string[sid_string.size()])); } } // namespace bool GetRawMachineId(std::vector* sid_bytes, int* volume_id) { // Calculate the Windows SID. wchar_t computer_name[MAX_COMPUTERNAME_LENGTH + 1] = {0}; DWORD size = mozilla::ArrayLength(computer_name); if (GetComputerNameW(computer_name, &size)) { char sid_buffer[SECURITY_MAX_SID_SIZE]; SID* sid = reinterpret_cast(sid_buffer); if (GetComputerSid(computer_name, sid, SECURITY_MAX_SID_SIZE)) { *sid_bytes = ConvertSidToBytes(sid); } } // Get the system drive volume serial number. *volume_id = 0; if (!GetSystemVolumeSerialNumber(volume_id)) { ASSERT_STRING("GetMachineId: Failed to retrieve volume serial number"); *volume_id = 0; } return true; } } // namespace rlz_lib