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 "keychain/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: ---------- SOSXPCCloudTransport ---------- 
 165 typedef struct SOSXPCCloudTransport 
*SOSXPCCloudTransportRef
; 
 166 struct SOSXPCCloudTransport
 
 168     struct SOSCloudTransport transport
; 
 169     xpc_connection_t serviceConnection
; 
 170     dispatch_queue_t xpc_queue
; 
 173 static void teardownServiceConnection(SOSXPCCloudTransportRef transport
) 
 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
; 
 183 static void setupServiceConnection(SOSXPCCloudTransportRef transport
) 
 185     secnotice(SOSCKCSCOPE
, "CKP Transport: setting up xpc connection"); 
 186     dispatch_assert_queue(transport
->xpc_queue
); 
 188     transport
->serviceConnection 
= xpc_connection_create_mach_service(kCKPServiceName
, transport
->xpc_queue
, 0); 
 190     secdebug(SOSCKCSCOPE
, "serviceConnection: %@", transport
->serviceConnection
); 
 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
); 
 202     xpc_connection_activate(transport
->serviceConnection
); 
 205 static void SOSXPCCloudTransportInit(SOSXPCCloudTransportRef transport
) 
 207     secdebug(SOSCKCSCOPE
, "initXPCConnection"); 
 209     transport
