1 // Copyright 2014 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 "components/metrics/machine_id_provider.h" 6 7 #include <windows.h> 8 #include <winioctl.h> 9 10 #include "base/base_paths.h" 11 #include "base/files/file_path.h" 12 #include "base/path_service.h" 13 #include "base/threading/thread_restrictions.h" 14 #include "base/win/scoped_handle.h" 15 16 namespace metrics { 17 18 MachineIdProvider::MachineIdProvider() { 19 } 20 21 MachineIdProvider::~MachineIdProvider() { 22 } 23 24 // On windows, the machine id is based on the serial number of the drive Chrome 25 // is running from. 26 std::string MachineIdProvider::GetMachineId() { 27 base::ThreadRestrictions::AssertIOAllowed(); 28 29 // Use the program's path to get the drive used for the machine id. This means 30 // that whenever the underlying drive changes, it's considered a new machine. 31 // This is fine as we do not support migrating Chrome installs to new drives. 32 base::FilePath executable_path; 33 34 if (!PathService::Get(base::FILE_EXE, &executable_path)) { 35 NOTREACHED(); 36 return std::string(); 37 } 38 39 std::vector<base::FilePath::StringType> path_components; 40 executable_path.GetComponents(&path_components); 41 if (path_components.empty()) { 42 NOTREACHED(); 43 return std::string(); 44 } 45 base::FilePath::StringType drive_name = L"\\\\.\\" + path_components[0]; 46 47 base::win::ScopedHandle drive_handle( 48 CreateFile(drive_name.c_str(), 49 0, 50 FILE_SHARE_READ | FILE_SHARE_WRITE, 51 NULL, 52 OPEN_EXISTING, 53 0, 54 NULL)); 55 56 STORAGE_PROPERTY_QUERY query = {}; 57 query.PropertyId = StorageDeviceProperty; 58 query.QueryType = PropertyStandardQuery; 59 60 // Perform an initial query to get the number of bytes being returned. 61 DWORD bytes_returned; 62 STORAGE_DESCRIPTOR_HEADER header = {}; 63 BOOL status = DeviceIoControl(drive_handle, 64 IOCTL_STORAGE_QUERY_PROPERTY, 65 &query, 66 sizeof(STORAGE_PROPERTY_QUERY), 67 &header, 68 sizeof(STORAGE_DESCRIPTOR_HEADER), 69 &bytes_returned, 70 NULL); 71 72 if (!status) 73 return std::string(); 74 75 // Query for the actual serial number. 76 std::vector<int8> output_buf(header.Size); 77 status = DeviceIoControl(drive_handle, 78 IOCTL_STORAGE_QUERY_PROPERTY, 79 &query, 80 sizeof(STORAGE_PROPERTY_QUERY), 81 &output_buf[0], 82 output_buf.size(), 83 &bytes_returned, 84 NULL); 85 86 if (!status) 87 return std::string(); 88 89 const STORAGE_DEVICE_DESCRIPTOR* device_descriptor = 90 reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR*>(&output_buf[0]); 91 92 // The serial number is stored in the |output_buf| as a null-terminated 93 // string starting at the specified offset. 94 const DWORD offset = device_descriptor->SerialNumberOffset; 95 if (offset >= output_buf.size()) 96 return std::string(); 97 98 // Make sure that the null-terminator exists. 99 const std::vector<int8>::iterator serial_number_begin = 100 output_buf.begin() + offset; 101 const std::vector<int8>::iterator null_location = 102 std::find(serial_number_begin, output_buf.end(), '\0'); 103 if (null_location == output_buf.end()) 104 return std::string(); 105 106 const char* serial_number = 107 reinterpret_cast<const char*>(&output_buf[offset]); 108 109 return std::string(serial_number); 110 } 111 112 // static 113 MachineIdProvider* MachineIdProvider::CreateInstance() { 114 return new MachineIdProvider(); 115 } 116 117 } // namespace metrics 118