]> git.saurik.com Git - apple/security.git/blob - OSX/sec/ipc/client_endpoint.m
Security-58286.1.32.tar.gz
[apple/security.git] / OSX / sec / ipc / 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
30 #include <ipc/securityd_client.h>
31
32 @implementation SecuritydXPCClient
33 @synthesize connection = _connection;
34
35 - (instancetype) initWithEndpoint:(xpc_endpoint_t)endpoint
36 {
37 if ((self = [super init])) {
38 NSXPCInterface *interface = [NSXPCInterface interfaceWithProtocol:@protocol(SecuritydXPCProtocol)];
39 NSXPCListenerEndpoint *listenerEndpoint = [[NSXPCListenerEndpoint alloc] init];
40
41 [listenerEndpoint _setEndpoint:endpoint];
42
43 self.connection = [[NSXPCConnection alloc] initWithListenerEndpoint:listenerEndpoint];
44 if (self.connection == NULL) {
45 return NULL;
46 }
47
48 self.connection.remoteObjectInterface = interface;
49 [SecuritydXPCClient configureSecuritydXPCProtocol: self.connection.remoteObjectInterface];
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 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
68
69 errClasses = [[NSMutableSet alloc] init];
70 char *classes[] = {
71 "NSError",
72 "NSArray",
73 "NSString",
74 "NSNumber",
75 "NSData",
76 "NSDate",
77 "CKReference",
78 "CKAsset",
79 "CLLocation",
80 "CKPackage",
81 "CKArchivedAnchoredPackage",
82 "CKPrettyError",
83 "CKRecordID",
84 "NSURL",
85 };
86
87 for (unsigned n = 0; n < sizeof(classes)/sizeof(classes[0]); n++) {
88 Class cls = objc_getClass(classes[n]);
89 if (cls) {
90 [errClasses addObject:cls];
91 }
92 }
93 });
94
95 @try {
96 [rpcCallbackInterface setClasses:errClasses forSelector:@selector(callCallback:error:) argumentIndex:1 ofReply:NO];
97
98 [interface setClasses:errClasses forSelector:@selector(SecItemAddAndNotifyOnSync:
99 syncCallback:
100 complete:) argumentIndex:2 ofReply:YES];
101 [interface setClasses:errClasses forSelector:@selector(secItemFetchCurrentItemAcrossAllDevices:
102 identifier:
103 viewHint:
104 fetchCloudValue:
105 complete:) argumentIndex:1 ofReply:YES];
106 [interface setClasses:errClasses forSelector:@selector(secItemDigest:
107 accessGroup:
108 complete:) argumentIndex:1 ofReply:YES];
109 [interface setClasses:errClasses forSelector:@selector(secItemSetCurrentItemAcrossAllDevices:
110 newCurrentItemHash:
111 accessGroup:
112 identifier:
113 viewHint:
114 oldCurrentItemReference:
115 oldCurrentItemHash:
116 complete:) argumentIndex:0 ofReply:YES];
117 }
118 @catch(NSException* e) {
119 secerror("Could not configure SecuritydXPCProtocol: %@", e);
120 #if DEBUG
121 @throw e;
122 #endif // DEBUG
123 }
124 #endif // OCTAGON
125 }
126 @end
127
128 @implementation SecuritydXPCCallback
129 @synthesize callback = _callback;
130
131 -(instancetype)initWithCallback: (SecBoolNSErrorCallback) callback {
132 if((self = [super init])) {
133 _callback = callback;
134 }
135 return self;
136 }
137
138 - (void)callCallback: (bool) result error:(NSError*) error {
139 self.callback(result, error);
140 }
141 @end
142
143 id<SecuritydXPCProtocol> SecuritydXPCProxyObject(void (^rpcErrorHandler)(NSError *))
144 {
145 if (gSecurityd && gSecurityd->secd_xpc_server) {
146 return (__bridge id<SecuritydXPCProtocol>)gSecurityd->secd_xpc_server;
147 }
148
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;
154
155 dispatch_once(&onceToken, ^{
156 queue = dispatch_queue_create("SecuritydXPCProxyObject", DISPATCH_QUEUE_SERIAL);
157 });
158
159 dispatch_sync(queue, ^{
160 if (rpc) {
161 result = rpc;
162 return;
163 }
164
165 xpc_endpoint_t endpoint = _SecSecuritydCopyEndpoint(kSecXPCOpSecuritydXPCServerEndpoint, &cferror);
166 if (endpoint == NULL) {
167 return;
168 }
169 rpc = [[SecuritydXPCClient alloc] initWithEndpoint:endpoint];
170 rpc.connection.invalidationHandler = ^{
171 dispatch_sync(queue, ^{
172 rpc = nil;
173 });
174 };
175 [rpc.connection resume];
176
177 result = rpc;
178 });
179
180 if (result == NULL) {
181 rpcErrorHandler((__bridge NSError *)cferror);
182 return NULL;
183 } else {
184 return [result.connection remoteObjectProxyWithErrorHandler: rpcErrorHandler];
185 }
186 }
187