2 * Copyright (c) 2017 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
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>
30 #include <ipc/securityd_client.h>
32 @implementation SecuritydXPCClient
33 @synthesize connection = _connection;
35 - (instancetype) initWithEndpoint:(xpc_endpoint_t)endpoint
37 if ((self = [super init])) {
38 NSXPCInterface *interface = [NSXPCInterface interfaceWithProtocol:@protocol(SecuritydXPCProtocol)];
39 NSXPCListenerEndpoint *listenerEndpoint = [[NSXPCListenerEndpoint alloc] init];
41 [listenerEndpoint _setEndpoint:endpoint];
43 self.connection = [[NSXPCConnection alloc] initWithListenerEndpoint:listenerEndpoint];
44 if (self.connection == NULL) {
48 self.connection.remoteObjectInterface = interface;
49 [SecuritydXPCClient configureSecuritydXPCProtocol: self.connection.remoteObjectInterface];
55 +(void)configureSecuritydXPCProtocol: (NSXPCInterface*) interface {
56 NSXPCInterface *rpcCallbackInterface = [NSXPCInterface interfaceWithProtocol: @protocol(SecuritydXPCCallbackProtocol)];
57 [interface setInterface:rpcCallbackInterface
58 forSelector:@selector(SecItemAddAndNotifyOnSync:syncCallback:complete:)
63 static NSMutableSet *errClasses;
64 static dispatch_once_t onceToken;
65 dispatch_once(&onceToken, ^{
66 // By finding classes by strings at runtime, we'll only get the CloudKit helpers if you link CloudKit
67 // Plus, we don't have to weak-link cloudkit from Security.framework
69 errClasses = [[NSMutableSet alloc] init];
81 "CKArchivedAnchoredPackage",
87 for (unsigned n = 0; n < sizeof(classes)/sizeof(classes[0]); n++) {
88 Class cls = objc_getClass(classes[n]);
90 [errClasses addObject:cls];
96 [rpcCallbackInterface setClasses:errClasses forSelector:@selector(callCallback:error:) argumentIndex:1 ofReply:NO];
98 [interface setClasses:errClasses forSelector:@selector(SecItemAddAndNotifyOnSync:
100 complete:) argumentIndex:2 ofReply:YES];
101 [interface setClasses:errClasses forSelector:@selector(secItemFetchCurrentItemAcrossAllDevices:
105 complete:) argumentIndex:1 ofReply:YES];
106 [interface setClasses:errClasses forSelector:@selector(secItemDigest:
108 complete:) argumentIndex:1 ofReply:YES];
109 [interface setClasses:errClasses forSelector:@selector(secItemSetCurrentItemAcrossAllDevices:
114 oldCurrentItemReference:
116 complete:) argumentIndex:0 ofReply:YES];
118 @catch(NSException* e) {
119 secerror("Could not configure SecuritydXPCProtocol: %@", e);
128 @implementation SecuritydXPCCallback
129 @synthesize callback = _callback;
131 -(instancetype)initWithCallback: (SecBoolNSErrorCallback) callback {
132 if((self = [super init])) {
133 _callback = callback;
138 - (void)callCallback: (bool) result error:(NSError*) error {
139 self.callback(result, error);
143 id<SecuritydXPCProtocol> SecuritydXPCProxyObject(void (^rpcErrorHandler)(NSError *))
145 if (gSecurityd && gSecurityd->secd_xpc_server) {
146 return (__bridge id<SecuritydXPCProtocol>)gSecurityd->secd_xpc_server;
149 static SecuritydXPCClient* rpc;
150 static dispatch_once_t onceToken;
151 static CFErrorRef cferror = NULL;
152 static dispatch_queue_t queue;
153 __block SecuritydXPCClient *result = nil;
155 dispatch_once(&onceToken, ^{
156 queue = dispatch_queue_create("SecuritydXPCProxyObject", DISPATCH_QUEUE_SERIAL);
159 dispatch_sync(queue, ^{
165 xpc_endpoint_t endpoint = _SecSecuritydCopyEndpoint(kSecXPCOpSecuritydXPCServerEndpoint, &cferror);
166 if (endpoint == NULL) {
169 rpc = [[SecuritydXPCClient alloc] initWithEndpoint:endpoint];
170 rpc.connection.invalidationHandler = ^{
171 dispatch_sync(queue, ^{
175 [rpc.connection resume];
180 if (result == NULL) {
181 rpcErrorHandler((__bridge NSError *)cferror);
184 return [result.connection remoteObjectProxyWithErrorHandler: rpcErrorHandler];