// Copyright 2014 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 "components/metrics/machine_id_provider.h" #include #include #include "base/base_paths.h" #include "base/files/file_path.h" #include "base/path_service.h" #include "base/threading/thread_restrictions.h" #include "base/win/scoped_handle.h" namespace metrics { MachineIdProvider::MachineIdProvider() { } MachineIdProvider::~MachineIdProvider() { } // On windows, the machine id is based on the serial number of the drive Chrome // is running from. std::string MachineIdProvider::GetMachineId() { base::ThreadRestrictions::AssertIOAllowed(); // Use the program's path to get the drive used for the machine id. This means // that whenever the underlying drive changes, it's considered a new machine. // This is fine as we do not support migrating Chrome installs to new drives. base::FilePath executable_path; if (!PathService::Get(base::FILE_EXE, &executable_path)) { NOTREACHED(); return std::string(); } std::vector path_components; executable_path.GetComponents(&path_components); if (path_components.empty()) { NOTREACHED(); return std::string(); } base::FilePath::StringType drive_name = L"\\\\.\\" + path_components[0]; base::win::ScopedHandle drive_handle( CreateFile(drive_name.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL)); STORAGE_PROPERTY_QUERY query = {}; query.PropertyId = StorageDeviceProperty; query.QueryType = PropertyStandardQuery; // Perform an initial query to get the number of bytes being returned. DWORD bytes_returned; STORAGE_DESCRIPTOR_HEADER header = {}; BOOL status = DeviceIoControl(drive_handle.Get(), IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(STORAGE_PROPERTY_QUERY), &header, sizeof(STORAGE_DESCRIPTOR_HEADER), &bytes_returned, NULL); if (!status) return std::string(); // Query for the actual serial number. std::vector output_buf(header.Size); status = DeviceIoControl(drive_handle.Get(), IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(STORAGE_PROPERTY_QUERY), &output_buf[0], output_buf.size(), &bytes_returned, NULL); if (!status) return std::string(); const STORAGE_DEVICE_DESCRIPTOR* device_descriptor = reinterpret_cast(&output_buf[0]); // The serial number is stored in the |output_buf| as a null-terminated // string starting at the specified offset. const DWORD offset = device_descriptor->SerialNumberOffset; if (offset >= output_buf.size()) return std::string(); // Make sure that the null-terminator exists. const std::vector::iterator serial_number_begin = output_buf.begin() + offset; const std::vector::iterator null_location = std::find(serial_number_begin, output_buf.end(), '\0'); if (null_location == output_buf.end()) return std::string(); const char* serial_number = reinterpret_cast(&output_buf[offset]); return std::string(serial_number); } // static MachineIdProvider* MachineIdProvider::CreateInstance() { return new MachineIdProvider(); } } // namespace metrics