->xpc_queue 
= dispatch_queue_create(kCKPServiceName
, DISPATCH_QUEUE_SERIAL
); 
 211     dispatch_sync(transport
->xpc_queue
, ^{ 
 212         setupServiceConnection(transport
); 
 215     // Any time a new session starts, reestablish the XPC connections. 
 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
); 
 223 typedef void (^ProxyReplyBlock
)(xpc_object_t reply
); 
 225 static bool messageToProxy(SOSXPCCloudTransportRef transport
, xpc_object_t message
, CFErrorRef 
*error
, dispatch_queue_t processQueue
, ProxyReplyBlock replyBlock
) { 
 226     __block CFErrorRef connectionError 
= NULL
; 
 228     dispatch_sync(transport
->xpc_queue
, ^{ 
 229         if (transport
->serviceConnection 
== NULL
) { 
 230             setupServiceConnection(transport
); 
 233         if (transport
->serviceConnection 
&& message
) { 
 234             xpc_connection_send_message_with_reply(transport
->serviceConnection
, message
, processQueue
, replyBlock
); 
 236             connectionError 
= makeError(kSOSConnectionNotOpen
); 
 239     return CFErrorPropagate(connectionError
, error
); 
 242 static void talkWithKVS(SOSXPCCloudTransportRef transport
, xpc_object_t message
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 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
; 
 250         if (xpc_get_type(reply
) == XPC_TYPE_DICTIONARY
) { 
 251             xpc_object_t xrv 
= xpc_dictionary_get_value(reply
, kMessageKeyValue
); 
 253                 object 
= _CFXPCCreateCFObjectFromXPCObject(xrv
); 
 255                 secerror("missing value reply"); 
 258             xpc_object_t xerror 
= xpc_dictionary_get_value(reply
, kMessageKeyError
); 
 260                 serverError 
= SecCreateCFErrorWithXPCObject(xerror
); 
 263             serverError 
= makeError(kSOSMessageInvalid
); 
 264             secerror("Odd reply from CloudKeychainProxy: %@: %@", reply
, serverError
); 
 266         dispatch_async(processQueue
, ^{ 
 268                 replyBlock(object
, serverError
); 
 270             CFReleaseSafe(object
); 
 272                 secerror("callback error: %@", serverError
); 
 273                 CFReleaseSafe(serverError
); 
 275             dispatch_release(processQueue
); 
 280         secerror("talkWithKVS error: %@", messagingError
); 
 281         dispatch_async(processQueue
, ^{ 
 283                 replyBlock(NULL
, messagingError
); 
 284             CFReleaseSafe(messagingError
); 
 285             dispatch_release(processQueue
); 
 290 // MARK: ---------- SOSXPCCloudTransport Client Calls ---------- 
 292 /* Concrete function backend implementations. */ 
 293 static void SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportRef transport
, 
 294                                                   CloudItemsChangedBlock itemsChangedBlock
) { 
 295     if (transport
->itemsChangedBlock 
!= itemsChangedBlock
) 
 297         secnotice(SOSCKCSCOPE
, "Changing itemsChangedBlock"); 
 298         if (transport
->itemsChangedBlock
) 
 299             Block_release(transport
->itemsChangedBlock
); 
 300         transport
->itemsChangedBlock 
= Block_copy(itemsChangedBlock
); 
 304 /* Virtual function backend implementations. */ 
 305 static void SOSCloudTransportPut(SOSCloudTransportRef transport
, CFDictionaryRef values
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 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
)); 
 314     message 
= xpc_dictionary_create(NULL
, NULL
, 0); 
 315     xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
); 
 316     xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationPUTDictionary
); 
 318     xobject 
= _CFXPCCreateXPCObjectFromCFObject(values
); 
 319     require_action(xobject
, xit
, error 
= makeError(kSOSObjectCantBeConvertedToXPCObject
)); 
 320     xpc_dictionary_set_value(message
, kMessageKeyValue
, xobject
); 
 321     xpc_release(xobject
); 
 323     talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
); 
 324     xpc_release(message
); 
 329         replyBlock(NULL
, error
); 
 330     CFReleaseSafe(error
); 
 334 void SOSCloudTransportGet(SOSCloudTransportRef transport
, CFArrayRef keysToGet
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 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(); 
 342     require_action(xkeysToGet
, xit
, error 
= makeError(kSOSObjectNotFoundError
)); 
 344     if (keysToGet
)  // don't add if nulll; will call getall 
 345         xpc_dictionary_set_value(xkeysOfInterest
, kMessageKeyKeysToGet
, xkeysToGet
); 
 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
); 
 352     talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
); 
 353     xpc_release(xkeysToGet
); 
 354     xpc_release(xkeysOfInterest
); 
 355     xpc_release(message
); 
 360         xpc_release(xkeysOfInterest
); 
 362         xpc_release(xkeysToGet
); 
 364         replyBlock(NULL
, error
); 
 365     CFReleaseSafe(error
); 
 369 // Handles NULL by seting xpc_null. 
 370 static void SecXPCDictionarySetCFObject(xpc_object_t xdict
, const char *key
, CFTypeRef object
) 
 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
); 
 377 static void SOSCloudTransportUpdateKeys(SOSCloudTransportRef transport
, 
 378                                         CFDictionaryRef keys
, 
 379                                         CFStringRef accountUUID
, 
 380                                         dispatch_queue_t processQueue
, 
 381                                         CloudKeychainReplyBlock replyBlock
) 
 383     SOSXPCCloudTransportRef xpcTransport 
= (SOSXPCCloudTransportRef
)transport
; 
 385     xpc_object_t xkeysOfInterest 
= xpc_dictionary_create(NULL
, NULL
, 0); 
 386     SecXPCDictionarySetCFObject(xkeysOfInterest
, kMessageAllKeys
, keys
); 
 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
); 
 394     talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
); 
 395     xpc_release(message
); 
 396     xpc_release(xkeysOfInterest
); 
 399 static void SOSCloudTransportRemoveKeys(SOSCloudTransportRef transport
, 
 401                                         CFStringRef accountUUID
, 
 402                                         dispatch_queue_t processQueue
, 
 403                                         CloudKeychainReplyBlock replyBlock
) 
 405         SOSXPCCloudTransportRef xpcTransport 
= (SOSXPCCloudTransportRef
)transport
; 
 407         xpc_object_t message 
= xpc_dictionary_create(NULL
, NULL
, 0); 
 408         xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
); 
 410         xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationRemoveKeys
); 
 411         SecXPCDictionarySetCFObject(message
, kMessageKeyAccountUUID
, accountUUID
); 
 412         SecXPCDictionarySetCFObject(message
, kMessageKeyValue
, keys
); 
 414         talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
); 
 415         xpc_release(message
); 
 418 static void SOSCloudTransportGetAll(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 420     secdebug(SOSCKCSCOPE
, "start"); 
 421     SOSCloudTransportGet(transport
, NULL
, processQueue
, replyBlock
); 
 424 static void SOSCloudTransportSync(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 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
); 
 435 static void SOSCloudTransportSyncAndWait(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 437     SOSXPCCloudTransportRef xpcTransport 
= (SOSXPCCloudTransportRef
)transport
; 
 438     secnotice(SOSCKCSCOPE
, "%s XPC request to CKD: %s", kWAIT2MINID
, kOperationSynchronizeAndWait
); 
 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
); 
 444     talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
); 
 445     xpc_release(message
); 
 448 static void SOSCloudTransportClearAll(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 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
); 
 459 static void SOSCloudTransportRequestSyncWithPeers(SOSCloudTransportRef transport
, CFArrayRef 
/* CFStringRef */ peers
, CFArrayRef 
/* CFStringRef */ backupPeers
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 461     secdebug(SOSCKCSCOPE
, "start"); 
 462     SOSXPCCloudTransportRef xpcTransport 
= (SOSXPCCloudTransportRef
)transport
; 
 464     xpc_object_t xpcmessage 
= xpc_dictionary_create(NULL
, NULL
, 0); 
 466     xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
); 
 467     xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationRequestSyncWithPeers
); 
 469     SecXPCDictionarySetCFObject(xpcmessage
, kMessageKeyPeerIDList
, peers
); 
 470     SecXPCDictionarySetCFObject(xpcmessage
, kMesssgeKeyBackupPeerIDList
, backupPeers
); 
 472     talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
); 
 474     xpc_release(xpcmessage
); 
 478 static bool SOSCloudTransportHasPendingKey(SOSCloudTransportRef transport
, CFStringRef keyName
, CFErrorRef
* error
) 
 480     secdebug(SOSCKCSCOPE
, "start"); 
 481     SOSXPCCloudTransportRef xpcTransport 
