/ keychain / SecureObjectSync / SOSControlServer.m
SOSControlServer.m
  1  #import <Foundation/Foundation.h>
  2  #import <Foundation/NSXPCConnection_Private.h>
  3  #import <Security/SecEntitlements.h>
  4  #import <ipc/securityd_client.h>
  5  #import "SOSAccount.h"
  6  #import "SOSControlHelper.h"
  7  #import "SOSControlServer.h"
  8  
  9  @interface SOSControlServer : NSObject <NSXPCListenerDelegate>
 10  @end
 11  
 12  @interface SOSClient ()
 13  @property (strong) SOSAccount * account;
 14  - (instancetype)initSOSClientWithAccount:(SOSAccount *)account;
 15  - (bool)checkEntitlement:(NSString *)entitlement;
 16  @end
 17  
 18  @interface SOSClientRemote : SOSClient
 19  @property (weak) NSXPCConnection * connection;
 20  - (instancetype)initSOSConnectionWithConnection:(NSXPCConnection *)connection account:(SOSAccount *)account;
 21  @end
 22  
 23  @implementation SOSControlServer
 24  
 25  - (BOOL)listener:(__unused NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection
 26  {
 27      NSNumber *num = [newConnection valueForEntitlement:(__bridge NSString *)kSecEntitlementKeychainCloudCircle];
 28      if (![num isKindOfClass:[NSNumber class]] || ![num boolValue]) {
 29          secerror("sos: Client pid: %d doesn't have entitlement: %@",
 30                  [newConnection processIdentifier], kSecEntitlementKeychainCloudCircle);
 31          return NO;
 32      }
 33  
 34      SOSAccount *account = (__bridge SOSAccount *)SOSKeychainAccountGetSharedAccount();
 35      if (account == nil) {
 36          secerror("sos: SOS have not launched yet, come later, pid: %d",
 37                  [newConnection processIdentifier]);
 38          return NO;
 39      }
 40  
 41      SOSClientRemote *sosClient = [[SOSClientRemote alloc] initSOSConnectionWithConnection:newConnection account:account];
 42  
 43      newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(SOSControlProtocol)];
 44      _SOSControlSetupInterface(newConnection.exportedInterface);
 45      newConnection.exportedObject = sosClient;
 46  
 47      [newConnection resume];
 48  
 49      return YES;
 50  }
 51  
 52  - (SOSClient *)internalSOSClient
 53  {
 54      return [[SOSClient alloc] initSOSClientWithAccount:(__bridge SOSAccount *)SOSKeychainAccountGetSharedAccount()];
 55  }
 56  
 57  @end
 58  
 59  @implementation SOSClient
 60  
 61  @synthesize account = _account;
 62  
 63  - (instancetype)initSOSClientWithAccount:(SOSAccount *)account
 64  {
 65      if ((self = [super init])) {
 66          _account = account;
 67      }
 68      return self;
 69  }
 70  
 71  - (bool)checkEntitlement:(NSString *)entitlement
 72  {
 73      return true;
 74  }
 75  
 76  - (void)userPublicKey:(void ((^))(BOOL trusted, NSData *spki, NSError *error))reply
 77  {
 78      [self.account userPublicKey:reply];
 79  }
 80  
 81  - (void)kvsPerformanceCounters:(void(^)(NSDictionary <NSString *, NSNumber *> *))reply
 82  {
 83      [self.account kvsPerformanceCounters:reply];
 84  }
 85  
 86  - (void)rateLimitingPerformanceCounters:(void(^)(NSDictionary <NSString *, NSString *> *))reply
 87  {
 88      [self.account rateLimitingPerformanceCounters:reply];
 89  }
 90  
 91  - (void)stashedCredentialPublicKey:(void(^)(NSData *, NSError *error))reply
 92  {
 93      [self.account stashedCredentialPublicKey:reply];
 94  }
 95  
 96  - (void)assertStashedAccountCredential:(void(^)(BOOL result, NSError *error))reply
 97  {
 98      [self.account assertStashedAccountCredential:reply];
 99  }
