]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainClient.c
Security-58286.51.6.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / 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 <Security/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
134 static SOSCloudTransportRef SOSCloudTransportDefaultTransport(void)
135 {
136 static dispatch_once_t sTransportOnce;
137 static SOSCloudTransportRef sTransport = NULL;
138 dispatch_once(&sTransportOnce, ^{
139 sTransport = SOSCloudTransportCreateXPCTransport();
140 // provide state handler to sysdiagnose and logging
141 os_state_add_handler(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), kvsStateBlock);
142 });
143 return sTransport;
144 }
145
146
147 // MARK: ----- utilities -----
148
149 static CFErrorRef makeError(CFIndex which)
150 {
151 CFDictionaryRef userInfo = NULL;
152 return CFErrorCreate(kCFAllocatorDefault, sErrorDomain, which, userInfo);
153 }
154
155 // MARK: ----- DEBUG Utilities -----
156
157 //------------------------------------------------------------------------------------------------
158 // DEBUG only
159 //------------------------------------------------------------------------------------------------
160
161 static void describeXPCObject(char *prefix, xpc_object_t object)
162 {
163 //#ifndef NDEBUG
164 // This is useful for debugging.
165 if (object)
166 {
167 char *desc = xpc_copy_description(object);
168 secdebug(SOSCKCSCOPE, "%s%s\n", prefix, desc);
169 free(desc);
170 }
171 else
172 secdebug(SOSCKCSCOPE, "%s<NULL>\n", prefix);
173 //#endif
174 }
175
176 static void describeXPCType(char *prefix, xpc_type_t xtype)
177 {
178 // Add others as necessary, e.g. XPC_TYPE_DOUBLE
179 #ifndef NDEBUG
180 // This is useful for debugging.
181 char msg[256]={0,};
182 if (XPC_TYPE_CONNECTION == xtype)
183 strcpy(msg, "XPC_TYPE_CONNECTION");
184 else if (XPC_TYPE_ERROR == xtype)
185 strcpy(msg, "XPC_TYPE_ERROR");
186 else if (XPC_TYPE_DICTIONARY == xtype)
187 strcpy(msg, "XPC_TYPE_DICTIONARY");
188 else
189 strcpy(msg, "<unknown>");
190
191 secdebug(SOSCKCSCOPE, "%s type:%s\n", prefix, msg);
192 #endif
193 }
194
195 // MARK: ---------- SOSXPCCloudTransport ----------
196
197 typedef struct SOSXPCCloudTransport *SOSXPCCloudTransportRef;
198 struct SOSXPCCloudTransport
199 {
200 struct SOSCloudTransport transport;
201 xpc_connection_t serviceConnection;
202 xpc_connection_t idsProxyServiceConnection;
203 dispatch_queue_t xpc_queue;
204 };
205
206 static bool xpc_event_filter(const xpc_connection_t peer, xpc_object_t event, CFErrorRef *error)
207 {
208 // return true if the type is XPC_TYPE_DICTIONARY (and therefore something more to process)
209 secdebug(SOSCKCSCOPE, "handle_connection_event\n");
210 xpc_type_t xtype = xpc_get_type(event);
211 describeXPCType("handle_xpc_event", xtype);
212 if (XPC_TYPE_CONNECTION == xtype)
213 {
214 secdebug(SOSCKCSCOPE, "handle_xpc_event: XPC_TYPE_CONNECTION (unexpected)");
215 // The client of an XPC service does not get connection events
216 // For now, we log this and keep going
217 describeXPCObject("handle_xpc_event: XPC_TYPE_CONNECTION, obj : ", event);
218 }
219 else
220 if (XPC_TYPE_ERROR == xtype)
221 {
222 #ifndef NDEBUG
223 const char *estr = xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION);
224 #endif
225 secdebug(SOSCKCSCOPE, "default: xpc error: %s\n", estr);
226 }
227 else
228 if (XPC_TYPE_DICTIONARY == xtype)
229 {
230 secdebug(SOSCKCSCOPE, "received dictionary event %p\n", event);
231 return true;
232 }
233 else
234 {
235 secdebug(SOSCKCSCOPE, "default: unexpected connection event %p\n", event);
236 describeXPCObject("handle_xpc_event: obj : ", event);
237 if (error)
238 *error = makeError(kSOSOUnexpectedXPCEvent);
239 }
240 return false;
241 }
242
243 static void setupIDSProxyServiceConnection(SOSXPCCloudTransportRef transport)
244 {
245 secnotice(SOSCKCSCOPE, "IDS Transport: setting up xpc connection");
246 transport->idsProxyServiceConnection = xpc_connection_create_mach_service(xpcIDSServiceName, transport->xpc_queue, 0);
247
248 secdebug(SOSCKCSCOPE, "ids service connection: %p\n", transport->idsProxyServiceConnection);
249
250 xpc_connection_set_event_handler(transport->idsProxyServiceConnection, ^(xpc_object_t event) {
251 secdebug(SOSCKCSCOPE, "IDS Transport, xpc_connection_set_event_handler\n");
252 if(event == XPC_ERROR_CONNECTION_INVALID){
253 secnotice(SOSCKCSCOPE, "IDS Transport: xpc connection invalid. Oh well.");
254 }
255 });
256
257 xpc_connection_activate(transport->idsProxyServiceConnection);
258 }
259
260 static void teardownIDSProxyServiceConnection(SOSXPCCloudTransportRef transport)
261 {
262 secnotice(SOSCKCSCOPE, "IDS Transport: tearing down xpc connection");
263 dispatch_assert_queue(transport->xpc_queue);
264 xpc_release(transport->idsProxyServiceConnection);
265 transport->idsProxyServiceConnection = NULL;
266 }
267
268 static void setupServiceConnection(SOSXPCCloudTransportRef transport)
269 {
270 secnotice(SOSCKCSCOPE, "CKP Transport: setting up xpc connection");
271 transport->serviceConnection = xpc_connection_create_mach_service(xpcServiceName, transport->xpc_queue, 0);
272
273 secdebug(SOSCKCSCOPE, "serviceConnection: %p\n", transport->serviceConnection);
274
275 xpc_connection_set_event_handler(transport->serviceConnection, ^(xpc_object_t event) {
276 secdebug(SOSCKCSCOPE, "CKP Transport, xpc_connection_set_event_handler\n");
277 if(event == XPC_ERROR_CONNECTION_INVALID){
278 secnotice(SOSCKCSCOPE, "CKP Transport: xpc connection invalid. Oh well.");
279 }
280 });
281
282 xpc_connection_activate(transport->serviceConnection);
283 }
284
285 static void teardownServiceConnection(SOSXPCCloudTransportRef transport)
286 {
287 secnotice(SOSCKCSCOPE, "CKP Transport: tearing down xpc connection");
288 dispatch_assert_queue(transport->xpc_queue);
289 xpc_release(transport->serviceConnection);
290 transport->serviceConnection = NULL;
291 }
292
293 static void SOSXPCCloudTransportInit(SOSXPCCloudTransportRef transport)
294 {
295 secdebug(SOSCKCSCOPE, "initXPCConnection\n");
296
297 transport->xpc_queue = dispatch_queue_create(xpcServiceName, DISPATCH_QUEUE_SERIAL);
298
299 setupServiceConnection(transport);
300 setupIDSProxyServiceConnection(transport);
301
302 // Any time a new session starts, reestablish the XPC connections.
303 int token;
304 notify_register_dispatch("com.apple.system.loginwindow.desktopUp", &token, transport->xpc_queue, ^(int token2) {
305 secnotice(SOSCKCSCOPE, "CKP/IDS Transport: desktopUp happened, reestablishing xpc connections");
306 teardownServiceConnection(transport);
307 setupServiceConnection(transport);
308 teardownIDSProxyServiceConnection(transport);
309 setupIDSProxyServiceConnection(transport);
310 });
311 }
312
313 static void talkWithIDS(SOSXPCCloudTransportRef transport, xpc_object_t message, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
314 {
315 CFErrorRef connectionError = NULL;
316
317 os_activity_t trace_activity = os_activity_start("talkWithIDS", OS_ACTIVITY_FLAG_DEFAULT);
318 require_action(transport->idsProxyServiceConnection, xit, connectionError = makeError(kSOSConnectionNotOpen));
319 require_action(message, xit, connectionError = makeError(kSOSObjectNotFoundError));
320 dispatch_retain(processQueue);
321
322 xpc_connection_send_message_with_reply(transport->idsProxyServiceConnection, message, transport->xpc_queue, ^(xpc_object_t reply)
323 {
324 CFErrorRef serverError = NULL;
325 CFTypeRef object = NULL;
326 if (xpc_event_filter(transport->idsProxyServiceConnection, reply, &serverError) && reply)
327 {
328 if (serverError)
329 secerror("Error from xpc_event_filter: %@", serverError);
330 xpc_object_t xrv = xpc_dictionary_get_value(reply, kMessageKeyValue);
331 if (xrv)
332 {
333 /*
334 * The given XPC object must be one that was previously returned by
335 * _CFXPCCreateXPCMessageWithCFObject().
336 */
337 object = _CFXPCCreateCFObjectFromXPCObject(xrv); // CF object is retained; release in callback
338 secnotice("talkwithIDS", "converted CF object: %@", object);
339 }
340 else
341 secerror("missing value reply");
342
343 xpc_object_t xerror = xpc_dictionary_get_value(reply, kMessageKeyError);
344 if (xerror)
345 serverError = SecCreateCFErrorWithXPCObject(xerror); // use SecCFCreateErrorWithFormat?
346 }
347 dispatch_async(processQueue, ^{
348 if (replyBlock)
349 replyBlock(object, serverError);
350 CFReleaseSafe(object);
351 if (serverError)
352 {
353 secerror("talkwithIDS callback error: %@", serverError);
354 CFReleaseSafe(serverError);
355 }
356 dispatch_release(processQueue);
357 });
358 });
359 return;
360
361 xit:
362 secerror("talkWithIDS error: %@", connectionError);
363 dispatch_async(processQueue, ^{
364 if (replyBlock)
365 replyBlock(NULL, connectionError);
366 CFReleaseSafe(connectionError);
367 dispatch_release(processQueue);
368 });
369
370 os_activity_end(trace_activity);
371 }
372
373 typedef void (^ProxyReplyBlock)(xpc_object_t reply);
374
375 static bool messageToProxy(SOSXPCCloudTransportRef transport, xpc_object_t message, CFErrorRef *error, dispatch_queue_t processQueue, ProxyReplyBlock replyBlock) {
376 __block CFErrorRef connectionError = NULL;
377
378 dispatch_sync(transport->xpc_queue, ^{
379 if (transport->serviceConnection && message) {
380 xpc_connection_send_message_with_reply(transport->serviceConnection, message, processQueue, replyBlock);
381 } else {
382 connectionError = makeError(kSOSConnectionNotOpen);
383 }
384 });
385 return CFErrorPropagate(connectionError, error);
386 }
387
388 static void talkWithKVS(SOSXPCCloudTransportRef transport, xpc_object_t message, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
389 {
390 CFErrorRef messagingError = NULL;
391 dispatch_retain(processQueue);
392 bool messaged = messageToProxy(transport, message, &messagingError, transport->xpc_queue, ^(xpc_object_t reply)
393 {
394 CFErrorRef serverError = NULL;
395 CFTypeRef object = NULL;
396 if (xpc_event_filter(transport->serviceConnection, reply, &serverError) && reply)
397 {
398 if (serverError)
399 secerror("Error from xpc_event_filter: %@", serverError);
400 xpc_object_t xrv = xpc_dictionary_get_value(reply, kMessageKeyValue);
401 if (xrv)
402 {
403 /*
404 * The given XPC object must be one that was previously returned by
405 * _CFXPCCreateXPCMessageWithCFObject().
406 */
407 object = _CFXPCCreateCFObjectFromXPCObject(xrv); // CF object is retained; release in callback
408 }
409 else
410 secerror("missing value reply");
411
412 xpc_object_t xerror = xpc_dictionary_get_value(reply, kMessageKeyError);
413 if (xerror)
414 serverError = SecCreateCFErrorWithXPCObject(xerror); // use SecCFCreateErrorWithFormat?
415 }
416 dispatch_async(processQueue, ^{
417 if (replyBlock)
418 replyBlock(object, serverError);
419 CFReleaseSafe(object);
420 if (serverError)
421 {
422 secerror("callback error: %@", serverError);
423 CFReleaseSafe(serverError);
424 }
425 dispatch_release(processQueue);
426 });
427 });
428
429 if (!messaged) {
430 secerror("talkWithKVS error: %@", messagingError);
431 dispatch_async(processQueue, ^{
432 if (replyBlock)
433 replyBlock(NULL, messagingError);
434 CFReleaseSafe(messagingError);
435 dispatch_release(processQueue);
436 });
437 }
438 }
439
440 // MARK: ---------- SOSXPCCloudTransport Client Calls ----------
441
442 /* Concrete function backend implementations. */
443 static void SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportRef transport,
444 CloudItemsChangedBlock itemsChangedBlock) {
445 if (transport->itemsChangedBlock != itemsChangedBlock)
446 {
447 secnotice(SOSCKCSCOPE, "Changing itemsChangedBlock");
448 if (transport->itemsChangedBlock)
449 Block_release(transport->itemsChangedBlock);
450 transport->itemsChangedBlock = Block_copy(itemsChangedBlock);
451 }
452 }
453
454 /* Virtual function backend implementations. */
455 static void SOSCloudTransportPut(SOSCloudTransportRef transport, CFDictionaryRef values, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
456 {
457 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
458 secdebug(SOSCKCSCOPE, "%@", values);
459 CFErrorRef error = NULL;
460 xpc_object_t message = NULL;
461 xpc_object_t xobject = NULL;
462 require_action(values, xit, error = makeError(kSOSObjectNotFoundError));
463
464 message = xpc_dictionary_create(NULL, NULL, 0);
465 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
466 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationPUTDictionary);
467
468 xobject = _CFXPCCreateXPCObjectFromCFObject(values);
469 require_action(xobject, xit, error = makeError(kSOSObjectCantBeConvertedToXPCObject));
470 xpc_dictionary_set_value(message, kMessageKeyValue, xobject);
471 xpc_release(xobject);
472
473 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
474 xpc_release(message);
475 return;
476
477 xit:
478 if (replyBlock)
479 replyBlock(NULL, error);
480 CFReleaseSafe(error);
481 }
482
483 /* Get from KVS */
484 void SOSCloudTransportGet(SOSCloudTransportRef transport, CFArrayRef keysToGet, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
485 {
486 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
487 secdebug(SOSCKCSCOPE, "%@", keysToGet);
488 CFErrorRef error = NULL;
489 xpc_object_t xkeysOfInterest = xpc_dictionary_create(NULL, NULL, 0);
490 xpc_object_t xkeysToGet = keysToGet ? _CFXPCCreateXPCObjectFromCFObject(keysToGet) : xpc_null_create();
491
492 require_action(xkeysToGet, xit, error = makeError(kSOSObjectNotFoundError));
493
494 if (keysToGet) // don't add if nulll; will call getall
495 xpc_dictionary_set_value(xkeysOfInterest, kMessageKeyKeysToGet, xkeysToGet);
496
497 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
498 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
499 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationGETv2);
500 xpc_dictionary_set_value(message, kMessageKeyValue, xkeysOfInterest);
501
502 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
503 xpc_release(xkeysToGet);
504 xpc_release(xkeysOfInterest);
505 xpc_release(message);
506 return;
507
508 xit:
509 if(xkeysOfInterest)
510 xpc_release(xkeysOfInterest);
511 if(xkeysToGet)
512 xpc_release(xkeysToGet);
513 if (replyBlock)
514 replyBlock(NULL, error);
515 CFReleaseSafe(error);
516 }
517
518 //
519 // Handles NULL by seting xpc_null.
520 static void SecXPCDictionarySetCFObject(xpc_object_t xdict, const char *key, CFTypeRef object)
521 {
522 xpc_object_t xpc_obj = object ? _CFXPCCreateXPCObjectFromCFObject(object) : xpc_null_create();
523 xpc_dictionary_set_value(xdict, key, xpc_obj);
524 xpc_release(xpc_obj);
525 }
526
527 static void SOSCloudTransportGetIDSDeviceID(SOSCloudTransportRef transport, CloudKeychainReplyBlock replyBlock)
528 {
529 dispatch_queue_t processQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
530
531 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
532
533 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
534 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
535 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationGetDeviceID);
536
537 talkWithIDS(xpcTransport, message, processQueue, replyBlock);
538 xpc_release(message);
539 }
540
541 static void SOSCloudTransportGetPerformanceStats(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
542 {
543 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
544
545 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
546 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
547 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationGetIDSPerfCounters);
548
549 talkWithIDS(xpcTransport, message, processQueue, replyBlock);
550 xpc_release(message);
551 }
552
553 static void SOSCloudTransportSendFragmentedIDSMessage(SOSCloudTransportRef transport, CFDictionaryRef messageData, CFStringRef deviceName, CFStringRef peerID, CFStringRef myDeviceID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock){
554
555 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
556 xpc_object_t xmessageData = _CFXPCCreateXPCObjectFromCFObject(messageData);
557
558 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
559 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
560 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationSendFragmentedIDSMessage);
561
562 xpc_dictionary_set_value(message, kMessageKeyValue, xmessageData);
563 SecXPCDictionarySetCFObject(message, kMessageKeyDeviceName, deviceName);
564 SecXPCDictionarySetCFObject(message, kMessageKeyPeerID, peerID);
565 SecXPCDictionarySetCFObject(message, kMessageKeyDeviceID, myDeviceID);
566
567 talkWithIDS(xpcTransport, message, processQueue, replyBlock);
568
569 xpc_release(xmessageData);
570 xpc_release(message);
571 }
572
573 static void SOSCloudTransportRetrievePendingMessagesInFlight(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock){
574
575 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
576
577 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
578 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
579 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationGetPendingMesages);
580
581 talkWithIDS(xpcTransport, message, processQueue, replyBlock);
582
583 xpc_release(message);
584 }
585
586 static void SOSCloudTransportCheckIDSDeviceIDAvailability(SOSCloudTransportRef transport, CFArrayRef ids, CFStringRef peerID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
587 {
588 secdebug(SOSCKCSCOPE, "start");
589 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
590
591 xpc_object_t xIDSArray = _CFXPCCreateXPCObjectFromCFObject(ids);
592
593 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
594 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
595 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationSendDeviceList);
596
597 SecXPCDictionarySetCFObject(message, kMessageKeyPeerID, peerID);
598 xpc_dictionary_set_value(message, kMessageKeyValue, xIDSArray);
599
600 talkWithIDS(xpcTransport, message, processQueue, replyBlock);
601
602 xpc_release(xIDSArray);
603 xpc_release(message);
604
605 }
606
607 static void SOSCloudTransportSendIDSMessage(SOSCloudTransportRef transport, CFDictionaryRef messageData, CFStringRef deviceName, CFStringRef peerID, CFStringRef myDeviceID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock){
608
609 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
610 xpc_object_t xmessageData = _CFXPCCreateXPCObjectFromCFObject(messageData);
611
612 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
613 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
614 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationSendIDSMessage);
615
616 xpc_dictionary_set_value(message, kMessageKeyValue, xmessageData);
617 SecXPCDictionarySetCFObject(message, kMessageKeyDeviceName, deviceName);
618 SecXPCDictionarySetCFObject(message, kMessageKeyPeerID, peerID);
619 SecXPCDictionarySetCFObject(message, kMessageKeyDeviceID, myDeviceID);
620 talkWithIDS(xpcTransport, message, processQueue, replyBlock);
621
622 xpc_release(xmessageData);
623 xpc_release(message);
624 }
625
626 static void SOSCloudTransportUpdateKeys(SOSCloudTransportRef transport,
627 CFDictionaryRef keys,
628 CFStringRef accountUUID,
629 dispatch_queue_t processQueue,
630 CloudKeychainReplyBlock replyBlock)
631 {
632 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
633
634 xpc_object_t xkeysOfInterest = xpc_dictionary_create(NULL, NULL, 0);
635 SecXPCDictionarySetCFObject(xkeysOfInterest, kMessageAllKeys, keys);
636
637 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
638 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
639 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationRegisterKeys);
640 xpc_dictionary_set_value(message, kMessageKeyValue, xkeysOfInterest);
641 SecXPCDictionarySetCFObject(message, kMessageKeyAccountUUID, accountUUID);
642
643 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
644 xpc_release(message);
645 xpc_release(xkeysOfInterest);
646 }
647
648 static void SOSCloudTransportRemoveKeys(SOSCloudTransportRef transport,
649 CFArrayRef keys,
650 CFStringRef accountUUID,
651 dispatch_queue_t processQueue,
652 CloudKeychainReplyBlock replyBlock)
653 {
654 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
655
656 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
657 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
658
659 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationRemoveKeys);
660 SecXPCDictionarySetCFObject(message, kMessageKeyAccountUUID, accountUUID);
661 SecXPCDictionarySetCFObject(message, kMessageKeyValue, keys);
662
663 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
664 xpc_release(message);
665 }
666
667 static void SOSCloudTransportGetAll(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
668 {
669 secdebug(SOSCKCSCOPE, "start");
670 SOSCloudTransportGet(transport, NULL, processQueue, replyBlock);
671 }
672
673 static void SOSCloudTransportSync(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
674 {
675 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
676 secdebug(SOSCKCSCOPE, "start");
677 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
678 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
679 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationSynchronize);
680 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
681 xpc_release(message);
682 }
683
684 static void SOSCloudTransportSyncAndWait(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
685 {
686 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
687 secnotice(SOSCKCSCOPE, "%s XPC request to CKD: %s", kWAIT2MINID, kOperationSynchronizeAndWait);
688
689 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
690 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
691 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationSynchronizeAndWait);
692
693 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
694 xpc_release(message);
695 }
696
697 static void SOSCloudTransportClearAll(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
698 {
699 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
700 secdebug(SOSCKCSCOPE, "start");
701 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
702 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
703 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationClearStore);
704 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
705 xpc_release(message);
706 }
707
708 static void SOSCloudTransportRequestSyncWithPeers(SOSCloudTransportRef transport, CFArrayRef /* CFStringRef */ peers, CFArrayRef /* CFStringRef */ backupPeers, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
709 {
710 secdebug(SOSCKCSCOPE, "start");
711 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
712
713 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
714
715 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
716 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationRequestSyncWithPeers);
717
718 SecXPCDictionarySetCFObject(xpcmessage, kMessageKeyPeerIDList, peers);
719 SecXPCDictionarySetCFObject(xpcmessage, kMesssgeKeyBackupPeerIDList, backupPeers);
720
721 talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock);
722
723 xpc_release(xpcmessage);
724 }
725
726
727 static bool SOSCloudTransportHasPeerSyncPending(SOSCloudTransportRef transport, CFStringRef peerID, CFErrorRef* error)
728 {
729 secdebug(SOSCKCSCOPE, "start");
730 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
731
732 __block bool isSyncing = false;
733
734 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
735
736 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
737 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationHasPendingSyncWithPeer);
738
739 SecXPCDictionarySetCFObject(xpcmessage, kMessageKeyPeerID, peerID);
740
741 dispatch_semaphore_t wait = dispatch_semaphore_create(0);
742 bool sent = messageToProxy(xpcTransport, xpcmessage, error, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(xpc_object_t reply) {
743 isSyncing = xpc_dictionary_get_bool(reply, kMessageKeyValue);
744 dispatch_semaphore_signal(wait);
745 });
746
747 if (sent) {
748 dispatch_semaphore_wait(wait, DISPATCH_TIME_FOREVER);
749 }
750
751 dispatch_release(wait);
752
753 return sent && isSyncing;
754 }
755
756
757 static bool SOSCloudTransportHasPendingKey(SOSCloudTransportRef transport, CFStringRef keyName, CFErrorRef* error)
758 {
759 secdebug(SOSCKCSCOPE, "start");
760 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
761
762 __block bool kvsHasMessage = false;
763
764 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
765
766 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
767 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationHasPendingKey);
768
769 SecXPCDictionarySetCFObject(xpcmessage, kMessageKeyKey, keyName);
770
771 dispatch_semaphore_t kvsWait = dispatch_semaphore_create(0);
772 bool kvsSent = messageToProxy(xpcTransport, xpcmessage, error, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(xpc_object_t reply) {
773 kvsHasMessage = xpc_dictionary_get_bool(reply, kMessageKeyValue);
774 dispatch_semaphore_signal(kvsWait);
775 });
776
777 if (kvsSent) {
778 dispatch_semaphore_wait(kvsWait, DISPATCH_TIME_FOREVER);
779 }
780
781 dispatch_release(kvsWait);
782
783 return kvsSent && kvsHasMessage;
784 }
785
786
787 static void SOSCloudTransportRequestEnsurePeerRegistration(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
788 {
789 secdebug(SOSCKCSCOPE, "start");
790 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
791
792 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
793 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
794 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationRequestEnsurePeerRegistration);
795
796 talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock);
797
798 xpc_release(xpcmessage);
799 }
800
801 static void SOSCloudTransportRequestPerfCounters(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
802 {
803 secdebug(SOSCKCSCOPE, "start");
804 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
805
806 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
807 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
808 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationPerfCounters);
809
810 talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock);
811
812 xpc_release(xpcmessage);
813 }
814
815
816 static void SOSCloudTransportFlush(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
817 {
818 secdebug(SOSCKCSCOPE, "start");
819 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
820
821 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
822 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
823 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationFlush);
824
825 talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock);
826
827 xpc_release(xpcmessage);
828 }
829
830 static SOSCloudTransportRef SOSCloudTransportCreateXPCTransport(void)
831 {
832 SOSXPCCloudTransportRef st;
833 st = calloc(1, sizeof(*st));
834 st->transport.put = SOSCloudTransportPut;
835 st->transport.updateKeys = SOSCloudTransportUpdateKeys;
836 st->transport.sendIDSMessage = SOSCloudTransportSendIDSMessage;
837 st->transport.sendFragmentedIDSMessage = SOSCloudTransportSendFragmentedIDSMessage;
838 st->transport.retrieveMessages = SOSCloudTransportRetrievePendingMessagesInFlight;
839
840 st->transport.getDeviceID = SOSCloudTransportGetIDSDeviceID;
841 st->transport.get = SOSCloudTransportGet;
842 st->transport.getAll = SOSCloudTransportGetAll;
843 st->transport.synchronize = SOSCloudTransportSync;
844 st->transport.synchronizeAndWait = SOSCloudTransportSyncAndWait;
845 st->transport.clearAll = SOSCloudTransportClearAll;
846 st->transport.requestSyncWithPeers = SOSCloudTransportRequestSyncWithPeers;
847 st->transport.hasPeerSyncPending = SOSCloudTransportHasPeerSyncPending;
848 st->transport.hasPendingKey = SOSCloudTransportHasPendingKey;
849 st->transport.requestEnsurePeerRegistration = SOSCloudTransportRequestEnsurePeerRegistration;
850 st->transport.requestPerfCounters = SOSCloudTransportRequestPerfCounters;
851 st->transport.getIDSDeviceAvailability = SOSCloudTransportCheckIDSDeviceIDAvailability;
852 st->transport.flush = SOSCloudTransportFlush;
853 st->transport.removeKeys = SOSCloudTransportRemoveKeys;
854 st->transport.counters = SOSCloudTransportGetPerformanceStats;
855 st->transport.itemsChangedBlock = Block_copy(^CFArrayRef(CFDictionaryRef changes) {
856 secerror("Calling default itemsChangedBlock - fatal: %@", changes);
857 assert(false);
858 return NULL;
859 });
860 SOSXPCCloudTransportInit(st);
861 return &st->transport;
862 }
863
864 // MARK: ---------- SOSCloudKeychain concrete client APIs ----------
865 void SOSCloudKeychainSetItemsChangedBlock(CloudItemsChangedBlock itemsChangedBlock)
866 {
867 secdebug(SOSCKCSCOPE, "start");
868 SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportDefaultTransport(),
869 itemsChangedBlock);
870 }
871
872 // MARK: ---------- SOSCloudKeychain virtual client APIs ----------
873
874 void SOSCloudKeychainPutObjectsInCloud(CFDictionaryRef objects, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
875 {
876 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
877 if (cTransportRef)
878 cTransportRef->put(cTransportRef, objects, processQueue, replyBlock);
879 }
880
881 void SOSCloudKeychainUpdateKeys(CFDictionaryRef keys, CFStringRef accountUUID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
882 {
883 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
884 if (cTransportRef)
885 cTransportRef->updateKeys(cTransportRef, keys, accountUUID, processQueue, replyBlock);
886 }
887
888
889 void SOSCloudKeychainRemoveKeys(CFArrayRef keys, CFStringRef accountUUID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
890 {
891 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
892 if (cTransportRef)
893 cTransportRef->removeKeys(cTransportRef, keys, accountUUID, processQueue, replyBlock);
894 }
895
896 void SOSCloudKeychainSendIDSMessage(CFDictionaryRef message, CFStringRef deviceName, CFStringRef peerID, CFStringRef myDeviceID, dispatch_queue_t processQueue, CFBooleanRef fragmentation, CloudKeychainReplyBlock replyBlock)
897 {
898 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
899
900 if(cTransportRef && fragmentation == kCFBooleanTrue)
901 cTransportRef->sendFragmentedIDSMessage(cTransportRef, message, deviceName, peerID, myDeviceID, processQueue, replyBlock);
902 else if(cTransportRef)
903 cTransportRef->sendIDSMessage(cTransportRef, message, deviceName, peerID, myDeviceID, processQueue, replyBlock);
904
905 }
906
907 void SOSCloudKeychainRetrievePendingMessageFromProxy(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
908 {
909 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
910
911 if(cTransportRef)
912 cTransportRef->retrieveMessages(cTransportRef, processQueue, replyBlock);
913
914 }
915 void SOSCloudKeychainRetrieveCountersFromIDSProxy(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
916 {
917 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
918
919 if(cTransportRef)
920 cTransportRef->counters(cTransportRef, processQueue, replyBlock);
921
922 }
923 void SOSCloudKeychainGetIDSDeviceID(CloudKeychainReplyBlock replyBlock)
924 {
925 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
926 if (cTransportRef)
927 cTransportRef->getDeviceID(cTransportRef, replyBlock);
928
929 }
930 void SOSCloudKeychainGetIDSDeviceAvailability(CFArrayRef ids, CFStringRef peerID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock){
931
932 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
933
934 if (cTransportRef)
935 cTransportRef->getIDSDeviceAvailability(cTransportRef, ids, peerID, processQueue, replyBlock);
936 }
937 CF_RETURNS_RETAINED CFArrayRef SOSCloudKeychainHandleUpdateMessage(CFDictionaryRef updates)
938 {
939 CFArrayRef result = NULL;
940 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
941 if (cTransportRef->itemsChangedBlock)
942 result = ((CloudItemsChangedBlock)cTransportRef->itemsChangedBlock)(updates);
943 return result;
944 }
945
946 void SOSCloudKeychainGetObjectsFromCloud(CFArrayRef keysToGet, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
947 {
948 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
949 if (cTransportRef)
950 cTransportRef->get(cTransportRef, keysToGet, processQueue, replyBlock);
951 }
952
953 void SOSCloudKeychainGetAllObjectsFromCloud(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
954 {
955 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
956 if (cTransportRef)
957 cTransportRef->getAll(cTransportRef, processQueue, replyBlock);
958 }
959
960 void SOSCloudKeychainSynchronizeAndWait(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
961 {
962 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
963 if (cTransportRef)
964 cTransportRef->synchronizeAndWait(cTransportRef, processQueue, replyBlock);
965 }
966
967 //DEBUG ONLY
968 void SOSCloudKeychainSynchronize(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
969 {
970 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
971 if (cTransportRef)
972 cTransportRef->synchronize(cTransportRef, processQueue, replyBlock);
973 }
974
975 //DEBUG ONLY
976 void SOSCloudKeychainClearAll(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
977 {
978 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
979 if (cTransportRef)
980 cTransportRef->clearAll(cTransportRef, processQueue, replyBlock);
981 }
982
983 void SOSCloudKeychainRequestSyncWithPeers(CFArrayRef /* CFStringRef */ peers, CFArrayRef /* CFStringRef */ backupPeers, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
984 {
985 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
986 if (cTransportRef)
987 cTransportRef->requestSyncWithPeers(cTransportRef, peers, backupPeers, processQueue, replyBlock);
988 }
989
990 bool SOSCloudKeychainHasPendingKey(CFStringRef keyName, CFErrorRef* error) {
991 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
992
993 return cTransportRef && cTransportRef->hasPendingKey(cTransportRef, keyName, error);
994 }
995
996 bool SOSCloudKeychainHasPendingSyncWithPeer(CFStringRef peerID, CFErrorRef* error) {
997 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
998
999 return cTransportRef && cTransportRef->hasPeerSyncPending(cTransportRef, peerID, error);
1000 }
1001
1002 void SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
1003 {
1004 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
1005 if (cTransportRef)
1006 cTransportRef->requestEnsurePeerRegistration(cTransportRef, processQueue, replyBlock);
1007 }
1008
1009 void SOSCloudKeychainRequestPerfCounters(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
1010 {
1011 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
1012 if (cTransportRef)
1013 cTransportRef->requestPerfCounters(cTransportRef, processQueue, replyBlock);
1014 }
1015
1016
1017 void SOSCloudKeychainFlush(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
1018 {
1019 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
1020 if (cTransportRef)
1021 cTransportRef->flush(cTransportRef, processQueue, replyBlock);
1022 }