15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <CoreFoundation/CoreFoundation.h> 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <IOKit/IOKitLib.h> 7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <IOKit/network/IOEthernetController.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <IOKit/network/IOEthernetInterface.h> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <IOKit/network/IONetworkInterface.h> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/foundation_util.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/scoped_cftyperef.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/scoped_ioobject.h" 15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string16.h" 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/sys_string_conversions.h" 18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace rlz_lib { 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// See http://developer.apple.com/library/mac/#technotes/tn1103/_index.html 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The caller is responsible for freeing |matching_services|. 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FindEthernetInterfaces(io_iterator_t* matching_services) { 28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ScopedCFTypeRef<CFMutableDictionaryRef> matching_dict( 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IOServiceMatching(kIOEthernetInterfaceClass)); 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!matching_dict) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ScopedCFTypeRef<CFMutableDictionaryRef> primary_interface( 34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CFDictionaryCreateMutable(kCFAllocatorDefault, 35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 0, 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &kCFTypeDictionaryKeyCallBacks, 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &kCFTypeDictionaryValueCallBacks)); 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!primary_interface) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFDictionarySetValue( 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) primary_interface, CFSTR(kIOPrimaryInterface), kCFBooleanTrue); 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFDictionarySetValue( 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) matching_dict, CFSTR(kIOPropertyMatchKey), primary_interface); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kern_return_t kern_result = IOServiceGetMatchingServices( 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kIOMasterPortDefault, matching_dict.release(), matching_services); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return kern_result == KERN_SUCCESS; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetMACAddressFromIterator(io_iterator_t primary_interface_iterator, 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8_t* buffer, size_t buffer_size) { 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (buffer_size < kIOEthernetAddressSize) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool success = false; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bzero(buffer, buffer_size); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::mac::ScopedIOObject<io_object_t> primary_interface; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (primary_interface.reset(IOIteratorNext(primary_interface_iterator)), 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) primary_interface) { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) io_object_t primary_interface_parent; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kern_return_t kern_result = IORegistryEntryGetParentEntry( 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) primary_interface, kIOServicePlane, &primary_interface_parent); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::mac::ScopedIOObject<io_object_t> primary_interface_parent_deleter( 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) primary_interface_parent); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) success = kern_result == KERN_SUCCESS; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!success) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ScopedCFTypeRef<CFTypeRef> mac_data( 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IORegistryEntryCreateCFProperty(primary_interface_parent, 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFSTR(kIOMACAddress), 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kCFAllocatorDefault, 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0)); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFDataRef mac_data_data = base::mac::CFCast<CFDataRef>(mac_data); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mac_data_data) { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFDataGetBytes( 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mac_data_data, CFRangeMake(0, kIOEthernetAddressSize), buffer); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return success; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetMacAddress(unsigned char* buffer, size_t size) { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) io_iterator_t primary_interface_iterator; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!FindEthernetInterfaces(&primary_interface_iterator)) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool result = GetMACAddressFromIterator( 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) primary_interface_iterator, buffer, size); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IOObjectRelease(primary_interface_iterator); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CFStringRef CopySerialNumber() { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::mac::ScopedIOObject<io_service_t> expert_device( 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IOServiceGetMatchingService(kIOMasterPortDefault, 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IOServiceMatching("IOPlatformExpertDevice"))); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!expert_device) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::ScopedCFTypeRef<CFTypeRef> serial_number( 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IORegistryEntryCreateCFProperty(expert_device, 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFSTR(kIOPlatformSerialNumberKey), 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kCFAllocatorDefault, 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0)); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFStringRef serial_number_cfstring = 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::mac::CFCast<CFStringRef>(serial_number); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!serial_number_cfstring) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ignore_result(serial_number.release()); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return serial_number_cfstring; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GetRawMachineId(base::string16* data, int* more_data) { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8_t mac_address[kIOEthernetAddressSize]; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data->clear(); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetMacAddress(mac_address, sizeof(mac_address))) { 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *data += base::ASCIIToUTF16( 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::StringPrintf("mac:%02x%02x%02x%02x%02x%02x", 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mac_address[0], mac_address[1], mac_address[2], 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mac_address[3], mac_address[4], mac_address[5])); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A MAC address is enough to uniquely identify a machine, but it's only 6 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // bytes, 3 of which are manufacturer-determined. To make brute-forcing the 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SHA1 of this harder, also append the system's serial number. 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFStringRef serial = CopySerialNumber(); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (serial) { 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!data->empty()) 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *data += base::UTF8ToUTF16(" "); 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *data += base::UTF8ToUTF16("serial:") + base::SysCFStringRefToUTF16(serial); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CFRelease(serial); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // On windows, this is set to the volume id. Since it's not scrambled before 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // being sent, just set it to 1. 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *more_data = 1; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace rlz_lib 150