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