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
);