2 * Copyright (c) 2012-2014 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@
25 SOSCloudTransport.c - Implementation of the transport layer from CKBridge to SOSAccount/SOSCircle
26 These are the exported functions from CloudKeychainProxy
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.
33 See sendTSARequestWithXPC in tsaSupport.c for how to call the service
35 The client of an XPC service does not get connection events, nor does it
36 need to deal with transactions.
39 #include <AssertMacros.h>
42 #include <CoreFoundation/CoreFoundation.h>
43 #include <CoreFoundation/CFXPCBridge.h>
46 #include <os/activity.h>
47 #include <CoreFoundation/CFUserNotification.h>
48 #include <Security/SecureObjectSync/SOSInternal.h>
51 #include <utilities/debugging.h>
52 #include <utilities/SecCFWrappers.h>
53 #include <utilities/SecXPCError.h>
55 #include "SOSCloudKeychainConstants.h"
56 #include "SOSCloudKeychainClient.h"
57 #include "SOSUserKeygen.h"
58 #include "SecOTRSession.h"
60 #include <os/activity.h>
61 #include <os/state_private.h>
64 static CFStringRef sErrorDomain
= CFSTR("com.apple.security.sos.transport.error");
66 #define SOSCKCSCOPE "sync"
68 // MARK: ---------- SOSCloudTransport ----------
70 static SOSCloudTransportRef
SOSCloudTransportCreateXPCTransport(void);
72 void SOSCloudTransportGet(SOSCloudTransportRef transport
, CFArrayRef keysToGet
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
);
76 /* Return the singleton cloud transport instance. */
77 CFDictionaryRef
SOSCloudCopyKVSState(void) {
78 __block CFDictionaryRef retval
= NULL
;
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
);
86 if (processQueue
== NULL
)
89 dispatch_semaphore_t waitSemaphore
= NULL
;
91 waitSemaphore
= dispatch_semaphore_create(0);
93 CloudKeychainReplyBlock replyBlock
= ^ (CFDictionaryRef returnedValues
, CFErrorRef error
) {
94 retval
= returnedValues
;
95 if (retval
) CFRetain(retval
);
96 dispatch_semaphore_signal(waitSemaphore
);
99 SOSCloudKeychainGetAllObjectsFromCloud(processQueue
, replyBlock
);
101 dispatch_semaphore_wait(waitSemaphore
, DISPATCH_TIME_FOREVER
);
102 dispatch_release(waitSemaphore
);
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
;
113 require_quiet(hints
->osh_api
== 3, errOut
); // only grab on sysdiagnose or command lin
115 kvsdict
= SOSCloudCopyKVSState();
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
);
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");
128 CFReleaseNull(kvsdict
);
129 CFReleaseNull(serializedKVS
);
133 static SOSCloudTransportRef defaultTransport
= NULL
;
136 SOSCloudTransportSetDefaultTransport(SOSCloudTransportRef transport
)
138 defaultTransport
= transport
;
141 static SOSCloudTransportRef
SOSCloudTransportDefaultTransport(void)
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(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), kvsStateBlock
);
151 return defaultTransport
;
155 // MARK: ----- utilities -----
157 static CFErrorRef
makeError(CFIndex which
)
159 CFDictionaryRef userInfo
= NULL
;
160 return CFErrorCreate(kCFAllocatorDefault
, sErrorDomain
, which
, userInfo
);
163 // MARK: ----- DEBUG Utilities -----
165 //------------------------------------------------------------------------------------------------
167 //------------------------------------------------------------------------------------------------
169 static void describeXPCObject(char *prefix
, xpc_object_t object
)
172 // This is useful for debugging.
175 char *desc
= xpc_copy_description(object
);
176 secdebug(SOSCKCSCOPE
, "%s%s\n", prefix
, desc
);
180 secdebug(SOSCKCSCOPE
, "%s<NULL>\n", prefix
);
184 static void describeXPCType(char *prefix
, xpc_type_t xtype
)
186 // Add others as necessary, e.g. XPC_TYPE_DOUBLE
188 // This is useful for debugging.
190 if (XPC_TYPE_CONNECTION
== xtype
)
191 strcpy(msg
, "XPC_TYPE_CONNECTION");
192 else if (XPC_TYPE_ERROR
== xtype
)
193 strcpy(msg
, "XPC_TYPE_ERROR");
194 else if (XPC_TYPE_DICTIONARY
== xtype
)
195 strcpy(msg
, "XPC_TYPE_DICTIONARY");
197 strcpy(msg
, "<unknown>");
199 secdebug(SOSCKCSCOPE
, "%s type:%s\n", prefix
, msg
);
203 // MARK: ---------- SOSXPCCloudTransport ----------
205 typedef struct SOSXPCCloudTransport
*SOSXPCCloudTransportRef
;
206 struct SOSXPCCloudTransport
208 struct SOSCloudTransport transport
;
209 xpc_connection_t serviceConnection
;
210 dispatch_queue_t xpc_queue
;
213 static bool xpc_event_filter(const xpc_connection_t peer
, xpc_object_t event
, CFErrorRef
*error
)
215 // return true if the type is XPC_TYPE_DICTIONARY (and therefore something more to process)
216 secdebug(SOSCKCSCOPE
, "handle_connection_event\n");
217 xpc_type_t xtype
= xpc_get_type(event
);
218 describeXPCType("handle_xpc_event", xtype
);
219 if (XPC_TYPE_CONNECTION
== xtype
)
221 secdebug(SOSCKCSCOPE
, "handle_xpc_event: XPC_TYPE_CONNECTION (unexpected)");
222 // The client of an XPC service does not get connection events
223 // For now, we log this and keep going
224 describeXPCObject("handle_xpc_event: XPC_TYPE_CONNECTION, obj : ", event
);
227 if (XPC_TYPE_ERROR
== xtype
)
230 const char *estr
= xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
);
232 secdebug(SOSCKCSCOPE
, "default: xpc error: %s\n", estr
);
235 if (XPC_TYPE_DICTIONARY
== xtype
)
237 secdebug(SOSCKCSCOPE
, "received dictionary event %p\n", event
);
242 secdebug(SOSCKCSCOPE
, "default: unexpected connection event %p\n", event
);
243 describeXPCObject("handle_xpc_event: obj : ", event
);
245 *error
= makeError(kSOSOUnexpectedXPCEvent
);
250 static void setupServiceConnection(SOSXPCCloudTransportRef transport
)
252 secnotice(SOSCKCSCOPE
, "CKP Transport: setting up xpc connection");
253 transport
->serviceConnection
= xpc_connection_create_mach_service(xpcServiceName
, transport
->xpc_queue
, 0);
255 secdebug(SOSCKCSCOPE
, "serviceConnection: %p\n", transport
->serviceConnection
);
257 xpc_connection_set_event_handler(transport
->serviceConnection
, ^(xpc_object_t event
) {
258 secdebug(SOSCKCSCOPE
, "CKP Transport, xpc_connection_set_event_handler\n");
259 if(event
== XPC_ERROR_CONNECTION_INVALID
){
260 secnotice(SOSCKCSCOPE
, "CKP Transport: xpc connection invalid. Oh well.");
264 xpc_connection_activate(transport
->serviceConnection
);
267 static void teardownServiceConnection(SOSXPCCloudTransportRef transport
)
269 secnotice(SOSCKCSCOPE
, "CKP Transport: tearing down xpc connection");
270 dispatch_assert_queue(transport
->xpc_queue
);
271 xpc_release(transport
->serviceConnection
);
272 transport
->serviceConnection
= NULL
;
275 static void SOSXPCCloudTransportInit(SOSXPCCloudTransportRef transport
)
277 secdebug(SOSCKCSCOPE
, "initXPCConnection\n");
279 transport
->xpc_queue
= dispatch_queue_create(xpcServiceName
, DISPATCH_QUEUE_SERIAL
);
281 setupServiceConnection(transport
);
283 // Any time a new session starts, reestablish the XPC connections.
285 notify_register_dispatch("com.apple.system.loginwindow.desktopUp", &token
, transport
->xpc_queue
, ^(int token2
) {
286 secnotice(SOSCKCSCOPE
, "CKP Transport: desktopUp happened, reestablishing xpc connections");
287 teardownServiceConnection(transport
);
288 setupServiceConnection(transport
);
292 typedef void (^ProxyReplyBlock
)(xpc_object_t reply
);
294 static bool messageToProxy(SOSXPCCloudTransportRef transport
, xpc_object_t message
, CFErrorRef
*error
, dispatch_queue_t processQueue
, ProxyReplyBlock replyBlock
) {
295 __block CFErrorRef connectionError
= NULL
;
297 dispatch_sync(transport
->xpc_queue
, ^{
298 if (transport
->serviceConnection
&& message
) {
299 xpc_connection_send_message_with_reply(transport
->serviceConnection
, message
, processQueue
, replyBlock
);
301 connectionError
= makeError(kSOSConnectionNotOpen
);
304 return CFErrorPropagate(connectionError
, error
);
307 static void talkWithKVS(SOSXPCCloudTransportRef transport
, xpc_object_t message
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
309 CFErrorRef messagingError
= NULL
;
310 dispatch_retain(processQueue
);
311 bool messaged
= messageToProxy(transport
, message
, &messagingError
, transport
->xpc_queue
, ^(xpc_object_t reply
)
313 CFErrorRef serverError
= NULL
;
314 CFTypeRef object
= NULL
;
315 if (xpc_event_filter(transport
->serviceConnection
, reply
, &serverError
) && reply
)
318 secerror("Error from xpc_event_filter: %@", serverError
);
319 xpc_object_t xrv
= xpc_dictionary_get_value(reply
, kMessageKeyValue
);
323 * The given XPC object must be one that was previously returned by
324 * _CFXPCCreateXPCMessageWithCFObject().
326 object
= _CFXPCCreateCFObjectFromXPCObject(xrv
); // CF object is retained; release in callback
329 secerror("missing value reply");
331 xpc_object_t xerror
= xpc_dictionary_get_value(reply
, kMessageKeyError
);
333 serverError
= SecCreateCFErrorWithXPCObject(xerror
); // use SecCFCreateErrorWithFormat?
335 dispatch_async(processQueue
, ^{
337 replyBlock(object
, serverError
);
338 CFReleaseSafe(object
);
341 secerror("callback error: %@", serverError
);
342 CFReleaseSafe(serverError
);
344 dispatch_release(processQueue
);
349 secerror("talkWithKVS error: %@", messagingError
);
350 dispatch_async(processQueue
, ^{
352 replyBlock(NULL
, messagingError
);
353 CFReleaseSafe(messagingError
);
354 dispatch_release(processQueue
);
359 // MARK: ---------- SOSXPCCloudTransport Client Calls ----------
361 /* Concrete function backend implementations. */
362 static void SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportRef transport
,
363 CloudItemsChangedBlock itemsChangedBlock
) {
364 if (transport
->itemsChangedBlock
!= itemsChangedBlock
)
366 secnotice(SOSCKCSCOPE
, "Changing itemsChangedBlock");
367 if (transport
->itemsChangedBlock
)
368 Block_release(transport
->itemsChangedBlock
);
369 transport
->itemsChangedBlock
= Block_copy(itemsChangedBlock
);
373 /* Virtual function backend implementations. */
374 static void SOSCloudTransportPut(SOSCloudTransportRef transport
, CFDictionaryRef values
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
376 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
377 secdebug(SOSCKCSCOPE
, "%@", values
);
378 CFErrorRef error
= NULL
;
379 xpc_object_t message
= NULL
;
380 xpc_object_t xobject
= NULL
;
381 require_action(values
, xit
, error
= makeError(kSOSObjectNotFoundError
));
383 message
= xpc_dictionary_create(NULL
, NULL
, 0);
384 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
385 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationPUTDictionary
);
387 xobject
= _CFXPCCreateXPCObjectFromCFObject(values
);
388 require_action(xobject
, xit
, error
= makeError(kSOSObjectCantBeConvertedToXPCObject
));
389 xpc_dictionary_set_value(message
, kMessageKeyValue
, xobject
);
390 xpc_release(xobject
);
392 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
393 xpc_release(message
);
398 replyBlock(NULL
, error
);
399 CFReleaseSafe(error
);
403 void SOSCloudTransportGet(SOSCloudTransportRef transport
, CFArrayRef keysToGet
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
405 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
406 secdebug(SOSCKCSCOPE
, "%@", keysToGet
);
407 CFErrorRef error
= NULL
;
408 xpc_object_t xkeysOfInterest
= xpc_dictionary_create(NULL
, NULL
, 0);
409 xpc_object_t xkeysToGet
= keysToGet
? _CFXPCCreateXPCObjectFromCFObject(keysToGet
) : xpc_null_create();
411 require_action(xkeysToGet
, xit
, error
= makeError(kSOSObjectNotFoundError
));
413 if (keysToGet
) // don't add if nulll; will call getall
414 xpc_dictionary_set_value(xkeysOfInterest
, kMessageKeyKeysToGet
, xkeysToGet
);
416 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
417 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
418 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationGETv2
);
419 xpc_dictionary_set_value(message
, kMessageKeyValue
, xkeysOfInterest
);
421 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
422 xpc_release(xkeysToGet
);
423 xpc_release(xkeysOfInterest
);
424 xpc_release(message
);
429 xpc_release(xkeysOfInterest
);
431 xpc_release(xkeysToGet
);
433 replyBlock(NULL
, error
);
434 CFReleaseSafe(error
);
438 // Handles NULL by seting xpc_null.
439 static void SecXPCDictionarySetCFObject(xpc_object_t xdict
, const char *key
, CFTypeRef object
)
441 xpc_object_t xpc_obj
= object
? _CFXPCCreateXPCObjectFromCFObject(object
) : xpc_null_create();
442 xpc_dictionary_set_value(xdict
, key
, xpc_obj
);
443 xpc_release(xpc_obj
);
446 static void SOSCloudTransportUpdateKeys(SOSCloudTransportRef transport
,
447 CFDictionaryRef keys
,
448 CFStringRef accountUUID
,
449 dispatch_queue_t processQueue
,
450 CloudKeychainReplyBlock replyBlock
)
452 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
454 xpc_object_t xkeysOfInterest
= xpc_dictionary_create(NULL
, NULL
, 0);
455 SecXPCDictionarySetCFObject(xkeysOfInterest
, kMessageAllKeys
, keys
);
457 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
458 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
459 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationRegisterKeys
);
460 xpc_dictionary_set_value(message
, kMessageKeyValue
, xkeysOfInterest
);
461 SecXPCDictionarySetCFObject(message
, kMessageKeyAccountUUID
, accountUUID
);
463 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
464 xpc_release(message
);
465 xpc_release(xkeysOfInterest
);
468 static void SOSCloudTransportRemoveKeys(SOSCloudTransportRef transport
,
470 CFStringRef accountUUID
,
471 dispatch_queue_t processQueue
,
472 CloudKeychainReplyBlock replyBlock
)
474 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
476 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
477 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
479 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationRemoveKeys
);
480 SecXPCDictionarySetCFObject(message
, kMessageKeyAccountUUID
, accountUUID
);
481 SecXPCDictionarySetCFObject(message
, kMessageKeyValue
, keys
);
483 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
484 xpc_release(message
);
487 static void SOSCloudTransportGetAll(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
489 secdebug(SOSCKCSCOPE
, "start");
490 SOSCloudTransportGet(transport
, NULL
, processQueue
, replyBlock
);
493 static void SOSCloudTransportSync(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
495 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
496 secdebug(SOSCKCSCOPE
, "start");
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
, kOperationSynchronize
);
500 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
501 xpc_release(message
);
504 static void SOSCloudTransportSyncAndWait(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
506 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
507 secnotice(SOSCKCSCOPE
, "%s XPC request to CKD: %s", kWAIT2MINID
, kOperationSynchronizeAndWait
);
509 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
510 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
511 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationSynchronizeAndWait
);
513 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
514 xpc_release(message
);
517 static void SOSCloudTransportClearAll(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
519 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
520 secdebug(SOSCKCSCOPE
, "start");
521 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
522 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
523 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationClearStore
);
524 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
525 xpc_release(message
);
528 static void SOSCloudTransportRequestSyncWithPeers(SOSCloudTransportRef transport
, CFArrayRef
/* CFStringRef */ peers
, CFArrayRef
/* CFStringRef */ backupPeers
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
530 secdebug(SOSCKCSCOPE
, "start");
531 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
533 xpc_object_t xpcmessage
= xpc_dictionary_create(NULL
, NULL
, 0);
535 xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
);
536 xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationRequestSyncWithPeers
);
538 SecXPCDictionarySetCFObject(xpcmessage
, kMessageKeyPeerIDList
, peers
);
539 SecXPCDictionarySetCFObject(xpcmessage
, kMesssgeKeyBackupPeerIDList
, backupPeers
);
541 talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
);
543 xpc_release(xpcmessage
);
547 static bool SOSCloudTransportHasPeerSyncPending(SOSCloudTransportRef transport
, CFStringRef peerID
, CFErrorRef
* error
)
549 secdebug(SOSCKCSCOPE
, "start");
550 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
552 __block
bool isSyncing
= false;
554 xpc_object_t xpcmessage
= xpc_dictionary_create(NULL
, NULL
, 0);
556 xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
);
557 xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationHasPendingSyncWithPeer
);
559 SecXPCDictionarySetCFObject(xpcmessage
, kMessageKeyPeerID
, peerID
);
561 dispatch_semaphore_t wait
= dispatch_semaphore_create(0);
562 bool sent
= messageToProxy(xpcTransport
, xpcmessage
, error
, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(xpc_object_t reply
) {
563 isSyncing
= xpc_dictionary_get_bool(reply
, kMessageKeyValue
);
564 dispatch_semaphore_signal(wait
);
568 dispatch_semaphore_wait(wait
, DISPATCH_TIME_FOREVER
);
571 dispatch_release(wait
);
573 return sent
&& isSyncing
;
577 static bool SOSCloudTransportHasPendingKey(SOSCloudTransportRef transport
, CFStringRef keyName
, CFErrorRef
* error
)
579 secdebug(SOSCKCSCOPE
, "start");
580 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
582 __block
bool kvsHasMessage
= false;
584 xpc_object_t xpcmessage
= xpc_dictionary_create(NULL
, NULL
, 0);
586 xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
);
587 xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationHasPendingKey
);
589 SecXPCDictionarySetCFObject(xpcmessage
, kMessageKeyKey
, keyName
);
591 dispatch_semaphore_t kvsWait
= dispatch_semaphore_create(0);
592 bool kvsSent
= messageToProxy(xpcTransport
, xpcmessage
, error
, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(xpc_object_t reply
) {
593 kvsHasMessage
= xpc_dictionary_get_bool(reply
, kMessageKeyValue
);
594 dispatch_semaphore_signal(kvsWait
);
598 dispatch_semaphore_wait(kvsWait
, DISPATCH_TIME_FOREVER
);
601 dispatch_release(kvsWait
);
603 return kvsSent
&& kvsHasMessage
;
607 static void SOSCloudTransportRequestEnsurePeerRegistration(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
609 secdebug(SOSCKCSCOPE
, "start");
610 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
612 xpc_object_t xpcmessage
= xpc_dictionary_create(NULL
, NULL
, 0);
613 xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
);
614 xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationRequestEnsurePeerRegistration
);
616 talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
);
618 xpc_release(xpcmessage
);
621 static void SOSCloudTransportRequestPerfCounters(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
623 secdebug(SOSCKCSCOPE
, "start");
624 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
626 xpc_object_t xpcmessage
= xpc_dictionary_create(NULL
, NULL
, 0);
627 xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
);
628 xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationPerfCounters
);
630 talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
);
632 xpc_release(xpcmessage
);
636 static void SOSCloudTransportFlush(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
638 secdebug(SOSCKCSCOPE
, "start");
639 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
641 xpc_object_t xpcmessage
= xpc_dictionary_create(NULL
, NULL
, 0);
642 xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
);
643 xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationFlush
);
645 talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
);
647 xpc_release(xpcmessage
);
650 static SOSCloudTransportRef
SOSCloudTransportCreateXPCTransport(void)
652 SOSXPCCloudTransportRef st
;
653 st
= calloc(1, sizeof(*st
));
654 st
->transport
.put
= SOSCloudTransportPut
;
655 st
->transport
.updateKeys
= SOSCloudTransportUpdateKeys
;
657 st
->transport
.get
= SOSCloudTransportGet
;
658 st
->transport
.getAll
= SOSCloudTransportGetAll
;
659 st
->transport
.synchronize
= SOSCloudTransportSync
;
660 st
->transport
.synchronizeAndWait
= SOSCloudTransportSyncAndWait
;
661 st
->transport
.clearAll
= SOSCloudTransportClearAll
;
662 st
->transport
.requestSyncWithPeers
= SOSCloudTransportRequestSyncWithPeers
;
663 st
->transport
.hasPeerSyncPending
= SOSCloudTransportHasPeerSyncPending
;
664 st
->transport
.hasPendingKey
= SOSCloudTransportHasPendingKey
;
665 st
->transport
.requestEnsurePeerRegistration
= SOSCloudTransportRequestEnsurePeerRegistration
;
666 st
->transport
.requestPerfCounters
= SOSCloudTransportRequestPerfCounters
;
667 st
->transport
.flush
= SOSCloudTransportFlush
;
668 st
->transport
.removeKeys
= SOSCloudTransportRemoveKeys
;
669 st
->transport
.itemsChangedBlock
= Block_copy(^CFArrayRef(CFDictionaryRef changes
) {
670 secerror("Calling default itemsChangedBlock - fatal: %@", changes
);
674 SOSXPCCloudTransportInit(st
);
675 return &st
->transport
;
678 // MARK: ---------- SOSCloudKeychain concrete client APIs ----------
679 void SOSCloudKeychainSetItemsChangedBlock(CloudItemsChangedBlock itemsChangedBlock
)
681 secdebug(SOSCKCSCOPE
, "start");
682 SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportDefaultTransport(),
686 // MARK: ---------- SOSCloudKeychain virtual client APIs ----------
688 void SOSCloudKeychainPutObjectsInCloud(CFDictionaryRef objects
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
690 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
692 cTransportRef
->put(cTransportRef
, objects
, processQueue
, replyBlock
);
695 void SOSCloudKeychainUpdateKeys(CFDictionaryRef keys
, CFStringRef accountUUID
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
697 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
699 cTransportRef
->updateKeys(cTransportRef
, keys
, accountUUID
, processQueue
, replyBlock
);
703 void SOSCloudKeychainRemoveKeys(CFArrayRef keys
, CFStringRef accountUUID
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
705 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
707 cTransportRef
->removeKeys(cTransportRef
, keys
, accountUUID
, processQueue
, replyBlock
);
710 CF_RETURNS_RETAINED CFArrayRef
SOSCloudKeychainHandleUpdateMessage(CFDictionaryRef updates
)
712 CFArrayRef result
= NULL
;
713 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
714 if (cTransportRef
->itemsChangedBlock
)
715 result
= ((CloudItemsChangedBlock
)cTransportRef
->itemsChangedBlock
)(updates
);
719 void SOSCloudKeychainGetObjectsFromCloud(CFArrayRef keysToGet
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
721 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
723 cTransportRef
->get(cTransportRef
, keysToGet
, processQueue
, replyBlock
);
726 void SOSCloudKeychainGetAllObjectsFromCloud(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
728 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
730 cTransportRef
->getAll(cTransportRef
, processQueue
, replyBlock
);
733 void SOSCloudKeychainSynchronizeAndWait(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
735 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
737 cTransportRef
->synchronizeAndWait(cTransportRef
, processQueue
, replyBlock
);
741 void SOSCloudKeychainSynchronize(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
743 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
745 cTransportRef
->synchronize(cTransportRef
, processQueue
, replyBlock
);
749 void SOSCloudKeychainClearAll(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
751 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
753 cTransportRef
->clearAll(cTransportRef
, processQueue
, replyBlock
);
756 void SOSCloudKeychainRequestSyncWithPeers(CFArrayRef
/* CFStringRef */ peers
, CFArrayRef
/* CFStringRef */ backupPeers
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
758 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
760 cTransportRef
->requestSyncWithPeers(cTransportRef
, peers
, backupPeers
, processQueue
, replyBlock
);
763 bool SOSCloudKeychainHasPendingKey(CFStringRef keyName
, CFErrorRef
* error
) {
764 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
766 return cTransportRef
&& cTransportRef
->hasPendingKey(cTransportRef
, keyName
, error
);
769 bool SOSCloudKeychainHasPendingSyncWithPeer(CFStringRef peerID
, CFErrorRef
* error
) {
770 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
772 return cTransportRef
&& cTransportRef
->hasPeerSyncPending(cTransportRef
, peerID
, error
);
775 void SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
777 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
779 cTransportRef
->requestEnsurePeerRegistration(cTransportRef
, processQueue
, replyBlock
);
782 void SOSCloudKeychainRequestPerfCounters(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
784 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
786 cTransportRef
->requestPerfCounters(cTransportRef
, processQueue
, replyBlock
);
790 void SOSCloudKeychainFlush(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
792 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
794 cTransportRef
->flush(cTransportRef
, processQueue
, replyBlock
);