]> git.saurik.com Git - apple/security.git/blob - keychain/ckks/CKKSControl.m
Security-59754.80.3.tar.gz
[apple/security.git] / keychain / ckks / CKKSControl.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 #if __OBJC2__
25
26 #import <Foundation/NSXPCConnection_Private.h>
27 #import <xpc/xpc.h>
28
29 #import <Security/SecItemPriv.h>
30
31 #import "keychain/ckks/CKKSControl.h"
32 #import "keychain/ckks/CKKSControlProtocol.h"
33 #import "keychain/ckks/CKKSControlServer.h"
34 #import "utilities/debugging.h"
35
36 @interface CKKSControl ()
37 @property (readwrite,assign) BOOL synchronous;
38 @property xpc_endpoint_t endpoint;
39 @property NSXPCConnection *connection;
40 @end
41
42 @implementation CKKSControl
43
44 - (instancetype)initWithConnection:(NSXPCConnection*)connection {
45 if(self = [super init]) {
46 _connection = connection;
47 }
48 return self;
49 }
50
51 - (void)dealloc {
52 [self.connection invalidate];
53 }
54
55 - (id<CKKSControlProtocol>)objectProxyWithErrorHandler:(void(^)(NSError * _Nonnull error))failureHandler
56 {
57 if (self.synchronous) {
58 return [self.connection synchronousRemoteObjectProxyWithErrorHandler:failureHandler];
59 } else {
60 return [self.connection remoteObjectProxyWithErrorHandler:failureHandler];
61 }
62 }
63
64 - (void)rpcStatus:(NSString*)viewName reply:(void(^)(NSArray<NSDictionary*>* result, NSError* error)) reply {
65 [[self objectProxyWithErrorHandler: ^(NSError* error) {
66 reply(nil, error);
67
68 }] rpcStatus:viewName reply:^(NSArray<NSDictionary*>* result, NSError* error){
69 reply(result, error);
70 }];
71 }
72
73 - (void)rpcFastStatus:(NSString*)viewName reply:(void(^)(NSArray<NSDictionary*>* result, NSError* error)) reply {
74 [[self objectProxyWithErrorHandler: ^(NSError* error) {
75 reply(nil, error);
76
77 }] rpcFastStatus:viewName reply:^(NSArray<NSDictionary*>* result, NSError* error){
78 reply(result, error);
79 }];
80 }
81
82
83 - (void)rpcResetLocal:(NSString*)viewName reply:(void(^)(NSError* error))reply {
84 secnotice("ckkscontrol", "Requesting a local reset for view %@", viewName);
85 [[self objectProxyWithErrorHandler:^(NSError* error) {
86 reply(error);
87 }] rpcResetLocal:viewName reply:^(NSError* error){
88 reply(error);
89 }];
90 }
91
92 - (void)rpcResetCloudKit:(NSString*)viewName reason:(NSString *)reason reply:(void(^)(NSError* error))reply {
93 secnotice("ckkscontrol", "Requesting a CloudKit reset for view %@", viewName);
94 [[self objectProxyWithErrorHandler:^(NSError* error) {
95 reply(error);
96 }] rpcResetCloudKit:viewName reason:reason reply:^(NSError* error){
97 reply(error);
98 }];
99 }
100
101 - (void)rpcResyncLocal:(NSString* _Nullable)viewName reply:(void (^)(NSError* _Nullable error))reply
102 {
103 secnotice("ckkscontrol", "Requesting a local resync for view %@", viewName);
104 [[self objectProxyWithErrorHandler:^(NSError* error) {
105 reply(error);
106 }] rpcResyncLocal:viewName reply:^(NSError* error){
107 reply(error);
108 }];
109 }
110 - (void)rpcResync:(NSString*)viewName reply:(void(^)(NSError* error))reply {
111 secnotice("ckkscontrol", "Requesting a resync for view %@", viewName);
112 [[self objectProxyWithErrorHandler:^(NSError* error) {
113 reply(error);
114 }] rpcResync:viewName reply:^(NSError* error){
115 reply(error);
116 }];
117 }
118 - (void)rpcFetchAndProcessChanges:(NSString*)viewName reply:(void(^)(NSError* error))reply {
119 secnotice("ckkscontrol", "Requesting a fetch for view %@", viewName);
120 [[self objectProxyWithErrorHandler:^(NSError* error) {
121 reply(error);
122 }] rpcFetchAndProcessChanges:viewName reply:^(NSError* error){
123 reply(error);
124 }];
125 }
126 - (void)rpcFetchAndProcessClassAChanges:(NSString*)viewName reply:(void(^)(NSError* error))reply {
127 secnotice("ckkscontrol", "Requesting a fetch(classA) for view %@", viewName);
128 [[self objectProxyWithErrorHandler:^(NSError* error) {
129 reply(error);
130 }] rpcFetchAndProcessClassAChanges:viewName reply:^(NSError* error){
131 reply(error);
132 }];
133 }
134 - (void)rpcPushOutgoingChanges:(NSString*)viewName reply:(void(^)(NSError* error))reply {
135 secnotice("ckkscontrol", "Requesting a push for view %@", viewName);
136 [[self objectProxyWithErrorHandler:^(NSError* error) {
137 reply(error);
138 }] rpcPushOutgoingChanges:viewName reply:^(NSError* error){
139 reply(error);
140 }];
141 }
142
143 - (void)rpcCKMetric:(NSString *)eventName attributes:(NSDictionary *)attributes reply:(void(^)(NSError* error))reply {
144 [[self objectProxyWithErrorHandler:^(NSError* error) {
145 reply(error);
146 }] rpcCKMetric:eventName attributes:attributes reply:^(NSError* error){
147 reply(error);
148 }];
149 }
150
151 - (void)rpcPerformanceCounters:(void(^)(NSDictionary <NSString *,NSNumber *> *,NSError*))reply {
152 [[self objectProxyWithErrorHandler: ^(NSError* error) {
153 reply(nil, error);
154 }] performanceCounters:^(NSDictionary <NSString *, NSNumber *> *counters){
155 reply(counters, nil);
156 }];
157 }
158
159 - (void)rpcGetCKDeviceIDWithReply:(void (^)(NSString *))reply {
160 [[self objectProxyWithErrorHandler:^(NSError * _Nonnull error) {
161 reply(nil);
162 }] rpcGetCKDeviceIDWithReply:^(NSString *ckdeviceID) {
163 reply(ckdeviceID);
164 }];
165 }
166
167 - (void)rpcTLKMissing:(NSString*)viewName reply:(void(^)(bool missing))reply {
168 [self rpcFastStatus:viewName reply:^(NSArray<NSDictionary*>* results, NSError* blockError) {
169 bool missing = false;
170
171 for(NSDictionary* result in results) {
172 NSString* name = result[@"view"];
173 NSString* keystate = result[@"keystate"];
174
175 if([name isEqualToString:@"global"]) {
176 // this is global status; no view implicated
177 continue;
178 }
179
180 if ([keystate isEqualToString:@"waitfortlk"] || [keystate isEqualToString:@"error"]) {
181 missing = true;
182 }
183 }
184
185 reply(missing);
186 }];
187 }
188
189 - (void)rpcKnownBadState:(NSString* _Nullable)viewName reply:(void (^)(CKKSKnownBadState))reply {
190 [self rpcFastStatus:viewName reply:^(NSArray<NSDictionary*>* results, NSError* blockError) {
191 bool tlkMissing = false;
192 bool waitForUnlock = false;
193 bool waitForOctagon = false;
194 bool noAccount = false;
195
196 CKKSKnownBadState response = CKKSKnownStatePossiblyGood;
197
198 for(NSDictionary* result in results) {
199 NSString* name = result[@"view"];
200 NSString* keystate = result[@"keystate"];
201
202 if([name isEqualToString:@"global"]) {
203 // this is global status; no view implicated
204 continue;
205 }
206
207 if ([keystate isEqualToString:@"waitfortlk"] || [keystate isEqualToString:@"error"]) {
208 tlkMissing = true;
209 }
210 if ([keystate isEqualToString:@"waitforunlock"]) {
211 waitForUnlock = true;
212 }
213
214 if([keystate isEqualToString:@"waitfortlkcreation"] ||
215 [keystate isEqualToString:@"waitfortlkupload"] ||
216 [keystate isEqualToString:@"waitfortrust"]) {
217 waitForOctagon = true;
218 }
219
220 if([keystate isEqualToString:@"loggedout"]) {
221 noAccount = true;
222 }
223 }
224
225 response = (noAccount ? CKKSKnownStateNoCloudKitAccount :
226 (tlkMissing ? CKKSKnownStateTLKsMissing :
227 (waitForUnlock ? CKKSKnownStateWaitForUnlock :
228 (waitForOctagon ? CKKSKnownStateWaitForOctagon :
229 CKKSKnownStatePossiblyGood))));
230
231 reply(response);
232 }];
233 }
234
235 + (CKKSControl*)controlObject:(NSError* __autoreleasing *)error {
236 return [CKKSControl CKKSControlObject:NO error:error];
237 }
238
239 + (CKKSControl*)CKKSControlObject:(BOOL)synchronous error:(NSError* __autoreleasing *)error {
240
241 NSXPCConnection* connection = [[NSXPCConnection alloc] initWithMachServiceName:@(kSecuritydCKKSServiceName) options:0];
242
243 if (connection == nil) {
244 if(error) {
245 *error = [NSError errorWithDomain:@"securityd" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Couldn't create connection (no reason given)"}];
246 }
247 return nil;
248 }
249
250 NSXPCInterface *interface = CKKSSetupControlProtocol([NSXPCInterface interfaceWithProtocol:@protocol(CKKSControlProtocol)]);
251 connection.remoteObjectInterface = interface;
252 [connection resume];
253
254 CKKSControl* c = [[CKKSControl alloc] initWithConnection:connection];
255 c.synchronous = synchronous;
256 return c;
257 }
258
259 @end
260
261 #endif // __OBJC2__