]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainClient.c
Security-58286.270.3.0.1.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / CKBridge / SOSCloudKeychainClient.c
1 /*
2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 SOSCloudTransport.c - Implementation of the transport layer from CKBridge to SOSAccount/SOSCircle
26 These are the exported functions from CloudKeychainProxy
27 */
28
29 /*
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.
32
33 See sendTSARequestWithXPC in tsaSupport.c for how to call the service
34
35 The client of an XPC service does not get connection events, nor does it
36 need to deal with transactions.
37 */
38
39 #include <AssertMacros.h>
40
41 #include <xpc/xpc.h>
42 #include <CoreFoundation/CoreFoundation.h>
43 #include <CoreFoundation/CFXPCBridge.h>
44 #include <sysexits.h>
45 #include <syslog.h>
46 #include <os/activity.h>
47 #include <CoreFoundation/CFUserNotification.h>
48 #include <Security/SecureObjectSync/SOSInternal.h>
49 #include <notify.h>
50
51 #include <utilities/debugging.h>
52 #include <utilities/SecCFWrappers.h>
53 #include <utilities/SecXPCError.h>
54
55 #include "SOSCloudKeychainConstants.h"
56 #include "SOSCloudKeychainClient.h"
57 #include "SOSUserKeygen.h"
58 #include "SecOTRSession.h"
59
60 #include <os/activity.h>
61 #include <os/state_private.h>
62
63
64 static CFStringRef sErrorDomain = CFSTR("com.apple.security.sos.transport.error");
65
66 #define SOSCKCSCOPE "sync"
67
68 // MARK: ---------- SOSCloudTransport ----------
69
70 static SOSCloudTransportRef SOSCloudTransportCreateXPCTransport(void);
71
72 void SOSCloudTransportGet(SOSCloudTransportRef transport, CFArrayRef keysToGet, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock);
73
74
75
76 /* Return the singleton cloud transport instance. */
77 CFDictionaryRef SOSCloudCopyKVSState(void) {
78 __block CFDictionaryRef retval = NULL;
79
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);
84 });
85
86 if (processQueue == NULL)
87 return NULL;
88
89 dispatch_semaphore_t waitSemaphore = NULL;
90
91 waitSemaphore = dispatch_semaphore_create(0);
92
93 CloudKeychainReplyBlock replyBlock = ^ (CFDictionaryRef returnedValues, CFErrorRef error) {
94 retval = returnedValues;
95 if (retval) CFRetain(retval);
96 dispatch_semaphore_signal(waitSemaphore);
97 };
98
99 SOSCloudKeychainGetAllObjectsFromCloud(processQueue, replyBlock);
100
101 dispatch_semaphore_wait(waitSemaphore, DISPATCH_TIME_FOREVER);
102 dispatch_release(waitSemaphore);
103
104 return retval;
105 }
106
107
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;
112
113 require_quiet(hints->osh_api == 3, errOut); // only grab on sysdiagnose or command lin
114
115 kvsdict = SOSCloudCopyKVSState();
116
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);
122
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");
127 errOut:
128 CFReleaseNull(kvsdict);
129 CFReleaseNull(serializedKVS);
130 return retval;
131 };
132
133 static SOSCloudTransportRef defaultTransport = NULL;
134
135 void
136 SOSCloudTransportSetDefaultTransport(SOSCloudTransportRef transport)
137 {
138 defaultTransport = transport;
139 }
140
141 static SOSCloudTransportRef SOSCloudTransportDefaultTransport(void)
142 {
143 static dispatch_once_t sTransportOnce;
144 dispatch_once(&sTransportOnce, ^{
145 if (defaultTransport == NULL) {
146 defaultTransport = SOSCloudTransportCreateXPCTransport();
147 // provide state handler to sysdiagnose and logging
148 os_state_add_handler(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), kvsStateBlock);
149 }
150 });
151 return defaultTransport;
152 }
153
154
155 // MARK: ----- utilities -----
156
157 static CFErrorRef makeError(CFIndex which)
158 {
159 CFDictionaryRef userInfo = NULL;
160 return CFErrorCreate(kCFAllocatorDefault, sErrorDomain, which, userInfo);
161 }
162
163 // MARK: ----- DEBUG Utilities -----
164
165 //------------------------------------------------------------------------------------------------
166 // DEBUG only
167 //------------------------------------------------------------------------------------------------
168
169 static void describeXPCObject(char *prefix, xpc_object_t object)
170 {
171 //#ifndef NDEBUG
172 // This is useful for debugging.
173 if (object)
174 {
175 char *desc = xpc_copy_description(object);
176 secdebug(SOSCKCSCOPE, "%s%s\n", prefix, desc);
177 free(desc);
178 }
179 else
180 secdebug(SOSCKCSCOPE, "%s<NULL>\n", prefix);
181 //#endif
182 }
183
184 static void describeXPCType(char *prefix, xpc_type_t xtype)
185 {
186 // Add others as necessary, e.g. XPC_TYPE_DOUBLE
187 #ifndef NDEBUG
188 // This is useful for debugging.
189 char msg[256]={0,};
190 if (XPC_TYPE_CONNECTION == xtype)
191 strcpy(msg, "XPC_TYPE_CONNECTION");
192 else if (XPC_TYPE_ERROR == xtype)
193 strcpy(msg, "XPC_TYPE_ERROR");
194 else if (XPC_TYPE_DICTIONARY == xtype)
195 strcpy(msg, "XPC_TYPE_DICTIONARY");
196 else
197 strcpy(msg, "<unknown>");
198
199 secdebug(SOSCKCSCOPE, "%s type:%s\n", prefix, msg);
200 #endif
201 }
202
203 // MARK: ---------- SOSXPCCloudTransport ----------
204
205 typedef struct SOSXPCCloudTransport *SOSXPCCloudTransportRef;
206 struct SOSXPCCloudTransport
207 {
208 struct SOSCloudTransport transport;
209 xpc_connection_t serviceConnection;
210 dispatch_queue_t xpc_queue;
211 };
212
213 static bool xpc_event_filter(const xpc_connection_t peer, xpc_object_t event, CFErrorRef *error)
214 {
215 // return true if the type is XPC_TYPE_DICTIONARY (and therefore something more to process)
216 secdebug(SOSCKCSCOPE, "handle_connection_event\n");
217 xpc_type_t xtype = xpc_get_type(event);
218 describeXPCType("handle_xpc_event", xtype);
219 if (XPC_TYPE_CONNECTION == xtype)
220 {
221 secdebug(SOSCKCSCOPE, "handle_xpc_event: XPC_TYPE_CONNECTION (unexpected)");
222 // The client of an XPC service does not get connection events
223 // For now, we log this and keep going
224 describeXPCObject("handle_xpc_event: XPC_TYPE_CONNECTION, obj : ", event);
225 }
226 else
227 if (XPC_TYPE_ERROR == xtype)
228 {
229 #ifndef NDEBUG
230 const char *estr = xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION);
231 #endif
232 secdebug(SOSCKCSCOPE, "default: xpc error: %s\n", estr);
233 }
234 else
235 if (XPC_TYPE_DICTIONARY == xtype)
236 {
237 secdebug(SOSCKCSCOPE, "received dictionary event %p\n", event);
238 return true;
239 }
240 else
241 {
242 secdebug(SOSCKCSCOPE, "default: unexpected connection event %p\n", event);
243 describeXPCObject("handle_xpc_event: obj : ", event);
244 if (error)
245 *error = makeError(kSOSOUnexpectedXPCEvent);
246 }
247 return false;
248 }
249
250 static void setupServiceConnection(SOSXPCCloudTransportRef transport)
251 {
252 secnotice(SOSCKCSCOPE, "CKP Transport: setting up xpc connection");
253 transport->serviceConnection = xpc_connection_create_mach_service(xpcServiceName, transport->xpc_queue, 0);
254
255 secdebug(SOSCKCSCOPE, "serviceConnection: %p\n", transport->serviceConnection);
256
257 xpc_connection_set_event_handler(transport->serviceConnection, ^(xpc_object_t event) {
258 secdebug(SOSCKCSCOPE, "CKP Transport, xpc_connection_set_event_handler\n");
259 if(event == XPC_ERROR_CONNECTION_INVALID){
260 secnotice(SOSCKCSCOPE, "CKP Transport: xpc connection invalid. Oh well.");
261 }
262 });
263
264 xpc_connection_activate(transport->serviceConnection);
265 }
266
267 static void teardownServiceConnection(SOSXPCCloudTransportRef transport)
268 {
269 secnotice(SOSCKCSCOPE, "CKP Transport: tearing down xpc connection");
270 dispatch_assert_queue(transport->xpc_queue);
271 xpc_release(transport->serviceConnection);
272 transport->serviceConnection = NULL;
273 }
274
275 static void SOSXPCCloudTransportInit(SOSXPCCloudTransportRef transport)
276 {
277 secdebug(SOSCKCSCOPE, "initXPCConnection\n");
278
279 transport->xpc_queue = dispatch_queue_create(xpcServiceName, DISPATCH_QUEUE_SERIAL);
280
281 setupServiceConnection(transport);
282
283 // Any time a new session starts, reestablish the XPC connections.
284 int token;
285 notify_register_dispatch("com.apple.system.loginwindow.desktopUp", &token, transport->xpc_queue, ^(int token2) {
286 secnotice(SOSCKCSCOPE, "CKP Transport: desktopUp happened, reestablishing xpc connections");
287 teardownServiceConnection(transport);
288 setupServiceConnection(transport);
289 });
290 }
291
292 typedef void (^ProxyReplyBlock)(xpc_object_t reply);
293
294 static bool messageToProxy(SOSXPCCloudTransportRef transport, xpc_object_t message, CFErrorRef *error, dispatch_queue_t processQueue, ProxyReplyBlock replyBlock) {
295 __block CFErrorRef connectionError = NULL;
296
297 dispatch_sync(transport->xpc_queue, ^{
298 if (transport->serviceConnection && message) {
299 xpc_connection_send_message_with_reply(transport->serviceConnection, message, processQueue, replyBlock);
300 } else {
301 connectionError = makeError(kSOSConnectionNotOpen);
302 }
303 });
304 return CFErrorPropagate(connectionError, error);
305 }
306
307 static void talkWithKVS(SOSXPCCloudTransportRef transport, xpc_object_t message, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
308 {
309 CFErrorRef messagingError = NULL;
310 dispatch_retain(processQueue);
311 bool messaged = messageToProxy(transport, message, &messagingError, transport->xpc_queue, ^(xpc_object_t reply)
312 {
313 CFErrorRef serverError = NULL;
314 CFTypeRef object = NULL;
315 if (xpc_event_filter(transport->serviceConnection, reply, &serverError) && reply)
316 {
317 if (serverError)
318 secerror("Error from xpc_event_filter: %@", serverError);
319 xpc_object_t xrv = xpc_dictionary_get_value(reply, kMessageKeyValue);
320 if (xrv)
321 {
322 /*
323 * The given XPC object must be one that was previously returned by
324 * _CFXPCCreateXPCMessageWithCFObject().
325 */
326 object = _CFXPCCreateCFObjectFromXPCObject(xrv); // CF object is retained; release in callback
327 }
328 else
329 secerror("missing value reply");
330
331 xpc_object_t xerror = xpc_dictionary_get_value(reply, kMessageKeyError);
332 if (xerror)
333 serverError = SecCreateCFErrorWithXPCObject(xerror); // use SecCFCreateErrorWithFormat?
334 }
335 dispatch_async(processQueue, ^{
336 if (replyBlock)
337 replyBlock(object, serverError);
338 CFReleaseSafe(object);
339 if (serverError)
340 {
341 secerror("callback error: %@", serverError);
342 CFReleaseSafe(serverError);
343 }
344 dispatch_release(processQueue);
345 });
346 });
347
348 if (!messaged) {
349 secerror("talkWithKVS error: %@", messagingError);
350 dispatch_async(processQueue, ^{
351 if (replyBlock)
352 replyBlock(NULL, messagingError);
353 CFReleaseSafe(messagingError);
354 dispatch_release(processQueue);
355 });
356 }
357 }
358
359 // MARK: ---------- SOSXPCCloudTransport Client Calls ----------
360
361 /* Concrete function backend implementations. */
362 static void SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportRef transport,
363 CloudItemsChangedBlock itemsChangedBlock) {
364 if (transport->itemsChangedBlock != itemsChangedBlock)
365 {
366 secnotice(SOSCKCSCOPE, "Changing itemsChangedBlock");
367 if (transport->itemsChangedBlock)
368 Block_release(transport->itemsChangedBlock);
369 transport->itemsChangedBlock = Block_copy(itemsChangedBlock);
370 }
371 }
372
373 /* Virtual function backend implementations. */
374 static void SOSCloudTransportPut(SOSCloudTransportRef transport, CFDictionaryRef values, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
375 {
376 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
377 secdebug(SOSCKCSCOPE, "%@", values);
378 CFErrorRef error = NULL;
379 xpc_object_t message = NULL;
380 xpc_object_t xobject = NULL;
381 require_action(values, xit, error = makeError(kSOSObjectNotFoundError));
382
383 message = xpc_dictionary_create(NULL, NULL, 0);
384 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
385 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationPUTDictionary);
386
387 xobject = _CFXPCCreateXPCObjectFromCFObject(values);
388 require_action(xobject, xit, error = makeError(kSOSObjectCantBeConvertedToXPCObject));
389 xpc_dictionary_set_value(message, kMessageKeyValue, xobject);
390 xpc_release(xobject);
391
392 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
393 xpc_release(message);
394 return;
395
396 xit:
397 if (replyBlock)
398 replyBlock(NULL, error);
399 CFReleaseSafe(error);
400 }
401
402 /* Get from KVS */
403 void SOSCloudTransportGet(SOSCloudTransportRef transport, CFArrayRef keysToGet, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
404 {
405 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
406 secdebug(SOSCKCSCOPE, "%@", keysToGet);
407 CFErrorRef error = NULL;
408 xpc_object_t xkeysOfInterest = xpc_dictionary_create(NULL, NULL, 0);
409 xpc_object_t xkeysToGet = keysToGet ? _CFXPCCreateXPCObjectFromCFObject(keysToGet) : xpc_null_create();
410
411 require_action(xkeysToGet, xit, error = makeError(kSOSObjectNotFoundError));
412
413 if (keysToGet) // don't add if nulll; will call getall
414 xpc_dictionary_set_value(xkeysOfInterest, kMessageKeyKeysToGet, xkeysToGet);
415
416 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
417 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
418 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationGETv2);
419 xpc_dictionary_set_value(message, kMessageKeyValue, xkeysOfInterest);
420
421 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
422 xpc_release(xkeysToGet);
423 xpc_release(xkeysOfInterest);
424 xpc_release(message);
425 return;
426
427 xit:
428 if(xkeysOfInterest)
429 xpc_release(xkeysOfInterest);
430 if(xkeysToGet)
431 xpc_release(xkeysToGet);
432 if (replyBlock)
433 replyBlock(NULL, error);
434 CFReleaseSafe(error);
435 }
436
437 //
438 // Handles NULL by seting xpc_null.
439 static void SecXPCDictionarySetCFObject(xpc_object_t xdict, const char *key, CFTypeRef object)
440 {
441 xpc_object_t xpc_obj = object ? _CFXPCCreateXPCObjectFromCFObject(object) : xpc_null_create();
442 xpc_dictionary_set_value(xdict, key, xpc_obj);
443 xpc_release(xpc_obj);
444 }
445
446 static void SOSCloudTransportUpdateKeys(SOSCloudTransportRef transport,
447 CFDictionaryRef keys,
448 CFStringRef accountUUID,
449 dispatch_queue_t processQueue,
450 CloudKeychainReplyBlock replyBlock)
451 {
452 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
453
454 xpc_object_t xkeysOfInterest = xpc_dictionary_create(NULL, NULL, 0);
455 SecXPCDictionarySetCFObject(xkeysOfInterest, kMessageAllKeys, keys);
456
457 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
458 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
459 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationRegisterKeys);
460 xpc_dictionary_set_value(message, kMessageKeyValue, xkeysOfInterest);
461 SecXPCDictionarySetCFObject(message, kMessageKeyAccountUUID, accountUUID);
462
463 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
464 xpc_release(message);
465 xpc_release(xkeysOfInterest);
466 }
467
468 static void SOSCloudTransportRemoveKeys(SOSCloudTransportRef transport,
469 CFArrayRef keys,
470 CFStringRef accountUUID,
471 dispatch_queue_t processQueue,
472 CloudKeychainReplyBlock replyBlock)
473 {
474 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
475
476 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
477 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
478
479 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationRemoveKeys);
480 SecXPCDictionarySetCFObject(message, kMessageKeyAccountUUID, accountUUID);
481 SecXPCDictionarySetCFObject(message, kMessageKeyValue, keys);
482
483 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
484 xpc_release(message);
485 }
486
487 static void SOSCloudTransportGetAll(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
488 {
489 secdebug(SOSCKCSCOPE, "start");
490 SOSCloudTransportGet(transport, NULL, processQueue, replyBlock);
491 }
492
493 static void SOSCloudTransportSync(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
494 {
495 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
496 secdebug(SOSCKCSCOPE, "start");
497 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
498 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
499 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationSynchronize);
500 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
501 xpc_release(message);
502 }
503
504 static void SOSCloudTransportSyncAndWait(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
505 {
506 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
507 secnotice(SOSCKCSCOPE, "%s XPC request to CKD: %s", kWAIT2MINID, kOperationSynchronizeAndWait);
508
509 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
510 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
511 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationSynchronizeAndWait);
512
513 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
514 xpc_release(message);
515 }
516
517 static void SOSCloudTransportClearAll(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
518 {
519 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
520 secdebug(SOSCKCSCOPE, "start");
521 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
522 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
523 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationClearStore);
524 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
525 xpc_release(message);
526 }
527
528 static void SOSCloudTransportRequestSyncWithPeers(SOSCloudTransportRef transport, CFArrayRef /* CFStringRef */ peers, CFArrayRef /* CFStringRef */ backupPeers, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
529 {
530 secdebug(SOSCKCSCOPE, "start");
531 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
532
533 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
534
535 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
536 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationRequestSyncWithPeers);
537
538 SecXPCDictionarySetCFObject(xpcmessage, kMessageKeyPeerIDList, peers);
539 SecXPCDictionarySetCFObject(xpcmessage, kMesssgeKeyBackupPeerIDList, backupPeers);
540
541 talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock);
542
543 xpc_release(xpcmessage);
544 }
545
546
547 static bool SOSCloudTransportHasPeerSyncPending(SOSCloudTransportRef transport, CFStringRef peerID, CFErrorRef* error)
548 {
549 secdebug(SOSCKCSCOPE, "start");
550 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
551
552 __block bool isSyncing = false;
553
554 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
555
556 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
557 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationHasPendingSyncWithPeer);
558
559 SecXPCDictionarySetCFObject(xpcmessage, kMessageKeyPeerID, peerID);
560
561 dispatch_semaphore_t wait = dispatch_semaphore_create(0);
562 bool sent = messageToProxy(xpcTransport, xpcmessage, error, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(xpc_object_t reply) {
563 isSyncing = xpc_dictionary_get_bool(reply, kMessageKeyValue);
564 dispatch_semaphore_signal(wait);
565 });
566
567 if (sent) {
568 dispatch_semaphore_wait(wait, DISPATCH_TIME_FOREVER);
569 }
570
571 dispatch_release(wait);
572
573 return sent && isSyncing;
574 }
575
576
577 static bool SOSCloudTransportHasPendingKey(SOSCloudTransportRef transport, CFStringRef keyName, CFErrorRef* error)
578 {
579 secdebug(SOSCKCSCOPE, "start");
580 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
581
582 __block bool kvsHasMessage = false;
583
584 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
585
586 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
587 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationHasPendingKey);
588
589 SecXPCDictionarySetCFObject(xpcmessage, kMessageKeyKey, keyName);
590
591 dispatch_semaphore_t kvsWait = dispatch_semaphore_create(0);
592 bool kvsSent = messageToProxy(xpcTransport, xpcmessage, error, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(xpc_object_t reply) {
593 kvsHasMessage = xpc_dictionary_get_bool(reply, kMessageKeyValue);
594 dispatch_semaphore_signal(kvsWait);
595 });
596
597 if (kvsSent) {
598 dispatch_semaphore_wait(kvsWait, DISPATCH_TIME_FOREVER);
599 }
600
601 dispatch_release(kvsWait);
602
603 return kvsSent && kvsHasMessage;
604 }
605
606
607 static void SOSCloudTransportRequestEnsurePeerRegistration(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
608 {
609 secdebug(SOSCKCSCOPE, "start");
610 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
611
612 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
613 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
614 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationRequestEnsurePeerRegistration);
615
616 talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock);
617
618 xpc_release(xpcmessage);
619 }
620
621 static void SOSCloudTransportRequestPerfCounters(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
622 {
623 secdebug(SOSCKCSCOPE, "start");
624 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
625
626 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
627 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
628 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationPerfCounters);
629
630 talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock);
631
632 xpc_release(xpcmessage);
633 }
634
635
636 static void SOSCloudTransportFlush(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
637 {
638 secdebug(SOSCKCSCOPE, "start");
639 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
640
641 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
642 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
643 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationFlush);
644
645 talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock);
646
647 xpc_release(xpcmessage);
648 }
649
650 static SOSCloudTransportRef SOSCloudTransportCreateXPCTransport(void)
651 {
652 SOSXPCCloudTransportRef st;
653 st = calloc(1, sizeof(*st));
654 st->transport.put = SOSCloudTransportPut;
655 st->transport.updateKeys = SOSCloudTransportUpdateKeys;
656
657 st->transport.get = SOSCloudTransportGet;
658 st->transport.getAll = SOSCloudTransportGetAll;
659 st->transport.synchronize = SOSCloudTransportSync;
660 st->transport.synchronizeAndWait = SOSCloudTransportSyncAndWait;
661 st->transport.clearAll = SOSCloudTransportClearAll;
662 st->transport.requestSyncWithPeers = SOSCloudTransportRequestSyncWithPeers;
663 st->transport.hasPeerSyncPending = SOSCloudTransportHasPeerSyncPending;
664 st->transport.hasPendingKey = SOSCloudTransportHasPendingKey;
665 st->transport.requestEnsurePeerRegistration = SOSCloudTransportRequestEnsurePeerRegistration;
666 st->transport.requestPerfCounters = SOSCloudTransportRequestPerfCounters;
667 st->transport.flush = SOSCloudTransportFlush;
668 st->transport.removeKeys = SOSCloudTransportRemoveKeys;
669 st->transport.itemsChangedBlock = Block_copy(^CFArrayRef(CFDictionaryRef changes) {
670 secerror("Calling default itemsChangedBlock - fatal: %@", changes);
671 assert(false);
672 return NULL;
673 });
674 SOSXPCCloudTransportInit(st);
675 return &st->transport;
676 }
677
678 // MARK: ---------- SOSCloudKeychain concrete client APIs ----------
679 void SOSCloudKeychainSetItemsChangedBlock(CloudItemsChangedBlock itemsChangedBlock)
680 {
681 secdebug(SOSCKCSCOPE, "start");
682 SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportDefaultTransport(),
683 itemsChangedBlock);
684 }
685
686 // MARK: ---------- SOSCloudKeychain virtual client APIs ----------
687
688 void SOSCloudKeychainPutObjectsInCloud(CFDictionaryRef objects, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
689 {
690 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
691 if (cTransportRef)
692 cTransportRef->put(cTransportRef, objects, processQueue, replyBlock);
693 }
694
695 void SOSCloudKeychainUpdateKeys(CFDictionaryRef keys, CFStringRef accountUUID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
696 {
697 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
698 if (cTransportRef)
699 cTransportRef->updateKeys(cTransportRef, keys, accountUUID, processQueue, replyBlock);
700 }
701
702
703 void SOSCloudKeychainRemoveKeys(CFArrayRef keys, CFStringRef accountUUID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
704 {
705 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
706 if (cTransportRef)
707 cTransportRef->removeKeys(cTransportRef, keys, accountUUID, processQueue, replyBlock);
708 }
709
710 CF_RETURNS_RETAINED CFArrayRef SOSCloudKeychainHandleUpdateMessage(CFDictionaryRef updates)
711 {
712 CFArrayRef result = NULL;
713 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
714 if (cTransportRef->itemsChangedBlock)
715 result = ((CloudItemsChangedBlock)cTransportRef->itemsChangedBlock)(updates);
716 return result;
717 }
718
719 void SOSCloudKeychainGetObjectsFromCloud(CFArrayRef keysToGet, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
720 {
721 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
722 if (cTransportRef)
723 cTransportRef->get(cTransportRef, keysToGet, processQueue, replyBlock);
724 }
725
726 void SOSCloudKeychainGetAllObjectsFromCloud(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
727 {
728 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
729 if (cTransportRef)
730 cTransportRef->getAll(cTransportRef, processQueue, replyBlock);
731 }
732
733 void SOSCloudKeychainSynchronizeAndWait(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
734 {
735 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
736 if (cTransportRef)
737 cTransportRef->synchronizeAndWait(cTransportRef, processQueue, replyBlock);
738 }
739
740 //DEBUG ONLY
741 void SOSCloudKeychainSynchronize(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
742 {
743 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
744 if (cTransportRef)
745 cTransportRef->synchronize(cTransportRef, processQueue, replyBlock);
746 }
747
748 //DEBUG ONLY
749 void SOSCloudKeychainClearAll(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
750 {
751 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
752 if (cTransportRef)
753 cTransportRef->clearAll(cTransportRef, processQueue, replyBlock);
754 }
755
756 void SOSCloudKeychainRequestSyncWithPeers(CFArrayRef /* CFStringRef */ peers, CFArrayRef /* CFStringRef */ backupPeers, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
757 {
758 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
759 if (cTransportRef)
760 cTransportRef->requestSyncWithPeers(cTransportRef, peers, backupPeers, processQueue, replyBlock);
761 }
762
763 bool SOSCloudKeychainHasPendingKey(CFStringRef keyName, CFErrorRef* error) {
764 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
765
766 return cTransportRef && cTransportRef->hasPendingKey(cTransportRef, keyName, error);
767 }
768
769 bool SOSCloudKeychainHasPendingSyncWithPeer(CFStringRef peerID, CFErrorRef* error) {
770 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
771
772 return cTransportRef && cTransportRef->hasPeerSyncPending(cTransportRef, peerID, error);
773 }
774
775 void SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
776 {
777 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
778 if (cTransportRef)
779 cTransportRef->requestEnsurePeerRegistration(cTransportRef, processQueue, replyBlock);
780 }
781
782 void SOSCloudKeychainRequestPerfCounters(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
783 {
784 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
785 if (cTransportRef)
786 cTransportRef->requestPerfCounters(cTransportRef, processQueue, replyBlock);
787 }
788
789
790 void SOSCloudKeychainFlush(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
791 {
792 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
793 if (cTransportRef)
794 cTransportRef->flush(cTransportRef, processQueue, replyBlock);
795 }