100  
101  - (void)validatedStashedAccountCredential:(void(^)(NSData *credential, NSError *error))complete
102  {
103      [self.account validatedStashedAccountCredential:complete];
104  }
105  
106  - (void)stashAccountCredential:(NSData *)credential complete:(void(^)(bool success, NSError *error))complete
107  {
108      [self.account stashAccountCredential:credential complete:complete];
109  }
110  
111  - (void)myPeerInfo:(void (^)(NSData *, NSError *))complete
112  {
113      [self.account myPeerInfo:complete];
114  }
115  
116  - (void)circleHash:(void (^)(NSString *, NSError *))complete
117  {
118      [self.account circleHash:complete];
119  }
120  
121  
122  - (void)circleJoiningBlob:(NSData *)applicant complete:(void (^)(NSData *blob, NSError *))complete
123  {
124      [self.account circleJoiningBlob:applicant complete:complete];
125  }
126  
127  - (void)joinCircleWithBlob:(NSData *)blob version:(PiggyBackProtocolVersion)version complete:(void (^)(bool success, NSError *))complete
128  {
129      [self.account joinCircleWithBlob:blob version:version complete:complete];
130  }
131  
132  - (void)initialSyncCredentials:(uint32_t)flags complete:(void (^)(NSArray *, NSError *))complete
133  {
134      if (![self checkEntitlement:(__bridge NSString *)kSecEntitlementKeychainInitialSync]) {
135          complete(@[], [NSError errorWithDomain:(__bridge NSString *)kSOSErrorDomain code:kSOSEntitlementMissing userInfo:NULL]);
136          return;
137      }
138  
139      [self.account initialSyncCredentials:flags complete:complete];
140  }
141  
142  - (void)importInitialSyncCredentials:(NSArray *)items complete:(void (^)(bool success, NSError *))complete
143  {
144      if (![self checkEntitlement:(__bridge NSString *)kSecEntitlementKeychainInitialSync]) {
145          complete(false, [NSError errorWithDomain:(__bridge NSString *)kSOSErrorDomain code:kSOSEntitlementMissing userInfo:NULL]);
146          return;
147      }
148  
149      [self.account importInitialSyncCredentials:items complete:complete];
150  }
151  
152  - (void)rpcTriggerSync:(NSArray <NSString *> *)peers complete:(void(^)(bool success, NSError *))complete
153  {
154      [self.account rpcTriggerSync:peers complete:complete];
155  }
156  
157  - (void)getWatchdogParameters:(void (^)(NSDictionary* parameters, NSError* error))complete
158  {
159      [self.account getWatchdogParameters:complete];
160  }
161  
162  - (void)setWatchdogParmeters:(NSDictionary*)parameters complete:(void (^)(NSError* error))complete
163  {
164      [self.account setWatchdogParmeters:parameters complete:complete];
165  }
166  
167  - (void) ghostBust:(SOSAccountGhostBustingOptions)options complete: (void(^)(bool ghostBusted, NSError *error))complete {
168      [self.account ghostBust:options complete:complete];
169  }
170  
171  - (void)ghostBustTriggerTimed:(SOSAccountGhostBustingOptions)options complete: (void(^)(bool ghostBusted, NSError *error))complete {
172      [self.account ghostBustTriggerTimed:options complete:complete];
173  }
174  
175  - (void) ghostBustPeriodic:(SOSAccountGhostBustingOptions)options complete: (void(^)(bool busted, NSError *error))complete {
176      [self.account ghostBustPeriodic:options complete:complete];
177  }
178  
179  - (void) ghostBustInfo: (void(^)(NSData *json, NSError *error))complete {
180      [self.account ghostBustInfo:complete];
181  }
182  
183  - (void)iCloudIdentityStatus: (void (^)(NSData *json, NSError *error))complete {
184      [self.account iCloudIdentityStatus: complete];
185  }
186  
187  - (void)rpcTriggerBackup:(NSArray<NSString *>* _Nullable)backupPeers complete:(void (^)(NSError *error))complete
188  {
189      [self.account rpcTriggerBackup:backupPeers complete:complete];
190  }
191  
192  - (void)rpcTriggerRingUpdate:(void (^)(NSError *))complete {
193      [self.account rpcTriggerRingUpdate:complete];
194  }
195  
196  - (void)iCloudIdentityStatus_internal:(void (^)(NSDictionary *, NSError *))complete {
197      [self.account iCloudIdentityStatus_internal:complete];
198  }
199  
200  - (void)removeV0Peers:(void (^)(bool, NSError *))reply { 
201      [self.account removeV0Peers:reply];
202  }
203  
204  
205  
206  @end
207  
208  @implementation SOSClientRemote
209  
210  - (instancetype)initSOSConnectionWithConnection:(NSXPCConnection *)connection account:(SOSAccount *)account
211  {
212      if ((self = [super initSOSClientWithAccount:account])) {
213          self.connection = connection;
214      }
215      return self;
216  }
217  
218  - (bool)checkEntitlement:(NSString *)entitlement
219  {
220      NSXPCConnection *strongConnection = _connection;
221  
222      NSNumber *num = [strongConnection valueForEntitlement:entitlement];
223      if (![num isKindOfClass:[NSNumber class]] || ![num boolValue]) {
224          secerror("sos: Client pid: %d doesn't have entitlement: %@",
225                   [strongConnection processIdentifier], entitlement);
226          return false;
227      }
228      return true;
229  }
230  @end
231  
232  static SOSControlServer *sosServer;
233  
234  void
235  SOSControlServerInitialize(void)
236  {
237      static dispatch_once_t once;
238      static NSXPCListener *listener;
239  
240      dispatch_once(&once, ^{
241          @autoreleasepool {
242              sosServer = [SOSControlServer new];
243  
244              listener = [[NSXPCListener alloc] initWithMachServiceName:@(kSecuritydSOSServiceName)];
245              listener.delegate = sosServer;
246              [listener resume];
247          }
248      });
249  }
250  
251  SOSClient *
252  SOSControlServerInternalClient(void)
253  {
254      SOSControlServerInitialize();
255      return [sosServer internalSOSClient];
256  }