]> git.saurik.com Git - apple/security.git/blob - keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.c
Security-59754.80.3.tar.gz
[apple/security.git] / keychain / SecureObjectSync / CKBridge / SOSCloudKeychainClient.c
1 /*
2 * Copyright (c) 2012-2014 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 /*
25 SOSCloudTransport.c - Implementation of the transport layer from CKBridge to SOSAccount/SOSCircle
26 These are the exported functions from CloudKeychainProxy
27 */
28
29 /*
30 This XPC service is essentially just a proxy to iCloud KVS, which exists since
31 at one time the main security code could not link against Foundation.
32
33 See sendTSARequestWithXPC in tsaSupport.c for how to call the service
34
35 The client of an XPC service does not get connection events, nor does it
36 need to deal with transactions.
37 */
38
39 #include <AssertMacros.h>
40
41 #include <xpc/xpc.h>
42 #include <CoreFoundation/CoreFoundation.h>
43 #include <CoreFoundation/CFXPCBridge.h>
44 #include <sysexits.h>
45 #include <syslog.h>
46 #include <os/activity.h>
47 #include <CoreFoundation/CFUserNotification.h>
48 #include "keychain/SecureObjectSync/SOSInternal.h"
49 #include <notify.h>
50
51 #include <utilities/debugging.h>
52 #include <utilities/SecCFWrappers.h>
53 #include <utilities/SecXPCError.h>
54
55 #include "SOSCloudKeychainConstants.h"
56 #include "SOSCloudKeychainClient.h"
57 #include "SOSUserKeygen.h"
58 #include "SecOTRSession.h"
59
60 #include <os/activity.h>
61 #include <os/state_private.h>
62
63
64 static CFStringRef sErrorDomain = CFSTR("com.apple.security.sos.transport.error");
65
66 #define SOSCKCSCOPE "sync"
67
68 // MARK: ---------- SOSCloudTransport ----------
69
70 static SOSCloudTransportRef SOSCloudTransportCreateXPCTransport(void);
71
72 void SOSCloudTransportGet(SOSCloudTransportRef transport, CFArrayRef keysToGet, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock);
73
74
75
76 /* Return the singleton cloud transport instance. */
77 CFDictionaryRef SOSCloudCopyKVSState(void) {
78 __block CFDictionaryRef retval = NULL;
79
80 static dispatch_queue_t processQueue = NULL;
81 static dispatch_once_t onceToken;
82 dispatch_once(&onceToken, ^{
83 processQueue = dispatch_queue_create("KVSStateCapture", DISPATCH_QUEUE_SERIAL);
84 });
85
86 if (processQueue == NULL)
87 return NULL;
88
89 dispatch_semaphore_t waitSemaphore = NULL;
90
91 waitSemaphore = dispatch_semaphore_create(0);
92
93 CloudKeychainReplyBlock replyBlock = ^ (CFDictionaryRef returnedValues, CFErrorRef error) {
94 retval = returnedValues;
95 if (retval) CFRetain(retval);
96 dispatch_semaphore_signal(waitSemaphore);
97 };
98
99 SOSCloudKeychainGetAllObjectsFromCloud(processQueue, replyBlock);
100
101 dispatch_semaphore_wait(waitSemaphore, DISPATCH_TIME_FOREVER);
102 dispatch_release(waitSemaphore);
103
104 return retval;
105 }
106
107
108 os_state_block_t kvsStateBlock = ^os_state_data_t(os_state_hints_t hints) {
109 os_state_data_t retval = NULL;
110 __block CFDictionaryRef kvsdict = NULL;
111 CFDataRef serializedKVS = NULL;
112
113 require_quiet(hints->osh_api == 3, errOut); // only grab on sysdiagnose or command lin
114
115 kvsdict = SOSCloudCopyKVSState();
116
117 require_quiet(kvsdict, errOut);
118 serializedKVS = CFPropertyListCreateData(kCFAllocatorDefault, kvsdict, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
119 size_t statelen = CFDataGetLength(serializedKVS);
120 retval = (os_state_data_t)calloc(1, OS_STATE_DATA_SIZE_NEEDED(statelen));
121 require_quiet(retval, errOut);
122
123 retval->osd_type = OS_STATE_DATA_SERIALIZED_NSCF_OBJECT;
124 memcpy(retval->osd_data, CFDataGetBytePtr(serializedKVS), statelen);
125 retval->osd_size = statelen;
126 strcpy(retval->osd_title, "CloudCircle KVS Object");
127 errOut:
128 CFReleaseNull(kvsdict);
129 CFReleaseNull(serializedKVS);
130 return retval;
131 };
132
133 static SOSCloudTransportRef defaultTransport = NULL;
134
135 void
136 SOSCloudTransportSetDefaultTransport(SOSCloudTransportRef transport)
137 {
138 defaultTransport = transport;
139 }
140
141 static SOSCloudTransportRef SOSCloudTransportDefaultTransport(void)
142 {
143 static dispatch_once_t sTransportOnce;
144 dispatch_once(&sTransportOnce, ^{
145 if (defaultTransport == NULL) {
146 defaultTransport = SOSCloudTransportCreateXPCTransport();
147 // provide state handler to sysdiagnose and logging
148 os_state_add_handler(dispatch_get_global_queue(SOS_TRANSPORT_PRIORITY, 0), kvsStateBlock);
149 }
150 });
151 return defaultTransport;
152 }
153
154
155 // MARK: ----- utilities -----
156
157 static CFErrorRef makeError(CFIndex which)
158 {
159 CFDictionaryRef userInfo = NULL;
160 return CFErrorCreate(kCFAllocatorDefault, sErrorDomain, which, userInfo);
161 }
162
163 // MARK: ---------- SOSXPCCloudTransport ----------
164
165 typedef struct SOSXPCCloudTransport *SOSXPCCloudTransportRef;
166 struct SOSXPCCloudTransport
167 {
168 struct SOSCloudTransport transport;
169 xpc_connection_t serviceConnection;
170 dispatch_queue_t xpc_queue;
171 };
172
173 static void teardownServiceConnection(SOSXPCCloudTransportRef transport)
174 {
175 secnotice(SOSCKCSCOPE, "CKP Transport: tearing down xpc connection");
176 dispatch_assert_queue(transport->xpc_queue);
177 if (transport->serviceConnection) {
178 xpc_release(transport->serviceConnection);
179 transport->serviceConnection = NULL;
180 }
181 }
182
183 static void setupServiceConnection(SOSXPCCloudTransportRef transport)
184 {
185 secnotice(SOSCKCSCOPE, "CKP Transport: setting up xpc connection");
186 dispatch_assert_queue(transport->xpc_queue);
187
188 transport->serviceConnection = xpc_connection_create_mach_service(kCKPServiceName, transport->xpc_queue, 0);
189
190 secdebug(SOSCKCSCOPE, "serviceConnection: %@", transport->serviceConnection);
191
192 xpc_connection_set_event_handler(transport->serviceConnection, ^(xpc_object_t event) {
193 secdebug(SOSCKCSCOPE, "CKP Transport, xpc_connection_set_event_handler");
194 if(event == XPC_ERROR_CONNECTION_INVALID){
195 secnotice(SOSCKCSCOPE, "CKP Transport: xpc connection invalid. Will tear down connection.");
196 dispatch_async(transport->xpc_queue, ^{
197 teardownServiceConnection(transport);
198 });
199 }
200 });
201
202 xpc_connection_activate(transport->serviceConnection);
203 }
204
205 static void SOSXPCCloudTransportInit(SOSXPCCloudTransportRef transport)
206 {
207 secdebug(SOSCKCSCOPE, "initXPCConnection");
208
209 transport->xpc_queue = dispatch_queue_create(kCKPServiceName, DISPATCH_QUEUE_SERIAL);
210
211 dispatch_sync(transport->xpc_queue, ^{
212 setupServiceConnection(transport);
213 });
214
215 // Any time a new session starts, reestablish the XPC connections.
216 int token;
217 notify_register_dispatch("com.apple.system.loginwindow.desktopUp", &token, transport->xpc_queue, ^(int token2) {
218 secnotice(SOSCKCSCOPE, "CKP Transport: desktopUp happened, reestablishing xpc connections");
219 teardownServiceConnection(transport);
220 });
221 }
222
223 typedef void (^ProxyReplyBlock)(xpc_object_t reply);
224
225 static bool messageToProxy(SOSXPCCloudTransportRef transport, xpc_object_t message, CFErrorRef *error, dispatch_queue_t processQueue, ProxyReplyBlock replyBlock) {
226 __block CFErrorRef connectionError = NULL;
227
228 dispatch_sync(transport->xpc_queue, ^{
229 if (transport->serviceConnection == NULL) {
230 setupServiceConnection(transport);
231 }
232
233 if (transport->serviceConnection && message) {
234 xpc_connection_send_message_with_reply(transport->serviceConnection, message, processQueue, replyBlock);
235 } else {
236 connectionError = makeError(kSOSConnectionNotOpen);
237 }
238 });
239 return CFErrorPropagate(connectionError, error);
240 }
241
242 static void talkWithKVS(SOSXPCCloudTransportRef transport, xpc_object_t message, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
243 {
244 CFErrorRef messagingError = NULL;
245 dispatch_retain(processQueue);
246 bool messaged = messageToProxy(transport, message, &messagingError, transport->xpc_queue, ^(xpc_object_t reply) {
247 CFErrorRef serverError = NULL;
248 CFTypeRef object = NULL;
249
250 if (xpc_get_type(reply) == XPC_TYPE_DICTIONARY) {
251 xpc_object_t xrv = xpc_dictionary_get_value(reply, kMessageKeyValue);
252 if (xrv) {
253 object = _CFXPCCreateCFObjectFromXPCObject(xrv);
254 } else {
255 secerror("missing value reply");
256 }
257
258 xpc_object_t xerror = xpc_dictionary_get_value(reply, kMessageKeyError);
259 if (xerror) {
260 serverError = SecCreateCFErrorWithXPCObject(xerror);
261 }
262 } else {
263 serverError = makeError(kSOSMessageInvalid);
264 secerror("Odd reply from CloudKeychainProxy: %@: %@", reply, serverError);
265 }
266 dispatch_async(processQueue, ^{
267 if (replyBlock) {
268 replyBlock(object, serverError);
269 }
270 CFReleaseSafe(object);
271 if (serverError) {
272 secerror("callback error: %@", serverError);
273 CFReleaseSafe(serverError);
274 }
275 dispatch_release(processQueue);
276 });
277 });
278
279 if (!messaged) {
280 secerror("talkWithKVS error: %@", messagingError);
281 dispatch_async(processQueue, ^{
282 if (replyBlock)
283 replyBlock(NULL, messagingError);
284 CFReleaseSafe(messagingError);
285 dispatch_release(processQueue);
286 });
287 }
288 }
289
290 // MARK: ---------- SOSXPCCloudTransport Client Calls ----------
291
292 /* Concrete function backend implementations. */
293 static void SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportRef transport,
294 CloudItemsChangedBlock itemsChangedBlock) {
295 if (transport->itemsChangedBlock != itemsChangedBlock)
296 {
297 secnotice(SOSCKCSCOPE, "Changing itemsChangedBlock");
298 if (transport->itemsChangedBlock)
299 Block_release(transport->itemsChangedBlock);
300 transport->itemsChangedBlock = Block_copy(itemsChangedBlock);
301 }
302 }
303
304 /* Virtual function backend implementations. */
305 static void SOSCloudTransportPut(SOSCloudTransportRef transport, CFDictionaryRef values, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
306 {
307 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
308 secdebug(SOSCKCSCOPE, "%@", values);
309 CFErrorRef error = NULL;
310 xpc_object_t message = NULL;
311 xpc_object_t xobject = NULL;
312 require_action(values, xit, error = makeError(kSOSObjectNotFoundError));
313
314 message = xpc_dictionary_create(NULL, NULL, 0);
315 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
316 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationPUTDictionary);
317
318 xobject = _CFXPCCreateXPCObjectFromCFObject(values);
319 require_action(xobject, xit, error = makeError(kSOSObjectCantBeConvertedToXPCObject));
320 xpc_dictionary_set_value(message, kMessageKeyValue, xobject);
321 xpc_release(xobject);
322
323 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
324 xpc_release(message);
325 return;
326
327 xit:
328 if (replyBlock)
329 replyBlock(NULL, error);
330 CFReleaseSafe(error);
331 }
332
333 /* Get from KVS */
334 void SOSCloudTransportGet(SOSCloudTransportRef transport, CFArrayRef keysToGet, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
335 {
336 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
337 secdebug(SOSCKCSCOPE, "%@", keysToGet);
338 CFErrorRef error = NULL;
339 xpc_object_t xkeysOfInterest = xpc_dictionary_create(NULL, NULL, 0);
340 xpc_object_t xkeysToGet = keysToGet ? _CFXPCCreateXPCObjectFromCFObject(keysToGet) : xpc_null_create();
341
342 require_action(xkeysToGet, xit, error = makeError(kSOSObjectNotFoundError));
343
344 if (keysToGet) // don't add if nulll; will call getall
345 xpc_dictionary_set_value(xkeysOfInterest, kMessageKeyKeysToGet, xkeysToGet);
346
347 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
348 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
349 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationGETv2);
350 xpc_dictionary_set_value(message, kMessageKeyValue, xkeysOfInterest);
351
352 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
353 xpc_release(xkeysToGet);
354 xpc_release(xkeysOfInterest);
355 xpc_release(message);
356 return;
357
358 xit:
359 if(xkeysOfInterest)
360 xpc_release(xkeysOfInterest);
361 if(xkeysToGet)
362 xpc_release(xkeysToGet);
363 if (replyBlock)
364 replyBlock(NULL, error);
365 CFReleaseSafe(error);
366 }
367
368 //
369 // Handles NULL by seting xpc_null.
370 static void SecXPCDictionarySetCFObject(xpc_object_t xdict, const char *key, CFTypeRef object)
371 {
372 xpc_object_t xpc_obj = object ? _CFXPCCreateXPCObjectFromCFObject(object) : xpc_null_create();
373 xpc_dictionary_set_value(xdict, key, xpc_obj);
374 xpc_release(xpc_obj);
375 }
376
377 static void SOSCloudTransportUpdateKeys(SOSCloudTransportRef transport,
378 CFDictionaryRef keys,
379 CFStringRef accountUUID,
380 dispatch_queue_t processQueue,
381 CloudKeychainReplyBlock replyBlock)
382 {
383 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
384
385 xpc_object_t xkeysOfInterest = xpc_dictionary_create(NULL, NULL, 0);
386 SecXPCDictionarySetCFObject(xkeysOfInterest, kMessageAllKeys, keys);
387
388 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
389 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
390 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationRegisterKeys);
391 xpc_dictionary_set_value(message, kMessageKeyValue, xkeysOfInterest);
392 SecXPCDictionarySetCFObject(message, kMessageKeyAccountUUID, accountUUID);
393
394 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
395 xpc_release(message);
396 xpc_release(xkeysOfInterest);
397 }
398
399 static void SOSCloudTransportRemoveKeys(SOSCloudTransportRef transport,
400 CFArrayRef keys,
401 CFStringRef accountUUID,
402 dispatch_queue_t processQueue,
403 CloudKeychainReplyBlock replyBlock)
404 {
405 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
406
407 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
408 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
409
410 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationRemoveKeys);
411 SecXPCDictionarySetCFObject(message, kMessageKeyAccountUUID, accountUUID);
412 SecXPCDictionarySetCFObject(message, kMessageKeyValue, keys);
413
414 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
415 xpc_release(message);
416 }
417
418 static void SOSCloudTransportGetAll(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
419 {
420 secdebug(SOSCKCSCOPE, "start");
421 SOSCloudTransportGet(transport, NULL, processQueue, replyBlock);
422 }
423
424 static void SOSCloudTransportSync(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
425 {
426 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
427 secdebug(SOSCKCSCOPE, "start");
428 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
429 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
430 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationSynchronize);
431 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
432 xpc_release(message);
433 }
434
435 static void SOSCloudTransportSyncAndWait(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
436 {
437 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
438 secnotice(SOSCKCSCOPE, "%s XPC request to CKD: %s", kWAIT2MINID, kOperationSynchronizeAndWait);
439
440 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
441 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
442 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationSynchronizeAndWait);
443
444 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
445 xpc_release(message);
446 }
447
448 static void SOSCloudTransportClearAll(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
449 {
450 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
451 secdebug(SOSCKCSCOPE, "start");
452 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
453 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
454 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationClearStore);
455 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
456 xpc_release(message);
457 }
458
459 static void SOSCloudTransportRequestSyncWithPeers(SOSCloudTransportRef transport, CFArrayRef /* CFStringRef */ peers, CFArrayRef /* CFStringRef */ backupPeers, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
460 {
461 secdebug(SOSCKCSCOPE, "start");
462 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
463
464 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
465
466 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
467 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationRequestSyncWithPeers);
468
469 SecXPCDictionarySetCFObject(xpcmessage, kMessageKeyPeerIDList, peers);
470 SecXPCDictionarySetCFObject(xpcmessage, kMesssgeKeyBackupPeerIDList, backupPeers);
471
472 talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock);
473
474 xpc_release(xpcmessage);
475 }
476
477
478 static bool SOSCloudTransportHasPendingKey(SOSCloudTransportRef transport, CFStringRef keyName, CFErrorRef* error)
479 {
480 secdebug(SOSCKCSCOPE, "start");
481 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
482
483 __block bool kvsHasMessage = false;
484
485 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
486
487 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
488 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationHasPendingKey);
489
490 SecXPCDictionarySetCFObject(xpcmessage, kMessageKeyKey, keyName);
491
492 dispatch_semaphore_t kvsWait = dispatch_semaphore_create(0);
493 bool kvsSent = messageToProxy(xpcTransport, xpcmessage, error, dispatch_get_global_queue(SOS_TRANSPORT_PRIORITY, 0), ^(xpc_object_t reply) {
494 kvsHasMessage = xpc_dictionary_get_bool(reply, kMessageKeyValue);
495 dispatch_semaphore_signal(kvsWait);
496 });
497
498 if (kvsSent) {
499 dispatch_semaphore_wait(kvsWait, DISPATCH_TIME_FOREVER);
500 }
501
502 dispatch_release(kvsWait);
503
504 return kvsSent && kvsHasMessage;
505 }
506
507
508 static void SOSCloudTransportRequestEnsurePeerRegistration(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
509 {
510 secdebug(SOSCKCSCOPE, "start");
511 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
512
513 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
514 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
515 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationRequestEnsurePeerRegistration);
516
517 talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock);
518
519 xpc_release(xpcmessage);
520 }
521
522 static void SOSCloudTransportRequestPerfCounters(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
523 {
524 secdebug(SOSCKCSCOPE, "start");
525 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
526
527 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
528 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
529 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationPerfCounters);
530
531 talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock);
532
533 xpc_release(xpcmessage);
534 }
535
536
537 static void SOSCloudTransportFlush(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
538 {
539 secdebug(SOSCKCSCOPE, "start");
540 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
541
542 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
543 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
544 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationFlush);
545
546 talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock);
547
548 xpc_release(xpcmessage);
549 }
550
551 static SOSCloudTransportRef SOSCloudTransportCreateXPCTransport(void)
552 {
553 SOSXPCCloudTransportRef st;
554 st = calloc(1, sizeof(*st));
555 st->transport.put = SOSCloudTransportPut;
556 st->transport.updateKeys = SOSCloudTransportUpdateKeys;
557
558 st->transport.get = SOSCloudTransportGet;
559 st->transport.getAll = SOSCloudTransportGetAll;
560 st->transport.synchronize = SOSCloudTransportSync;
561 st->transport.synchronizeAndWait = SOSCloudTransportSyncAndWait;
562 st->transport.clearAll = SOSCloudTransportClearAll;
563 st->transport.requestSyncWithPeers = SOSCloudTransportRequestSyncWithPeers;
564 st->transport.hasPendingKey = SOSCloudTransportHasPendingKey;
565 st->transport.requestEnsurePeerRegistration = SOSCloudTransportRequestEnsurePeerRegistration;
566 st->transport.requestPerfCounters = SOSCloudTransportRequestPerfCounters;
567 st->transport.flush = SOSCloudTransportFlush;
568 st->transport.removeKeys = SOSCloudTransportRemoveKeys;
569 st->transport.itemsChangedBlock = Block_copy(^CFArrayRef(CFDictionaryRef changes) {
570 secerror("Calling default itemsChangedBlock - fatal: %@", changes);
571 assert(false);
572 return NULL;
573 });
574 SOSXPCCloudTransportInit(st);
575 return &st->transport;
576 }
577
578 // MARK: ---------- SOSCloudKeychain concrete client APIs ----------
579 void SOSCloudKeychainSetItemsChangedBlock(CloudItemsChangedBlock itemsChangedBlock)
580 {
581 secdebug(SOSCKCSCOPE, "start");
582 SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportDefaultTransport(),
583 itemsChangedBlock);
584 }
585
586 // MARK: ---------- SOSCloudKeychain virtual client APIs ----------
587
588 void SOSCloudKeychainPutObjectsInCloud(CFDictionaryRef objects, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
589 {
590 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
591 if (cTransportRef)
592 cTransportRef->put(cTransportRef, objects, processQueue, replyBlock);
593 }
594
595 void SOSCloudKeychainUpdateKeys(CFDictionaryRef keys, CFStringRef accountUUID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
596 {
597 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
598 if (cTransportRef)
599 cTransportRef->updateKeys(cTransportRef, keys, accountUUID, processQueue, replyBlock);
600 }
601
602
603 void SOSCloudKeychainRemoveKeys(CFArrayRef keys, CFStringRef accountUUID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
604 {
605 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
606 if (cTransportRef)
607 cTransportRef->removeKeys(cTransportRef, keys, accountUUID, processQueue, replyBlock);
608 }
609
610 CF_RETURNS_RETAINED CFArrayRef SOSCloudKeychainHandleUpdateMessage(CFDictionaryRef updates)
611 {
612 CFArrayRef result = NULL;
613 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
614 if (cTransportRef->itemsChangedBlock)
615 result = ((CloudItemsChangedBlock)cTransportRef->itemsChangedBlock)(updates);
616 return result;
617 }
618
619 void SOSCloudKeychainGetObjectsFromCloud(CFArrayRef keysToGet, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
620 {
621 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
622 if (cTransportRef)
623 cTransportRef->get(cTransportRef, keysToGet, processQueue, replyBlock);
624 }
625
626 void SOSCloudKeychainGetAllObjectsFromCloud(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
627 {
628 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
629 if (cTransportRef)
630 cTransportRef->getAll(cTransportRef, processQueue, replyBlock);
631 }
632
633 void SOSCloudKeychainSynchronizeAndWait(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
634 {
635 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
636 if (cTransportRef)
637 cTransportRef->synchronizeAndWait(cTransportRef, processQueue, replyBlock);
638 }
639
640 //DEBUG ONLY
641 void SOSCloudKeychainSynchronize(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
642 {
643 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
644 if (cTransportRef)
645 cTransportRef->synchronize(cTransportRef, processQueue, replyBlock);
646 }
647
648 //DEBUG ONLY
649 void SOSCloudKeychainClearAll(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
650 {
651 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
652 secnotice("circleOps", "SOSCloudKeychainClearAll called");
653 if (cTransportRef)
654 cTransportRef->clearAll(cTransportRef, processQueue, replyBlock);
655 }
656
657 void SOSCloudKeychainRequestSyncWithPeers(CFArrayRef /* CFStringRef */ peers, CFArrayRef /* CFStringRef */ backupPeers, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
658 {
659 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
660 if (cTransportRef)
661 cTransportRef->requestSyncWithPeers(cTransportRef, peers, backupPeers, processQueue, replyBlock);
662 }
663
664 bool SOSCloudKeychainHasPendingKey(CFStringRef keyName, CFErrorRef* error) {
665 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
666
667 return cTransportRef && cTransportRef->hasPendingKey(cTransportRef, keyName, error);
668 }
669
670 void SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
671 {
672 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
673 if (cTransportRef)
674 cTransportRef->requestEnsurePeerRegistration(cTransportRef, processQueue, replyBlock);
675 }
676
677 void SOSCloudKeychainRequestPerfCounters(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
678 {
679 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
680 if (cTransportRef)
681 cTransportRef->requestPerfCounters(cTransportRef, processQueue, replyBlock);
682 }
683
684
685 void SOSCloudKeychainFlush(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
686 {
687 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
688 if (cTransportRef)
689 cTransportRef->flush(cTransportRef, processQueue, replyBlock);
690 }