= (SOSXPCCloudTransportRef
)transport
; 
 483     __block 
bool kvsHasMessage 
= false; 
 485     xpc_object_t xpcmessage 
= xpc_dictionary_create(NULL
, NULL
, 0); 
 487     xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
); 
 488     xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationHasPendingKey
); 
 490     SecXPCDictionarySetCFObject(xpcmessage
, kMessageKeyKey
, keyName
); 
 492     dispatch_semaphore_t kvsWait 
= dispatch_semaphore_create(0); 
 493     bool kvsSent 
= messageToProxy(xpcTransport
, xpcmessage
, error
, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(xpc_object_t reply
) { 
 494         kvsHasMessage 
= xpc_dictionary_get_bool(reply
, kMessageKeyValue
); 
 495         dispatch_semaphore_signal(kvsWait
); 
 499         dispatch_semaphore_wait(kvsWait
, DISPATCH_TIME_FOREVER
); 
 502     dispatch_release(kvsWait
); 
 504     return kvsSent 
&& kvsHasMessage
; 
 508 static void SOSCloudTransportRequestEnsurePeerRegistration(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 510     secdebug(SOSCKCSCOPE
, "start"); 
 511     SOSXPCCloudTransportRef xpcTransport 
= (SOSXPCCloudTransportRef
)transport
; 
 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
); 
 517     talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
); 
 519     xpc_release(xpcmessage
); 
 522 static void SOSCloudTransportRequestPerfCounters(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 524     secdebug(SOSCKCSCOPE
, "start"); 
 525     SOSXPCCloudTransportRef xpcTransport 
= (SOSXPCCloudTransportRef
)transport
; 
 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
); 
 531     talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
); 
 533     xpc_release(xpcmessage
); 
 537 static void SOSCloudTransportFlush(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 539     secdebug(SOSCKCSCOPE
, "start"); 
 540     SOSXPCCloudTransportRef xpcTransport 
= (SOSXPCCloudTransportRef
)transport
; 
 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
); 
 546     talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
); 
 548     xpc_release(xpcmessage
); 
 551 static SOSCloudTransportRef 
SOSCloudTransportCreateXPCTransport(void) 
 553     SOSXPCCloudTransportRef st
; 
 554     st 
= calloc(1, sizeof(*st
)); 
 555     st
->transport
.put 
= SOSCloudTransportPut
; 
 556     st
->transport
.updateKeys 
= SOSCloudTransportUpdateKeys
; 
 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
); 
 574     SOSXPCCloudTransportInit(st
); 
 575     return &st
