2 * Copyright (c) 2017 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #import "SecC2DeviceInfo.h"
26 #import <os/variant_private.h>
27 #import <CoreFoundation/CFPriv.h>
30 #import <MobileGestalt.h>
32 #import <sys/sysctl.h>
35 static NSString* C2MetricBuildVersion(void);
36 static NSString* C2MetricProductName(void);
37 static NSString* C2MetricProductType(void);
38 static NSString* C2MetricProductVersion(void);
39 static NSString* C2MetricProcessName(void);
40 static NSString* C2MetricProcessVersion(void);
41 static NSString* C2MetricProcessUUID(void);
43 @implementation SecC2DeviceInfo
45 + (BOOL) isAppleInternal {
46 return os_variant_has_internal_content("com.apple.security.analytics");
49 + (NSString*) buildVersion {
50 return C2MetricBuildVersion();
53 + (NSString*) productName {
54 return C2MetricProductName();
57 + (NSString*) productType {
58 return C2MetricProductType();
61 + (NSString*) productVersion {
62 return C2MetricProductVersion();
65 + (NSString*) processName {
66 return C2MetricProcessName();
69 + (NSString*) processVersion {
70 return C2MetricProcessVersion();
73 + (NSString*) processUUID {
74 return C2MetricProcessUUID();
79 /* Stolen without remorse from CloudKit. */
81 #pragma mark - NSBundleInfoDictionary Constants
83 static NSDictionary *processInfoDict() {
84 static NSDictionary *processInfoDict = nil;
85 static dispatch_once_t onceToken;
86 dispatch_once(&onceToken, ^{
87 NSBundle *processBundle = [NSBundle mainBundle];
88 processInfoDict = [processBundle infoDictionary];
90 return processInfoDict;
93 static NSString* C2MetricProcessName() {
94 return processInfoDict()[(NSString *)kCFBundleIdentifierKey];
97 static NSString* C2MetricProcessVersion() {
98 return processInfoDict()[(NSString *)_kCFBundleShortVersionStringKey];
101 static NSString* C2MetricProcessUUID() {
102 static NSString* processUUIDString;
103 static dispatch_once_t onceToken;
104 dispatch_once(&onceToken, ^{
105 processUUIDString = [[NSUUID UUID] UUIDString];
107 return processUUIDString;
110 #pragma mark - MobileGestalt Constants
114 static NSMutableDictionary* _CKCachedGestaltValues = nil;
116 static NSArray* _CKCachedLockdownKeys() {
117 return @[(NSString *)kMGQUniqueDeviceID,
118 (NSString *)kMGQBuildVersion,
119 (NSString *)kMGQProductName,
120 (NSString *)kMGQProductType,
121 (NSString *)kMGQProductVersion];
124 static NSDictionary* _CKGetCachedGestaltValues() {
125 static dispatch_once_t pred;
126 dispatch_once(&pred, ^{
127 _CKCachedGestaltValues = [[NSMutableDictionary alloc] initWithCapacity:0];
129 for (NSString *key in _CKCachedLockdownKeys()) {
130 NSString *value = CFBridgingRelease(MGCopyAnswer((__bridge CFStringRef)key, NULL));
132 _CKCachedGestaltValues[key] = value;
134 os_log(OS_LOG_DEFAULT, "Error getting %@ from MobileGestalt", key);
138 return _CKCachedGestaltValues;
141 static NSString* _CKGetCachedGestaltValue(NSString *key) {
142 return _CKGetCachedGestaltValues()[key];
145 static NSString* C2MetricBuildVersion() {
146 return _CKGetCachedGestaltValue((NSString *)kMGQBuildVersion);
149 static NSString* C2MetricProductName() {
150 return _CKGetCachedGestaltValue((NSString *)kMGQProductName);
153 static NSString* C2MetricProductType() {
154 return _CKGetCachedGestaltValue((NSString *)kMGQProductType);
157 static NSString* C2MetricProductVersion() {
158 return _CKGetCachedGestaltValue((NSString *)kMGQProductVersion);
163 static CFStringRef CKCopySysctl(int mib[2]) {
164 char sysctlString[128];
165 size_t len = sizeof(sysctlString);
167 // add the system product
168 if (sysctl(mib, 2, sysctlString, &len, 0, 0) >= 0) {
169 return CFStringCreateWithCString(kCFAllocatorDefault, sysctlString, kCFStringEncodingUTF8);
175 static NSDictionary* systemVersionDict() {
176 static NSDictionary *sysVers = nil;
177 static dispatch_once_t onceToken;
178 dispatch_once(&onceToken, ^{
179 sysVers = (__bridge NSDictionary *)_CFCopySystemVersionDictionary();
184 static NSString* C2MetricBuildVersion() {
185 return systemVersionDict()[(NSString *)_kCFSystemVersionBuildVersionKey];
188 static NSString* C2MetricProductName() {
189 return systemVersionDict()[(NSString *)_kCFSystemVersionProductNameKey];
192 static NSString* C2MetricProductType() {
193 static dispatch_once_t onceToken;
194 static NSString *productType = nil;
195 dispatch_once(&onceToken, ^{
196 productType = (__bridge NSString *)CKCopySysctl((int[2]) { CTL_HW, HW_MODEL });
201 static NSString* C2MetricProductVersion() {
202 return systemVersionDict()[(NSString *)_kCFSystemVersionProductVersionKey];