]> git.saurik.com Git - apple/security.git/blob - keychain/ot/OTDeviceInformationAdapter.m
Security-59306.61.1.tar.gz
[apple/security.git] / keychain / ot / OTDeviceInformationAdapter.m
1 #import "keychain/ot/OTDeviceInformationAdapter.h"
2 #import "keychain/ot/OTConstants.h"
3 #import "keychain/ckks/CKKSListenerCollection.h"
4 #import "keychain/ckks/CKKS.h"
5
6 #include <SystemConfiguration/SystemConfiguration.h>
7 #import <Security/SecInternalReleasePriv.h>
8
9 #if TARGET_OS_OSX
10 #include <sys/sysctl.h>
11 #include <IOKit/IOKitLib.h>
12 #else
13 #import <sys/utsname.h>
14 #include <MobileGestalt.h>
15 #endif
16
17 static void updateDeviceNameChanges(SCDynamicStoreRef store, CFArrayRef keys, void *context);
18
19 @interface OTDeviceInformationActualAdapter ()
20 @property CKKSListenerCollection<id<OTDeviceInformationNameUpdateListener>>* deviceNameUpdateListeners;
21 @property (assign) SCDynamicStoreRef store;
22 @end
23
24 @implementation OTDeviceInformationActualAdapter
25
26 - (void)dealloc {
27 if (self.store) {
28 CFRelease(self.store);
29 self.store = NULL;
30 }
31 }
32
33 - (NSString*)modelID
34 {
35 static NSString *hwModel = nil;
36 static dispatch_once_t onceToken;
37 dispatch_once(&onceToken, ^{
38 #if TARGET_OS_SIMULATOR
39 // Asking for a real value in the simulator gives the results for the underlying mac. Not particularly useful.
40 hwModel = [NSString stringWithFormat:@"%s", getenv("SIMULATOR_MODEL_IDENTIFIER")];
41 #elif TARGET_OS_OSX
42 size_t size;
43 sysctlbyname("hw.model", NULL, &size, NULL, 0);
44 char *sysctlString = malloc(size);
45 sysctlbyname("hw.model", sysctlString, &size, NULL, 0);
46 hwModel = [[NSString alloc] initWithUTF8String:sysctlString];
47 free(sysctlString);
48
49 // macOS running virtualized sometimes has new and unknown model IDs.
50 // So, if we don't recognize the model ID, return something more useful.
51 if(!([hwModel hasPrefix:@"iMac"] ||
52 [hwModel hasPrefix:@"Mac"])) {
53 hwModel = [NSString stringWithFormat:@"MacUnknown-%@", hwModel];
54 }
55 #else
56 struct utsname systemInfo;
57 uname(&systemInfo);
58
59 hwModel = [NSString stringWithCString:systemInfo.machine
60 encoding:NSUTF8StringEncoding];
61 #endif
62 });
63 return hwModel;
64 }
65
66 - (NSString* _Nullable)deviceName
67 {
68 if (SecIsInternalRelease()) {
69 NSString *deviceName = CFBridgingRelease(SCDynamicStoreCopyComputerName(NULL, NULL));
70 return deviceName;
71 } else {
72 return nil;
73 }
74 }
75
76 - (void)registerForDeviceNameUpdates:(id<OTDeviceInformationNameUpdateListener>)listener
77 {
78 // Octagon only uses the device name on internal releases.
79 // Therefore, if this is not an internal release, don't bother registering clients--they don't need the update.
80 if (SecIsInternalRelease()) {
81 @synchronized (self) {
82 [self setupDeviceNameListener];
83 [self.deviceNameUpdateListeners registerListener:listener];
84 }
85 }
86 }
87
88 - (NSString*)osVersion
89 {
90 return SecCKKSHostOSVersion();
91 }
92
93 #if TARGET_OS_IPHONE
94
95 #include <MobileGestalt.h>
96
97 - (NSString*)serialNumber
98 {
99 int mgError = kMGNoError;
100 NSString *serialNumber = CFBridgingRelease(MGCopyAnswerWithError(kMGQSerialNumber, NULL, &mgError));
101 if (![serialNumber isKindOfClass:[NSString class]]) {
102 serialNumber = nil;
103 secnotice("octagon", "failed getting serial number: %d", mgError);
104 }
105 return serialNumber;
106 }
107
108 #else
109
110 - (NSString*)serialNumber
111 {
112 io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
113 if (platformExpert == MACH_PORT_NULL) {
114 secnotice("octagon", "failed getting serial number (platform IOPlatformExpertDevice)");
115 return nil;
116 }
117 NSString *serialNumber = CFBridgingRelease(IORegistryEntryCreateCFProperty(platformExpert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0));
118 if (![serialNumber isKindOfClass:[NSString class]]) {
119 serialNumber = nil;
120 secnotice("octagon", "failed getting serial number (IORegistryEntry)");
121 }
122 IOObjectRelease(platformExpert);
123 return serialNumber;
124 }
125
126 #endif
127
128
129 - (void)setupDeviceNameListener {
130 if (self.deviceNameUpdateListeners == nil) {
131 self.deviceNameUpdateListeners = [[CKKSListenerCollection alloc] initWithName:@"OTDeviceInformationActualAdapter"];
132
133 CFStringRef computerKey = SCDynamicStoreKeyCreateComputerName(NULL);
134 if (computerKey == NULL) {
135 return;
136 }
137 NSArray *keys = @[ (__bridge NSString *)computerKey];
138 CFRelease(computerKey);
139
140 SCDynamicStoreContext context = { .info = (void *)(__bridge CFTypeRef)self };
141 self.store = SCDynamicStoreCreate(NULL, CFSTR("OTDeviceInformationActualAdapter"), updateDeviceNameChanges, &context);
142 if (self.store == NULL) {
143 return;
144 }
145
146 SCDynamicStoreSetNotificationKeys(self.store, (__bridge CFArrayRef)keys, NULL);
147 SCDynamicStoreSetDispatchQueue(self.store, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
148 }
149 }
150
151 @end
152
153 static void updateDeviceNameChanges(SCDynamicStoreRef store, CFArrayRef keys, void *info)
154 {
155 secnotice("octagon", "Notified that the device name has changed");
156 OTDeviceInformationActualAdapter *adapter = (__bridge id)info;
157
158 [adapter.deviceNameUpdateListeners iterateListeners:^void(id<OTDeviceInformationNameUpdateListener> object){
159 [object deviceNameUpdated];
160 }];
161 }
162