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