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>
49 #include <utilities/debugging.h>
50 #include <utilities/SecCFWrappers.h>
51 #include <utilities/SecXPCError.h>
53 #include "SOSCloudKeychainConstants.h"
54 #include "SOSCloudKeychainClient.h"
56 static CFStringRef sErrorDomain
= CFSTR("com.apple.security.sos.transport.error");
58 #define SOSCKCSCOPE "sync"
60 // MARK: ---------- SOSCloudTransport ----------
62 /* SOSCloudTransport, a statically initialized transport singleton. */
63 static SOSCloudTransportRef sTransport
= NULL
;
65 static SOSCloudTransportRef
SOSCloudTransportCreateXPCTransport(void);
67 void SOSCloudKeychainSetTransport(SOSCloudTransportRef transport
) {
68 sTransport
= transport
;
71 /* Return the singleton cloud transport instance. */
72 static SOSCloudTransportRef
SOSCloudTransportDefaultTransport(void)
74 static dispatch_once_t sTransportOnce
;
75 dispatch_once(&sTransportOnce
, ^{
77 SOSCloudKeychainSetTransport(SOSCloudTransportCreateXPCTransport());
83 // MARK: ----- utilities -----
85 static CFErrorRef
makeError(CFIndex which
)
87 CFDictionaryRef userInfo
= NULL
;
88 return CFErrorCreate(kCFAllocatorDefault
, sErrorDomain
, which
, userInfo
);
91 // MARK: ----- DEBUG Utilities -----
93 //------------------------------------------------------------------------------------------------
95 //------------------------------------------------------------------------------------------------
97 static void describeXPCObject(char *prefix
, xpc_object_t object
)
100 // This is useful for debugging.
103 char *desc
= xpc_copy_description(object
);
104 secdebug(SOSCKCSCOPE
, "%s%s\n", prefix
, desc
);
108 secdebug(SOSCKCSCOPE
, "%s<NULL>\n", prefix
);
112 static void describeXPCType(char *prefix
, xpc_type_t xtype
)
114 // Add others as necessary, e.g. XPC_TYPE_DOUBLE
116 // This is useful for debugging.
118 if (XPC_TYPE_CONNECTION
== xtype
)
119 strcpy(msg
, "XPC_TYPE_CONNECTION");
120 else if (XPC_TYPE_ERROR
== xtype
)
121 strcpy(msg
, "XPC_TYPE_ERROR");
122 else if (XPC_TYPE_DICTIONARY
== xtype
)
123 strcpy(msg
, "XPC_TYPE_DICTIONARY");
125 strcpy(msg
, "<unknown>");
127 secdebug(SOSCKCSCOPE
, "%s type:%s\n", prefix
, msg
);
131 // MARK: ---------- SOSXPCCloudTransport ----------
133 typedef struct SOSXPCCloudTransport
*SOSXPCCloudTransportRef
;
134 struct SOSXPCCloudTransport
136 struct SOSCloudTransport transport
;
137 xpc_connection_t serviceConnection
;
138 xpc_connection_t idsProxyServiceConnection
;
139 dispatch_queue_t xpc_queue
;
142 static bool xpc_event_filter(const xpc_connection_t peer
, xpc_object_t event
, CFErrorRef
*error
)
144 // return true if the type is XPC_TYPE_DICTIONARY (and therefore something more to process)
145 secdebug(SOSCKCSCOPE
, "handle_connection_event\n");
146 xpc_type_t xtype
= xpc_get_type(event
);
147 describeXPCType("handle_xpc_event", xtype
);
148 if (XPC_TYPE_CONNECTION
== xtype
)
150 secdebug(SOSCKCSCOPE
, "handle_xpc_event: XPC_TYPE_CONNECTION (unexpected)");
151 // The client of an XPC service does not get connection events
152 // For now, we log this and keep going
153 describeXPCObject("handle_xpc_event: XPC_TYPE_CONNECTION, obj : ", event
);
156 *error
= makeError(kSOSOUnexpectedConnectionEvent
); // FIX
161 if (XPC_TYPE_ERROR
== xtype
)
164 const char *estr
= xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
);
166 secdebug(SOSCKCSCOPE
, "default: xpc error: %s\n", estr
);
167 #if 0 // just log for now
168 CFStringRef errStr
= CFStringCreateWithCString(kCFAllocatorDefault
, estr
, kCFStringEncodingUTF8
);
169 CFMutableDictionaryRef userInfo
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
171 CFDictionaryAddValue(userInfo
, kCFErrorLocalizedDescriptionKey
, errStr
);
173 *error
= CFErrorCreate(kCFAllocatorDefault
, sErrorDomain
, kSOSOXPCErrorEvent
, userInfo
);
174 CFReleaseSafe(errStr
);
175 CFReleaseSafe(userInfo
);
179 if (XPC_TYPE_DICTIONARY
== xtype
)
181 secdebug(SOSCKCSCOPE
, "received dictionary event %p\n", event
);
186 secdebug(SOSCKCSCOPE
, "default: unexpected connection event %p\n", event
);
187 describeXPCObject("handle_xpc_event: obj : ", event
);
189 *error
= makeError(kSOSOUnexpectedXPCEvent
);
194 static void SOSXPCCloudTransportInit(SOSXPCCloudTransportRef transport
)
196 secdebug(SOSCKCSCOPE
, "initXPCConnection\n");
198 transport
->xpc_queue
= dispatch_queue_create(xpcServiceName
, DISPATCH_QUEUE_SERIAL
);
200 transport
->serviceConnection
= xpc_connection_create_mach_service(xpcServiceName
, transport
->xpc_queue
, 0);
203 secdebug(SOSCKCSCOPE
, "serviceConnection: %p\n", transport
->serviceConnection
);
206 xpc_connection_set_event_handler(transport
->serviceConnection
, ^(xpc_object_t event
)
208 secdebug(SOSCKCSCOPE
, "xpc_connection_set_event_handler\n");
211 xpc_connection_resume(transport
->serviceConnection
);
212 xpc_retain(transport
->serviceConnection
);
214 transport
->idsProxyServiceConnection
= xpc_connection_create_mach_service(xpcIDSServiceName
, transport
->xpc_queue
, 0);
216 secdebug(SOSCKCSCOPE
, "ids service connection: %p\n", transport
->idsProxyServiceConnection
);
218 xpc_connection_set_event_handler(transport
->idsProxyServiceConnection
, ^(xpc_object_t object
) {
219 secdebug(SOSCKCSCOPE
, "IDS Transport, xpc_connection_set_event_handler\n");
221 xpc_connection_resume(transport
->idsProxyServiceConnection
);
222 xpc_retain(transport
->idsProxyServiceConnection
);
225 static void talkWithIDS(SOSXPCCloudTransportRef transport
, xpc_object_t message
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
227 CFErrorRef connectionError
= NULL
;
229 os_activity_t trace_activity
= os_activity_start("talkWithIDS", OS_ACTIVITY_FLAG_DEFAULT
);
230 require_action(transport
->idsProxyServiceConnection
, xit
, connectionError
= makeError(kSOSConnectionNotOpen
));
231 require_action(message
, xit
, connectionError
= makeError(kSOSObjectNotFoundError
));
232 dispatch_retain(processQueue
);
234 xpc_connection_send_message_with_reply(transport
->idsProxyServiceConnection
, message
, transport
->xpc_queue
, ^(xpc_object_t reply
)
236 CFErrorRef serverError
= NULL
;
237 CFTypeRef object
= NULL
;
238 if (xpc_event_filter(transport
->idsProxyServiceConnection
, reply
, &serverError
) && reply
)
240 describeXPCObject("IDS Proxy: reply : ", reply
);
242 secerror("Error from xpc_event_filter: %@", serverError
);
243 xpc_object_t xrv
= xpc_dictionary_get_value(reply
, kMessageKeyValue
);
246 describeXPCObject("talkwithIDS: xrv: ", xrv
);
248 * The given XPC object must be one that was previously returned by
249 * _CFXPCCreateXPCMessageWithCFObject().
251 object
= _CFXPCCreateCFObjectFromXPCObject(xrv
); // CF object is retained; release in callback
252 secnotice("talkwithIDS", "converted CF object: %@", object
);
255 secerror("missing value reply");
257 xpc_object_t xerror
= xpc_dictionary_get_value(reply
, kMessageKeyError
);
259 serverError
= SecCreateCFErrorWithXPCObject(xerror
); // use SecCFCreateErrorWithFormat?
261 dispatch_async(processQueue
, ^{
263 replyBlock(object
, serverError
);
264 CFReleaseSafe(object
);
267 secerror("talkwithIDS callback error: %@", serverError
);
268 CFReleaseSafe(serverError
);
270 dispatch_release(processQueue
);
276 secerror("talkWithIDS error: %@", connectionError
);
277 dispatch_async(processQueue
, ^{
279 replyBlock(NULL
, connectionError
);
280 CFReleaseSafe(connectionError
);
281 dispatch_release(processQueue
);
284 os_activity_end(trace_activity
);
286 static void talkWithKVS(SOSXPCCloudTransportRef transport
, xpc_object_t message
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
288 CFErrorRef connectionError
= NULL
;
290 os_activity_t trace_activity
= os_activity_start("talkWithKVS", OS_ACTIVITY_FLAG_DEFAULT
);
291 require_action(transport
->serviceConnection
, xit
, connectionError
= makeError(kSOSConnectionNotOpen
));
292 require_action(message
, xit
, connectionError
= makeError(kSOSObjectNotFoundError
));
293 dispatch_retain(processQueue
);
295 xpc_connection_send_message_with_reply(transport
->serviceConnection
, message
, transport
->xpc_queue
, ^(xpc_object_t reply
)
297 CFErrorRef serverError
= NULL
;
298 CFTypeRef object
= NULL
;
299 if (xpc_event_filter(transport
->serviceConnection
, reply
, &serverError
) && reply
)
301 describeXPCObject("getValuesFromKVS: reply : ", reply
);
303 secerror("Error from xpc_event_filter: %@", serverError
);
304 xpc_object_t xrv
= xpc_dictionary_get_value(reply
, kMessageKeyValue
);
307 describeXPCObject("talkWithKVS: xrv: ", xrv
);
309 * The given XPC object must be one that was previously returned by
310 * _CFXPCCreateXPCMessageWithCFObject().
312 object
= _CFXPCCreateCFObjectFromXPCObject(xrv
); // CF object is retained; release in callback
313 secnotice("talkwithkvs", "converted CF object: %@", object
);
316 secerror("missing value reply");
318 xpc_object_t xerror
= xpc_dictionary_get_value(reply
, kMessageKeyError
);
320 serverError
= SecCreateCFErrorWithXPCObject(xerror
); // use SecCFCreateErrorWithFormat?
322 dispatch_async(processQueue
, ^{
324 replyBlock(object
, serverError
);
325 CFReleaseSafe(object
);
328 secerror("callback error: %@", serverError
);
329 CFReleaseSafe(serverError
);
331 dispatch_release(processQueue
);
337 secerror("talkWithKVS error: %@", connectionError
);
338 dispatch_async(processQueue
, ^{
340 replyBlock(NULL
, connectionError
);
341 CFReleaseSafe(connectionError
);
342 dispatch_release(processQueue
);
345 os_activity_end(trace_activity
);
348 // MARK: ---------- SOSXPCCloudTransport Client Calls ----------
350 /* Concrete function backend implementations. */
351 static void SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportRef transport
,
352 CloudItemsChangedBlock itemsChangedBlock
) {
353 if (transport
->itemsChangedBlock
!= itemsChangedBlock
)
355 secnotice(SOSCKCSCOPE
, "Changing itemsChangedBlock");
356 if (transport
->itemsChangedBlock
)
357 Block_release(transport
->itemsChangedBlock
);
358 transport
->itemsChangedBlock
= Block_copy(itemsChangedBlock
);
362 /* Virtual function backend implementations. */
363 static void SOSCloudTransportPut(SOSCloudTransportRef transport
, CFDictionaryRef values
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
365 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
366 secdebug(SOSCKCSCOPE
, "%@", values
);
367 CFErrorRef error
= NULL
;
368 xpc_object_t message
= NULL
;
369 xpc_object_t xobject
= NULL
;
370 require_action(values
, xit
, error
= makeError(kSOSObjectNotFoundError
));
372 message
= xpc_dictionary_create(NULL
, NULL
, 0);
373 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
374 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationPUTDictionary
);
376 xobject
= _CFXPCCreateXPCObjectFromCFObject(values
);
377 require_action(xobject
, xit
, error
= makeError(kSOSObjectCantBeConvertedToXPCObject
));
378 xpc_dictionary_set_value(message
, kMessageKeyValue
, xobject
);
379 xpc_release(xobject
);
381 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
382 xpc_release(message
);
387 replyBlock(NULL
, error
);
388 CFReleaseSafe(error
);
392 static void SOSCloudTransportGet(SOSCloudTransportRef transport
, CFArrayRef keysToGet
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
394 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
395 secdebug(SOSCKCSCOPE
, "%@", keysToGet
);
396 CFErrorRef error
= NULL
;
397 xpc_object_t xkeysOfInterest
= xpc_dictionary_create(NULL
, NULL
, 0);
398 xpc_object_t xkeysToGet
= keysToGet
? _CFXPCCreateXPCObjectFromCFObject(keysToGet
) : xpc_null_create();
400 require_action(xkeysToGet
, xit
, error
= makeError(kSOSObjectNotFoundError
));
402 if (keysToGet
) // don't add if nulll; will call getall
403 xpc_dictionary_set_value(xkeysOfInterest
, kMessageKeyKeysToGet
, xkeysToGet
);
405 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
406 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
407 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationGETv2
);
408 xpc_dictionary_set_value(message
, kMessageKeyValue
, xkeysOfInterest
);
410 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
411 xpc_release(xkeysToGet
);
412 xpc_release(xkeysOfInterest
);
413 xpc_release(message
);
418 xpc_release(xkeysOfInterest
);
420 xpc_release(xkeysToGet
);
422 replyBlock(NULL
, error
);
423 CFReleaseSafe(error
);
427 // Handles NULL by seting xpc_null.
428 static void SecXPCDictionarySetCFObject(xpc_object_t xdict
, const char *key
, CFTypeRef object
)
430 xpc_object_t xpc_obj
= object
? _CFXPCCreateXPCObjectFromCFObject(object
) : xpc_null_create();
431 xpc_dictionary_set_value(xdict
, key
, xpc_obj
);
432 xpc_release(xpc_obj
);
435 static void SOSCloudTransportGetIDSDeviceID(SOSCloudTransportRef transport
, CloudKeychainReplyBlock replyBlock
)
437 dispatch_queue_t processQueue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0);
439 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
441 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
442 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
443 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationGetDeviceID
);
445 talkWithIDS(xpcTransport
, message
, processQueue
, replyBlock
);
446 xpc_release(message
);
449 static void SOSCloudTransportSendIDSMessage(SOSCloudTransportRef transport
, CFDictionaryRef messageData
, CFStringRef deviceName
, CFStringRef peerID
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
){
451 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
452 xpc_object_t xmessageData
= _CFXPCCreateXPCObjectFromCFObject(messageData
);
454 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
455 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
456 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationSendIDSMessage
);
457 xpc_dictionary_set_value(message
, kMessageKeyValue
, xmessageData
);
458 SecXPCDictionarySetCFObject(message
, kMessageKeyDeviceName
, deviceName
);
459 SecXPCDictionarySetCFObject(message
, kMessageKeyPeerID
, peerID
);
460 talkWithIDS(xpcTransport
, message
, processQueue
, replyBlock
);
462 xpc_release(xmessageData
);
463 xpc_release(message
);
466 static void SOSCloudTransportUpdateKeys(SOSCloudTransportRef transport
,
467 CFDictionaryRef keys
,
468 dispatch_queue_t processQueue
,
469 CloudKeychainReplyBlock replyBlock
)
471 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
473 xpc_object_t xkeysOfInterest
= xpc_dictionary_create(NULL
, NULL
, 0);
474 SecXPCDictionarySetCFObject(xkeysOfInterest
, kMessageAllKeys
, keys
);
476 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
477 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
478 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationRegisterKeys
);
479 xpc_dictionary_set_value(message
, kMessageKeyValue
, xkeysOfInterest
);
481 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
482 xpc_release(message
);
483 xpc_release(xkeysOfInterest
);
486 static void SOSCloudTransportGetAll(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
488 secdebug(SOSCKCSCOPE
, "start");
489 SOSCloudTransportGet(transport
, NULL
, processQueue
, replyBlock
);
492 static void SOSCloudTransportSync(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
494 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
495 secdebug(SOSCKCSCOPE
, "start");
496 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
497 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
498 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationSynchronize
);
499 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
500 xpc_release(message
);
503 static void SOSCloudTransportSyncAndWait(SOSCloudTransportRef transport
, CFArrayRef keysToGet
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
505 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
506 secdebug(SOSCKCSCOPE
, "%@", keysToGet
);
507 secnotice(SOSCKCSCOPE
, "%s XPC request to CKD: %s", kWAIT2MINID
, kOperationSynchronizeAndWait
);
508 xpc_object_t xkeysOfInterest
= xpc_dictionary_create(NULL
, NULL
, 0);
510 xpc_object_t xkeysToRegister
= keysToGet
? _CFXPCCreateXPCObjectFromCFObject(keysToGet
) : xpc_null_create();
511 xpc_dictionary_set_value(xkeysOfInterest
, kMessageKeyKeysToGet
, xkeysToRegister
);
512 xpc_release(xkeysToRegister
);
513 xkeysToRegister
= NULL
;
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
, kOperationSynchronizeAndWait
);
518 xpc_dictionary_set_value(message
, kMessageKeyValue
, xkeysOfInterest
);
519 xpc_release(xkeysOfInterest
);
520 xkeysOfInterest
= NULL
;
522 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
523 xpc_release(message
);
526 static void SOSCloudTransportClearAll(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
528 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
529 secdebug(SOSCKCSCOPE
, "start");
530 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
531 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
532 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationClearStore
);
533 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
534 xpc_release(message
);
537 static void SOSCloudTransportRemoveObjectForKey(SOSCloudTransportRef transport
, CFStringRef keyToRemove
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
539 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
540 secdebug(SOSCKCSCOPE
, "start");
541 CFErrorRef error
= NULL
;
542 xpc_object_t message
= NULL
;
543 xpc_object_t xkeytoremove
= NULL
;
545 require_action(keyToRemove
, xit
, error
= makeError(kSOSObjectNotFoundError
));
547 message
= xpc_dictionary_create(NULL
, NULL
, 0);
548 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
549 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationRemoveObjectForKey
);
551 xkeytoremove
= _CFXPCCreateXPCObjectFromCFObject(keyToRemove
);
552 require_action(xkeytoremove
, xit
, error
= makeError(kSOSObjectCantBeConvertedToXPCObject
));
553 xpc_dictionary_set_value(message
, kMessageKeyKey
, xkeytoremove
);
554 xpc_release(xkeytoremove
);
556 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
557 xpc_release(message
);
562 xpc_release(xkeytoremove
);
564 xpc_release(message
);
566 replyBlock(NULL
, error
);
567 CFReleaseSafe(error
);
569 static void SOSCloudTransportLocalNotification(SOSCloudTransportRef transport
, CFStringRef messageToUser
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
571 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
572 secdebug(SOSCKCSCOPE
, "start");
573 xpc_object_t xLocalNotificationDict
= xpc_dictionary_create(NULL
, NULL
, 0);
574 char *headerKey
= CFStringToCString(kCFUserNotificationAlertHeaderKey
);
575 char *message
= CFStringToCString(messageToUser
);
576 xpc_dictionary_set_string(xLocalNotificationDict
, headerKey
, message
);
578 xpc_object_t xpcmessage
= xpc_dictionary_create(NULL
, NULL
, 0);
579 xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
);
580 xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationUILocalNotification
);
581 xpc_dictionary_set_value (xpcmessage
, kMessageKeyValue
, xLocalNotificationDict
);
582 xpc_release(xLocalNotificationDict
);
584 talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
);
588 xpc_release(xpcmessage
);
591 static void SOSCloudTransportRequestSyncWithAllPeers(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
593 secdebug(SOSCKCSCOPE
, "start");
594 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
596 xpc_object_t xpcmessage
= xpc_dictionary_create(NULL
, NULL
, 0);
597 xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
);
598 xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationRequestSyncWithAllPeers
);
600 talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
);
602 xpc_release(xpcmessage
);
605 static void SOSCloudTransportRequestEnsurePeerRegistration(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
607 secdebug(SOSCKCSCOPE
, "start");
608 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
610 xpc_object_t xpcmessage
= xpc_dictionary_create(NULL
, NULL
, 0);
611 xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
);
612 xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationRequestEnsurePeerRegistration
);
614 talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
);
616 xpc_release(xpcmessage
);
619 static void SOSCloudTransportFlush(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
621 secdebug(SOSCKCSCOPE
, "start");
622 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
624 xpc_object_t xpcmessage
= xpc_dictionary_create(NULL
, NULL
, 0);
625 xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
);
626 xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationFlush
);
628 talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
);
630 xpc_release(xpcmessage
);
633 static SOSCloudTransportRef
SOSCloudTransportCreateXPCTransport(void)
635 SOSXPCCloudTransportRef st
;
636 st
= calloc(1, sizeof(*st
));
637 st
->transport
.put
= SOSCloudTransportPut
;
638 st
->transport
.updateKeys
= SOSCloudTransportUpdateKeys
;
639 st
->transport
.sendIDSMessage
= SOSCloudTransportSendIDSMessage
;
640 st
->transport
.getDeviceID
= SOSCloudTransportGetIDSDeviceID
;
641 st
->transport
.get
= SOSCloudTransportGet
;
642 st
->transport
.getAll
= SOSCloudTransportGetAll
;
643 st
->transport
.synchronize
= SOSCloudTransportSync
;
644 st
->transport
.synchronizeAndWait
= SOSCloudTransportSyncAndWait
;
645 st
->transport
.clearAll
= SOSCloudTransportClearAll
;
646 st
->transport
.removeObjectForKey
= SOSCloudTransportRemoveObjectForKey
;
647 st
->transport
.localNotification
= SOSCloudTransportLocalNotification
;
648 st
->transport
.requestSyncWithAllPeers
= SOSCloudTransportRequestSyncWithAllPeers
;
649 st
->transport
.requestEnsurePeerRegistration
= SOSCloudTransportRequestEnsurePeerRegistration
;
650 st
->transport
.flush
= SOSCloudTransportFlush
;
651 st
->transport
.itemsChangedBlock
= Block_copy(^CFArrayRef(CFDictionaryRef changes
) {
652 secerror("Calling default itemsChangedBlock - fatal: %@", changes
);
656 SOSXPCCloudTransportInit(st
);
657 return &st
->transport
;
660 // MARK: ---------- SOSCloudKeychain concrete client APIs ----------
661 void SOSCloudKeychainSetItemsChangedBlock(CloudItemsChangedBlock itemsChangedBlock
)
663 secdebug(SOSCKCSCOPE
, "start");
664 SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportDefaultTransport(),
668 // MARK: ---------- SOSCloudKeychain virtual client APIs ----------
670 void SOSCloudKeychainPutObjectsInCloud(CFDictionaryRef objects
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
672 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
674 cTransportRef
->put(cTransportRef
, objects
, processQueue
, replyBlock
);
677 void SOSCloudKeychainUpdateKeys(CFDictionaryRef keys
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
679 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
681 cTransportRef
->updateKeys(cTransportRef
, keys
, processQueue
, replyBlock
);
684 void SOSCloudKeychainSendIDSMessage(CFDictionaryRef message
, CFStringRef deviceName
, CFStringRef peerID
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
686 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
688 cTransportRef
->sendIDSMessage(cTransportRef
, message
, deviceName
, peerID
, processQueue
, replyBlock
);
691 void SOSCloudKeychainGetIDSDeviceID(CloudKeychainReplyBlock replyBlock
)
693 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
695 cTransportRef
->getDeviceID(cTransportRef
, replyBlock
);
699 CF_RETURNS_RETAINED CFArrayRef
SOSCloudKeychainHandleUpdateMessage(CFDictionaryRef updates
)
701 CFArrayRef result
= NULL
;
702 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
703 if (cTransportRef
->itemsChangedBlock
)
704 result
= ((CloudItemsChangedBlock
)cTransportRef
->itemsChangedBlock
)(updates
);
708 void SOSCloudKeychainGetObjectsFromCloud(CFArrayRef keysToGet
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
710 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
712 cTransportRef
->get(cTransportRef
, keysToGet
, processQueue
, replyBlock
);
715 void SOSCloudKeychainGetAllObjectsFromCloud(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
717 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
719 cTransportRef
->getAll(cTransportRef
, processQueue
, replyBlock
);
722 void SOSCloudKeychainSynchronizeAndWait(CFArrayRef keysToGet
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
724 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
726 cTransportRef
->synchronizeAndWait(cTransportRef
, keysToGet
, processQueue
, replyBlock
);
730 void SOSCloudKeychainSynchronize(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
732 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
734 cTransportRef
->synchronize(cTransportRef
, processQueue
, replyBlock
);
738 void SOSCloudKeychainClearAll(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
740 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
742 cTransportRef
->clearAll(cTransportRef
, processQueue
, replyBlock
);
745 void SOSCloudKeychainRemoveObjectForKey(CFStringRef keyToRemove
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
747 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
749 cTransportRef
->removeObjectForKey(cTransportRef
, keyToRemove
, processQueue
, replyBlock
);
752 void SOSCloudKeychainRequestSyncWithAllPeers(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
754 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
756 cTransportRef
->requestSyncWithAllPeers(cTransportRef
, processQueue
, replyBlock
);
759 void SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
761 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
763 cTransportRef
->requestEnsurePeerRegistration(cTransportRef
, processQueue
, replyBlock
);
766 void SOSCloudKeychainFlush(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
768 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
770 cTransportRef
->flush(cTransportRef
, processQueue
, replyBlock
);