]> git.saurik.com Git - apple/security.git/blob - MultiDeviceSimulator/DeviceSimulator/DeviceSimulatorMain.m
Security-58286.270.3.0.1.tar.gz
[apple/security.git] / MultiDeviceSimulator / DeviceSimulator / DeviceSimulatorMain.m
1 //
2 // main.m
3 // DeviceSimulator
4 //
5 //
6
7 #import <Foundation/Foundation.h>
8 #import <Foundation/NSXPCConnection_Private.h>
9 #import <SOSCircle/CKBridge/SOSCloudKeychainConstants.h>
10 #import <objc/runtime.h>
11 #import <utilities/debugging.h>
12
13 #import <securityd/SOSCloudCircleServer.h>
14 #import <Security/SecureObjectSync/SOSPeerInfo.h>
15 #import <Security/SecureObjectSync/SOSCloudCircleInternal.h>
16 #import <Security/SecureObjectSync/SOSViews.h>
17 #import <Security/SecureObjectSync/SOSInternal.h>
18
19 #import "DeviceSimulator.h"
20 #import "SOSCloudKeychainClient.h"
21 #import "MultiDeviceNetworkingProtocol.h"
22 #import "SecCFWrappers.h"
23 #import "spi.h"
24
25 struct SOSCloudTransport MDNTransport;
26
27 @class MDNetwork;
28
29 NSString *deviceInstance = NULL;
30 static NSString *deviceHomeDir = NULL;
31 static MDNetwork *deviceNetwork = NULL;
32
33 @interface MDNetwork : NSObject<MultiDeviceNetworkingProtocol,MultiDeviceNetworkingCallbackProtocol,NSXPCListenerDelegate>
34 @property NSXPCConnection *connection;
35 @property NSXPCListener *callbackListener;
36 @property dispatch_queue_t flushQueue;
37 @property NSMutableDictionary *pendingKeys;
38 @property NSSet *registeredKeys;
39 - (instancetype)initWithConnection:(NSXPCConnection *)connection;
40 @end
41
42 #pragma clang diagnostic push
43 #pragma clang diagnostic ignored "-Wprotocol"
44 @implementation MDNetwork
45
46 - (instancetype)initWithConnection:(NSXPCConnection *)connection
47 {
48 self = [super init];
49 if (self) {
50 self.connection = connection;
51 self.callbackListener = [NSXPCListener anonymousListener];
52 self.callbackListener.delegate = self;
53 [self.callbackListener resume];
54
55 __typeof(self) weakSelf = self;
56 self.connection.invalidationHandler = ^{
57 __typeof(self) strongSelf = weakSelf;
58 [strongSelf.callbackListener invalidate];
59 strongSelf.callbackListener = nil;
60
61 exit(0);
62 };
63
64 self.flushQueue = dispatch_queue_create("MDNetwork.flushqueue", 0);
65 self.pendingKeys = [NSMutableDictionary dictionary];
66 self.registeredKeys = [NSSet set];
67
68 [[self.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
69 NSLog(@"network register callback failed with: %@", error);
70 //abort();
71 }] MDNRegisterCallback:[self.callbackListener endpoint] complete:^void(NSDictionary *values, NSError *error) {
72 ;
73 }];
74
75 }
76 return self;
77 }
78
79 - (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection
80 {
81 newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MultiDeviceNetworkingCallbackProtocol)];
82 newConnection.exportedObject = self;
83 [newConnection resume];
84 return YES;
85 }
86
87 - (void)MDNCItemsChanged:(NSDictionary *)values complete:(MDNComplete)complete
88 {
89 NSMutableDictionary *requestedKeys = [NSMutableDictionary dictionary];
90 @synchronized(self.pendingKeys) {
91 secnotice("MDN", "items update: %@ (already pending: %@)", values, self.pendingKeys);
92
93 [self.pendingKeys addEntriesFromDictionary:values];
94 for (NSString *key in self.registeredKeys) {
95 id data = self.pendingKeys[key];
96 if (data) {
97 requestedKeys[key] = data;
98 self.pendingKeys[key] = nil;
99 }
100 }
101 }
102 if (requestedKeys.count) {
103 dispatch_async(self.flushQueue, ^{
104 secnotice("MDN", "engine processing keys: %@", requestedKeys);
105 NSArray *handled = CFBridgingRelease(SOSCCHandleUpdateMessage((__bridge CFDictionaryRef)requestedKeys));
106 /*
107 * Ok, our dear Engine might not have handled all messages.
108 * So put them back unless there are new messages around that
109 * have overwritten the previous message.
110 */
111 for (NSString *key in handled) {
112 requestedKeys[key] = NULL;
113 }
114 if (requestedKeys.count) {
115 @synchronized(self.pendingKeys) {
116 for (NSString *key in requestedKeys) {
117 if (self.pendingKeys[key] == nil) {
118 self.pendingKeys[key] = requestedKeys[key];
119 }
120 }
121 }
122 }
123 });
124 }
125 complete(NULL, NULL);
126 }
127
128 /* Oh, ObjC, you are my friend */
129 - (void)forwardInvocation:(NSInvocation *)invocation
130 {
131 struct objc_method_description desc = protocol_getMethodDescription(@protocol(MultiDeviceNetworkingProtocol), [invocation selector], true, true);
132 if (desc.name == NULL) {
133 [super forwardInvocation:invocation];
134 } else {
135 __block bool gogogo = true;
136 id object = [self.connection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
137 gogogo = false;
138 NSLog(@"network failed with: %@", error);
139 //abort();
140 }];
141 if(gogogo) [invocation invokeWithTarget:object];
142 }
143 }
144 @end
145 #pragma clang diagnostic pop
146
147 #define HANDLE_NO_NETWORK(_replyBlock) \
148 if (deviceNetwork == NULL) { \
149 replyBlock((__bridge CFDictionaryRef)@{}, (__bridge CFErrorRef)[NSError errorWithDomain:@"MDNNetwork" code:1 userInfo:NULL]); \
150 return; \
151 }
152
153
154 static void
155 DSCloudPut(SOSCloudTransportRef transport, CFDictionaryRef valuesToPut, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
156 {
157 @autoreleasepool {
158 HANDLE_NO_NETWORK(replyBlock);
159 secnotice("MDN", "CloudPut: %@", valuesToPut);
160
161 [deviceNetwork MDNCloudPut:(__bridge NSDictionary *)valuesToPut complete:^(NSDictionary *returnedValues, NSError *error) {
162 dispatch_async(processQueue, ^{
163 replyBlock((__bridge CFDictionaryRef)returnedValues, (__bridge CFErrorRef)error);
164 });
165 }];
166 }
167 }
168
169 static NSString *nKeyAlwaysKeys = @"AlwaysKeys";
170 static NSString *nKeyFirstUnlockKeys = @"FirstUnlockKeys";
171 static NSString *nKeyUnlockedKeys = @"UnlockedKeys";
172 static NSString *nMessageKeyParameter = @"KeyParameter";
173 static NSString *nMessageCircle = @"Circle";
174 static NSString *nMessageMessage = @"Message";
175
176
177 static void
178 DSCloudUpdateKeys(SOSCloudTransportRef transport, CFDictionaryRef cfkeys, CFStringRef accountUUID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
179 {
180 /*
181 * Currently doesn't deal with lock state, just smash (HULK!) them all together
182 */
183 @autoreleasepool {
184 NSDictionary *keys = (__bridge NSDictionary *)cfkeys;
185 NSMutableSet *newSet = [NSMutableSet set];
186
187 @synchronized(deviceNetwork.pendingKeys) {
188 for (NSString *type in @[ nMessageKeyParameter, nMessageCircle, nMessageMessage]) {
189 NSDictionary *typeDict = keys[type];
190
191 for (NSString *lockType in @[ nKeyAlwaysKeys, nKeyFirstUnlockKeys, nKeyUnlockedKeys]) {
192 NSArray *lockArray = typeDict[lockType];
193 if (lockArray) {
194 [newSet unionSet:[NSMutableSet setWithArray:lockArray]];
195 }
196 }
197 }
198 deviceNetwork.registeredKeys = newSet;
199 }
200 /* update engine with stuff */
201 [deviceNetwork MDNCItemsChanged:@{} complete:^(NSDictionary *returnedValues, NSError *error) {
202 if (replyBlock)
203 replyBlock((__bridge CFDictionaryRef)returnedValues, (__bridge CFErrorRef)error);
204 }];
205 }
206 }
207
208 static void
209 DSCloudGetDeviceID(SOSCloudTransportRef transport, CloudKeychainReplyBlock replyBlock)
210 {
211 if (replyBlock)
212 replyBlock((__bridge CFDictionaryRef)@{}, NULL);
213 }
214
215 // Debug calls
216 static void
217 DSCloudGet(SOSCloudTransportRef transport, CFArrayRef keysToGet, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
218 {
219 if (replyBlock)
220 replyBlock((__bridge CFDictionaryRef)@{}, NULL);
221 }
222
223 static void
224 DSCloudGetAll(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
225 {
226 if (replyBlock)
227 replyBlock((__bridge CFDictionaryRef)@{}, NULL);
228 }
229
230 static void
231 DSCloudsynchronize(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
232 {
233 if (replyBlock)
234 replyBlock((__bridge CFDictionaryRef)@{}, NULL);
235 }
236
237 static void
238 DSCloudsynchronizeAndWait(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
239 {
240 @autoreleasepool {
241 HANDLE_NO_NETWORK(replyBlock);
242
243 [deviceNetwork MDNCloudsynchronizeAndWait:@{} complete:^(NSDictionary *returnedValues, NSError *error) {
244 dispatch_async(processQueue, ^{
245 replyBlock((__bridge CFDictionaryRef)returnedValues, (__bridge CFErrorRef)error);
246 });
247 }];
248 }
249 }
250
251 static void
252 DSCloudRemoveObjectForKey(SOSCloudTransportRef transport, CFStringRef keyToRemove, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
253 {
254 if (keyToRemove == NULL) {
255 dispatch_async(processQueue, ^{
256 replyBlock(NULL, NULL);
257 });
258 return;
259 }
260
261 @autoreleasepool {
262 HANDLE_NO_NETWORK(replyBlock);
263 [deviceNetwork MDNCloudRemoveKeys:@[(__bridge NSString *)keyToRemove] complete:^(NSDictionary *returnedValues, NSError *error) {
264 dispatch_async(processQueue, ^{
265 replyBlock((__bridge CFDictionaryRef)returnedValues, (__bridge CFErrorRef)error);
266 });
267 }];
268 }
269 }
270
271 static void DSCloudremoveKeys(SOSCloudTransportRef transport, CFArrayRef keys, CFStringRef accountUUID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
272 {
273 @autoreleasepool {
274 HANDLE_NO_NETWORK(replyBlock);
275 [deviceNetwork MDNCloudRemoveKeys:(__bridge NSArray *)keys complete:^(NSDictionary *returnedValues, NSError *error) {
276 dispatch_async(processQueue, ^{
277 replyBlock((__bridge CFDictionaryRef)returnedValues, (__bridge CFErrorRef)error);
278 });
279 }];
280 }
281 }
282
283 static void
284 DSCloudclearAll(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
285 {
286 @autoreleasepool {
287 HANDLE_NO_NETWORK(replyBlock);
288 [deviceNetwork MDNCloudRemoveKeys:NULL complete:^(NSDictionary *returnedValues, NSError *error) {
289 dispatch_async(processQueue, ^{
290 replyBlock((__bridge CFDictionaryRef)returnedValues, (__bridge CFErrorRef)error);
291 });
292 }];
293 }
294 }
295
296 static bool
297 DSCloudhasPendingKey(SOSCloudTransportRef transport, CFStringRef keyName, CFErrorRef* error)
298 {
299 bool status = false;
300 @synchronized(deviceNetwork.pendingKeys) {
301 status = deviceNetwork.pendingKeys[(__bridge NSString *)keyName] != nil;
302 }
303 return status;
304 }
305
306
307 static void
308 DSCloudrequestSyncWithPeers(SOSCloudTransportRef transport, CFArrayRef /* CFStringRef */ peers, CFArrayRef /* CFStringRef */ backupPeers, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
309 {
310 CFSetRef sPeers = CFSetCreateCopyOfArrayForCFTypes(peers);
311 CFSetRef sBackupPeers = CFSetCreateCopyOfArrayForCFTypes(backupPeers);
312
313 if (sPeers == NULL || sBackupPeers == NULL) {
314 CFReleaseNull(sPeers);
315 CFReleaseNull(sBackupPeers);
316 } else {
317 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
318 CFErrorRef error = NULL;
319 CFSetRef result = SOSCCProcessSyncWithPeers_Server(sPeers, sBackupPeers, &error);
320
321 CFRelease(sPeers);
322 CFRelease(sBackupPeers);
323 CFReleaseNull(result);
324 CFReleaseNull(error);
325 });
326 }
327 if (replyBlock) {
328 dispatch_async(processQueue, ^{
329 replyBlock((__bridge CFDictionaryRef)@{}, NULL);
330 });
331 }
332 }
333
334 static bool
335 DSCloudhasPeerSyncPending(SOSCloudTransportRef transport, CFStringRef peerID, CFErrorRef* error)
336 {
337 return false;
338 }
339
340 static void
341 DSCloudrequestEnsurePeerRegistration(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
342 {
343 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
344 CFErrorRef eprError = NULL;
345 if (!SOSCCProcessEnsurePeerRegistration_Server(&eprError)) {
346 secnotice("coder", "SOSCCProcessEnsurePeerRegistration failed with: %@", eprError);
347 }
348 CFReleaseNull(eprError);
349 if (replyBlock)
350 replyBlock((__bridge CFDictionaryRef)@{}, NULL);
351 });
352 }
353
354 static void DSCloudrequestPerfCounters(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
355 {
356 if (replyBlock)
357 replyBlock((__bridge CFDictionaryRef)@{}, NULL);
358 }
359
360 static void DSCloudflush(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
361 {
362 @autoreleasepool {
363 HANDLE_NO_NETWORK(replyBlock);
364
365 [deviceNetwork MDNCloudFlush:^(NSDictionary *returnedValues, NSError *error) {
366 dispatch_async(deviceNetwork.flushQueue, ^{
367 dispatch_async(processQueue, ^{
368 replyBlock((__bridge CFDictionaryRef)returnedValues, (__bridge CFErrorRef)error);
369 });
370 });
371 }];
372 }
373 }
374
375 static void DSCloudcounters(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
376 {
377 if (replyBlock)
378 replyBlock((__bridge CFDictionaryRef)@{}, NULL);
379 }
380
381 @interface ServiceDelegate : NSObject <NSXPCListenerDelegate>
382 @end
383
384 @implementation ServiceDelegate
385
386 - (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
387 newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(DeviceSimulatorProtocol)];
388
389 DeviceSimulator *exportedObject = [DeviceSimulator new];
390 exportedObject.conn = newConnection;
391 newConnection.exportedObject = exportedObject;
392
393 [newConnection resume];
394
395 return YES;
396 }
397
398 @end
399
400 void
401 boot_securityd(NSXPCListenerEndpoint *network)
402 {
403 secLogDisable();
404 securityd_init((__bridge CFURLRef)[NSURL URLWithString:deviceHomeDir]);
405
406 NSXPCConnection *connection = [[NSXPCConnection alloc] initWithListenerEndpoint:network];
407 connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MultiDeviceNetworkingProtocol)];
408 [connection resume];
409
410 deviceNetwork = [[MDNetwork alloc] initWithConnection:connection];
411
412 }
413
414 /*
415 * Make sure each of th peers don't trample on each's others state
416 */
417
418 @interface SOSCachedNotification (override)
419 @end
420
421 @implementation SOSCachedNotification (override)
422 + (NSString *)swizzled_notificationName:(const char *)notificationName
423 {
424 return [NSString stringWithFormat:@"%@-%@",
425 [SOSCachedNotification swizzled_notificationName:notificationName], deviceInstance];
426 }
427
428 + (void)load {
429 static dispatch_once_t onceToken;
430 dispatch_once(&onceToken, ^{
431 Method orignal = class_getClassMethod(self, @selector(notificationName:));
432 Method swizzled = class_getClassMethod(self, @selector(swizzled_notificationName:));
433 method_exchangeImplementations(orignal, swizzled);
434 });
435 }
436 @end
437
438
439 int main(int argc, const char *argv[])
440 {
441 struct sigaction action;
442 memset(&action, 0, sizeof(action));
443
444 deviceInstance = [[NSXPCListener _UUID] UUIDString];
445
446 NSURL *tempPath = [[NSFileManager defaultManager] temporaryDirectory];
447 deviceHomeDir = [[tempPath path] stringByAppendingPathComponent:deviceInstance];
448
449 [[NSFileManager defaultManager] createDirectoryAtPath:deviceHomeDir
450 withIntermediateDirectories:NO
451 attributes:NULL
452 error:NULL];
453
454 MDNTransport.put = DSCloudPut;
455 MDNTransport.updateKeys = DSCloudUpdateKeys;
456 MDNTransport.getDeviceID = DSCloudGetDeviceID;
457 MDNTransport.get = DSCloudGet;
458 MDNTransport.getAll = DSCloudGetAll;
459 MDNTransport.synchronize = DSCloudsynchronize;
460 MDNTransport.synchronizeAndWait = DSCloudsynchronizeAndWait;
461 MDNTransport.clearAll = DSCloudclearAll;
462 MDNTransport.removeObjectForKey = DSCloudRemoveObjectForKey;
463 MDNTransport.hasPendingKey = DSCloudhasPendingKey;
464 MDNTransport.requestSyncWithPeers = DSCloudrequestSyncWithPeers;
465 MDNTransport.hasPeerSyncPending = DSCloudhasPeerSyncPending;
466 MDNTransport.requestEnsurePeerRegistration = DSCloudrequestEnsurePeerRegistration;
467 MDNTransport.requestPerfCounters = DSCloudrequestPerfCounters;
468 MDNTransport.flush = DSCloudflush;
469 MDNTransport.itemsChangedBlock = CFBridgingRetain(^CFArrayRef(CFDictionaryRef values) {
470 // default change block doesn't handle messages, keep em
471 return CFBridgingRetain(@[]);
472 });
473 MDNTransport.removeKeys = DSCloudremoveKeys;
474 MDNTransport.counters = DSCloudcounters;
475
476 SOSCloudTransportSetDefaultTransport(&MDNTransport);
477
478 // Create the delegate for the service.
479 ServiceDelegate *delegate = [ServiceDelegate new];
480 signal(SIGPIPE, SIG_IGN);
481
482 // Set up the one NSXPCListener for this service. It will handle all incoming connections.
483 NSXPCListener *listener = [NSXPCListener serviceListener];
484 listener.delegate = delegate;
485
486 // Resuming the serviceListener starts this service. This method does not return.
487 [listener resume];
488 return 0;
489 }