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 "chrome/browser/prefs/tracked/pref_hash_calculator_helper.h" 6 7 // Implementation fully duplicated from 8 // chrome/browser/extensions/api/music_manager_private/device_id_win.cc (see 9 // pref_hash_calculator_helper_win.h for motivation). 10 11 // Note: The order of header includes is important, as we want both pre-Vista 12 // and post-Vista data structures to be defined, specifically 13 // PIP_ADAPTER_ADDRESSES and PMIB_IF_ROW2. 14 #include <winsock2.h> 15 #include <ws2def.h> 16 #include <ws2ipdef.h> 17 #include <iphlpapi.h> 18 19 #include "base/files/file_path.h" 20 #include "base/logging.h" 21 #include "base/macros.h" 22 #include "base/scoped_native_library.h" 23 #include "base/strings/string_number_conversions.h" 24 #include "base/strings/string_util.h" 25 #include "base/threading/thread_restrictions.h" 26 #include "net/base/net_util.h" 27 28 namespace { 29 30 bool IsValidMacAddress(const void* bytes, size_t size) { 31 const size_t MAC_LENGTH = 6; 32 const size_t OUI_LENGTH = 3; 33 struct InvalidMacEntry { 34 size_t size; 35 unsigned char address[MAC_LENGTH]; 36 }; 37 38 // VPN, virtualization, tethering, bluetooth, etc. 39 static const InvalidMacEntry kInvalidAddresses[] = { 40 // Empty address 41 {MAC_LENGTH, {0, 0, 0, 0, 0, 0}}, 42 // VMware 43 {OUI_LENGTH, {0x00, 0x50, 0x56}}, 44 {OUI_LENGTH, {0x00, 0x05, 0x69}}, 45 {OUI_LENGTH, {0x00, 0x0c, 0x29}}, 46 {OUI_LENGTH, {0x00, 0x1c, 0x14}}, 47 // VirtualBox 48 {OUI_LENGTH, {0x08, 0x00, 0x27}}, 49 // PdaNet 50 {MAC_LENGTH, {0x00, 0x26, 0x37, 0xbd, 0x39, 0x42}}, 51 // Cisco AnyConnect VPN 52 {MAC_LENGTH, {0x00, 0x05, 0x9a, 0x3c, 0x7a, 0x00}}, 53 // Marvell sometimes uses this as a dummy address 54 {MAC_LENGTH, {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}}, 55 // Apple uses this across machines for Bluetooth ethernet adapters. 56 {MAC_LENGTH-1, {0x65, 0x90, 0x07, 0x42, 0xf1}}, 57 // Juniper uses this for their Virtual Adapter, the other 4 bytes are 58 // reassigned at every boot. 00-ff-xx is not assigned to anyone. 59 {2, {0x00, 0xff}}, 60 // T-Mobile Wireless Ethernet 61 {MAC_LENGTH, {0x00, 0xa0, 0xc6, 0x00, 0x00, 0x00}}, 62 // Generic Bluetooth device 63 {MAC_LENGTH, {0x00, 0x15, 0x83, 0x3d, 0x0a, 0x57}}, 64 // RAS Async Adapter 65 {MAC_LENGTH, {0x20, 0x41, 0x53, 0x59, 0x4e, 0xff}}, 66 // Qualcomm USB ethernet adapter 67 {MAC_LENGTH, {0x00, 0xa0, 0xc6, 0x00, 0x00, 0x00}}, 68 // Windows VPN 69 {MAC_LENGTH, {0x00, 0x53, 0x45, 0x00, 0x00, 0x00}}, 70 // Bluetooth 71 {MAC_LENGTH, {0x00, 0x1f, 0x81, 0x00, 0x08, 0x30}}, 72 {MAC_LENGTH, {0x00, 0x1b, 0x10, 0x00, 0x2a, 0xec}}, 73 {MAC_LENGTH, {0x00, 0x15, 0x83, 0x15, 0xa3, 0x10}}, 74 {MAC_LENGTH, {0x00, 0x15, 0x83, 0x07, 0xC6, 0x5A}}, 75 {MAC_LENGTH, {0x00, 0x1f, 0x81, 0x00, 0x02, 0x00}}, 76 {MAC_LENGTH, {0x00, 0x1f, 0x81, 0x00, 0x02, 0xdd}}, 77 // Ceton TV tuner 78 {MAC_LENGTH, {0x00, 0x22, 0x2c, 0xff, 0xff, 0xff}}, 79 // Check Point VPN 80 {MAC_LENGTH, {0x54, 0x55, 0x43, 0x44, 0x52, 0x09}}, 81 {MAC_LENGTH, {0x54, 0xEF, 0x14, 0x71, 0xE4, 0x0E}}, 82 {MAC_LENGTH, {0x54, 0xBA, 0xC6, 0xFF, 0x74, 0x10}}, 83 // Cisco VPN 84 {MAC_LENGTH, {0x00, 0x05, 0x9a, 0x3c, 0x7a, 0x00}}, 85 // Cisco VPN 86 {MAC_LENGTH, {0x00, 0x05, 0x9a, 0x3c, 0x78, 0x00}}, 87 // Intel USB cell modem 88 {MAC_LENGTH, {0x00, 0x1e, 0x10, 0x1f, 0x00, 0x01}}, 89 // Microsoft tethering 90 {MAC_LENGTH, {0x80, 0x00, 0x60, 0x0f, 0xe8, 0x00}}, 91 // Nortel VPN 92 {MAC_LENGTH, {0x44, 0x45, 0x53, 0x54, 0x42, 0x00}}, 93 // AEP VPN 94 {MAC_LENGTH, {0x00, 0x30, 0x70, 0x00, 0x00, 0x01}}, 95 // Positive VPN 96 {MAC_LENGTH, {0x00, 0x02, 0x03, 0x04, 0x05, 0x06}}, 97 // Bluetooth 98 {MAC_LENGTH, {0x00, 0x15, 0x83, 0x0B, 0x13, 0xC0}}, 99 // Kerio Virtual Network Adapter 100 {MAC_LENGTH, {0x44, 0x45, 0x53, 0x54, 0x4f, 0x53}}, 101 // Sierra Wireless cell modems. 102 {OUI_LENGTH, {0x00, 0xA0, 0xD5}}, 103 // FRITZ!web DSL 104 {MAC_LENGTH, {0x00, 0x04, 0x0E, 0xFF, 0xFF, 0xFF}}, 105 // VirtualPC 106 {MAC_LENGTH, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}, 107 // Bluetooth 108 {MAC_LENGTH, {0x00, 0x1F, 0x81, 0x00, 0x01, 0x00}}, 109 {MAC_LENGTH, {0x00, 0x30, 0x91, 0x10, 0x00, 0x26}}, 110 {MAC_LENGTH, {0x00, 0x25, 0x00, 0x5A, 0xC3, 0xD0}}, 111 {MAC_LENGTH, {0x00, 0x15, 0x83, 0x0C, 0xBF, 0xEB}}, 112 // Huawei cell modem 113 {MAC_LENGTH, {0x58, 0x2C, 0x80, 0x13, 0x92, 0x63}}, 114 // Fortinet VPN 115 {OUI_LENGTH, {0x00, 0x09, 0x0F}}, 116 // Realtek 117 {MAC_LENGTH, {0x00, 0x00, 0x00, 0x00, 0x00, 0x30}}, 118 // Other rare dupes. 119 {MAC_LENGTH, {0x00, 0x11, 0xf5, 0x0d, 0x8a, 0xe8}}, // Atheros 120 {MAC_LENGTH, {0x00, 0x20, 0x07, 0x01, 0x16, 0x06}}, // Atheros 121 {MAC_LENGTH, {0x0d, 0x0b, 0x00, 0x00, 0xe0, 0x00}}, // Atheros 122 {MAC_LENGTH, {0x90, 0x4c, 0xe5, 0x0b, 0xc8, 0x8e}}, // Atheros 123 {MAC_LENGTH, {0x00, 0x1c, 0x23, 0x38, 0x49, 0xa4}}, // Broadcom 124 {MAC_LENGTH, {0x00, 0x12, 0x3f, 0x82, 0x7c, 0x32}}, // Broadcom 125 {MAC_LENGTH, {0x00, 0x11, 0x11, 0x32, 0xc3, 0x77}}, // Broadcom 126 {MAC_LENGTH, {0x00, 0x24, 0xd6, 0xae, 0x3e, 0x39}}, // Microsoft 127 {MAC_LENGTH, {0x00, 0x0f, 0xb0, 0x3a, 0xb4, 0x80}}, // Realtek 128 {MAC_LENGTH, {0x08, 0x10, 0x74, 0xa1, 0xda, 0x1b}}, // Realtek 129 {MAC_LENGTH, {0x00, 0x21, 0x9b, 0x2a, 0x0a, 0x9c}}, // Realtek 130 }; 131 132 if (size != MAC_LENGTH) { 133 return false; 134 } 135 136 if (static_cast<const unsigned char *>(bytes)[0] & 0x02) { 137 // Locally administered. 138 return false; 139 } 140 141 // Note: Use ARRAYSIZE_UNSAFE() instead of arraysize() because InvalidMacEntry 142 // is declared inside this function. 143 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kInvalidAddresses); ++i) { 144 size_t count = kInvalidAddresses[i].size; 145 if (memcmp(kInvalidAddresses[i].address, bytes, count) == 0) { 146 return false; 147 } 148 } 149 return true; 150 } 151 152 class MacAddressProcessor { 153 public: 154 MacAddressProcessor() : found_index_(ULONG_MAX) {} 155 156 // Iterate through the interfaces, looking for the valid MAC address with the 157 // lowest IfIndex. 158 void ProcessAdapterAddress(PIP_ADAPTER_ADDRESSES address) { 159 if (address->IfType == IF_TYPE_TUNNEL) 160 return; 161 162 ProcessPhysicalAddress(address->IfIndex, 163 address->PhysicalAddress, 164 address->PhysicalAddressLength); 165 } 166 167 void ProcessInterfaceRow(const PMIB_IF_ROW2 row) { 168 if (row->Type == IF_TYPE_TUNNEL || 169 !row->InterfaceAndOperStatusFlags.HardwareInterface) { 170 return; 171 } 172 173 ProcessPhysicalAddress(row->InterfaceIndex, 174 row->PhysicalAddress, 175 row->PhysicalAddressLength); 176 } 177 178 std::string mac_address() const { return found_mac_address_; } 179 180 private: 181 void ProcessPhysicalAddress(NET_IFINDEX index, 182 const void* bytes, 183 size_t size) { 184 if (index >= found_index_ || size == 0) 185 return; 186 187 if (!IsValidMacAddress(bytes, size)) 188 return; 189 190 found_mac_address_ = StringToLowerASCII(base::HexEncode(bytes, size)); 191 found_index_ = index; 192 } 193 194 std::string found_mac_address_; 195 NET_IFINDEX found_index_; 196 }; 197 198 std::string GetMacAddressFromGetAdaptersAddresses() { 199 base::ThreadRestrictions::AssertIOAllowed(); 200 201 // MS recommends a default size of 15k. 202 ULONG bufferSize = 15 * 1024; 203 // Disable as much as we can, since all we want is MAC addresses. 204 ULONG flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER | 205 GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_MULTICAST | 206 GAA_FLAG_SKIP_UNICAST; 207 std::vector<unsigned char> buffer(bufferSize); 208 PIP_ADAPTER_ADDRESSES adapterAddresses = 209 reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer.front()); 210 211 DWORD result = GetAdaptersAddresses(AF_UNSPEC, flags, 0, 212 adapterAddresses, &bufferSize); 213 if (result == ERROR_BUFFER_OVERFLOW) { 214 buffer.resize(bufferSize); 215 adapterAddresses = 216 reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer.front()); 217 result = GetAdaptersAddresses(AF_UNSPEC, flags, 0, 218 adapterAddresses, &bufferSize); 219 } 220 221 if (result != NO_ERROR) { 222 VLOG(ERROR) << "GetAdapatersAddresses failed with error " << result; 223 return ""; 224 } 225 226 MacAddressProcessor processor; 227 for (; adapterAddresses != NULL; adapterAddresses = adapterAddresses->Next) { 228 processor.ProcessAdapterAddress(adapterAddresses); 229 } 230 return processor.mac_address(); 231 } 232 233 std::string GetMacAddressFromGetIfTable2() { 234 base::ThreadRestrictions::AssertIOAllowed(); 235 236 // This is available on Vista+ only. 237 base::ScopedNativeLibrary library(base::FilePath(L"Iphlpapi.dll")); 238 239 typedef DWORD (NETIOAPI_API_ *GetIfTablePtr)(PMIB_IF_TABLE2*); 240 typedef void (NETIOAPI_API_ *FreeMibTablePtr)(PMIB_IF_TABLE2); 241 242 GetIfTablePtr getIfTable = reinterpret_cast<GetIfTablePtr>( 243 library.GetFunctionPointer("GetIfTable2")); 244 FreeMibTablePtr freeMibTablePtr = reinterpret_cast<FreeMibTablePtr>( 245 library.GetFunctionPointer("FreeMibTable")); 246 if (getIfTable == NULL || freeMibTablePtr == NULL) { 247 VLOG(ERROR) << "Could not get proc addresses for machine identifier."; 248 return ""; 249 } 250 251 PMIB_IF_TABLE2 ifTable = NULL; 252 DWORD result = getIfTable(&ifTable); 253 if (result != NO_ERROR || ifTable == NULL) { 254 VLOG(ERROR) << "GetIfTable failed with error " << result; 255 return ""; 256 } 257 258 MacAddressProcessor processor; 259 for (size_t i = 0; i < ifTable->NumEntries; i++) { 260 processor.ProcessInterfaceRow(&(ifTable->Table[i])); 261 } 262 263 if (ifTable != NULL) { 264 freeMibTablePtr(ifTable); 265 ifTable = NULL; 266 } 267 return processor.mac_address(); 268 } 269 270 } // namespace 271 272 // Returns the legacy device ID which was used involuntarily to generate hashes 273 // in M33 (crbug.com/350028). The algorithm to compute the legacy device ID was 274 // duplicated from the Windows implementation of GetRawDeviceId() inside 275 // extensions::api::GetDeviceId() for M33 where it originated from. It was 276 // deemed undesirable to move the code to a common path for re-use in this code 277 // as GetLegacyDeviceId() is meant to forever reproduce the ID that was 278 // generated on M33 and shouldn't otherwise evolve with the implementation of 279 // extensions::api::GetDeviceId() on trunk. 280 // TODO(gab): Delete this method when the vast majority of the population has 281 // migrated over to hashes based on the modern ID. 282 std::string GetLegacyDeviceId(const std::string& modern_device_id) { 283 base::ThreadRestrictions::AssertIOAllowed(); 284 285 // Just as in extensions::api::GetMacAddressCallback(), return the 286 // concatenation of |mac_address| and |modern_device_id|. Return the empty 287 // string if either of them is empty. 288 289 if (modern_device_id.empty()) 290 return std::string(); 291 292 // Get MAC address as in extensions::api::GetMacAddressCallback(): prefering 293 // GetMacAddressFromGetAdaptersAddresses() over 294 // GetMacAddressFromGetIfTable2() if the former can find a valid MAC address. 295 std::string mac_address = GetMacAddressFromGetAdaptersAddresses(); 296 if (mac_address.empty()) { 297 mac_address = GetMacAddressFromGetIfTable2(); 298 if (mac_address.empty()) 299 return std::string(); 300 } 301 302 return mac_address + modern_device_id; 303 } 304