+++ /dev/null
-//
-// main.m
-// DeviceSimulator
-//
-//
-
-#import <Foundation/Foundation.h>
-#import <Foundation/NSXPCConnection_Private.h>
-#import <SOSCircle/CKBridge/SOSCloudKeychainConstants.h>
-#import <objc/runtime.h>
-#import <utilities/debugging.h>
-
-#import <securityd/SOSCloudCircleServer.h>
-#import <Security/SecureObjectSync/SOSPeerInfo.h>
-#import <Security/SecureObjectSync/SOSCloudCircleInternal.h>
-#import <Security/SecureObjectSync/SOSViews.h>
-#import <Security/SecureObjectSync/SOSInternal.h>
-
-#import "DeviceSimulator.h"
-#import "SOSCloudKeychainClient.h"
-#import "MultiDeviceNetworkingProtocol.h"
-#import "SecCFWrappers.h"
-#import "spi.h"
-
-struct SOSCloudTransport MDNTransport;
-
-@class MDNetwork;
-
-NSString *deviceInstance = NULL;
-static NSString *deviceHomeDir = NULL;
-static MDNetwork *deviceNetwork = NULL;
-
-@interface MDNetwork : NSObject<MultiDeviceNetworkingProtocol,MultiDeviceNetworkingCallbackProtocol,NSXPCListenerDelegate>
-@property NSXPCConnection *connection;
-@property NSXPCListener *callbackListener;
-@property dispatch_queue_t flushQueue;
-@property NSMutableDictionary *pendingKeys;
-@property NSSet *registeredKeys;
-- (instancetype)initWithConnection:(NSXPCConnection *)connection;
-@end
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wprotocol"
-@implementation MDNetwork
-
-- (instancetype)initWithConnection:(NSXPCConnection *)connection
-{
- self = [super init];
- if (self) {
- self.connection = connection;
- self.callbackListener = [NSXPCListener anonymousListener];
- self.callbackListener.delegate = self;
- [self.callbackListener resume];
-
- __typeof(self) weakSelf = self;
- self.connection.invalidationHandler = ^{
- __typeof(self) strongSelf = weakSelf;
- [strongSelf.callbackListener invalidate];
- strongSelf.callbackListener = nil;
-
- exit(0);
- };
-
- self.flushQueue = dispatch_queue_create("MDNetwork.flushqueue", 0);
- self.pendingKeys = [NSMutableDictionary dictionary];
- self.registeredKeys = [NSSet set];
-
- [[self.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
- NSLog(@"network register callback failed with: %@", error);
- //abort();
- }] MDNRegisterCallback:[self.callbackListener endpoint] complete:^void(NSDictionary *values, NSError *error) {
- ;
- }];
-
- }
- return self;
-}
-
-- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection
-{
- newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MultiDeviceNetworkingCallbackProtocol)];
- newConnection.exportedObject = self;
- [newConnection resume];
- return YES;
-}
-
-- (void)MDNCItemsChanged:(NSDictionary *)values complete:(MDNComplete)complete
-{
- NSMutableDictionary *requestedKeys = [NSMutableDictionary dictionary];
- @synchronized(self.pendingKeys) {
- secnotice("MDN", "items update: %@ (already pending: %@)", values, self.pendingKeys);
-
- [self.pendingKeys addEntriesFromDictionary:values];
- for (NSString *key in self.registeredKeys) {
- id data = self.pendingKeys[key];
- if (data) {
- requestedKeys[key] = data;
- self.pendingKeys[key] = nil;
- }
- }
- }
- if (requestedKeys.count) {
- dispatch_async(self.flushQueue, ^{
- secnotice("MDN", "engine processing keys: %@", requestedKeys);
- NSArray *handled = CFBridgingRelease(SOSCCHandleUpdateMessage((__bridge CFDictionaryRef)requestedKeys));
- /*
- * Ok, our dear Engine might not have handled all messages.
- * So put them back unless there are new messages around that
- * have overwritten the previous message.
- */
- for (NSString *key in handled) {
- requestedKeys[key] = NULL;
- }
- if (requestedKeys.count) {
- @synchronized(self.pendingKeys) {
- for (NSString *key in requestedKeys) {
- if (self.pendingKeys[key] == nil) {
- self.pendingKeys[key] = requestedKeys[key];
- }
- }
- }
- }
- });
- }
- complete(NULL, NULL);
-}
-
-/* Oh, ObjC, you are my friend */
-- (void)forwardInvocation:(NSInvocation *)invocation
-{
- struct objc_method_description desc = protocol_getMethodDescription(@protocol(MultiDeviceNetworkingProtocol), [invocation selector], true, true);
- if (desc.name == NULL) {
- [super forwardInvocation:invocation];
- } else {
- __block bool gogogo = true;
- id object = [self.connection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
- gogogo = false;
- NSLog(@"network failed with: %@", error);
- //abort();
- }];
- if(gogogo) [invocation invokeWithTarget:object];
- }
-}
-@end
-#pragma clang diagnostic pop
-
-#define HANDLE_NO_NETWORK(_replyBlock) \
- if (deviceNetwork == NULL) { \
- replyBlock((__bridge CFDictionaryRef)@{}, (__bridge CFErrorRef)[NSError errorWithDomain:@"MDNNetwork" code:1 userInfo:NULL]); \
- return; \
- }
-
-
-static void
-DSCloudPut(SOSCloudTransportRef transport, CFDictionaryRef valuesToPut, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
-{
- @autoreleasepool {
- HANDLE_NO_NETWORK(replyBlock);
- secnotice("MDN", "CloudPut: %@", valuesToPut);
-
- [deviceNetwork MDNCloudPut:(__bridge NSDictionary *)valuesToPut complete:^(NSDictionary *returnedValues, NSError *error) {
- dispatch_async(processQueue, ^{
- replyBlock((__bridge CFDictionaryRef)returnedValues, (__bridge CFErrorRef)error);
- });
- }];
- }
-}
-
-static NSString *nKeyAlwaysKeys = @"AlwaysKeys";
-static NSString *nKeyFirstUnlockKeys = @"FirstUnlockKeys";
-static NSString *nKeyUnlockedKeys = @"UnlockedKeys";
-static NSString *nMessageKeyParameter = @"KeyParameter";
-static NSString *nMessageCircle = @"Circle";
-static NSString *nMessageMessage = @"Message";
-
-
-static void
-DSCloudUpdateKeys(SOSCloudTransportRef transport, CFDictionaryRef cfkeys, CFStringRef accountUUID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
-{
- /*
- * Currently doesn't deal with lock state, just smash (HULK!) them all together
- */
- @autoreleasepool {
- NSDictionary *keys = (__bridge NSDictionary *)cfkeys;
- NSMutableSet *newSet = [NSMutableSet set];
-
- @synchronized(deviceNetwork.pendingKeys) {
- for (NSString *type in @[ nMessageKeyParameter, nMessageCircle, nMessageMessage]) {
- NSDictionary *typeDict = keys[type];
-
- for (NSString *lockType in @[ nKeyAlwaysKeys, nKeyFirstUnlockKeys, nKeyUnlockedKeys]) {
- NSArray *lockArray = typeDict[lockType];
- if (lockArray) {
- [newSet unionSet:[NSMutableSet setWithArray:lockArray]];
- }
- }
- }
- deviceNetwork.registeredKeys = newSet;
- }
- /* update engine with stuff */
- [deviceNetwork MDNCItemsChanged:@{} complete:^(NSDictionary *returnedValues, NSError *error) {
- if (replyBlock)
- replyBlock((__bridge CFDictionaryRef)returnedValues, (__bridge CFErrorRef)error);
- }];
- }
-}
-
-static void
-DSCloudGetDeviceID(SOSCloudTransportRef transport, CloudKeychainReplyBlock replyBlock)
-{
- if (replyBlock)
- replyBlock((__bridge CFDictionaryRef)@{}, NULL);
-}
-
-// Debug calls
-static void
-DSCloudGet(SOSCloudTransportRef transport, CFArrayRef keysToGet, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
-{
- if (replyBlock)
- replyBlock((__bridge CFDictionaryRef)@{}, NULL);
-}
-
-static void
-DSCloudGetAll(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
-{
- if (replyBlock)
- replyBlock((__bridge CFDictionaryRef)@{}, NULL);
-}
-
-static void
-DSCloudsynchronize(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
-{
- if (replyBlock)
- replyBlock((__bridge CFDictionaryRef)@{}, NULL);
-}
-
-static void
-DSCloudsynchronizeAndWait(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
-{
- @autoreleasepool {
- HANDLE_NO_NETWORK(replyBlock);
-
- [deviceNetwork MDNCloudsynchronizeAndWait:@{} complete:^(NSDictionary *returnedValues, NSError *error) {
- dispatch_async(processQueue, ^{
- replyBlock((__bridge CFDictionaryRef)returnedValues, (__bridge CFErrorRef)error);
- });
- }];
- }
-}
-
-static void
-DSCloudRemoveObjectForKey(SOSCloudTransportRef transport, CFStringRef keyToRemove, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
-{
- if (keyToRemove == NULL) {
- dispatch_async(processQueue, ^{
- replyBlock(NULL, NULL);
- });
- return;
- }
-
- @autoreleasepool {
- HANDLE_NO_NETWORK(replyBlock);
- [deviceNetwork MDNCloudRemoveKeys:@[(__bridge NSString *)keyToRemove] complete:^(NSDictionary *returnedValues, NSError *error) {
- dispatch_async(processQueue, ^{
- replyBlock((__bridge CFDictionaryRef)returnedValues, (__bridge CFErrorRef)error);
- });
- }];
- }
-}
-
-static void DSCloudremoveKeys(SOSCloudTransportRef transport, CFArrayRef keys, CFStringRef accountUUID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
-{
- @autoreleasepool {
- HANDLE_NO_NETWORK(replyBlock);
- [deviceNetwork MDNCloudRemoveKeys:(__bridge NSArray *)keys complete:^(NSDictionary *returnedValues, NSError *error) {
- dispatch_async(processQueue, ^{
- replyBlock((__bridge CFDictionaryRef)returnedValues, (__bridge CFErrorRef)error);
- });
- }];
- }
-}
-
-static void
-DSCloudclearAll(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
-{
- @autoreleasepool {
- HANDLE_NO_NETWORK(replyBlock);
- [deviceNetwork MDNCloudRemoveKeys:NULL complete:^(NSDictionary *returnedValues, NSError *error) {
- dispatch_async(processQueue, ^{
- replyBlock((__bridge CFDictionaryRef)returnedValues, (__bridge CFErrorRef)error);
- });
- }];
- }
-}
-
-static bool
-DSCloudhasPendingKey(SOSCloudTransportRef transport, CFStringRef keyName, CFErrorRef* error)
-{
- bool status = false;
- @synchronized(deviceNetwork.pendingKeys) {
- status = deviceNetwork.pendingKeys[(__bridge NSString *)keyName] != nil;
- }
- return status;
-}
-
-
-static void
-DSCloudrequestSyncWithPeers(SOSCloudTransportRef transport, CFArrayRef /* CFStringRef */ peers, CFArrayRef /* CFStringRef */ backupPeers, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
-{
- CFSetRef sPeers = CFSetCreateCopyOfArrayForCFTypes(peers);
- CFSetRef sBackupPeers = CFSetCreateCopyOfArrayForCFTypes(backupPeers);
-
- if (sPeers == NULL || sBackupPeers == NULL) {
- CFReleaseNull(sPeers);
- CFReleaseNull(sBackupPeers);
- } else {
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- CFErrorRef error = NULL;
- CFSetRef result = SOSCCProcessSyncWithPeers_Server(sPeers, sBackupPeers, &error);
-
- CFRelease(sPeers);
- CFRelease(sBackupPeers);
- CFReleaseNull(result);
- CFReleaseNull(error);
- });
- }
- if (replyBlock) {
- dispatch_async(processQueue, ^{
- replyBlock((__bridge CFDictionaryRef)@{}, NULL);
- });
- }
-}
-
-static bool
-DSCloudhasPeerSyncPending(SOSCloudTransportRef transport, CFStringRef peerID, CFErrorRef* error)
-{
- return false;
-}
-
-static void
-DSCloudrequestEnsurePeerRegistration(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
-{
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- CFErrorRef eprError = NULL;
- if (!SOSCCProcessEnsurePeerRegistration_Server(&eprError)) {
- secnotice("coder", "SOSCCProcessEnsurePeerRegistration failed with: %@", eprError);
- }
- CFReleaseNull(eprError);
- if (replyBlock)
- replyBlock((__bridge CFDictionaryRef)@{}, NULL);
- });
-}
-
-static void DSCloudrequestPerfCounters(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
-{
- if (replyBlock)
- replyBlock((__bridge CFDictionaryRef)@{}, NULL);
-}
-
-static void DSCloudflush(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
-{
- @autoreleasepool {
- HANDLE_NO_NETWORK(replyBlock);
-
- [deviceNetwork MDNCloudFlush:^(NSDictionary *returnedValues, NSError *error) {
- dispatch_async(deviceNetwork.flushQueue, ^{
- dispatch_async(processQueue, ^{
- replyBlock((__bridge CFDictionaryRef)returnedValues, (__bridge CFErrorRef)error);
- });
- });
- }];
- }
-}
-
-static void DSCloudcounters(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
-{
- if (replyBlock)
- replyBlock((__bridge CFDictionaryRef)@{}, NULL);
-}
-
-@interface ServiceDelegate : NSObject <NSXPCListenerDelegate>
-@end
-
-@implementation ServiceDelegate
-
-- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
- newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(DeviceSimulatorProtocol)];
-
- DeviceSimulator *exportedObject = [DeviceSimulator new];
- exportedObject.conn = newConnection;
- newConnection.exportedObject = exportedObject;
-
- [newConnection resume];
-
- return YES;
-}
-
-@end
-
-void
-boot_securityd(NSXPCListenerEndpoint *network)
-{
- secLogDisable();
- securityd_init((__bridge CFURLRef)[NSURL URLWithString:deviceHomeDir]);
-
- NSXPCConnection *connection = [[NSXPCConnection alloc] initWithListenerEndpoint:network];
- connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MultiDeviceNetworkingProtocol)];
- [connection resume];
-
- deviceNetwork = [[MDNetwork alloc] initWithConnection:connection];
-
-}
-
-/*
- * Make sure each of th peers don't trample on each's others state
- */
-
-@interface SOSCachedNotification (override)
-@end
-
-@implementation SOSCachedNotification (override)
-+ (NSString *)swizzled_notificationName:(const char *)notificationName
-{
- return [NSString stringWithFormat:@"%@-%@",
- [SOSCachedNotification swizzled_notificationName:notificationName], deviceInstance];
-}
-
-+ (void)load {
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- Method orignal = class_getClassMethod(self, @selector(notificationName:));
- Method swizzled = class_getClassMethod(self, @selector(swizzled_notificationName:));
- method_exchangeImplementations(orignal, swizzled);
- });
-}
-@end
-
-
-int main(int argc, const char *argv[])
-{
- struct sigaction action;
- memset(&action, 0, sizeof(action));
-
- deviceInstance = [[NSXPCListener _UUID] UUIDString];
-
- NSURL *tempPath = [[NSFileManager defaultManager] temporaryDirectory];
- deviceHomeDir = [[tempPath path] stringByAppendingPathComponent:deviceInstance];
-
- [[NSFileManager defaultManager] createDirectoryAtPath:deviceHomeDir
- withIntermediateDirectories:NO
- attributes:NULL
- error:NULL];
-
- MDNTransport.put = DSCloudPut;
- MDNTransport.updateKeys = DSCloudUpdateKeys;
- MDNTransport.getDeviceID = DSCloudGetDeviceID;
- MDNTransport.get = DSCloudGet;
- MDNTransport.getAll = DSCloudGetAll;
- MDNTransport.synchronize = DSCloudsynchronize;
- MDNTransport.synchronizeAndWait = DSCloudsynchronizeAndWait;
- MDNTransport.clearAll = DSCloudclearAll;
- MDNTransport.removeObjectForKey = DSCloudRemoveObjectForKey;
- MDNTransport.hasPendingKey = DSCloudhasPendingKey;
- MDNTransport.requestSyncWithPeers = DSCloudrequestSyncWithPeers;
- MDNTransport.hasPeerSyncPending = DSCloudhasPeerSyncPending;
- MDNTransport.requestEnsurePeerRegistration = DSCloudrequestEnsurePeerRegistration;
- MDNTransport.requestPerfCounters = DSCloudrequestPerfCounters;
- MDNTransport.flush = DSCloudflush;
- MDNTransport.itemsChangedBlock = CFBridgingRetain(^CFArrayRef(CFDictionaryRef values) {
- // default change block doesn't handle messages, keep em
- return CFBridgingRetain(@[]);
- });
- MDNTransport.removeKeys = DSCloudremoveKeys;
- MDNTransport.counters = DSCloudcounters;
-
- SOSCloudTransportSetDefaultTransport(&MDNTransport);
-
- // Create the delegate for the service.
- ServiceDelegate *delegate = [ServiceDelegate new];
- signal(SIGPIPE, SIG_IGN);
-
- // Set up the one NSXPCListener for this service. It will handle all incoming connections.
- NSXPCListener *listener = [NSXPCListener serviceListener];
- listener.delegate = delegate;
-
- // Resuming the serviceListener starts this service. This method does not return.
- [listener resume];
- return 0;
-}