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