diff options
Diffstat (limited to 'dom/media/gmp/rlz')
-rw-r--r-- | dom/media/gmp/rlz/COPYING | 14 | ||||
-rw-r--r-- | dom/media/gmp/rlz/GMPDeviceBinding.cpp | 209 | ||||
-rw-r--r-- | dom/media/gmp/rlz/GMPDeviceBinding.h | 22 | ||||
-rw-r--r-- | dom/media/gmp/rlz/README.mozilla | 6 | ||||
-rw-r--r-- | dom/media/gmp/rlz/lib/assert.h | 14 | ||||
-rw-r--r-- | dom/media/gmp/rlz/lib/machine_id.h | 19 | ||||
-rw-r--r-- | dom/media/gmp/rlz/lib/string_utils.cc | 34 | ||||
-rw-r--r-- | dom/media/gmp/rlz/lib/string_utils.h | 20 | ||||
-rw-r--r-- | dom/media/gmp/rlz/mac/lib/machine_id_mac.cc | 320 | ||||
-rw-r--r-- | dom/media/gmp/rlz/moz.build | 42 | ||||
-rw-r--r-- | dom/media/gmp/rlz/sha256.c | 469 | ||||
-rw-r--r-- | dom/media/gmp/rlz/sha256.h | 46 | ||||
-rw-r--r-- | dom/media/gmp/rlz/win/lib/machine_id_win.cc | 134 |
13 files changed, 1349 insertions, 0 deletions
diff --git a/dom/media/gmp/rlz/COPYING b/dom/media/gmp/rlz/COPYING new file mode 100644 index 000000000..b89042ace --- /dev/null +++ b/dom/media/gmp/rlz/COPYING @@ -0,0 +1,14 @@ +Copyright 2010 Google Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + diff --git a/dom/media/gmp/rlz/GMPDeviceBinding.cpp b/dom/media/gmp/rlz/GMPDeviceBinding.cpp new file mode 100644 index 000000000..c8aee2bcd --- /dev/null +++ b/dom/media/gmp/rlz/GMPDeviceBinding.cpp @@ -0,0 +1,209 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#include "GMPDeviceBinding.h" +#include "mozilla/Attributes.h" +#include "prenv.h" + +#include <string> + +#ifdef XP_WIN +#include "windows.h" +#ifdef MOZ_SANDBOX +#include <intrin.h> +#include <assert.h> +#endif +#endif + +#if defined(HASH_NODE_ID_WITH_DEVICE_ID) + +// In order to provide EME plugins with a "device binding" capability, +// in the parent we generate and store some random bytes as salt for every +// (origin, urlBarOrigin) pair that uses EME. We store these bytes so +// that every time we revisit the same origin we get the same salt. +// We send this salt to the child on startup. The child collects some +// device specific data and munges that with the salt to create the +// "node id" that we expose to EME plugins. It then overwrites the device +// specific data, and activates the sandbox. + +#include "rlz/lib/machine_id.h" +#include "rlz/lib/string_utils.h" +#include "sha256.h" + +#ifdef XP_WIN +#include "windows.h" +#ifdef MOZ_SANDBOX +#include <intrin.h> +#include <assert.h> +#endif +#endif + +#ifdef XP_MACOSX +#include <assert.h> +#ifdef HASH_NODE_ID_WITH_DEVICE_ID +#include <unistd.h> +#include <mach/mach.h> +#include <mach/mach_vm.h> +#endif +#endif + +#endif // HASH_NODE_ID_WITH_DEVICE_ID + +namespace mozilla { +namespace gmp { + +#if defined(XP_WIN) && defined(HASH_NODE_ID_WITH_DEVICE_ID) +MOZ_NEVER_INLINE +static bool +GetStackAfterCurrentFrame(uint8_t** aOutTop, uint8_t** aOutBottom) +{ + // "Top" of the free space on the stack is directly after the memory + // holding our return address. + uint8_t* top = (uint8_t*)_AddressOfReturnAddress(); + + // Look down the stack until we find the guard page... + MEMORY_BASIC_INFORMATION memInfo = {0}; + uint8_t* bottom = top; + while (1) { + if (!VirtualQuery(bottom, &memInfo, sizeof(memInfo))) { + return false; + } + if ((memInfo.Protect & PAGE_GUARD) == PAGE_GUARD) { + bottom = (uint8_t*)memInfo.BaseAddress + memInfo.RegionSize; +#ifdef DEBUG + if (!VirtualQuery(bottom, &memInfo, sizeof(memInfo))) { + return false; + } + assert(!(memInfo.Protect & PAGE_GUARD)); // Should have found boundary. +#endif + break; + } else if (memInfo.State != MEM_COMMIT || + (memInfo.AllocationProtect & PAGE_READWRITE) != PAGE_READWRITE) { + return false; + } + bottom = (uint8_t*)memInfo.BaseAddress - 1; + } + *aOutTop = top; + *aOutBottom = bottom; + return true; +} +#endif + +#if defined(XP_MACOSX) && defined(HASH_NODE_ID_WITH_DEVICE_ID) +static mach_vm_address_t +RegionContainingAddress(mach_vm_address_t aAddress) +{ + mach_port_t task; + kern_return_t kr = task_for_pid(mach_task_self(), getpid(), &task); + if (kr != KERN_SUCCESS) { + return 0; + } + + mach_vm_address_t address = aAddress; + mach_vm_size_t size; + vm_region_basic_info_data_64_t info; + mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; + mach_port_t object_name; + kr = mach_vm_region(task, &address, &size, VM_REGION_BASIC_INFO_64, + reinterpret_cast<vm_region_info_t>(&info), &count, + &object_name); + if (kr != KERN_SUCCESS || size == 0 + || address > aAddress || address + size <= aAddress) { + // mach_vm_region failed, or couldn't find region at given address. + return 0; + } + + return address; +} + +MOZ_NEVER_INLINE +static bool +GetStackAfterCurrentFrame(uint8_t** aOutTop, uint8_t** aOutBottom) +{ + mach_vm_address_t stackFrame = + reinterpret_cast<mach_vm_address_t>(__builtin_frame_address(0)); + *aOutTop = reinterpret_cast<uint8_t*>(stackFrame); + // Kernel code shows that stack is always a single region. + *aOutBottom = reinterpret_cast<uint8_t*>(RegionContainingAddress(stackFrame)); + return *aOutBottom && (*aOutBottom < *aOutTop); +} +#endif + +#ifdef HASH_NODE_ID_WITH_DEVICE_ID +static void SecureMemset(void* start, uint8_t value, size_t size) +{ + // Inline instructions equivalent to RtlSecureZeroMemory(). + for (size_t i = 0; i < size; ++i) { + volatile uint8_t* p = static_cast<volatile uint8_t*>(start) + i; + *p = value; + } +} +#endif + +bool +CalculateGMPDeviceId(char* aOriginSalt, + uint32_t aOriginSaltLen, + std::string& aOutNodeId) +{ +#ifdef HASH_NODE_ID_WITH_DEVICE_ID + if (aOriginSaltLen > 0) { + std::vector<uint8_t> deviceId; + int volumeId; + if (!rlz_lib::GetRawMachineId(&deviceId, &volumeId)) { + return false; + } + + SHA256Context ctx; + SHA256_Begin(&ctx); + SHA256_Update(&ctx, (const uint8_t*)aOriginSalt, aOriginSaltLen); + SHA256_Update(&ctx, deviceId.data(), deviceId.size()); + SHA256_Update(&ctx, (const uint8_t*)&volumeId, sizeof(int)); + uint8_t digest[SHA256_LENGTH] = {0}; + unsigned int digestLen = 0; + SHA256_End(&ctx, digest, &digestLen, SHA256_LENGTH); + + // Overwrite all data involved in calculation as it could potentially + // identify the user, so there's no chance a GMP can read it and use + // it for identity tracking. + SecureMemset(&ctx, 0, sizeof(ctx)); + SecureMemset(aOriginSalt, 0, aOriginSaltLen); + SecureMemset(&volumeId, 0, sizeof(volumeId)); + SecureMemset(deviceId.data(), '*', deviceId.size()); + deviceId.clear(); + + if (!rlz_lib::BytesToString(digest, SHA256_LENGTH, &aOutNodeId)) { + return false; + } + + if (!PR_GetEnv("MOZ_GMP_DISABLE_NODE_ID_CLEANUP")) { + // We've successfully bound the origin salt to node id. + // rlz_lib::GetRawMachineId and/or the system functions it + // called could have left user identifiable data on the stack, + // so carefully zero the stack down to the guard page. + uint8_t* top; + uint8_t* bottom; + if (!GetStackAfterCurrentFrame(&top, &bottom)) { + return false; + } + assert(top >= bottom); + // Inline instructions equivalent to RtlSecureZeroMemory(). + // We can't just use RtlSecureZeroMemory here directly, as in debug + // builds, RtlSecureZeroMemory() can't be inlined, and the stack + // memory it uses would get wiped by itself running, causing crashes. + for (volatile uint8_t* p = (volatile uint8_t*)bottom; p < top; p++) { + *p = 0; + } + } + } else +#endif + { + aOutNodeId = std::string(aOriginSalt, aOriginSalt + aOriginSaltLen); + } + return true; +} + +} // namespace gmp +} // namespace mozilla diff --git a/dom/media/gmp/rlz/GMPDeviceBinding.h b/dom/media/gmp/rlz/GMPDeviceBinding.h new file mode 100644 index 000000000..835704054 --- /dev/null +++ b/dom/media/gmp/rlz/GMPDeviceBinding.h @@ -0,0 +1,22 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 GMP_DEVICE_BINDING_h_ +#define GMP_DEVICE_BINDING_h_ + +#include <string> + +namespace mozilla { +namespace gmp { + +bool CalculateGMPDeviceId(char* aOriginSalt, + uint32_t aOriginSaltLen, + std::string& aOutNodeId); + +} // namespace gmp +} // namespace mozilla + +#endif // GMP_DEVICE_BINDING_h_ diff --git a/dom/media/gmp/rlz/README.mozilla b/dom/media/gmp/rlz/README.mozilla new file mode 100644 index 000000000..fffc5deb5 --- /dev/null +++ b/dom/media/gmp/rlz/README.mozilla @@ -0,0 +1,6 @@ +Code taken from rlz project: https://code.google.com/p/rlz/ + +Revision: 134, then with unused code stripped out. + +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 000000000..68737b1e2 --- /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 <assert.h>
+
+#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 000000000..67661cfce --- /dev/null +++ b/dom/media/gmp/rlz/lib/machine_id.h @@ -0,0 +1,19 @@ +// Copyright 2012 Google Inc. All Rights Reserved. +// Use of this source code is governed by an Apache-style license that can be +// found in the COPYING file. + +#ifndef RLZ_LIB_MACHINE_ID_H_ +#define RLZ_LIB_MACHINE_ID_H_ + +#include <vector> + +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<uint8_t>* 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 000000000..b6a71acdb --- /dev/null +++ b/dom/media/gmp/rlz/lib/string_utils.cc @@ -0,0 +1,34 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// Use of this source code is governed by an Apache-style license that can be +// found in the COPYING 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 000000000..294f1b2d9 --- /dev/null +++ b/dom/media/gmp/rlz/lib/string_utils.h @@ -0,0 +1,20 @@ +// Copyright 2010 Google Inc. All Rights Reserved. +// Use of this source code is governed by an Apache-style license that can be +// found in the COPYING file. +// +// String manipulation functions used in the RLZ library. + +#ifndef RLZ_LIB_STRING_UTILS_H_ +#define RLZ_LIB_STRING_UTILS_H_ + +#include <string> + +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 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 diff --git a/dom/media/gmp/rlz/moz.build b/dom/media/gmp/rlz/moz.build new file mode 100644 index 000000000..f366c2b5d --- /dev/null +++ b/dom/media/gmp/rlz/moz.build @@ -0,0 +1,42 @@ +# -*- 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. + +Library('rlz') + +UNIFIED_SOURCES += [ + 'GMPDeviceBinding.cpp', +] + +if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_TARGET'] in ['WINNT', 'Darwin']: + DEFINES['HASH_NODE_ID_WITH_DEVICE_ID'] = 1; + UNIFIED_SOURCES += [ + 'lib/string_utils.cc', + 'sha256.c', + ] + +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 += [ + '..', +] + +EXPORTS += [ + 'GMPDeviceBinding.h', +] diff --git a/dom/media/gmp/rlz/sha256.c b/dom/media/gmp/rlz/sha256.c new file mode 100644 index 000000000..072de5195 --- /dev/null +++ b/dom/media/gmp/rlz/sha256.c @@ -0,0 +1,469 @@ +/* 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/. */ + +// Stripped down version of security/nss/lib/freebl/sha512.c +// and related headers. + +#include "sha256.h" +#include "string.h" +#include "prcpucfg.h" +#if defined(NSS_X86) || defined(SHA_NO_LONG_LONG) +#define NOUNROLL512 1 +#undef HAVE_LONG_LONG +#endif +
+#define SHA256_BLOCK_LENGTH 64 /* bytes */
+
+typedef enum _SECStatus {
+ SECWouldBlock = -2,
+ SECFailure = -1,
+ SECSuccess = 0
+} SECStatus; + +/* ============= Common constants and defines ======================= */ + +#define W ctx->u.w +#define B ctx->u.b +#define H ctx->h + +#define SHR(x,n) (x >> n) +#define SHL(x,n) (x << n) +#define Ch(x,y,z) ((x & y) ^ (~x & z)) +#define Maj(x,y,z) ((x & y) ^ (x & z) ^ (y & z)) +#define SHA_MIN(a,b) (a < b ? a : b) + +/* Padding used with all flavors of SHA */ +static const PRUint8 pad[240] = { +0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + /* compiler will fill the rest in with zeros */ +}; + +/* ============= SHA256 implementation ================================== */ + +/* SHA-256 constants, K256. */ +static const PRUint32 K256[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +/* SHA-256 initial hash values */ +static const PRUint32 H256[8] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 +}; + +#if defined(_MSC_VER) +#include <stdlib.h> +#pragma intrinsic(_byteswap_ulong) +#define SHA_HTONL(x) _byteswap_ulong(x) +#define BYTESWAP4(x) x = SHA_HTONL(x) +#elif defined(__GNUC__) && defined(NSS_X86_OR_X64) +static __inline__ PRUint32 swap4b(PRUint32 value) +{ + __asm__("bswap %0" : "+r" (value)); + return (value); +} +#define SHA_HTONL(x) swap4b(x) +#define BYTESWAP4(x) x = SHA_HTONL(x) + +#elif defined(__GNUC__) && (defined(__thumb2__) || \ + (!defined(__thumb__) && \ + (defined(__ARM_ARCH_6__) || \ + defined(__ARM_ARCH_6J__) || \ + defined(__ARM_ARCH_6K__) || \ + defined(__ARM_ARCH_6Z__) || \ + defined(__ARM_ARCH_6ZK__) || \ + defined(__ARM_ARCH_6T2__) || \ + defined(__ARM_ARCH_7__) || \ + defined(__ARM_ARCH_7A__) || \ + defined(__ARM_ARCH_7R__)))) +static __inline__ PRUint32 swap4b(PRUint32 value) +{ + PRUint32 ret; + __asm__("rev %0, %1" : "=r" (ret) : "r"(value)); + return ret; +} +#define SHA_HTONL(x) swap4b(x) +#define BYTESWAP4(x) x = SHA_HTONL(x) + +#else +#define SWAP4MASK 0x00FF00FF +#define SHA_HTONL(x) (t1 = (x), t1 = (t1 << 16) | (t1 >> 16), \ + ((t1 & SWAP4MASK) << 8) | ((t1 >> 8) & SWAP4MASK)) +#define BYTESWAP4(x) x = SHA_HTONL(x) +#endif + +#if defined(_MSC_VER) +#pragma intrinsic (_lrotr, _lrotl) +#define ROTR32(x,n) _lrotr(x,n) +#define ROTL32(x,n) _lrotl(x,n) +#else +#define ROTR32(x,n) ((x >> n) | (x << ((8 * sizeof x) - n))) +#define ROTL32(x,n) ((x << n) | (x >> ((8 * sizeof x) - n))) +#endif + +/* Capitol Sigma and lower case sigma functions */ +#define S0(x) (ROTR32(x, 2) ^ ROTR32(x,13) ^ ROTR32(x,22)) +#define S1(x) (ROTR32(x, 6) ^ ROTR32(x,11) ^ ROTR32(x,25)) +#define s0(x) (t1 = x, ROTR32(t1, 7) ^ ROTR32(t1,18) ^ SHR(t1, 3)) +#define s1(x) (t2 = x, ROTR32(t2,17) ^ ROTR32(t2,19) ^ SHR(t2,10)) + +void +SHA256_Begin(SHA256Context *ctx) +{ + memset(ctx, 0, sizeof *ctx); + memcpy(H, H256, sizeof H256); +} + +static void +SHA256_Compress(SHA256Context *ctx) +{ + { + register PRUint32 t1, t2; + +#if defined(IS_LITTLE_ENDIAN) + BYTESWAP4(W[0]); + BYTESWAP4(W[1]); + BYTESWAP4(W[2]); + BYTESWAP4(W[3]); + BYTESWAP4(W[4]); + BYTESWAP4(W[5]); + BYTESWAP4(W[6]); + BYTESWAP4(W[7]); + BYTESWAP4(W[8]); + BYTESWAP4(W[9]); + BYTESWAP4(W[10]); + BYTESWAP4(W[11]); + BYTESWAP4(W[12]); + BYTESWAP4(W[13]); + BYTESWAP4(W[14]); + BYTESWAP4(W[15]); +#endif + +#define INITW(t) W[t] = (s1(W[t-2]) + W[t-7] + s0(W[t-15]) + W[t-16]) + + /* prepare the "message schedule" */ +#ifdef NOUNROLL256 + { + int t; + for (t = 16; t < 64; ++t) { + INITW(t); + } + } +#else + INITW(16); + INITW(17); + INITW(18); + INITW(19); + + INITW(20); + INITW(21); + INITW(22); + INITW(23); + INITW(24); + INITW(25); + INITW(26); + INITW(27); + INITW(28); + INITW(29); + + INITW(30); + INITW(31); + INITW(32); + INITW(33); + INITW(34); + INITW(35); + INITW(36); + INITW(37); + INITW(38); + INITW(39); + + INITW(40); + INITW(41); + INITW(42); + INITW(43); + INITW(44); + INITW(45); + INITW(46); + INITW(47); + INITW(48); + INITW(49); + + INITW(50); + INITW(51); + INITW(52); + INITW(53); + INITW(54); + INITW(55); + INITW(56); + INITW(57); + INITW(58); + INITW(59); + + INITW(60); + INITW(61); + INITW(62); + INITW(63); + +#endif +#undef INITW + } + { + PRUint32 a, b, c, d, e, f, g, h; + + a = H[0]; + b = H[1]; + c = H[2]; + d = H[3]; + e = H[4]; + f = H[5]; + g = H[6]; + h = H[7]; + +#define ROUND(n,a,b,c,d,e,f,g,h) \ + h += S1(e) + Ch(e,f,g) + K256[n] + W[n]; \ + d += h; \ + h += S0(a) + Maj(a,b,c); + +#ifdef NOUNROLL256 + { + int t; + for (t = 0; t < 64; t+= 8) { + ROUND(t+0,a,b,c,d,e,f,g,h) + ROUND(t+1,h,a,b,c,d,e,f,g) + ROUND(t+2,g,h,a,b,c,d,e,f) + ROUND(t+3,f,g,h,a,b,c,d,e) + ROUND(t+4,e,f,g,h,a,b,c,d) + ROUND(t+5,d,e,f,g,h,a,b,c) + ROUND(t+6,c,d,e,f,g,h,a,b) + ROUND(t+7,b,c,d,e,f,g,h,a) + } + } +#else + ROUND( 0,a,b,c,d,e,f,g,h) + ROUND( 1,h,a,b,c,d,e,f,g) + ROUND( 2,g,h,a,b,c,d,e,f) + ROUND( 3,f,g,h,a,b,c,d,e) + ROUND( 4,e,f,g,h,a,b,c,d) + ROUND( 5,d,e,f,g,h,a,b,c) + ROUND( 6,c,d,e,f,g,h,a,b) + ROUND( 7,b,c,d,e,f,g,h,a) + + ROUND( 8,a,b,c,d,e,f,g,h) + ROUND( 9,h,a,b,c,d,e,f,g) + ROUND(10,g,h,a,b,c,d,e,f) + ROUND(11,f,g,h,a,b,c,d,e) + ROUND(12,e,f,g,h,a,b,c,d) + ROUND(13,d,e,f,g,h,a,b,c) + ROUND(14,c,d,e,f,g,h,a,b) + ROUND(15,b,c,d,e,f,g,h,a) + + ROUND(16,a,b,c,d,e,f,g,h) + ROUND(17,h,a,b,c,d,e,f,g) + ROUND(18,g,h,a,b,c,d,e,f) + ROUND(19,f,g,h,a,b,c,d,e) + ROUND(20,e,f,g,h,a,b,c,d) + ROUND(21,d,e,f,g,h,a,b,c) + ROUND(22,c,d,e,f,g,h,a,b) + ROUND(23,b,c,d,e,f,g,h,a) + + ROUND(24,a,b,c,d,e,f,g,h) + ROUND(25,h,a,b,c,d,e,f,g) + ROUND(26,g,h,a,b,c,d,e,f) + ROUND(27,f,g,h,a,b,c,d,e) + ROUND(28,e,f,g,h,a,b,c,d) + ROUND(29,d,e,f,g,h,a,b,c) + ROUND(30,c,d,e,f,g,h,a,b) + ROUND(31,b,c,d,e,f,g,h,a) + + ROUND(32,a,b,c,d,e,f,g,h) + ROUND(33,h,a,b,c,d,e,f,g) + ROUND(34,g,h,a,b,c,d,e,f) + ROUND(35,f,g,h,a,b,c,d,e) + ROUND(36,e,f,g,h,a,b,c,d) + ROUND(37,d,e,f,g,h,a,b,c) + ROUND(38,c,d,e,f,g,h,a,b) + ROUND(39,b,c,d,e,f,g,h,a) + + ROUND(40,a,b,c,d,e,f,g,h) + ROUND(41,h,a,b,c,d,e,f,g) + ROUND(42,g,h,a,b,c,d,e,f) + ROUND(43,f,g,h,a,b,c,d,e) + ROUND(44,e,f,g,h,a,b,c,d) + ROUND(45,d,e,f,g,h,a,b,c) + ROUND(46,c,d,e,f,g,h,a,b) + ROUND(47,b,c,d,e,f,g,h,a) + + ROUND(48,a,b,c,d,e,f,g,h) + ROUND(49,h,a,b,c,d,e,f,g) + ROUND(50,g,h,a,b,c,d,e,f) + ROUND(51,f,g,h,a,b,c,d,e) + ROUND(52,e,f,g,h,a,b,c,d) + ROUND(53,d,e,f,g,h,a,b,c) + ROUND(54,c,d,e,f,g,h,a,b) + ROUND(55,b,c,d,e,f,g,h,a) + + ROUND(56,a,b,c,d,e,f,g,h) + ROUND(57,h,a,b,c,d,e,f,g) + ROUND(58,g,h,a,b,c,d,e,f) + ROUND(59,f,g,h,a,b,c,d,e) + ROUND(60,e,f,g,h,a,b,c,d) + ROUND(61,d,e,f,g,h,a,b,c) + ROUND(62,c,d,e,f,g,h,a,b) + ROUND(63,b,c,d,e,f,g,h,a) +#endif + + H[0] += a; + H[1] += b; + H[2] += c; + H[3] += d; + H[4] += e; + H[5] += f; + H[6] += g; + H[7] += h; + } +#undef ROUND +} + +#undef s0 +#undef s1 +#undef S0 +#undef S1 + +void +SHA256_Update(SHA256Context *ctx, const unsigned char *input, + unsigned int inputLen) +{ + unsigned int inBuf = ctx->sizeLo & 0x3f; + if (!inputLen) + return; + + /* Add inputLen into the count of bytes processed, before processing */ + if ((ctx->sizeLo += inputLen) < inputLen) + ctx->sizeHi++; + + /* if data already in buffer, attemp to fill rest of buffer */ + if (inBuf) { + unsigned int todo = SHA256_BLOCK_LENGTH - inBuf; + if (inputLen < todo) + todo = inputLen; + memcpy(B + inBuf, input, todo); + input += todo; + inputLen -= todo; + if (inBuf + todo == SHA256_BLOCK_LENGTH) + SHA256_Compress(ctx); + } + + /* if enough data to fill one or more whole buffers, process them. */ + while (inputLen >= SHA256_BLOCK_LENGTH) { + memcpy(B, input, SHA256_BLOCK_LENGTH); + input += SHA256_BLOCK_LENGTH; + inputLen -= SHA256_BLOCK_LENGTH; + SHA256_Compress(ctx); + } + /* if data left over, fill it into buffer */ + if (inputLen) + memcpy(B, input, inputLen); +} + +void +SHA256_End(SHA256Context *ctx, unsigned char *digest, + unsigned int *digestLen, unsigned int maxDigestLen) +{ + unsigned int inBuf = ctx->sizeLo & 0x3f; + unsigned int padLen = (inBuf < 56) ? (56 - inBuf) : (56 + 64 - inBuf); + PRUint32 hi, lo; +#ifdef SWAP4MASK + PRUint32 t1; +#endif + + hi = (ctx->sizeHi << 3) | (ctx->sizeLo >> 29); + lo = (ctx->sizeLo << 3); + + SHA256_Update(ctx, pad, padLen); + +#if defined(IS_LITTLE_ENDIAN) + W[14] = SHA_HTONL(hi); + W[15] = SHA_HTONL(lo); +#else + W[14] = hi; + W[15] = lo; +#endif + SHA256_Compress(ctx); + + /* now output the answer */ +#if defined(IS_LITTLE_ENDIAN) + BYTESWAP4(H[0]); + BYTESWAP4(H[1]); + BYTESWAP4(H[2]); + BYTESWAP4(H[3]); + BYTESWAP4(H[4]); + BYTESWAP4(H[5]); + BYTESWAP4(H[6]); + BYTESWAP4(H[7]); +#endif + padLen = PR_MIN(SHA256_LENGTH, maxDigestLen); + memcpy(digest, H, padLen); + if (digestLen) + *digestLen = padLen; +} + +void +SHA256_EndRaw(SHA256Context *ctx, unsigned char *digest, + unsigned int *digestLen, unsigned int maxDigestLen) +{ + PRUint32 h[8]; + unsigned int len; +#ifdef SWAP4MASK + PRUint32 t1; +#endif + + memcpy(h, ctx->h, sizeof(h)); + +#if defined(IS_LITTLE_ENDIAN) + BYTESWAP4(h[0]); + BYTESWAP4(h[1]); + BYTESWAP4(h[2]); + BYTESWAP4(h[3]); + BYTESWAP4(h[4]); + BYTESWAP4(h[5]); + BYTESWAP4(h[6]); + BYTESWAP4(h[7]); +#endif + + len = PR_MIN(SHA256_LENGTH, maxDigestLen); + memcpy(digest, h, len); + if (digestLen) + *digestLen = len; +} + +SECStatus +SHA256_HashBuf(unsigned char *dest, const unsigned char *src, + PRUint32 src_length) +{ + SHA256Context ctx; + unsigned int outLen; + + SHA256_Begin(&ctx); + SHA256_Update(&ctx, src, src_length); + SHA256_End(&ctx, dest, &outLen, SHA256_LENGTH); + memset(&ctx, 0, sizeof ctx); + + return SECSuccess; +} diff --git a/dom/media/gmp/rlz/sha256.h b/dom/media/gmp/rlz/sha256.h new file mode 100644 index 000000000..6958e382c --- /dev/null +++ b/dom/media/gmp/rlz/sha256.h @@ -0,0 +1,46 @@ +/* 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/. */ + +// Stripped down version of security/nss/lib/freebl/blapi.h +// and related headers. + +#ifndef _SHA256_H_ +#define _SHA256_H_ + +#define SHA256_LENGTH 32 + +#include "prtypes.h" /* for PRUintXX */ +#include "prlong.h" + +#ifdef __cplusplus
+extern "C" {
+#endif + +struct SHA256Context {
+ union {
+ PRUint32 w[64]; /* message schedule, input buffer, plus 48 words */
+ PRUint8 b[256];
+ } u;
+ PRUint32 h[8]; /* 8 state variables */
+ PRUint32 sizeHi,sizeLo; /* 64-bit count of hashed bytes. */
+}; + +typedef struct SHA256Context SHA256Context; + +extern void +SHA256_Begin(SHA256Context *ctx); + +extern void +SHA256_Update(SHA256Context *ctx, const unsigned char *input, + unsigned int inputLen); + +extern void +SHA256_End(SHA256Context *ctx, unsigned char *digest, + unsigned int *digestLen, unsigned int maxDigestLen); + +#ifdef __cplusplus
+} /* extern C */ +#endif + +#endif /* _SHA256_H_ */ 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 000000000..0a636ebd3 --- /dev/null +++ b/dom/media/gmp/rlz/win/lib/machine_id_win.cc @@ -0,0 +1,134 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// Use of this source code is governed by an Apache-style license that can be +// found in the COPYING file. + +#include <windows.h> +#include <sddl.h> // For ConvertSidToStringSidW. +#include <string> +#include <vector> +#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::vector<wchar_t> domain_buffer(kStartDomainLength, 0); + 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.front(), + &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.resize(domain_size); + + success = ::LookupAccountNameW(NULL, account_name, sid, &sid_dword_size, + &domain_buffer.front(), &domain_size, + &sid_name_use); + } + + return success != FALSE; +} + +std::vector<uint8_t> 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<uint8_t>( + reinterpret_cast<uint8_t*>(&sid_string[0]), + reinterpret_cast<uint8_t*>(&sid_string[sid_string.size()])); +} + +} // namespace + +bool GetRawMachineId(std::vector<uint8_t>* 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)) { + return false; + } + char sid_buffer[SECURITY_MAX_SID_SIZE]; + SID* sid = reinterpret_cast<SID*>(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 |