->transport
; 
 578 // MARK: ---------- SOSCloudKeychain concrete client APIs ---------- 
 579 void SOSCloudKeychainSetItemsChangedBlock(CloudItemsChangedBlock itemsChangedBlock
) 
 581     secdebug(SOSCKCSCOPE
, "start"); 
 582     SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportDefaultTransport(), 
 586 // MARK: ---------- SOSCloudKeychain virtual client APIs ---------- 
 588 void SOSCloudKeychainPutObjectsInCloud(CFDictionaryRef objects
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 590     SOSCloudTransportRef cTransportRef 
= SOSCloudTransportDefaultTransport(); 
 592         cTransportRef
->put(cTransportRef
, objects
, processQueue
, replyBlock
); 
 595 void SOSCloudKeychainUpdateKeys(CFDictionaryRef keys
, CFStringRef accountUUID
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 597     SOSCloudTransportRef cTransportRef 
= SOSCloudTransportDefaultTransport(); 
 599         cTransportRef
->updateKeys(cTransportRef
, keys
, accountUUID
, processQueue
, replyBlock
); 
 603 void SOSCloudKeychainRemoveKeys(CFArrayRef keys
, CFStringRef accountUUID
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 605     SOSCloudTransportRef cTransportRef 
= SOSCloudTransportDefaultTransport(); 
 607         cTransportRef
->removeKeys(cTransportRef
, keys
, accountUUID
, processQueue
, replyBlock
); 
 610 CF_RETURNS_RETAINED CFArrayRef 
SOSCloudKeychainHandleUpdateMessage(CFDictionaryRef updates
) 
 612     CFArrayRef result 
= NULL
; 
 613     SOSCloudTransportRef cTransportRef 
= SOSCloudTransportDefaultTransport(); 
 614     if (cTransportRef
->itemsChangedBlock
) 
 615         result 
= ((CloudItemsChangedBlock
)cTransportRef
->itemsChangedBlock
)(updates
); 
 619 void SOSCloudKeychainGetObjectsFromCloud(CFArrayRef keysToGet
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 621     SOSCloudTransportRef cTransportRef 
= SOSCloudTransportDefaultTransport(); 
 623         cTransportRef
->get(cTransportRef
, keysToGet
, processQueue
, replyBlock
); 
 626 void SOSCloudKeychainGetAllObjectsFromCloud(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 628     SOSCloudTransportRef cTransportRef 
= SOSCloudTransportDefaultTransport(); 
 630         cTransportRef
->getAll(cTransportRef
, processQueue
, replyBlock
); 
 633 void SOSCloudKeychainSynchronizeAndWait(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 635     SOSCloudTransportRef cTransportRef 
= SOSCloudTransportDefaultTransport(); 
 637         cTransportRef
->synchronizeAndWait(cTransportRef
, processQueue
, replyBlock
); 
 641 void SOSCloudKeychainSynchronize(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 643     SOSCloudTransportRef cTransportRef 
= SOSCloudTransportDefaultTransport(); 
 645         cTransportRef
->synchronize(cTransportRef
, processQueue
, replyBlock
); 
 649 void SOSCloudKeychainClearAll(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 651     SOSCloudTransportRef cTransportRef 
= SOSCloudTransportDefaultTransport(); 
 652     secnotice("circleOps", "SOSCloudKeychainClearAll called"); 
 654         cTransportRef
->clearAll(cTransportRef
, processQueue
, replyBlock
); 
 657 void SOSCloudKeychainRequestSyncWithPeers(CFArrayRef 
/* CFStringRef */ peers
, CFArrayRef 
/* CFStringRef */ backupPeers
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 659     SOSCloudTransportRef cTransportRef 
= SOSCloudTransportDefaultTransport(); 
 661         cTransportRef
->requestSyncWithPeers(cTransportRef
, peers
, backupPeers
, processQueue
, replyBlock
); 
 664 bool SOSCloudKeychainHasPendingKey(CFStringRef keyName
, CFErrorRef
* error
) { 
 665     SOSCloudTransportRef cTransportRef 
= SOSCloudTransportDefaultTransport(); 
 667     return cTransportRef 
&& cTransportRef
->hasPendingKey(cTransportRef
, keyName
, error
); 
 670 void SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 672     SOSCloudTransportRef cTransportRef 
= SOSCloudTransportDefaultTransport(); 
 674         cTransportRef
->requestEnsurePeerRegistration(cTransportRef
, processQueue
, replyBlock
); 
 677 void SOSCloudKeychainRequestPerfCounters(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 679     SOSCloudTransportRef cTransportRef 
= SOSCloudTransportDefaultTransport(); 
 681         cTransportRef
->requestPerfCounters(cTransportRef
, processQueue
, replyBlock
); 
 685 void SOSCloudKeychainFlush(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
) 
 687     SOSCloudTransportRef cTransportRef 
= SOSCloudTransportDefaultTransport(); 
 689         cTransportRef
->flush(cTransportRef
, processQueue
, replyBlock
);