diff options
Diffstat (limited to 'dom/media/gmp/rlz/mac/lib/machine_id_mac.cc')
-rw-r--r-- | dom/media/gmp/rlz/mac/lib/machine_id_mac.cc | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/dom/media/gmp/rlz/mac/lib/machine_id_mac.cc b/dom/media/gmp/rlz/mac/lib/machine_id_mac.cc new file mode 100644 index 000000000..2bea0f55f --- /dev/null +++ b/dom/media/gmp/rlz/mac/lib/machine_id_mac.cc @@ -0,0 +1,320 @@ +// Copyright (c) 2012 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 <CoreFoundation/CoreFoundation.h> +#include <IOKit/IOKitLib.h> +#include <IOKit/network/IOEthernetController.h> +#include <IOKit/network/IOEthernetInterface.h> +#include <IOKit/network/IONetworkInterface.h> +#include <vector> +#include <string> + +// Note: The original machine_id_mac.cc code is in namespace rlz_lib below. +// It depends on some external files, which would bring in a log of Chromium +// code if imported as well. +// Instead only the necessary code has been extracted from the relevant files, +// and further combined and reduced to limit the maintenance burden. + +// [Extracted from base/logging.h] +#define DCHECK assert + +namespace base { + +// [Extracted from base/mac/scoped_typeref.h and base/mac/scoped_cftyperef.h] +template<typename T> +class ScopedCFTypeRef { + public: + typedef T element_type; + + explicit ScopedCFTypeRef(T object) + : object_(object) { + } + + ScopedCFTypeRef(const ScopedCFTypeRef<T>& that) = delete; + ScopedCFTypeRef(ScopedCFTypeRef<T>&& that) = delete; + + ~ScopedCFTypeRef() { + if (object_) + CFRelease(object_); + } + + ScopedCFTypeRef& operator=(const ScopedCFTypeRef<T>& that) = delete; + ScopedCFTypeRef& operator=(ScopedCFTypeRef<T>&& that) = delete; + + operator T() const { + return object_; + } + + // ScopedCFTypeRef<>::release() is like scoped_ptr<>::release. It is NOT + // a wrapper for CFRelease(). + T release() { + T temp = object_; + object_ = NULL; + return temp; + } + + private: + T object_; +}; + +namespace mac { + +// [Extracted from base/mac/scoped_ioobject.h] +// Just like ScopedCFTypeRef but for io_object_t and subclasses. +template<typename IOT> +class ScopedIOObject { + public: + typedef IOT element_type; + + explicit ScopedIOObject(IOT object = IO_OBJECT_NULL) + : object_(object) { + } + + ~ScopedIOObject() { + if (object_) + IOObjectRelease(object_); + } + + ScopedIOObject(const ScopedIOObject&) = delete; + void operator=(const ScopedIOObject&) = delete; + + void reset(IOT object = IO_OBJECT_NULL) { + if (object_) + IOObjectRelease(object_); + object_ = object; + } + + operator IOT() const { + return object_; + } + + private: + IOT object_; +}; + +// [Extracted from base/mac/foundation_util.h] +template<typename T> +T CFCast(const CFTypeRef& cf_val); + +template<> +CFDataRef +CFCast<CFDataRef>(const CFTypeRef& cf_val) { + if (cf_val == NULL) { + return NULL; + } + if (CFGetTypeID(cf_val) == CFDataGetTypeID()) { + return (CFDataRef)(cf_val); + } + return NULL; +} + +template<> +CFStringRef +CFCast<CFStringRef>(const CFTypeRef& cf_val) { + if (cf_val == NULL) { + return NULL; + } + if (CFGetTypeID(cf_val) == CFStringGetTypeID()) { + return (CFStringRef)(cf_val); + } + return NULL; +} + +} // namespace mac + +// [Extracted from base/strings/sys_string_conversions_mac.mm] +static const CFStringEncoding kNarrowStringEncoding = kCFStringEncodingUTF8; + +template<typename StringType> +static StringType CFStringToSTLStringWithEncodingT(CFStringRef cfstring, + CFStringEncoding encoding) { + CFIndex length = CFStringGetLength(cfstring); + if (length == 0) + return StringType(); + + CFRange whole_string = CFRangeMake(0, length); + CFIndex out_size; + CFIndex converted = CFStringGetBytes(cfstring, + whole_string, + encoding, + 0, // lossByte + false, // isExternalRepresentation + NULL, // buffer + 0, // maxBufLen + &out_size); + if (converted == 0 || out_size == 0) + return StringType(); + + // out_size is the number of UInt8-sized units needed in the destination. + // A buffer allocated as UInt8 units might not be properly aligned to + // contain elements of StringType::value_type. Use a container for the + // proper value_type, and convert out_size by figuring the number of + // value_type elements per UInt8. Leave room for a NUL terminator. + typename StringType::size_type elements = + out_size * sizeof(UInt8) / sizeof(typename StringType::value_type) + 1; + + std::vector<typename StringType::value_type> out_buffer(elements); + converted = CFStringGetBytes(cfstring, + whole_string, + encoding, + 0, // lossByte + false, // isExternalRepresentation + reinterpret_cast<UInt8*>(&out_buffer[0]), + out_size, + NULL); // usedBufLen + if (converted == 0) + return StringType(); + + out_buffer[elements - 1] = '\0'; + return StringType(&out_buffer[0], elements - 1); +} + +std::string SysCFStringRefToUTF8(CFStringRef ref) +{ + return CFStringToSTLStringWithEncodingT<std::string>(ref, + kNarrowStringEncoding); +} + +} // namespace base + + +namespace rlz_lib { + +namespace { + +// See http://developer.apple.com/library/mac/#technotes/tn1103/_index.html + +// The caller is responsible for freeing |matching_services|. +bool FindEthernetInterfaces(io_iterator_t* matching_services) { + base::ScopedCFTypeRef<CFMutableDictionaryRef> matching_dict( + IOServiceMatching(kIOEthernetInterfaceClass)); + if (!matching_dict) + return false; + + base::ScopedCFTypeRef<CFMutableDictionaryRef> primary_interface( + CFDictionaryCreateMutable(kCFAllocatorDefault, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + if (!primary_interface) + return false; + + CFDictionarySetValue( + primary_interface, CFSTR(kIOPrimaryInterface), kCFBooleanTrue); + CFDictionarySetValue( + matching_dict, CFSTR(kIOPropertyMatchKey), primary_interface); + + kern_return_t kern_result = IOServiceGetMatchingServices( + kIOMasterPortDefault, matching_dict.release(), matching_services); + + return kern_result == KERN_SUCCESS; +} + +bool GetMACAddressFromIterator(io_iterator_t primary_interface_iterator, + uint8_t* buffer, size_t buffer_size) { + if (buffer_size < kIOEthernetAddressSize) + return false; + + bool success = false; + + bzero(buffer, buffer_size); + base::mac::ScopedIOObject<io_object_t> primary_interface; + while (primary_interface.reset(IOIteratorNext(primary_interface_iterator)), + primary_interface) { + io_object_t primary_interface_parent; + kern_return_t kern_result = IORegistryEntryGetParentEntry( + primary_interface, kIOServicePlane, &primary_interface_parent); + base::mac::ScopedIOObject<io_object_t> primary_interface_parent_deleter( + primary_interface_parent); + success = kern_result == KERN_SUCCESS; + + if (!success) + continue; + + base::ScopedCFTypeRef<CFTypeRef> mac_data( + IORegistryEntryCreateCFProperty(primary_interface_parent, + CFSTR(kIOMACAddress), + kCFAllocatorDefault, + 0)); + CFDataRef mac_data_data = base::mac::CFCast<CFDataRef>(mac_data); + if (mac_data_data) { + CFDataGetBytes( + mac_data_data, CFRangeMake(0, kIOEthernetAddressSize), buffer); + } + } + + return success; +} + +bool GetMacAddress(unsigned char* buffer, size_t size) { + io_iterator_t primary_interface_iterator; + if (!FindEthernetInterfaces(&primary_interface_iterator)) + return false; + bool result = GetMACAddressFromIterator( + primary_interface_iterator, buffer, size); + IOObjectRelease(primary_interface_iterator); + return result; +} + +CFStringRef CopySerialNumber() { + base::mac::ScopedIOObject<io_service_t> expert_device( + IOServiceGetMatchingService(kIOMasterPortDefault, + IOServiceMatching("IOPlatformExpertDevice"))); + if (!expert_device) + return NULL; + + base::ScopedCFTypeRef<CFTypeRef> serial_number( + IORegistryEntryCreateCFProperty(expert_device, + CFSTR(kIOPlatformSerialNumberKey), + kCFAllocatorDefault, + 0)); + CFStringRef serial_number_cfstring = + base::mac::CFCast<CFStringRef>(serial_number.release()); + if (!serial_number_cfstring) + return NULL; + + return serial_number_cfstring; +} + +} // namespace + +bool GetRawMachineId(std::vector<uint8_t>* data, int* more_data) { + uint8_t mac_address[kIOEthernetAddressSize]; + + std::string id; + if (GetMacAddress(mac_address, sizeof(mac_address))) { + id += "mac:"; + static const char hex[] = + { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + for (int i = 0; i < kIOEthernetAddressSize; ++i) { + uint8_t byte = mac_address[i]; + id += hex[byte >> 4]; + id += hex[byte & 0xF]; + } + } + + // A MAC address is enough to uniquely identify a machine, but it's only 6 + // bytes, 3 of which are manufacturer-determined. To make brute-forcing the + // SHA1 of this harder, also append the system's serial number. + CFStringRef serial = CopySerialNumber(); + if (serial) { + if (!id.empty()) { + id += ' '; + } + id += "serial:"; + id += base::SysCFStringRefToUTF8(serial); + CFRelease(serial); + } + + // Get the contents of the string 'id' as a bunch of bytes. + data->assign(&id[0], &id[id.size()]); + + // On windows, this is set to the volume id. Since it's not scrambled before + // being sent, just set it to 1. + *more_data = 1; + return true; +} + +} // namespace rlz_lib |