1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <CoreFoundation/CoreFoundation.h>
6 #include <IOKit/IOKitLib.h>
7 #include <IOKit/network/IOEthernetController.h>
8 #include <IOKit/network/IOEthernetInterface.h>
9 #include <IOKit/network/IONetworkInterface.h>
11 #include "base/logging.h"
12 #include "base/mac/foundation_util.h"
13 #include "base/mac/scoped_cftyperef.h"
14 #include "base/mac/scoped_ioobject.h"
15 #include "base/strings/string16.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/sys_string_conversions.h"
18 #include "base/strings/utf_string_conversions.h"
24 // See http://developer.apple.com/library/mac/#technotes/tn1103/_index.html
26 // The caller is responsible for freeing |matching_services|.
27 bool FindEthernetInterfaces(io_iterator_t
* matching_services
) {
28 base::ScopedCFTypeRef
<CFMutableDictionaryRef
> matching_dict(
29 IOServiceMatching(kIOEthernetInterfaceClass
));
33 base::ScopedCFTypeRef
<CFMutableDictionaryRef
> primary_interface(
34 CFDictionaryCreateMutable(kCFAllocatorDefault
,
36 &kCFTypeDictionaryKeyCallBacks
,
37 &kCFTypeDictionaryValueCallBacks
));
38 if (!primary_interface
)
42 primary_interface
, CFSTR(kIOPrimaryInterface
), kCFBooleanTrue
);
44 matching_dict
, CFSTR(kIOPropertyMatchKey
), primary_interface
);
46 kern_return_t kern_result
= IOServiceGetMatchingServices(
47 kIOMasterPortDefault
, matching_dict
.release(), matching_services
);
49 return kern_result
== KERN_SUCCESS
;
52 bool GetMACAddressFromIterator(io_iterator_t primary_interface_iterator
,
53 uint8_t* buffer
, size_t buffer_size
) {
54 if (buffer_size
< kIOEthernetAddressSize
)
59 bzero(buffer
, buffer_size
);
60 base::mac::ScopedIOObject
<io_object_t
> primary_interface
;
61 while (primary_interface
.reset(IOIteratorNext(primary_interface_iterator
)),
63 io_object_t primary_interface_parent
;
64 kern_return_t kern_result
= IORegistryEntryGetParentEntry(
65 primary_interface
, kIOServicePlane
, &primary_interface_parent
);
66 base::mac::ScopedIOObject
<io_object_t
> primary_interface_parent_deleter(
67 primary_interface_parent
);
68 success
= kern_result
== KERN_SUCCESS
;
73 base::ScopedCFTypeRef
<CFTypeRef
> mac_data(
74 IORegistryEntryCreateCFProperty(primary_interface_parent
,
78 CFDataRef mac_data_data
= base::mac::CFCast
<CFDataRef
>(mac_data
);
81 mac_data_data
, CFRangeMake(0, kIOEthernetAddressSize
), buffer
);
88 bool GetMacAddress(unsigned char* buffer
, size_t size
) {
89 io_iterator_t primary_interface_iterator
;
90 if (!FindEthernetInterfaces(&primary_interface_iterator
))
92 bool result
= GetMACAddressFromIterator(
93 primary_interface_iterator
, buffer
, size
);
94 IOObjectRelease(primary_interface_iterator
);
98 CFStringRef
CopySerialNumber() {
99 base::mac::ScopedIOObject
<io_service_t
> expert_device(
100 IOServiceGetMatchingService(kIOMasterPortDefault
,
101 IOServiceMatching("IOPlatformExpertDevice")));
105 base::ScopedCFTypeRef
<CFTypeRef
> serial_number(
106 IORegistryEntryCreateCFProperty(expert_device
,
107 CFSTR(kIOPlatformSerialNumberKey
),
110 CFStringRef serial_number_cfstring
=
111 base::mac::CFCast
<CFStringRef
>(serial_number
);
112 if (!serial_number_cfstring
)
115 ignore_result(serial_number
.release());
116 return serial_number_cfstring
;
121 bool GetRawMachineId(base::string16
* data
, int* more_data
) {
122 uint8_t mac_address
[kIOEthernetAddressSize
];
125 if (GetMacAddress(mac_address
, sizeof(mac_address
))) {
126 *data
+= base::ASCIIToUTF16(
127 base::StringPrintf("mac:%02x%02x%02x%02x%02x%02x",
128 mac_address
[0], mac_address
[1], mac_address
[2],
129 mac_address
[3], mac_address
[4], mac_address
[5]));
132 // A MAC address is enough to uniquely identify a machine, but it's only 6
133 // bytes, 3 of which are manufacturer-determined. To make brute-forcing the
134 // SHA1 of this harder, also append the system's serial number.
135 CFStringRef serial
= CopySerialNumber();
138 *data
+= base::UTF8ToUTF16(" ");
139 *data
+= base::UTF8ToUTF16("serial:") + base::SysCFStringRefToUTF16(serial
);
143 // On windows, this is set to the volume id. Since it's not scrambled before
144 // being sent, just set it to 1.
149 } // namespace rlz_lib