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
);
134 static SOSCloudTransportRef
SOSCloudTransportDefaultTransport(void)
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
);
147 // MARK: ----- utilities -----
149 static CFErrorRef
makeError(CFIndex which
)
151 CFDictionaryRef userInfo
= NULL
;
152 return CFErrorCreate(kCFAllocatorDefault
, sErrorDomain
, which
, userInfo
);
155 // MARK: ----- DEBUG Utilities -----
157 //------------------------------------------------------------------------------------------------
159 //------------------------------------------------------------------------------------------------
161 static void describeXPCObject(char *prefix
, xpc_object_t object
)
164 // This is useful for debugging.
167 char *desc
= xpc_copy_description(object
);
168 secdebug(SOSCKCSCOPE
, "%s%s\n", prefix
, desc
);
172 secdebug(SOSCKCSCOPE
, "%s<NULL>\n", prefix
);
176 static void describeXPCType(char *prefix
, xpc_type_t xtype
)
178 // Add others as necessary, e.g. XPC_TYPE_DOUBLE
180 // This is useful for debugging.
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");
189 strcpy(msg
, "<unknown>");
191 secdebug(SOSCKCSCOPE
, "%s type:%s\n", prefix
, msg
);
195 // MARK: ---------- SOSXPCCloudTransport ----------
197 typedef struct SOSXPCCloudTransport
*SOSXPCCloudTransportRef
;
198 struct SOSXPCCloudTransport
200 struct SOSCloudTransport transport
;
201 xpc_connection_t serviceConnection
;
202 xpc_connection_t idsProxyServiceConnection
;
203 dispatch_queue_t xpc_queue
;
206 static bool xpc_event_filter(const xpc_connection_t peer
, xpc_object_t event
, CFErrorRef
*error
)
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
)
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
);
220 if (XPC_TYPE_ERROR
== xtype
)
223 const char *estr
= xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
);
225 secdebug(SOSCKCSCOPE
, "default: xpc error: %s\n", estr
);
228 if (XPC_TYPE_DICTIONARY
== xtype
)
230 secdebug(SOSCKCSCOPE
, "received dictionary event %p\n", event
);
235 secdebug(SOSCKCSCOPE
, "default: unexpected connection event %p\n", event
);
236 describeXPCObject("handle_xpc_event: obj : ", event
);
238 *error
= makeError(kSOSOUnexpectedXPCEvent
);
243 static void setupIDSProxyServiceConnection(SOSXPCCloudTransportRef transport
)
245 secnotice(SOSCKCSCOPE
, "IDS Transport: setting up xpc connection");
246 transport
->idsProxyServiceConnection
= xpc_connection_create_mach_service(xpcIDSServiceName
, transport
->xpc_queue
, 0);
248 secdebug(SOSCKCSCOPE
, "ids service connection: %p\n", transport
->idsProxyServiceConnection
);
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.");
257 xpc_connection_activate(transport
->idsProxyServiceConnection
);
260 static void teardownIDSProxyServiceConnection(SOSXPCCloudTransportRef transport
)
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
;
268 static void setupServiceConnection(SOSXPCCloudTransportRef transport
)
270 secnotice(SOSCKCSCOPE
, "CKP Transport: setting up xpc connection");
271 transport
->serviceConnection
= xpc_connection_create_mach_service(xpcServiceName
, transport
->xpc_queue
, 0);
273 secdebug(SOSCKCSCOPE
, "serviceConnection: %p\n", transport
->serviceConnection
);
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.");
282 xpc_connection_activate(transport
->serviceConnection
);
285 static void teardownServiceConnection(SOSXPCCloudTransportRef transport
)
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
;
293 static void SOSXPCCloudTransportInit(SOSXPCCloudTransportRef transport
)
295 secdebug(SOSCKCSCOPE
, "initXPCConnection\n");
297 transport
->xpc_queue
= dispatch_queue_create(xpcServiceName
, DISPATCH_QUEUE_SERIAL
);
299 setupServiceConnection(transport
);
300 setupIDSProxyServiceConnection(transport
);
302 // Any time a new session starts, reestablish the XPC connections.
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
);
313 static void talkWithIDS(SOSXPCCloudTransportRef transport
, xpc_object_t message
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
315 CFErrorRef connectionError
= NULL
;
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
);
322 xpc_connection_send_message_with_reply(transport
->idsProxyServiceConnection
, message
, transport
->xpc_queue
, ^(xpc_object_t reply
)
324 CFErrorRef serverError
= NULL
;
325 CFTypeRef object
= NULL
;
326 if (xpc_event_filter(transport
->idsProxyServiceConnection
, reply
, &serverError
) && reply
)
329 secerror("Error from xpc_event_filter: %@", serverError
);
330 xpc_object_t xrv
= xpc_dictionary_get_value(reply
, kMessageKeyValue
);
334 * The given XPC object must be one that was previously returned by
335 * _CFXPCCreateXPCMessageWithCFObject().
337 object
= _CFXPCCreateCFObjectFromXPCObject(xrv
); // CF object is retained; release in callback
338 secnotice("talkwithIDS", "converted CF object: %@", object
);
341 secerror("missing value reply");
343 xpc_object_t xerror
= xpc_dictionary_get_value(reply
, kMessageKeyError
);
345 serverError
= SecCreateCFErrorWithXPCObject(xerror
); // use SecCFCreateErrorWithFormat?
347 dispatch_async(processQueue
, ^{
349 replyBlock(object
, serverError
);
350 CFReleaseSafe(object
);
353 secerror("talkwithIDS callback error: %@", serverError
);
354 CFReleaseSafe(serverError
);
356 dispatch_release(processQueue
);
362 secerror("talkWithIDS error: %@", connectionError
);
363 dispatch_async(processQueue
, ^{
365 replyBlock(NULL
, connectionError
);
366 CFReleaseSafe(connectionError
);
367 dispatch_release(processQueue
);
370 os_activity_end(trace_activity
);
373 typedef void (^ProxyReplyBlock
)(xpc_object_t reply
);
375 static bool messageToProxy(SOSXPCCloudTransportRef transport
, xpc_object_t message
, CFErrorRef
*error
, dispatch_queue_t processQueue
, ProxyReplyBlock replyBlock
) {
376 __block CFErrorRef connectionError
= NULL
;
378 dispatch_sync(transport
->xpc_queue
, ^{
379 if (transport
->serviceConnection
&& message
) {
380 xpc_connection_send_message_with_reply(transport
->serviceConnection
, message
, processQueue
, replyBlock
);
382 connectionError
= makeError(kSOSConnectionNotOpen
);
385 return CFErrorPropagate(connectionError
, error
);
388 static void talkWithKVS(SOSXPCCloudTransportRef transport
, xpc_object_t message
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
390 CFErrorRef messagingError
= NULL
;
391 dispatch_retain(processQueue
);
392 bool messaged
= messageToProxy(transport
, message
, &messagingError
, transport
->xpc_queue
, ^(xpc_object_t reply
)
394 CFErrorRef serverError
= NULL
;
395 CFTypeRef object
= NULL
;
396 if (xpc_event_filter(transport
->serviceConnection
, reply
, &serverError
) && reply
)
399 secerror("Error from xpc_event_filter: %@", serverError
);
400 xpc_object_t xrv
= xpc_dictionary_get_value(reply
, kMessageKeyValue
);
404 * The given XPC object must be one that was previously returned by
405 * _CFXPCCreateXPCMessageWithCFObject().
407 object
= _CFXPCCreateCFObjectFromXPCObject(xrv
); // CF object is retained; release in callback
410 secerror("missing value reply");
412 xpc_object_t xerror
= xpc_dictionary_get_value(reply
, kMessageKeyError
);
414 serverError
= SecCreateCFErrorWithXPCObject(xerror
); // use SecCFCreateErrorWithFormat?
416 dispatch_async(processQueue
, ^{
418 replyBlock(object
, serverError
);
419 CFReleaseSafe(object
);
422 secerror("callback error: %@", serverError
);
423 CFReleaseSafe(serverError
);
425 dispatch_release(processQueue
);
430 secerror("talkWithKVS error: %@", messagingError
);
431 dispatch_async(processQueue
, ^{
433 replyBlock(NULL
, messagingError
);
434 CFReleaseSafe(messagingError
);
435 dispatch_release(processQueue
);
440 // MARK: ---------- SOSXPCCloudTransport Client Calls ----------
442 /* Concrete function backend implementations. */
443 static void SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportRef transport
,
444 CloudItemsChangedBlock itemsChangedBlock
) {
445 if (transport
->itemsChangedBlock
!= itemsChangedBlock
)
447 secnotice(SOSCKCSCOPE
, "Changing itemsChangedBlock");
448 if (transport
->itemsChangedBlock
)
449 Block_release(transport
->itemsChangedBlock
);
450 transport
->itemsChangedBlock
= Block_copy(itemsChangedBlock
);
454 /* Virtual function backend implementations. */
455 static void SOSCloudTransportPut(SOSCloudTransportRef transport
, CFDictionaryRef values
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
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
));
464 message
= xpc_dictionary_create(NULL
, NULL
, 0);
465 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
466 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationPUTDictionary
);
468 xobject
= _CFXPCCreateXPCObjectFromCFObject(values
);
469 require_action(xobject
, xit
, error
= makeError(kSOSObjectCantBeConvertedToXPCObject
));
470 xpc_dictionary_set_value(message
, kMessageKeyValue
, xobject
);
471 xpc_release(xobject
);
473 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
474 xpc_release(message
);
479 replyBlock(NULL
, error
);
480 CFReleaseSafe(error
);
484 void SOSCloudTransportGet(SOSCloudTransportRef transport
, CFArrayRef keysToGet
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
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();
492 require_action(xkeysToGet
, xit
, error
= makeError(kSOSObjectNotFoundError
));
494 if (keysToGet
) // don't add if nulll; will call getall
495 xpc_dictionary_set_value(xkeysOfInterest
, kMessageKeyKeysToGet
, xkeysToGet
);
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
);
502 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
503 xpc_release(xkeysToGet
);
504 xpc_release(xkeysOfInterest
);
505 xpc_release(message
);
510 xpc_release(xkeysOfInterest
);
512 xpc_release(xkeysToGet
);
514 replyBlock(NULL
, error
);
515 CFReleaseSafe(error
);
519 // Handles NULL by seting xpc_null.
520 static void SecXPCDictionarySetCFObject(xpc_object_t xdict
, const char *key
, CFTypeRef object
)
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
);
527 static void SOSCloudTransportGetIDSDeviceID(SOSCloudTransportRef transport
, CloudKeychainReplyBlock replyBlock
)
529 dispatch_queue_t processQueue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0);
531 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
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
);
537 talkWithIDS(xpcTransport
, message
, processQueue
, replyBlock
);
538 xpc_release(message
);
541 static void SOSCloudTransportGetPerformanceStats(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
543 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
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
);
549 talkWithIDS(xpcTransport
, message
, processQueue
, replyBlock
);
550 xpc_release(message
);
553 static void SOSCloudTransportSendFragmentedIDSMessage(SOSCloudTransportRef transport
, CFDictionaryRef messageData
, CFStringRef deviceName
, CFStringRef peerID
, CFStringRef myDeviceID
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
){
555 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
556 xpc_object_t xmessageData
= _CFXPCCreateXPCObjectFromCFObject(messageData
);
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
);
562 xpc_dictionary_set_value(message
, kMessageKeyValue
, xmessageData
);
563 SecXPCDictionarySetCFObject(message
, kMessageKeyDeviceName
, deviceName
);
564 SecXPCDictionarySetCFObject(message
, kMessageKeyPeerID
, peerID
);
565 SecXPCDictionarySetCFObject(message
, kMessageKeyDeviceID
, myDeviceID
);
567 talkWithIDS(xpcTransport
, message
, processQueue
, replyBlock
);
569 xpc_release(xmessageData
);
570 xpc_release(message
);
573 static void SOSCloudTransportRetrievePendingMessagesInFlight(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
){
575 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
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
);
581 talkWithIDS(xpcTransport
, message
, processQueue
, replyBlock
);
583 xpc_release(message
);
586 static void SOSCloudTransportCheckIDSDeviceIDAvailability(SOSCloudTransportRef transport
, CFArrayRef ids
, CFStringRef peerID
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
588 secdebug(SOSCKCSCOPE
, "start");
589 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
591 xpc_object_t xIDSArray
= _CFXPCCreateXPCObjectFromCFObject(ids
);
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
);
597 SecXPCDictionarySetCFObject(message
, kMessageKeyPeerID
, peerID
);
598 xpc_dictionary_set_value(message
, kMessageKeyValue
, xIDSArray
);
600 talkWithIDS(xpcTransport
, message
, processQueue
, replyBlock
);
602 xpc_release(xIDSArray
);
603 xpc_release(message
);
607 static void SOSCloudTransportSendIDSMessage(SOSCloudTransportRef transport
, CFDictionaryRef messageData
, CFStringRef deviceName
, CFStringRef peerID
, CFStringRef myDeviceID
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
){
609 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
610 xpc_object_t xmessageData
= _CFXPCCreateXPCObjectFromCFObject(messageData
);
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
);
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
);
622 xpc_release(xmessageData
);
623 xpc_release(message
);
626 static void SOSCloudTransportUpdateKeys(SOSCloudTransportRef transport
,
627 CFDictionaryRef keys
,
628 CFStringRef accountUUID
,
629 dispatch_queue_t processQueue
,
630 CloudKeychainReplyBlock replyBlock
)
632 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
634 xpc_object_t xkeysOfInterest
= xpc_dictionary_create(NULL
, NULL
, 0);
635 SecXPCDictionarySetCFObject(xkeysOfInterest
, kMessageAllKeys
, keys
);
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
);
643 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
644 xpc_release(message
);
645 xpc_release(xkeysOfInterest
);
648 static void SOSCloudTransportRemoveKeys(SOSCloudTransportRef transport
,
650 CFStringRef accountUUID
,
651 dispatch_queue_t processQueue
,
652 CloudKeychainReplyBlock replyBlock
)
654 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
656 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
657 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
659 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationRemoveKeys
);
660 SecXPCDictionarySetCFObject(message
, kMessageKeyAccountUUID
, accountUUID
);
661 SecXPCDictionarySetCFObject(message
, kMessageKeyValue
, keys
);
663 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
664 xpc_release(message
);
667 static void SOSCloudTransportGetAll(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
669 secdebug(SOSCKCSCOPE
, "start");
670 SOSCloudTransportGet(transport
, NULL
, processQueue
, replyBlock
);
673 static void SOSCloudTransportSync(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
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
);
684 static void SOSCloudTransportSyncAndWait(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
686 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
687 secnotice(SOSCKCSCOPE
, "%s XPC request to CKD: %s", kWAIT2MINID
, kOperationSynchronizeAndWait
);
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
);
693 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
694 xpc_release(message
);
697 static void SOSCloudTransportClearAll(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
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
);
708 static void SOSCloudTransportRequestSyncWithPeers(SOSCloudTransportRef transport
, CFArrayRef
/* CFStringRef */ peers
, CFArrayRef
/* CFStringRef */ backupPeers
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
710 secdebug(SOSCKCSCOPE
, "start");
711 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
713 xpc_object_t xpcmessage
= xpc_dictionary_create(NULL
, NULL
, 0);
715 xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
);
716 xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationRequestSyncWithPeers
);
718 SecXPCDictionarySetCFObject(xpcmessage
, kMessageKeyPeerIDList
, peers
);
719 SecXPCDictionarySetCFObject(xpcmessage
, kMesssgeKeyBackupPeerIDList
, backupPeers
);
721 talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
);
723 xpc_release(xpcmessage
);
727 static bool SOSCloudTransportHasPeerSyncPending(SOSCloudTransportRef transport
, CFStringRef peerID
, CFErrorRef
* error
)
729 secdebug(SOSCKCSCOPE
, "start");
730 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
732 __block
bool isSyncing
= false;
734 xpc_object_t xpcmessage
= xpc_dictionary_create(NULL
, NULL
, 0);
736 xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
);
737 xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationHasPendingSyncWithPeer
);
739 SecXPCDictionarySetCFObject(xpcmessage
, kMessageKeyPeerID
, peerID
);
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
);
748 dispatch_semaphore_wait(wait
, DISPATCH_TIME_FOREVER
);
751 dispatch_release(wait
);
753 return sent
&& isSyncing
;
757 static bool SOSCloudTransportHasPendingKey(SOSCloudTransportRef transport
, CFStringRef keyName
, CFErrorRef
* error
)
759 secdebug(SOSCKCSCOPE
, "start");
760 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
762 __block
bool kvsHasMessage
= false;
764 xpc_object_t xpcmessage
= xpc_dictionary_create(NULL
, NULL
, 0);
766 xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
);
767 xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationHasPendingKey
);
769 SecXPCDictionarySetCFObject(xpcmessage
, kMessageKeyKey
, keyName
);
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
);
778 dispatch_semaphore_wait(kvsWait
, DISPATCH_TIME_FOREVER
);
781 dispatch_release(kvsWait
);
783 return kvsSent
&& kvsHasMessage
;
787 static void SOSCloudTransportRequestEnsurePeerRegistration(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
789 secdebug(SOSCKCSCOPE
, "start");
790 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
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
);
796 talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
);
798 xpc_release(xpcmessage
);
801 static void SOSCloudTransportRequestPerfCounters(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
803 secdebug(SOSCKCSCOPE
, "start");
804 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
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
);
810 talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
);
812 xpc_release(xpcmessage
);
816 static void SOSCloudTransportFlush(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
818 secdebug(SOSCKCSCOPE
, "start");
819 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
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
);
825 talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
);
827 xpc_release(xpcmessage
);
830 static SOSCloudTransportRef
SOSCloudTransportCreateXPCTransport(void)
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
;
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
);
860 SOSXPCCloudTransportInit(st
);
861 return &st
->transport
;
864 // MARK: ---------- SOSCloudKeychain concrete client APIs ----------
865 void SOSCloudKeychainSetItemsChangedBlock(CloudItemsChangedBlock itemsChangedBlock
)
867 secdebug(SOSCKCSCOPE
, "start");
868 SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportDefaultTransport(),
872 // MARK: ---------- SOSCloudKeychain virtual client APIs ----------
874 void SOSCloudKeychainPutObjectsInCloud(CFDictionaryRef objects
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
876 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
878 cTransportRef
->put(cTransportRef
, objects
, processQueue
, replyBlock
);
881 void SOSCloudKeychainUpdateKeys(CFDictionaryRef keys
, CFStringRef accountUUID
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
883 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
885 cTransportRef
->updateKeys(cTransportRef
, keys
, accountUUID
, processQueue
, replyBlock
);
889 void SOSCloudKeychainRemoveKeys(CFArrayRef keys
, CFStringRef accountUUID
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
891 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
893 cTransportRef
->removeKeys(cTransportRef
, keys
, accountUUID
, processQueue
, replyBlock
);
896 void SOSCloudKeychainSendIDSMessage(CFDictionaryRef message
, CFStringRef deviceName
, CFStringRef peerID
, CFStringRef myDeviceID
, dispatch_queue_t processQueue
, CFBooleanRef fragmentation
, CloudKeychainReplyBlock replyBlock
)
898 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
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
);
907 void SOSCloudKeychainRetrievePendingMessageFromProxy(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
909 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
912 cTransportRef
->retrieveMessages(cTransportRef
, processQueue
, replyBlock
);
915 void SOSCloudKeychainRetrieveCountersFromIDSProxy(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
917 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
920 cTransportRef
->counters(cTransportRef
, processQueue
, replyBlock
);
923 void SOSCloudKeychainGetIDSDeviceID(CloudKeychainReplyBlock replyBlock
)
925 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
927 cTransportRef
->getDeviceID(cTransportRef
, replyBlock
);
930 void SOSCloudKeychainGetIDSDeviceAvailability(CFArrayRef ids
, CFStringRef peerID
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
){
932 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
935 cTransportRef
->getIDSDeviceAvailability(cTransportRef
, ids
, peerID
, processQueue
, replyBlock
);
937 CF_RETURNS_RETAINED CFArrayRef
SOSCloudKeychainHandleUpdateMessage(CFDictionaryRef updates
)
939 CFArrayRef result
= NULL
;
940 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
941 if (cTransportRef
->itemsChangedBlock
)
942 result
= ((CloudItemsChangedBlock
)cTransportRef
->itemsChangedBlock
)(updates
);
946 void SOSCloudKeychainGetObjectsFromCloud(CFArrayRef keysToGet
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
948 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
950 cTransportRef
->get(cTransportRef
, keysToGet
, processQueue
, replyBlock
);
953 void SOSCloudKeychainGetAllObjectsFromCloud(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
955 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
957 cTransportRef
->getAll(cTransportRef
, processQueue
, replyBlock
);
960 void SOSCloudKeychainSynchronizeAndWait(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
962 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
964 cTransportRef
->synchronizeAndWait(cTransportRef
, processQueue
, replyBlock
);
968 void SOSCloudKeychainSynchronize(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
970 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
972 cTransportRef
->synchronize(cTransportRef
, processQueue
, replyBlock
);
976 void SOSCloudKeychainClearAll(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
978 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
980 cTransportRef
->clearAll(cTransportRef
, processQueue
, replyBlock
);
983 void SOSCloudKeychainRequestSyncWithPeers(CFArrayRef
/* CFStringRef */ peers
, CFArrayRef
/* CFStringRef */ backupPeers
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
985 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
987 cTransportRef
->requestSyncWithPeers(cTransportRef
, peers
, backupPeers
, processQueue
, replyBlock
);
990 bool SOSCloudKeychainHasPendingKey(CFStringRef keyName
, CFErrorRef
* error
) {
991 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
993 return cTransportRef
&& cTransportRef
->hasPendingKey(cTransportRef
, keyName
, error
);
996 bool SOSCloudKeychainHasPendingSyncWithPeer(CFStringRef peerID
, CFErrorRef
* error
) {
997 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
999 return cTransportRef
&& cTransportRef
->hasPeerSyncPending(cTransportRef
, peerID
, error
);
1002 void SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
1004 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
1006 cTransportRef
->requestEnsurePeerRegistration(cTransportRef
, processQueue
, replyBlock
);
1009 void SOSCloudKeychainRequestPerfCounters(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
1011 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
1013 cTransportRef
->requestPerfCounters(cTransportRef
, processQueue
, replyBlock
);
1017 void SOSCloudKeychainFlush(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
1019 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
1021 cTransportRef
->flush(cTransportRef
, processQueue
, replyBlock
);