/ OSX / sec / ipc / client_endpoint.m
client_endpoint.m
  1  /*
  2   * Copyright (c) 2017 Apple Inc.  All Rights Reserved.
  3   *
  4   * @APPLE_LICENSE_HEADER_START@
  5   *
  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
 11   * file.
 12   *
 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.
 20   *
 21   * @APPLE_LICENSE_HEADER_END@
 22   */
 23  
 24  #import <Foundation/Foundation.h>
 25  #import <Foundation/NSXPCConnection.h>
 26  #import <Foundation/NSXPCConnection_Private.h>
 27  #import <objc/runtime.h>
 28  #import <utilities/debugging.h>
 29  #import <Security/SecXPCHelper.h>
 30  
 31  #include <ipc/securityd_client.h>
 32  
 33  @implementation SecuritydXPCClient
 34  @synthesize connection = _connection;
 35  
 36  - (instancetype) init
 37  {
 38      if ((self = [super init])) {
 39          NSXPCInterface *interface = [NSXPCInterface interfaceWithProtocol:@protocol(SecuritydXPCProtocol)];
 40  
 41          self.connection = [[NSXPCConnection alloc] initWithMachServiceName:@(kSecuritydGeneralServiceName) options:0];
 42          if (self.connection == NULL) {
 43              return NULL;
 44          }
 45  
 46          self.connection.remoteObjectInterface = interface;
 47          [SecuritydXPCClient configureSecuritydXPCProtocol: self.connection.remoteObjectInterface];
 48  
 49          [self.connection resume];
 50      }
 51  
 52      return self;
 53  }
 54  
 55  +(void)configureSecuritydXPCProtocol: (NSXPCInterface*) interface {
 56      NSXPCInterface *rpcCallbackInterface = [NSXPCInterface interfaceWithProtocol: @protocol(SecuritydXPCCallbackProtocol)];
 57      [interface setInterface:rpcCallbackInterface
 58                  forSelector:@selector(SecItemAddAndNotifyOnSync:syncCallback:complete:)
 59                argumentIndex:1
 60                      ofReply:0];
 61  
 62  #if OCTAGON
 63      NSSet<Class> *errClasses = [SecXPCHelper safeErrorClasses];
 64  
 65      @try {
 66          [rpcCallbackInterface setClasses:errClasses forSelector:@selector(callCallback:error:) argumentIndex:1 ofReply:NO];
 67  
 68          [interface setClasses:errClasses forSelector:@selector(SecItemAddAndNotifyOnSync:
 69                                                                 syncCallback:
 70                                                                 complete:) argumentIndex:2 ofReply:YES];
 71          [interface setClasses:errClasses forSelector:@selector(secItemSetCurrentItemAcrossAllDevices:
 72                                                                 newCurrentItemHash:
 73                                                                 accessGroup:
 74                                                                 identifier:
 75                                                                 viewHint:
 76                                                                 oldCurrentItemReference:
 77                                                                 oldCurrentItemHash:
 78                                                                 complete:) argumentIndex:0 ofReply:YES];
 79          [interface setClasses:errClasses forSelector:@selector(secItemFetchCurrentItemAcrossAllDevices:
 80                                                                 identifier:
 81                                                                 viewHint:
 82                                                                 fetchCloudValue:
 83                                                                 complete:) argumentIndex:1 ofReply:YES];
 84          [interface setClasses:errClasses forSelector:@selector(secItemDigest:
 85                                                                 accessGroup:
 86                                                                 complete:) argumentIndex:1 ofReply:YES];
 87          [interface setClasses:errClasses forSelector:@selector(secKeychainDeleteMultiuser:complete:) argumentIndex:1 ofReply:YES];
 88          [interface setClasses:errClasses forSelector:@selector(secItemVerifyBackupIntegrity:completion:) argumentIndex:1 ofReply:YES];
 89  
 90      }
 91      @catch(NSException* e) {
 92          secerror("Could not configure SecuritydXPCProtocol: %@", e);
 93          @throw e;
 94      }
 95  #endif // OCTAGON
 96  }
 97  @end
 98  
 99  @implementation SecuritydXPCCallback
100  @synthesize callback = _callback;
101  
102  -(instancetype)initWithCallback: (SecBoolNSErrorCallback) callback {
103      if((self = [super init])) {
104          _callback = callback;
105      }
106      return self;
107  }
108  
109  - (void)callCallback: (bool) result error:(NSError*) error {
110      self.callback(result, error);
111  }
112  @end
113  
114  id<SecuritydXPCProtocol> SecuritydXPCProxyObject(bool synchronous, void (^rpcErrorHandler)(NSError *))
115  {
116      if (gSecurityd && gSecurityd->secd_xpc_server) {
117          return (__bridge id<SecuritydXPCProtocol>)gSecurityd->secd_xpc_server;
118      }
119  
120      static SecuritydXPCClient* rpc;
121      static dispatch_once_t onceToken;
122  
123      dispatch_once(&onceToken, ^{
124          rpc = [[SecuritydXPCClient alloc] init];
125      });
126  
127      if (rpc == NULL) {
128          rpcErrorHandler([NSError errorWithDomain:@"securityd" code:-1 userInfo:@{ NSLocalizedDescriptionKey : @"Could not create SecuritydXPCClient" }]);
129          return NULL;
130      } else {
131          if (synchronous) {
132              return [rpc.connection synchronousRemoteObjectProxyWithErrorHandler:rpcErrorHandler];
133          } else {
134              return [rpc.connection remoteObjectProxyWithErrorHandler:rpcErrorHandler];
135          }
136      }
137  }
138