diff --git a/dom/media/gmp/moz.build b/dom/media/gmp/moz.build index 47a34651ec2f..e55c062a5464 100644 --- a/dom/media/gmp/moz.build +++ b/dom/media/gmp/moz.build @@ -104,6 +104,7 @@ UNIFIED_SOURCES += [ ] DIRS += [ + 'rlz', 'widevine-adapter', ] diff --git a/dom/media/gmp/rlz/OWNERS b/dom/media/gmp/rlz/OWNERS new file mode 100644 index 000000000000..66f24ebb3729 --- /dev/null +++ b/dom/media/gmp/rlz/OWNERS @@ -0,0 +1,4 @@ +rogerta@chromium.org +thakis@chromium.org + +# COMPONENT: Internals>Core diff --git a/dom/media/gmp/rlz/README.mozilla b/dom/media/gmp/rlz/README.mozilla new file mode 100644 index 000000000000..4408737a5e7a --- /dev/null +++ b/dom/media/gmp/rlz/README.mozilla @@ -0,0 +1,4 @@ +Code taken from rlz project in Chromium repository: https://chromium.googlesource.com/chromium/src.git/+/6f3478dfd7d29b9872871718bd08493ed0c8bc8e + +Note: base/ contains wrappers/dummies to provide implementations of the +Chromium APIs that this code relies upon. diff --git a/dom/media/gmp/rlz/lib/assert.h b/dom/media/gmp/rlz/lib/assert.h new file mode 100644 index 000000000000..c64dd7ff827a --- /dev/null +++ b/dom/media/gmp/rlz/lib/assert.h @@ -0,0 +1,14 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef FAKE_ASSERT_H_ +#define FAKE_ASSERT_H_ + +#include + +#define ASSERT_STRING(x) { assert(false); } +#define VERIFY(x) { assert(x); }; + +#endif diff --git a/dom/media/gmp/rlz/lib/machine_id.h b/dom/media/gmp/rlz/lib/machine_id.h new file mode 100644 index 000000000000..0b86e19af2da --- /dev/null +++ b/dom/media/gmp/rlz/lib/machine_id.h @@ -0,0 +1,19 @@ +// 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. + +#ifndef RLZ_LIB_MACHINE_ID_H_ +#define RLZ_LIB_MACHINE_ID_H_ + +#include + +namespace rlz_lib { + +// Retrieves a raw machine identifier string and a machine-specific +// 4 byte value. GetMachineId() will SHA1 |data|, append |more_data|, compute +// the Crc8 of that, and return a hex-encoded string of that data. +bool GetRawMachineId(std::vector* data, int* more_data); + +} // namespace rlz_lib + +#endif // RLZ_LIB_MACHINE_ID_H_ diff --git a/dom/media/gmp/rlz/lib/string_utils.cc b/dom/media/gmp/rlz/lib/string_utils.cc new file mode 100644 index 000000000000..6da732382368 --- /dev/null +++ b/dom/media/gmp/rlz/lib/string_utils.cc @@ -0,0 +1,34 @@ +// 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. +// +// String manipulation functions used in the RLZ library. + +#include "rlz/lib/string_utils.h" + +namespace rlz_lib { + +bool BytesToString(const unsigned char* data, + int data_len, + std::string* string) { + if (!string) + return false; + + string->clear(); + if (data_len < 1 || !data) + return false; + + static const char kHex[] = "0123456789ABCDEF"; + + // Fix the buffer size to begin with to avoid repeated re-allocation. + string->resize(data_len * 2); + int index = data_len; + while (index--) { + string->at(2 * index) = kHex[data[index] >> 4]; // high digit + string->at(2 * index + 1) = kHex[data[index] & 0x0F]; // low digit + } + + return true; +} + +} // namespace rlz_lib diff --git a/dom/media/gmp/rlz/lib/string_utils.h b/dom/media/gmp/rlz/lib/string_utils.h new file mode 100644 index 000000000000..500133ade1f4 --- /dev/null +++ b/dom/media/gmp/rlz/lib/string_utils.h @@ -0,0 +1,20 @@ +// 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. +// +// String manipulation functions used in the RLZ library. + +#ifndef RLZ_LIB_STRING_UTILS_H_ +#define RLZ_LIB_STRING_UTILS_H_ + +#include + +namespace rlz_lib { + +bool BytesToString(const unsigned char* data, + int data_len, + std::string* string); + +}; // namespace + +#endif // RLZ_LIB_STRING_UTILS_H_ 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 000000000000..8e81bdf38c69 --- /dev/null +++ b/dom/media/gmp/rlz/mac/lib/machine_id_mac.cc @@ -0,0 +1,321 @@ +// 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 +#include +#include +#include +#include +#include +#include + +#include +#include +// 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 +class ScopedCFTypeRef { + public: + typedef T element_type; + + explicit ScopedCFTypeRef(T object) + : object_(object) { + } + + ScopedCFTypeRef(const ScopedCFTypeRef& that) = delete; + ScopedCFTypeRef(ScopedCFTypeRef&& that) = delete; + + ~ScopedCFTypeRef() { + if (object_) + CFRelease(object_); + } + + ScopedCFTypeRef& operator=(const ScopedCFTypeRef& that) = delete; + ScopedCFTypeRef& operator=(ScopedCFTypeRef&& 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 +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 +T CFCast(const CFTypeRef& cf_val); + +template<> +CFDataRef +CFCast(const CFTypeRef& cf_val) { + if (cf_val == NULL) { + return NULL; + } + if (CFGetTypeID(cf_val) == CFDataGetTypeID()) { + return (CFDataRef)(cf_val); + } + return NULL; +} + +template<> +CFStringRef +CFCast(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 +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 out_buffer(elements); + converted = CFStringGetBytes(cfstring, + whole_string, + encoding, + 0, // lossByte + false, // isExternalRepresentation + reinterpret_cast(&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(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 matching_dict( + IOServiceMatching(kIOEthernetInterfaceClass)); + if (!matching_dict) + return false; + + base::ScopedCFTypeRef 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 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 primary_interface_parent_deleter( + primary_interface_parent); + success = kern_result == KERN_SUCCESS; + + if (!success) + continue; + + base::ScopedCFTypeRef mac_data( + IORegistryEntryCreateCFProperty(primary_interface_parent, + CFSTR(kIOMACAddress), + kCFAllocatorDefault, + 0)); + CFDataRef mac_data_data = base::mac::CFCast(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 expert_device( + IOServiceGetMatchingService(kIOMasterPortDefault, + IOServiceMatching("IOPlatformExpertDevice"))); + if (!expert_device) + return NULL; + + base::ScopedCFTypeRef serial_number( + IORegistryEntryCreateCFProperty(expert_device, + CFSTR(kIOPlatformSerialNumberKey), + kCFAllocatorDefault, + 0)); + CFStringRef serial_number_cfstring = + base::mac::CFCast(serial_number.release()); + if (!serial_number_cfstring) + return NULL; + + return serial_number_cfstring; +} + +} // namespace + +bool GetRawMachineId(std::vector* 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 diff --git a/dom/media/gmp/rlz/moz.build b/dom/media/gmp/rlz/moz.build new file mode 100644 index 000000000000..03762bbd4538 --- /dev/null +++ b/dom/media/gmp/rlz/moz.build @@ -0,0 +1,32 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Note: build rlz in its own moz.build, so it doesn't pickup any of +# Chromium IPC's headers used in the moz.build of the parent file. + +FINAL_LIBRARY = 'xul' + +if CONFIG['OS_TARGET'] in ['WINNT', 'Darwin']: + UNIFIED_SOURCES += [ + 'lib/string_utils.cc', + ] + +if CONFIG['OS_TARGET'] == 'WINNT': + UNIFIED_SOURCES += [ + 'win/lib/machine_id_win.cc', + ] + +if CONFIG['OS_TARGET'] == 'Darwin': + UNIFIED_SOURCES += [ + 'mac/lib/machine_id_mac.cc', + ] + OS_LIBS += [ + '-framework IOKit', + ] + +LOCAL_INCLUDES += [ + '..', +] diff --git a/dom/media/gmp/rlz/win/lib/machine_id_win.cc b/dom/media/gmp/rlz/win/lib/machine_id_win.cc new file mode 100644 index 000000000000..85f1d6cf54a8 --- /dev/null +++ b/dom/media/gmp/rlz/win/lib/machine_id_win.cc @@ -0,0 +1,136 @@ +// 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 +#include // For ConvertSidToStringSidW. + +#include +#include +#include + +#include "mozilla/ArrayUtils.h" + +#include "rlz/lib/assert.h" + +namespace rlz_lib { + +namespace { + +bool GetSystemVolumeSerialNumber(int* number) { + if (!number) + return false; + + *number = 0; + + // Find the system root path (e.g: C:\). + wchar_t system_path[MAX_PATH + 1]; + if (!GetSystemDirectoryW(system_path, MAX_PATH)) + return false; + + wchar_t* first_slash = wcspbrk(system_path, L"\\/"); + if (first_slash != NULL) + *(first_slash + 1) = 0; + + DWORD number_local = 0; + if (!GetVolumeInformationW(system_path, NULL, 0, &number_local, NULL, NULL, + NULL, 0)) + return false; + + *number = (int)number_local; + return true; +} + +bool GetComputerSid(const wchar_t* account_name, SID* sid, DWORD sid_size) { + static const DWORD kStartDomainLength = 128; // reasonable to start with + + std::unique_ptr domain_buffer(new wchar_t[kStartDomainLength]); + DWORD domain_size = kStartDomainLength; + DWORD sid_dword_size = sid_size; + SID_NAME_USE sid_name_use; + + BOOL success = ::LookupAccountNameW(NULL, account_name, sid, + &sid_dword_size, domain_buffer.get(), + &domain_size, &sid_name_use); + if (!success && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + // We could have gotten the insufficient buffer error because + // one or both of sid and szDomain was too small. Check for that + // here. + if (sid_dword_size > sid_size) + return false; + + if (domain_size > kStartDomainLength) + domain_buffer.reset(new wchar_t[domain_size]); + + success = ::LookupAccountNameW(NULL, account_name, sid, &sid_dword_size, + domain_buffer.get(), &domain_size, + &sid_name_use); + } + + return success != FALSE; +} + +std::vector ConvertSidToBytes(SID* sid) { + std::wstring sid_string; +#if _WIN32_WINNT >= 0x500 + wchar_t* sid_buffer = NULL; + if (ConvertSidToStringSidW(sid, &sid_buffer)) { + sid_string = sid_buffer; + LocalFree(sid_buffer); + } +#else + SID_IDENTIFIER_AUTHORITY* sia = ::GetSidIdentifierAuthority(sid); + + if(sia->Value[0] || sia->Value[1]) { + base::SStringPrintf( + &sid_string, L"S-%d-0x%02hx%02hx%02hx%02hx%02hx%02hx", + SID_REVISION, (USHORT)sia->Value[0], (USHORT)sia->Value[1], + (USHORT)sia->Value[2], (USHORT)sia->Value[3], (USHORT)sia->Value[4], + (USHORT)sia->Value[5]); + } else { + ULONG authority = 0; + for (int i = 2; i < 6; ++i) { + authority <<= 8; + authority |= sia->Value[i]; + } + base::SStringPrintf(&sid_string, L"S-%d-%lu", SID_REVISION, authority); + } + + int sub_auth_count = *::GetSidSubAuthorityCount(sid); + for(int i = 0; i < sub_auth_count; ++i) + base::StringAppendF(&sid_string, L"-%lu", *::GetSidSubAuthority(sid, i)); +#endif + + // Get the contents of the string as a bunch of bytes. + return std::vector( + reinterpret_cast(&sid_string[0]), + reinterpret_cast(&sid_string[sid_string.size()])); +} + +} // namespace + +bool GetRawMachineId(std::vector* sid_bytes, int* volume_id) { + // Calculate the Windows SID. + + wchar_t computer_name[MAX_COMPUTERNAME_LENGTH + 1] = {0}; + DWORD size = mozilla::ArrayLength(computer_name); + + if (GetComputerNameW(computer_name, &size)) { + char sid_buffer[SECURITY_MAX_SID_SIZE]; + SID* sid = reinterpret_cast(sid_buffer); + if (GetComputerSid(computer_name, sid, SECURITY_MAX_SID_SIZE)) { + *sid_bytes = ConvertSidToBytes(sid); + } + } + + // Get the system drive volume serial number. + *volume_id = 0; + if (!GetSystemVolumeSerialNumber(volume_id)) { + ASSERT_STRING("GetMachineId: Failed to retrieve volume serial number"); + *volume_id = 0; + } + + return true; +} + +} // namespace rlz_lib