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 the main security code cannot 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>
50 #include <utilities/debugging.h>
51 #include <utilities/SecCFWrappers.h>
52 #include <utilities/SecXPCError.h>
54 #include "SOSCloudKeychainConstants.h"
55 #include "SOSCloudKeychainClient.h"
56 #include "SOSKVSKeys.h"
57 #include "SOSUserKeygen.h"
58 #include "SecOTRSession.h"
59 #include "SOSCloudKeychainLogging.h"
61 #include <os/activity.h>
62 #include <os/state_private.h>
65 static CFStringRef sErrorDomain
= CFSTR("com.apple.security.sos.transport.error");
67 #define KVSLOGSTATE "kvsLogState"
68 #define SOSCKCSCOPE "sync"
70 // MARK: ---------- SOSCloudTransport ----------
72 /* SOSCloudTransport, a statically initialized transport singleton. */
73 static SOSCloudTransportRef sTransport
= NULL
;
75 static SOSCloudTransportRef
SOSCloudTransportCreateXPCTransport(void);
77 void SOSCloudKeychainSetTransport(SOSCloudTransportRef transport
) {
78 sTransport
= transport
;
81 void SOSCloudTransportGet(SOSCloudTransportRef transport
, CFArrayRef keysToGet
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
);
85 /* Return the singleton cloud transport instance. */
86 CFDictionaryRef
SOSCloudCopyKVSState(void) {
87 __block CFDictionaryRef retval
= NULL
;
89 static dispatch_queue_t processQueue
= NULL
;
90 static dispatch_once_t onceToken
;
91 dispatch_once(&onceToken
, ^{
92 processQueue
= dispatch_queue_create("KVSStateCapture", DISPATCH_QUEUE_SERIAL
);
95 if (processQueue
== NULL
)
98 dispatch_semaphore_t waitSemaphore
= NULL
;
100 waitSemaphore
= dispatch_semaphore_create(0);
102 CloudKeychainReplyBlock replyBlock
= ^ (CFDictionaryRef returnedValues
, CFErrorRef error
) {
103 retval
= returnedValues
;
104 if (retval
) CFRetain(retval
);
105 dispatch_semaphore_signal(waitSemaphore
);
108 SOSCloudKeychainGetAllObjectsFromCloud(processQueue
, replyBlock
);
110 dispatch_semaphore_wait(waitSemaphore
, DISPATCH_TIME_FOREVER
);
111 dispatch_release(waitSemaphore
);
117 os_state_block_t kvsStateBlock
= ^os_state_data_t(os_state_hints_t hints
) {
118 os_state_data_t retval
= NULL
;
119 __block CFDictionaryRef kvsdict
= NULL
;
120 CFDataRef serializedKVS
= NULL
;
122 require_quiet(hints
->osh_api
== 3, errOut
); // only grab on sysdiagnose or command lin
124 kvsdict
= SOSCloudCopyKVSState();
126 require_quiet(kvsdict
, errOut
);
127 serializedKVS
= CFPropertyListCreateData(kCFAllocatorDefault
, kvsdict
, kCFPropertyListBinaryFormat_v1_0
, 0, NULL
);
128 size_t statelen
= CFDataGetLength(serializedKVS
);
129 retval
= (os_state_data_t
)calloc(1, OS_STATE_DATA_SIZE_NEEDED(statelen
));
130 require_quiet(retval
, errOut
);
132 retval
->osd_type
= OS_STATE_DATA_SERIALIZED_NSCF_OBJECT
;
133 memcpy(retval
->osd_data
, CFDataGetBytePtr(serializedKVS
), statelen
);
134 retval
->osd_size
= statelen
;
135 strcpy(retval
->osd_title
, "CloudCircle KVS Object");
137 CFReleaseNull(kvsdict
);
138 CFReleaseNull(serializedKVS
);
143 static SOSCloudTransportRef
SOSCloudTransportDefaultTransport(void)
145 static dispatch_once_t sTransportOnce
;
146 dispatch_once(&sTransportOnce
, ^{
148 SOSCloudKeychainSetTransport(SOSCloudTransportCreateXPCTransport());
149 // provide state handler to sysdiagnose and logging
150 os_state_add_handler(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), kvsStateBlock
);
156 // MARK: ----- utilities -----
158 static CFErrorRef
makeError(CFIndex which
)
160 CFDictionaryRef userInfo
= NULL
;
161 return CFErrorCreate(kCFAllocatorDefault
, sErrorDomain
, which
, userInfo
);
164 // MARK: ----- DEBUG Utilities -----
166 //------------------------------------------------------------------------------------------------
168 //------------------------------------------------------------------------------------------------
170 static void describeXPCObject(char *prefix
, xpc_object_t object
)
173 // This is useful for debugging.
176 char *desc
= xpc_copy_description(object
);
177 secdebug(SOSCKCSCOPE
, "%s%s\n", prefix
, desc
);
181 secdebug(SOSCKCSCOPE
, "%s<NULL>\n", prefix
);
185 static void describeXPCType(char *prefix
, xpc_type_t xtype
)
187 // Add others as necessary, e.g. XPC_TYPE_DOUBLE
189 // This is useful for debugging.
191 if (XPC_TYPE_CONNECTION
== xtype
)
192 strcpy(msg
, "XPC_TYPE_CONNECTION");
193 else if (XPC_TYPE_ERROR
== xtype
)
194 strcpy(msg
, "XPC_TYPE_ERROR");
195 else if (XPC_TYPE_DICTIONARY
== xtype
)
196 strcpy(msg
, "XPC_TYPE_DICTIONARY");
198 strcpy(msg
, "<unknown>");
200 secdebug(SOSCKCSCOPE
, "%s type:%s\n", prefix
, msg
);
204 // MARK: ---------- SOSXPCCloudTransport ----------
206 typedef struct SOSXPCCloudTransport
*SOSXPCCloudTransportRef
;
207 struct SOSXPCCloudTransport
209 struct SOSCloudTransport transport
;
210 xpc_connection_t serviceConnection
;
211 xpc_connection_t idsProxyServiceConnection
;
212 dispatch_queue_t xpc_queue
;
215 static bool xpc_event_filter(const xpc_connection_t peer
, xpc_object_t event
, CFErrorRef
*error
)
217 // return true if the type is XPC_TYPE_DICTIONARY (and therefore something more to process)
218 secdebug(SOSCKCSCOPE
, "handle_connection_event\n");
219 xpc_type_t xtype
= xpc_get_type(event
);
220 describeXPCType("handle_xpc_event", xtype
);
221 if (XPC_TYPE_CONNECTION
== xtype
)
223 secdebug(SOSCKCSCOPE
, "handle_xpc_event: XPC_TYPE_CONNECTION (unexpected)");
224 // The client of an XPC service does not get connection events
225 // For now, we log this and keep going
226 describeXPCObject("handle_xpc_event: XPC_TYPE_CONNECTION, obj : ", event
);
229 *error
= makeError(kSOSOUnexpectedConnectionEvent
); // FIX
234 if (XPC_TYPE_ERROR
== xtype
)
237 const char *estr
= xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
);
239 secdebug(SOSCKCSCOPE
, "default: xpc error: %s\n", estr
);
240 #if 0 // just log for now
241 CFStringRef errStr
= CFStringCreateWithCString(kCFAllocatorDefault
, estr
, kCFStringEncodingUTF8
);
242 CFMutableDictionaryRef userInfo
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
244 CFDictionaryAddValue(userInfo
, kCFErrorLocalizedDescriptionKey
, errStr
);
246 *error
= CFErrorCreate(kCFAllocatorDefault
, sErrorDomain
, kSOSOXPCErrorEvent
, userInfo
);
247 CFReleaseSafe(errStr
);
248 CFReleaseSafe(userInfo
);
252 if (XPC_TYPE_DICTIONARY
== xtype
)
254 secdebug(SOSCKCSCOPE
, "received dictionary event %p\n", event
);
259 secdebug(SOSCKCSCOPE
, "default: unexpected connection event %p\n", event
);
260 describeXPCObject("handle_xpc_event: obj : ", event
);
262 *error
= makeError(kSOSOUnexpectedXPCEvent
);
267 static void SOSXPCCloudTransportInit(SOSXPCCloudTransportRef transport
)
269 secdebug(SOSCKCSCOPE
, "initXPCConnection\n");
271 transport
->xpc_queue
= dispatch_queue_create(xpcServiceName
, DISPATCH_QUEUE_SERIAL
);
273 transport
->serviceConnection
= xpc_connection_create_mach_service(xpcServiceName
, transport
->xpc_queue
, 0);
276 secdebug(SOSCKCSCOPE
, "serviceConnection: %p\n", transport
->serviceConnection
);
279 xpc_connection_set_event_handler(transport
->serviceConnection
, ^(xpc_object_t event
)
281 secdebug(SOSCKCSCOPE
, "xpc_connection_set_event_handler\n");
284 xpc_connection_resume(transport
->serviceConnection
);
285 xpc_retain(transport
->serviceConnection
);
287 transport
->idsProxyServiceConnection
= xpc_connection_create_mach_service(xpcIDSServiceName
, transport
->xpc_queue
, 0);
289 secdebug(SOSCKCSCOPE
, "ids service connection: %p\n", transport
->idsProxyServiceConnection
);
291 xpc_connection_set_event_handler(transport
->idsProxyServiceConnection
, ^(xpc_object_t object
) {
292 secdebug(SOSCKCSCOPE
, "IDS Transport, xpc_connection_set_event_handler\n");
294 xpc_connection_resume(transport
->idsProxyServiceConnection
);
295 xpc_retain(transport
->idsProxyServiceConnection
);
299 static void talkWithIDS(SOSXPCCloudTransportRef transport
, xpc_object_t message
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
301 CFErrorRef connectionError
= NULL
;
303 os_activity_t trace_activity
= os_activity_start("talkWithIDS", OS_ACTIVITY_FLAG_DEFAULT
);
304 require_action(transport
->idsProxyServiceConnection
, xit
, connectionError
= makeError(kSOSConnectionNotOpen
));
305 require_action(message
, xit
, connectionError
= makeError(kSOSObjectNotFoundError
));
306 dispatch_retain(processQueue
);
308 xpc_connection_send_message_with_reply(transport
->idsProxyServiceConnection
, message
, transport
->xpc_queue
, ^(xpc_object_t reply
)
310 CFErrorRef serverError
= NULL
;
311 CFTypeRef object
= NULL
;
312 if (xpc_event_filter(transport
->idsProxyServiceConnection
, reply
, &serverError
) && reply
)
314 describeXPCObject("IDS Proxy: reply : ", reply
);
316 secerror("Error from xpc_event_filter: %@", serverError
);
317 xpc_object_t xrv
= xpc_dictionary_get_value(reply
, kMessageKeyValue
);
320 describeXPCObject("talkwithIDS: xrv: ", xrv
);
322 * The given XPC object must be one that was previously returned by
323 * _CFXPCCreateXPCMessageWithCFObject().
325 object
= _CFXPCCreateCFObjectFromXPCObject(xrv
); // CF object is retained; release in callback
326 secnotice("talkwithIDS", "converted CF object: %@", object
);
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("talkwithIDS callback error: %@", serverError
);
342 CFReleaseSafe(serverError
);
344 dispatch_release(processQueue
);
350 secerror("talkWithIDS error: %@", connectionError
);
351 dispatch_async(processQueue
, ^{
353 replyBlock(NULL
, connectionError
);
354 CFReleaseSafe(connectionError
);
355 dispatch_release(processQueue
);
358 os_activity_end(trace_activity
);
360 static void talkWithKVS(SOSXPCCloudTransportRef transport
, xpc_object_t message
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
362 CFErrorRef connectionError
= NULL
;
364 os_activity_t trace_activity
= os_activity_start("talkWithKVS", OS_ACTIVITY_FLAG_DEFAULT
);
365 require_action(transport
->serviceConnection
, xit
, connectionError
= makeError(kSOSConnectionNotOpen
));
366 require_action(message
, xit
, connectionError
= makeError(kSOSObjectNotFoundError
));
367 dispatch_retain(processQueue
);
369 xpc_connection_send_message_with_reply(transport
->serviceConnection
, message
, transport
->xpc_queue
, ^(xpc_object_t reply
)
371 CFErrorRef serverError
= NULL
;
372 CFTypeRef object
= NULL
;
373 if (xpc_event_filter(transport
->serviceConnection
, reply
, &serverError
) && reply
)
375 describeXPCObject("getValuesFromKVS: reply : ", reply
);
377 secerror("Error from xpc_event_filter: %@", serverError
);
378 xpc_object_t xrv
= xpc_dictionary_get_value(reply
, kMessageKeyValue
);
381 describeXPCObject("talkWithKVS: xrv: ", xrv
);
383 * The given XPC object must be one that was previously returned by
384 * _CFXPCCreateXPCMessageWithCFObject().
386 object
= _CFXPCCreateCFObjectFromXPCObject(xrv
); // CF object is retained; release in callback
387 secnotice("talkwithkvs", "converted CF object: %@", object
);
390 secerror("missing value reply");
392 xpc_object_t xerror
= xpc_dictionary_get_value(reply
, kMessageKeyError
);
394 serverError
= SecCreateCFErrorWithXPCObject(xerror
); // use SecCFCreateErrorWithFormat?
396 dispatch_async(processQueue
, ^{
398 replyBlock(object
, serverError
);
399 CFReleaseSafe(object
);
402 secerror("callback error: %@", serverError
);
403 CFReleaseSafe(serverError
);
405 dispatch_release(processQueue
);
411 secerror("talkWithKVS error: %@", connectionError
);
412 dispatch_async(processQueue
, ^{
414 replyBlock(NULL
, connectionError
);
415 CFReleaseSafe(connectionError
);
416 dispatch_release(processQueue
);
419 os_activity_end(trace_activity
);
422 // MARK: ---------- SOSXPCCloudTransport Client Calls ----------
424 /* Concrete function backend implementations. */
425 static void SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportRef transport
,
426 CloudItemsChangedBlock itemsChangedBlock
) {
427 if (transport
->itemsChangedBlock
!= itemsChangedBlock
)
429 secnotice(SOSCKCSCOPE
, "Changing itemsChangedBlock");
430 if (transport
->itemsChangedBlock
)
431 Block_release(transport
->itemsChangedBlock
);
432 transport
->itemsChangedBlock
= Block_copy(itemsChangedBlock
);
436 /* Virtual function backend implementations. */
437 static void SOSCloudTransportPut(SOSCloudTransportRef transport
, CFDictionaryRef values
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
439 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
440 secdebug(SOSCKCSCOPE
, "%@", values
);
441 CFErrorRef error
= NULL
;
442 xpc_object_t message
= NULL
;
443 xpc_object_t xobject
= NULL
;
444 require_action(values
, xit
, error
= makeError(kSOSObjectNotFoundError
));
446 message
= xpc_dictionary_create(NULL
, NULL
, 0);
447 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
448 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationPUTDictionary
);
450 xobject
= _CFXPCCreateXPCObjectFromCFObject(values
);
451 require_action(xobject
, xit
, error
= makeError(kSOSObjectCantBeConvertedToXPCObject
));
452 xpc_dictionary_set_value(message
, kMessageKeyValue
, xobject
);
453 xpc_release(xobject
);
455 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
456 xpc_release(message
);
461 replyBlock(NULL
, error
);
462 CFReleaseSafe(error
);
466 void SOSCloudTransportGet(SOSCloudTransportRef transport
, CFArrayRef keysToGet
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
468 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
469 secdebug(SOSCKCSCOPE
, "%@", keysToGet
);
470 CFErrorRef error
= NULL
;
471 xpc_object_t xkeysOfInterest
= xpc_dictionary_create(NULL
, NULL
, 0);
472 xpc_object_t xkeysToGet
= keysToGet
? _CFXPCCreateXPCObjectFromCFObject(keysToGet
) : xpc_null_create();
474 require_action(xkeysToGet
, xit
, error
= makeError(kSOSObjectNotFoundError
));
476 if (keysToGet
) // don't add if nulll; will call getall
477 xpc_dictionary_set_value(xkeysOfInterest
, kMessageKeyKeysToGet
, xkeysToGet
);
479 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
480 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
481 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationGETv2
);
482 xpc_dictionary_set_value(message
, kMessageKeyValue
, xkeysOfInterest
);
484 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
485 xpc_release(xkeysToGet
);
486 xpc_release(xkeysOfInterest
);
487 xpc_release(message
);
492 xpc_release(xkeysOfInterest
);
494 xpc_release(xkeysToGet
);
496 replyBlock(NULL
, error
);
497 CFReleaseSafe(error
);
501 // Handles NULL by seting xpc_null.
502 static void SecXPCDictionarySetCFObject(xpc_object_t xdict
, const char *key
, CFTypeRef object
)
504 xpc_object_t xpc_obj
= object
? _CFXPCCreateXPCObjectFromCFObject(object
) : xpc_null_create();
505 xpc_dictionary_set_value(xdict
, key
, xpc_obj
);
506 xpc_release(xpc_obj
);
509 static void SOSCloudTransportGetIDSDeviceID(SOSCloudTransportRef transport
, CloudKeychainReplyBlock replyBlock
)
511 dispatch_queue_t processQueue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0);
513 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
515 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
516 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
517 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationGetDeviceID
);
519 talkWithIDS(xpcTransport
, message
, processQueue
, replyBlock
);
520 xpc_release(message
);
523 static void SOSCloudTransportSendFragmentedIDSMessage(SOSCloudTransportRef transport
, CFDictionaryRef messageData
, CFStringRef deviceName
, CFStringRef peerID
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
){
525 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
526 xpc_object_t xmessageData
= _CFXPCCreateXPCObjectFromCFObject(messageData
);
528 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
529 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
530 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationSendFragmentedIDSMessage
);
532 xpc_dictionary_set_value(message
, kMessageKeyValue
, xmessageData
);
533 SecXPCDictionarySetCFObject(message
, kMessageKeyDeviceName
, deviceName
);
534 SecXPCDictionarySetCFObject(message
, kMessageKeyPeerID
, peerID
);
535 talkWithIDS(xpcTransport
, message
, processQueue
, replyBlock
);
537 xpc_release(xmessageData
);
538 xpc_release(message
);
541 static void SOSCloudTransportSendIDSMessage(SOSCloudTransportRef transport
, CFDictionaryRef messageData
, CFStringRef deviceName
, CFStringRef peerID
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
){
543 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
544 xpc_object_t xmessageData
= _CFXPCCreateXPCObjectFromCFObject(messageData
);
546 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
547 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
548 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationSendIDSMessage
);
550 xpc_dictionary_set_value(message
, kMessageKeyValue
, xmessageData
);
551 SecXPCDictionarySetCFObject(message
, kMessageKeyDeviceName
, deviceName
);
552 SecXPCDictionarySetCFObject(message
, kMessageKeyPeerID
, peerID
);
553 talkWithIDS(xpcTransport
, message
, processQueue
, replyBlock
);
555 xpc_release(xmessageData
);
556 xpc_release(message
);
559 static void SOSCloudTransportUpdateKeys(SOSCloudTransportRef transport
,
560 CFDictionaryRef keys
,
561 dispatch_queue_t processQueue
,
562 CloudKeychainReplyBlock replyBlock
)
564 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
566 xpc_object_t xkeysOfInterest
= xpc_dictionary_create(NULL
, NULL
, 0);
567 SecXPCDictionarySetCFObject(xkeysOfInterest
, kMessageAllKeys
, keys
);
569 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
570 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
571 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationRegisterKeys
);
572 xpc_dictionary_set_value(message
, kMessageKeyValue
, xkeysOfInterest
);
574 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
575 xpc_release(message
);
576 xpc_release(xkeysOfInterest
);
579 static void SOSCloudTransportGetAll(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
581 secdebug(SOSCKCSCOPE
, "start");
582 SOSCloudTransportGet(transport
, NULL
, processQueue
, replyBlock
);
585 static void SOSCloudTransportSync(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
587 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
588 secdebug(SOSCKCSCOPE
, "start");
589 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
590 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
591 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationSynchronize
);
592 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
593 xpc_release(message
);
596 static void SOSCloudTransportSyncAndWait(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
598 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
599 secnotice(SOSCKCSCOPE
, "%s XPC request to CKD: %s", kWAIT2MINID
, kOperationSynchronizeAndWait
);
601 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
602 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
603 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationSynchronizeAndWait
);
605 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
606 xpc_release(message
);
609 static void SOSCloudTransportClearAll(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
611 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
612 secdebug(SOSCKCSCOPE
, "start");
613 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
614 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
615 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationClearStore
);
616 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
617 xpc_release(message
);
620 static void SOSCloudTransportRequestSyncWithAllPeers(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
622 secdebug(SOSCKCSCOPE
, "start");
623 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
625 xpc_object_t xpcmessage
= xpc_dictionary_create(NULL
, NULL
, 0);
626 xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
);
627 xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationRequestSyncWithAllPeers
);
629 talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
);
631 xpc_release(xpcmessage
);
634 static void SOSCloudTransportRequestEnsurePeerRegistration(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
636 secdebug(SOSCKCSCOPE
, "start");
637 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
639 xpc_object_t xpcmessage
= xpc_dictionary_create(NULL
, NULL
, 0);
640 xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
);
641 xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationRequestEnsurePeerRegistration
);
643 talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
);
645 xpc_release(xpcmessage
);
648 static void SOSCloudTransportFlush(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
650 secdebug(SOSCKCSCOPE
, "start");
651 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
653 xpc_object_t xpcmessage
= xpc_dictionary_create(NULL
, NULL
, 0);
654 xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
);
655 xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationFlush
);
657 talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
);
659 xpc_release(xpcmessage
);
662 static void SOSCloudTransportCheckIDSDeviceIDAvailability(SOSCloudTransportRef transport
, CFArrayRef ids
, CFStringRef peerID
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
664 secdebug(SOSCKCSCOPE
, "start");
665 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
667 xpc_object_t xIDSArray
= _CFXPCCreateXPCObjectFromCFObject(ids
);
669 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
670 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
671 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationSendDeviceList
);
673 SecXPCDictionarySetCFObject(message
, kMessageKeyPeerID
, peerID
);
674 xpc_dictionary_set_value(message
, kMessageKeyValue
, xIDSArray
);
676 talkWithIDS(xpcTransport
, message
, processQueue
, replyBlock
);
678 xpc_release(xIDSArray
);
679 xpc_release(message
);
683 static SOSCloudTransportRef
SOSCloudTransportCreateXPCTransport(void)
685 SOSXPCCloudTransportRef st
;
686 st
= calloc(1, sizeof(*st
));
687 st
->transport
.put
= SOSCloudTransportPut
;
688 st
->transport
.updateKeys
= SOSCloudTransportUpdateKeys
;
689 st
->transport
.sendIDSMessage
= SOSCloudTransportSendIDSMessage
;
690 st
->transport
.sendFragmentedIDSMessage
= SOSCloudTransportSendFragmentedIDSMessage
;
692 st
->transport
.getDeviceID
= SOSCloudTransportGetIDSDeviceID
;
693 st
->transport
.get
= SOSCloudTransportGet
;
694 st
->transport
.getAll
= SOSCloudTransportGetAll
;
695 st
->transport
.synchronize
= SOSCloudTransportSync
;
696 st
->transport
.synchronizeAndWait
= SOSCloudTransportSyncAndWait
;
697 st
->transport
.clearAll
= SOSCloudTransportClearAll
;
698 st
->transport
.requestSyncWithAllPeers
= SOSCloudTransportRequestSyncWithAllPeers
;
699 st
->transport
.requestEnsurePeerRegistration
= SOSCloudTransportRequestEnsurePeerRegistration
;
700 st
->transport
.flush
= SOSCloudTransportFlush
;
701 st
->transport
.getIDSDeviceAvailability
= SOSCloudTransportCheckIDSDeviceIDAvailability
;
702 st
->transport
.itemsChangedBlock
= Block_copy(^CFArrayRef(CFDictionaryRef changes
) {
703 secerror("Calling default itemsChangedBlock - fatal: %@", changes
);
707 SOSXPCCloudTransportInit(st
);
708 return &st
->transport
;
711 // MARK: ---------- SOSCloudKeychain concrete client APIs ----------
712 void SOSCloudKeychainSetItemsChangedBlock(CloudItemsChangedBlock itemsChangedBlock
)
714 secdebug(SOSCKCSCOPE
, "start");
715 SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportDefaultTransport(),
719 // MARK: ---------- SOSCloudKeychain virtual client APIs ----------
721 void SOSCloudKeychainPutObjectsInCloud(CFDictionaryRef objects
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
723 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
725 cTransportRef
->put(cTransportRef
, objects
, processQueue
, replyBlock
);
728 void SOSCloudKeychainUpdateKeys(CFDictionaryRef keys
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
730 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
732 cTransportRef
->updateKeys(cTransportRef
, keys
, processQueue
, replyBlock
);
735 void SOSCloudKeychainSendIDSMessage(CFDictionaryRef message
, CFStringRef deviceName
, CFStringRef peerID
, dispatch_queue_t processQueue
, CFBooleanRef fragmentation
, CloudKeychainReplyBlock replyBlock
)
737 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
739 if(cTransportRef
&& fragmentation
== kCFBooleanTrue
)
740 cTransportRef
->sendFragmentedIDSMessage(cTransportRef
, message
, deviceName
, peerID
, processQueue
, replyBlock
);
741 else if(cTransportRef
)
742 cTransportRef
->sendIDSMessage(cTransportRef
, message
, deviceName
, peerID
, processQueue
, replyBlock
);
745 void SOSCloudKeychainGetIDSDeviceAvailability(CFArrayRef ids
, CFStringRef peerID
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
){
747 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
750 cTransportRef
->getIDSDeviceAvailability(cTransportRef
, ids
, peerID
, processQueue
, replyBlock
);
752 void SOSCloudKeychainGetIDSDeviceID(CloudKeychainReplyBlock replyBlock
)
754 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
756 cTransportRef
->getDeviceID(cTransportRef
, replyBlock
);
760 CF_RETURNS_RETAINED CFArrayRef
SOSCloudKeychainHandleUpdateMessage(CFDictionaryRef updates
)
762 CFArrayRef result
= NULL
;
763 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
764 if (cTransportRef
->itemsChangedBlock
)
765 result
= ((CloudItemsChangedBlock
)cTransportRef
->itemsChangedBlock
)(updates
);
769 void SOSCloudKeychainGetObjectsFromCloud(CFArrayRef keysToGet
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
771 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
773 cTransportRef
->get(cTransportRef
, keysToGet
, processQueue
, replyBlock
);
776 void SOSCloudKeychainGetAllObjectsFromCloud(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
778 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
780 cTransportRef
->getAll(cTransportRef
, processQueue
, replyBlock
);
783 void SOSCloudKeychainSynchronizeAndWait(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
785 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
787 cTransportRef
->synchronizeAndWait(cTransportRef
, processQueue
, replyBlock
);
791 void SOSCloudKeychainSynchronize(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
793 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
795 cTransportRef
->synchronize(cTransportRef
, processQueue
, replyBlock
);
799 void SOSCloudKeychainClearAll(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
801 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
803 cTransportRef
->clearAll(cTransportRef
, processQueue
, replyBlock
);
806 void SOSCloudKeychainRequestSyncWithAllPeers(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
808 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
810 cTransportRef
->requestSyncWithAllPeers(cTransportRef
, processQueue
, replyBlock
);
813 void SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
815 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
817 cTransportRef
->requestEnsurePeerRegistration(cTransportRef
, processQueue
, replyBlock
);
820 void SOSCloudKeychainFlush(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
822 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
824 cTransportRef
->flush(cTransportRef
, processQueue
, replyBlock
);