2 * Copyright (c) 2012 Apple Computer, 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 <CoreFoundation/CFUserNotification.h>
48 #include <utilities/debugging.h>
49 #include <utilities/SecCFWrappers.h>
50 #include <utilities/SecXPCError.h>
52 #include "SOSCloudKeychainConstants.h"
53 #include "SOSCloudKeychainClient.h"
55 static CFStringRef sErrorDomain
= CFSTR("com.apple.security.sos.transport.error");
57 #define SOSCKCSCOPE "sync"
59 // MARK: ---------- SOSCloudTransport ----------
61 /* SOSCloudTransport, a statically initialized transport singleton. */
62 static SOSCloudTransportRef sTransport
= NULL
;
64 static SOSCloudTransportRef
SOSCloudTransportCreateXPCTransport(void);
66 void SOSCloudKeychainSetTransport(SOSCloudTransportRef transport
) {
67 sTransport
= transport
;
70 /* Return the singleton cloud transport instance. */
71 static SOSCloudTransportRef
SOSCloudTransportDefaultTransport(void)
73 static dispatch_once_t sTransportOnce
;
74 dispatch_once(&sTransportOnce
, ^{
76 SOSCloudKeychainSetTransport(SOSCloudTransportCreateXPCTransport());
82 // MARK: ----- utilities -----
84 static CFErrorRef
makeError(CFIndex which
)
86 CFDictionaryRef userInfo
= NULL
;
87 return CFErrorCreate(kCFAllocatorDefault
, sErrorDomain
, which
, userInfo
);
90 // MARK: ----- DEBUG Utilities -----
92 //------------------------------------------------------------------------------------------------
94 //------------------------------------------------------------------------------------------------
96 static void describeXPCObject(char *prefix
, xpc_object_t object
)
99 // This is useful for debugging.
102 char *desc
= xpc_copy_description(object
);
103 secdebug(SOSCKCSCOPE
, "%s%s\n", prefix
, desc
);
107 secdebug(SOSCKCSCOPE
, "%s<NULL>\n", prefix
);
111 static void describeXPCType(char *prefix
, xpc_type_t xtype
)
113 // Add others as necessary, e.g. XPC_TYPE_DOUBLE
115 // This is useful for debugging.
117 if (XPC_TYPE_CONNECTION
== xtype
)
118 strcpy(msg
, "XPC_TYPE_CONNECTION");
119 else if (XPC_TYPE_ERROR
== xtype
)
120 strcpy(msg
, "XPC_TYPE_ERROR");
121 else if (XPC_TYPE_DICTIONARY
== xtype
)
122 strcpy(msg
, "XPC_TYPE_DICTIONARY");
124 strcpy(msg
, "<unknown>");
126 secdebug(SOSCKCSCOPE
, "%s type:%s\n", prefix
, msg
);
130 // MARK: ---------- SOSXPCCloudTransport ----------
132 typedef struct SOSXPCCloudTransport
*SOSXPCCloudTransportRef
;
133 struct SOSXPCCloudTransport
135 struct SOSCloudTransport transport
;
136 xpc_connection_t serviceConnection
;
137 dispatch_queue_t xpc_queue
;
140 static bool xpc_event_filter(const xpc_connection_t peer
, xpc_object_t event
, CFErrorRef
*error
)
142 // return true if the type is XPC_TYPE_DICTIONARY (and therefore something more to process)
143 secdebug(SOSCKCSCOPE
, "handle_connection_event\n");
144 xpc_type_t xtype
= xpc_get_type(event
);
145 describeXPCType("handle_xpc_event", xtype
);
146 if (XPC_TYPE_CONNECTION
== xtype
)
148 secdebug(SOSCKCSCOPE
, "handle_xpc_event: XPC_TYPE_CONNECTION (unexpected)");
149 // The client of an XPC service does not get connection events
150 // For now, we log this and keep going
151 describeXPCObject("handle_xpc_event: XPC_TYPE_CONNECTION, obj : ", event
);
154 *error
= makeError(kSOSOUnexpectedConnectionEvent
); // FIX
159 if (XPC_TYPE_ERROR
== xtype
)
162 const char *estr
= xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
);
164 secdebug(SOSCKCSCOPE
, "default: xpc error: %s\n", estr
);
165 #if 0 // just log for now
166 CFStringRef errStr
= CFStringCreateWithCString(kCFAllocatorDefault
, estr
, kCFStringEncodingUTF8
);
167 CFMutableDictionaryRef userInfo
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
169 CFDictionaryAddValue(userInfo
, kCFErrorLocalizedDescriptionKey
, errStr
);
171 *error
= CFErrorCreate(kCFAllocatorDefault
, sErrorDomain
, kSOSOXPCErrorEvent
, userInfo
);
172 CFReleaseSafe(errStr
);
173 CFReleaseSafe(userInfo
);
177 if (XPC_TYPE_DICTIONARY
== xtype
)
179 secdebug(SOSCKCSCOPE
, "received dictionary event %p\n", event
);
184 secdebug(SOSCKCSCOPE
, "default: unexpected connection event %p\n", event
);
185 describeXPCObject("handle_xpc_event: obj : ", event
);
187 *error
= makeError(kSOSOUnexpectedXPCEvent
);
192 static bool handle_xpc_event(SOSXPCCloudTransportRef transport
, xpc_object_t event
)
194 CFErrorRef localError
= NULL
;
195 // See <rdar://problem/14566253>
196 secerror(">>>>> handle_connection_event via event_handler <<<<<, WTF?");
198 if ((result
= xpc_event_filter(transport
->serviceConnection
, event
, &localError
)))
200 const char *operation
= xpc_dictionary_get_string(event
, kMessageKeyOperation
);
201 if (!operation
|| strcmp(operation
, kMessageOperationItemChanged
)) // some op we don't care about
203 secdebug(SOSCKCSCOPE
, "operation: %s", operation
);
207 xpc_object_t xrv
= xpc_dictionary_get_value(event
, kMessageKeyValue
);
210 secdebug(SOSCKCSCOPE
, "xrv null for kMessageKeyValue");
213 describeXPCObject("xrv", xrv
);
215 CFDictionaryRef returnedValues
= _CFXPCCreateCFObjectFromXPCObject(xrv
);
216 secdebug(SOSCKCSCOPE
, "returnedValues: %@", returnedValues
);
218 SOSCloudKeychainHandleUpdate(returnedValues
);
220 CFReleaseNull(returnedValues
);
222 CFReleaseSafe(localError
);
227 static void SOSXPCCloudTransportInit(SOSXPCCloudTransportRef transport
)
229 secdebug(SOSCKCSCOPE
, "initXPCConnection\n");
231 transport
->xpc_queue
= dispatch_queue_create(xpcServiceName
, DISPATCH_QUEUE_SERIAL
);
233 transport
->serviceConnection
= xpc_connection_create_mach_service(xpcServiceName
, transport
->xpc_queue
, 0);
235 secdebug(SOSCKCSCOPE
, "serviceConnection: %p\n", transport
->serviceConnection
);
237 xpc_connection_set_event_handler(transport
->serviceConnection
, ^(xpc_object_t event
)
239 secdebug(SOSCKCSCOPE
, "xpc_connection_set_event_handler\n");
240 handle_xpc_event(transport
, event
);
243 xpc_connection_resume(transport
->serviceConnection
);
244 xpc_retain(transport
->serviceConnection
);
247 static void talkWithKVS(SOSXPCCloudTransportRef transport
, xpc_object_t message
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
249 __block CFErrorRef error
= NULL
;
250 __block CFTypeRef object
= NULL
;
252 dispatch_block_t callback
= ^{
254 replyBlock(object
, error
);
256 CFReleaseNull(object
);
259 secerror("callback error: %@", error
);
260 CFReleaseNull(error
);
262 dispatch_release(processQueue
);
265 require_action(transport
->serviceConnection
, xit
, error
= makeError(kSOSConnectionNotOpen
));
266 require_action(message
, xit
, error
= makeError(kSOSObjectNotFoundError
));
267 dispatch_retain(processQueue
);
269 xpc_connection_send_message_with_reply(transport
->serviceConnection
, message
, transport
->xpc_queue
, ^(xpc_object_t reply
)
271 if (xpc_event_filter(transport
->serviceConnection
, reply
, &error
) && reply
)
273 describeXPCObject("getValuesFromKVS: reply : ", reply
);
275 secerror("Error from xpc_event_filter: %@", error
);
276 xpc_object_t xrv
= xpc_dictionary_get_value(reply
, kMessageKeyValue
);
279 describeXPCObject("talkWithKVS: xrv: ", xrv
);
281 * The given XPC object must be one that was previously returned by
282 * _CFXPCCreateXPCMessageWithCFObject().
284 object
= _CFXPCCreateCFObjectFromXPCObject(xrv
); // CF object is retained; release in callback
285 secnotice("talkwithkvs", "converted CF object: %@", object
);
288 secerror("missing value reply");
290 xpc_object_t xerror
= xpc_dictionary_get_value(reply
, kMessageKeyError
);
292 error
= SecCreateCFErrorWithXPCObject(xerror
); // use SecCFCreateErrorWithFormat?
294 dispatch_async(processQueue
, callback
);
299 secerror("talkWithKVS error: %@", error
);
301 dispatch_async(processQueue
, callback
);
302 CFReleaseSafe(error
);
305 // MARK: ---------- SOSXPCCloudTransport Client Calls ----------
307 /* Concrete function backend implementations. */
308 static void SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportRef transport
,
309 CloudItemsChangedBlock itemsChangedBlock
) {
310 if (transport
->itemsChangedBlock
!= itemsChangedBlock
)
312 if (transport
->itemsChangedBlock
)
313 Block_release(transport
->itemsChangedBlock
);
314 transport
->itemsChangedBlock
= Block_copy(itemsChangedBlock
);
318 /* Virtual function backend implementations. */
319 static void SOSCloudTransportPut(SOSCloudTransportRef transport
, CFDictionaryRef values
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
321 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
322 secdebug(SOSCKCSCOPE
, "%@", values
);
323 CFErrorRef error
= NULL
;
324 xpc_object_t message
= NULL
;
325 xpc_object_t xobject
= NULL
;
326 require_action(values
, xit
, error
= makeError(kSOSObjectNotFoundError
));
328 message
= xpc_dictionary_create(NULL
, NULL
, 0);
329 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
330 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationPUTDictionary
);
332 xobject
= _CFXPCCreateXPCObjectFromCFObject(values
);
333 require_action(xobject
, xit
, error
= makeError(kSOSObjectCantBeConvertedToXPCObject
));
334 xpc_dictionary_set_value(message
, kMessageKeyValue
, xobject
);
335 xpc_release(xobject
);
337 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
338 xpc_release(message
);
343 replyBlock(NULL
, error
);
344 CFReleaseSafe(error
);
348 static void SOSCloudTransportGet(SOSCloudTransportRef transport
, CFArrayRef keysToGet
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
350 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
351 secdebug(SOSCKCSCOPE
, "%@", keysToGet
);
352 CFErrorRef error
= NULL
;
353 xpc_object_t xkeysOfInterest
= xpc_dictionary_create(NULL
, NULL
, 0);
354 xpc_object_t xkeysToGet
= keysToGet
? _CFXPCCreateXPCObjectFromCFObject(keysToGet
) : xpc_null_create();
356 require_action(xkeysToGet
, xit
, error
= makeError(kSOSObjectNotFoundError
));
358 if (keysToGet
) // don't add if nulll; will call getall
359 xpc_dictionary_set_value(xkeysOfInterest
, kMessageKeyKeysToGet
, xkeysToGet
);
361 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
362 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
363 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationGETv2
);
364 xpc_dictionary_set_value(message
, kMessageKeyValue
, xkeysOfInterest
);
366 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
367 xpc_release(xkeysToGet
);
368 xpc_release(xkeysOfInterest
);
369 xpc_release(message
);
374 xpc_release(xkeysOfInterest
);
376 xpc_release(xkeysToGet
);
378 replyBlock(NULL
, error
);
379 CFReleaseSafe(error
);
382 static void SOSCloudTransportRegisterKeys(SOSCloudTransportRef transport
, CFArrayRef keysToGet
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
, CloudItemsChangedBlock notificationBlock
)
384 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
385 secdebug(SOSCKCSCOPE
, "%@", keysToGet
);
386 xpc_object_t xkeysOfInterest
= xpc_dictionary_create(NULL
, NULL
, 0);
387 xpc_object_t xkeysToRegister
= keysToGet
? _CFXPCCreateXPCObjectFromCFObject(keysToGet
) : xpc_null_create();
388 xpc_dictionary_set_value(xkeysOfInterest
, kMessageKeyKeysToGet
, xkeysToRegister
);
390 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
391 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
392 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationRegisterKeysAndGet
);
393 xpc_dictionary_set_value(message
, kMessageKeyValue
, xkeysOfInterest
);
395 SOSCloudTransportSetItemsChangedBlock(transport
, notificationBlock
);
396 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
397 xpc_release(xkeysOfInterest
);
398 xpc_release(xkeysToRegister
);
399 xpc_release(message
);
403 // Handles NULL by seting xpc_null.
404 static void SecXPCDictionarySetCFObject(xpc_object_t xdict
, const char *key
, CFTypeRef object
)
406 xpc_object_t xpc_obj
= object
? _CFXPCCreateXPCObjectFromCFObject(object
) : xpc_null_create();
407 xpc_dictionary_set_value(xdict
, key
, xpc_obj
);
408 xpc_release(xpc_obj
);
411 static bool SOSCloudTransportUpdateKeys(SOSCloudTransportRef transport
,
413 CFArrayRef alwaysKeys
,
414 CFArrayRef afterFirstUnlockKeys
,
415 CFArrayRef unlockedKeys
,
418 __block
bool success
= true;
419 dispatch_queue_t processQueue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0);
421 CloudKeychainReplyBlock replyBlock
= ^(CFDictionaryRef returnedValues
, CFErrorRef returnedError
)
426 *error
= returnedError
;
430 CFReleaseSafe(returnedError
);
433 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
435 xpc_object_t xkeysOfInterest
= xpc_dictionary_create(NULL
, NULL
, 0);
436 xpc_dictionary_set_bool(xkeysOfInterest
, kMessageKeyGetNewKeysOnly
, getNewKeysOnly
);
437 SecXPCDictionarySetCFObject(xkeysOfInterest
, kMessageKeyKeysToGet
, alwaysKeys
);
438 SecXPCDictionarySetCFObject(xkeysOfInterest
, kMessageKeyKeysRequireFirstUnlock
, afterFirstUnlockKeys
);
439 SecXPCDictionarySetCFObject(xkeysOfInterest
, kMessageKeyKeysRequiresUnlocked
, unlockedKeys
);
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
, kOperationRegisterKeysAndGet
);
444 xpc_dictionary_set_value(message
, kMessageKeyValue
, xkeysOfInterest
);
446 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
447 xpc_release(message
);
448 xpc_release(xkeysOfInterest
);
453 static void SOSCloudTransportUnregisterKeys(SOSCloudTransportRef transport
, CFArrayRef keysToUnregister
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
455 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
456 secdebug(SOSCKCSCOPE
, "%@", keysToUnregister
);
457 xpc_object_t xkeysOfInterest
= xpc_dictionary_create(NULL
, NULL
, 0);
458 xpc_object_t xkeysToUnregister
= keysToUnregister
? _CFXPCCreateXPCObjectFromCFObject(keysToUnregister
) : xpc_null_create();
459 xpc_dictionary_set_value(xkeysOfInterest
, kMessageKeyKeysToGet
, xkeysToUnregister
);
461 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
462 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
463 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationUnregisterKeys
);
464 xpc_dictionary_set_value(message
, kMessageKeyValue
, xkeysOfInterest
);
466 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
467 xpc_release(xkeysOfInterest
);
468 xpc_release(xkeysToUnregister
);
469 xpc_release(message
);
472 static void SOSCloudTransportGetAll(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
474 secdebug(SOSCKCSCOPE
, "start");
475 SOSCloudTransportGet(transport
, NULL
, processQueue
, replyBlock
);
478 static void SOSCloudTransportSync(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
480 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
481 secdebug(SOSCKCSCOPE
, "start");
482 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
483 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
484 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationSynchronize
);
485 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
486 xpc_release(message
);
489 static void SOSCloudTransportSyncAndWait(SOSCloudTransportRef transport
, CFArrayRef keysToGet
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
491 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
492 secdebug(SOSCKCSCOPE
, "%@", keysToGet
);
493 xpc_object_t xkeysOfInterest
= xpc_dictionary_create(NULL
, NULL
, 0);
495 xpc_object_t xkeysToRegister
= keysToGet
? _CFXPCCreateXPCObjectFromCFObject(keysToGet
) : xpc_null_create();
496 xpc_dictionary_set_value(xkeysOfInterest
, kMessageKeyKeysToGet
, xkeysToRegister
);
497 xpc_release(xkeysToRegister
);
498 xkeysToRegister
= NULL
;
500 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
501 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
502 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationSynchronizeAndWait
);
503 xpc_dictionary_set_value(message
, kMessageKeyValue
, xkeysOfInterest
);
504 xpc_release(xkeysOfInterest
);
505 xkeysOfInterest
= NULL
;
507 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
508 xpc_release(message
);
511 static void SOSCloudTransportClearAll(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
513 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
514 secdebug(SOSCKCSCOPE
, "start");
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
, kOperationClearStore
);
518 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
519 xpc_release(message
);
522 static void SOSCloudTransportRemoveObjectForKey(SOSCloudTransportRef transport
, CFStringRef keyToRemove
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
524 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
525 secdebug(SOSCKCSCOPE
, "start");
526 CFErrorRef error
= NULL
;
527 xpc_object_t message
= NULL
;
528 xpc_object_t xkeytoremove
= NULL
;
530 require_action(keyToRemove
, xit
, error
= makeError(kSOSObjectNotFoundError
));
532 message
= xpc_dictionary_create(NULL
, NULL
, 0);
533 xpc_dictionary_set_uint64(message
, kMessageKeyVersion
, kCKDXPCVersion
);
534 xpc_dictionary_set_string(message
, kMessageKeyOperation
, kOperationRemoveObjectForKey
);
536 xkeytoremove
= _CFXPCCreateXPCObjectFromCFObject(keyToRemove
);
537 require_action(xkeytoremove
, xit
, error
= makeError(kSOSObjectCantBeConvertedToXPCObject
));
538 xpc_dictionary_set_value(message
, kMessageKeyKey
, xkeytoremove
);
539 xpc_release(xkeytoremove
);
541 talkWithKVS(xpcTransport
, message
, processQueue
, replyBlock
);
542 xpc_release(message
);
547 xpc_release(xkeytoremove
);
549 xpc_release(message
);
551 replyBlock(NULL
, error
);
552 CFReleaseSafe(error
);
555 static void SOSCloudTransportLocalNotification(SOSCloudTransportRef transport
, CFStringRef messageToUser
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
557 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
558 secdebug(SOSCKCSCOPE
, "start");
559 xpc_object_t xLocalNotificationDict
= xpc_dictionary_create(NULL
, NULL
, 0);
560 char *headerKey
= CFStringToCString(kCFUserNotificationAlertHeaderKey
);
561 char *message
= CFStringToCString(messageToUser
);
562 xpc_dictionary_set_string(xLocalNotificationDict
, headerKey
, message
);
564 xpc_object_t xpcmessage
= xpc_dictionary_create(NULL
, NULL
, 0);
565 xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
);
566 xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationUILocalNotification
);
567 xpc_dictionary_set_value (xpcmessage
, kMessageKeyValue
, xLocalNotificationDict
);
568 xpc_release(xLocalNotificationDict
);
570 talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
);
574 xpc_release(xpcmessage
);
577 static void SOSCloudTransportSetParams(SOSCloudTransportRef transport
, CFDictionaryRef paramsDict
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
579 secdebug(SOSCKCSCOPE
, "start");
580 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
582 xpc_object_t xParamsDict
= paramsDict
? _CFXPCCreateXPCObjectFromCFObject(paramsDict
) : xpc_null_create();
584 xpc_object_t xpcmessage
= xpc_dictionary_create(NULL
, NULL
, 0);
585 xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
);
586 xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationSetParams
);
587 xpc_dictionary_set_value (xpcmessage
, kMessageKeyValue
, xParamsDict
);
588 xpc_release(xParamsDict
);
590 talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
);
592 xpc_release(xpcmessage
);
595 static void SOSCloudTransportRequestSyncWithAllPeers(SOSCloudTransportRef transport
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
597 secdebug(SOSCKCSCOPE
, "start");
598 SOSXPCCloudTransportRef xpcTransport
= (SOSXPCCloudTransportRef
)transport
;
600 xpc_object_t xpcmessage
= xpc_dictionary_create(NULL
, NULL
, 0);
601 xpc_dictionary_set_uint64(xpcmessage
, kMessageKeyVersion
, kCKDXPCVersion
);
602 xpc_dictionary_set_string(xpcmessage
, kMessageKeyOperation
, kOperationRequestSyncWithAllPeers
);
604 talkWithKVS(xpcTransport
, xpcmessage
, processQueue
, replyBlock
);
606 xpc_release(xpcmessage
);
609 static SOSCloudTransportRef
SOSCloudTransportCreateXPCTransport(void)
611 SOSXPCCloudTransportRef st
;
612 st
= calloc(1, sizeof(*st
));
613 st
->transport
.put
= SOSCloudTransportPut
;
614 st
->transport
.registerKeys
= SOSCloudTransportRegisterKeys
;
615 st
->transport
.updateKeys
= SOSCloudTransportUpdateKeys
;
616 st
->transport
.unregisterKeys
= SOSCloudTransportUnregisterKeys
;
617 st
->transport
.get
= SOSCloudTransportGet
;
618 st
->transport
.getAll
= SOSCloudTransportGetAll
;
619 st
->transport
.synchronize
= SOSCloudTransportSync
;
620 st
->transport
.synchronizeAndWait
= SOSCloudTransportSyncAndWait
;
621 st
->transport
.clearAll
= SOSCloudTransportClearAll
;
622 st
->transport
.removeObjectForKey
= SOSCloudTransportRemoveObjectForKey
;
623 st
->transport
.localNotification
= SOSCloudTransportLocalNotification
;
624 st
->transport
.setParams
= SOSCloudTransportSetParams
;
625 st
->transport
.requestSyncWithAllPeers
= SOSCloudTransportRequestSyncWithAllPeers
;
626 SOSXPCCloudTransportInit(st
);
627 return &st
->transport
;
630 // MARK: ---------- SOSCloudKeychain concrete client APIs ----------
631 void SOSCloudKeychainSetItemsChangedBlock(CloudItemsChangedBlock itemsChangedBlock
)
633 secdebug(SOSCKCSCOPE
, "start");
634 SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportDefaultTransport(),
638 // MARK: ---------- SOSCloudKeychain virtual client APIs ----------
640 void SOSCloudKeychainPutObjectsInCloud(CFDictionaryRef objects
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
642 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
644 cTransportRef
->put(cTransportRef
, objects
, processQueue
, replyBlock
);
647 void SOSCloudKeychainRegisterKeysAndGet(CFArrayRef keysToRegister
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
, CloudItemsChangedBlock notificationBlock
)
649 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
651 cTransportRef
->registerKeys(cTransportRef
, keysToRegister
, processQueue
, replyBlock
, notificationBlock
);
654 bool SOSCloudKeychainUpdateKeys(bool getNewKeysOnly
,
655 CFArrayRef alwaysKeys
,
656 CFArrayRef afterFirstUnlockKeys
,
657 CFArrayRef unlockedKeys
,
660 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
662 return cTransportRef
->updateKeys(cTransportRef
, getNewKeysOnly
, alwaysKeys
, afterFirstUnlockKeys
, unlockedKeys
, error
);
667 void SOSCloudKeychainUnRegisterKeys(CFArrayRef keysToUnregister
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
669 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
671 cTransportRef
->unregisterKeys(cTransportRef
, keysToUnregister
, processQueue
, replyBlock
);
674 void SOSCloudKeychainHandleUpdate(CFDictionaryRef updates
)
676 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
677 if (cTransportRef
->itemsChangedBlock
)
678 ((CloudItemsChangedBlock
)cTransportRef
->itemsChangedBlock
)(updates
);
681 void SOSCloudKeychainGetObjectsFromCloud(CFArrayRef keysToGet
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
683 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
685 cTransportRef
->get(cTransportRef
, keysToGet
, processQueue
, replyBlock
);
688 void SOSCloudKeychainGetAllObjectsFromCloud(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
690 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
692 cTransportRef
->getAll(cTransportRef
, processQueue
, replyBlock
);
695 void SOSCloudKeychainSynchronizeAndWait(CFArrayRef keysToGet
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
697 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
699 cTransportRef
->synchronizeAndWait(cTransportRef
, keysToGet
, processQueue
, replyBlock
);
703 void SOSCloudKeychainSynchronize(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
705 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
707 cTransportRef
->synchronize(cTransportRef
, processQueue
, replyBlock
);
711 void SOSCloudKeychainClearAll(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
713 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
715 cTransportRef
->clearAll(cTransportRef
, processQueue
, replyBlock
);
718 void SOSCloudKeychainRemoveObjectForKey(CFStringRef keyToRemove
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
720 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
722 cTransportRef
->removeObjectForKey(cTransportRef
, keyToRemove
, processQueue
, replyBlock
);
725 void SOSCloudKeychainUserNotification(CFStringRef messageToUser
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
727 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
729 cTransportRef
->localNotification(cTransportRef
, messageToUser
, processQueue
, replyBlock
);
732 void SOSCloudKeychainSetParams(CFDictionaryRef paramsDict
, dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
734 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
736 cTransportRef
->setParams(cTransportRef
, paramsDict
, processQueue
, replyBlock
);
739 void SOSCloudKeychainRequestSyncWithAllPeers(dispatch_queue_t processQueue
, CloudKeychainReplyBlock replyBlock
)
741 SOSCloudTransportRef cTransportRef
= SOSCloudTransportDefaultTransport();
743 cTransportRef
->requestSyncWithAllPeers(cTransportRef
, processQueue
, replyBlock
);
746 void SOSCloudKeychainSetCallbackMethodXPC(void)
748 // Call this before making any other calls to CloudKeychainProxy
749 CFDictionaryRef paramsDict
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
750 kParamCallbackMethod
, kParamCallbackMethodXPC
, NULL
);
751 dispatch_queue_t processQueue
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0);
752 SOSCloudKeychainSetParams(paramsDict
, processQueue
, ^(CFDictionaryRef returnedValues
, CFErrorRef error
)
754 secerror("set params called back");
756 CFReleaseSafe(paramsDict
);