]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainClient.c
Security-57740.1.18.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 the main security code cannot 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
50 #include <utilities/debugging.h>
51 #include <utilities/SecCFWrappers.h>
52 #include <utilities/SecXPCError.h>
53
54 #include "SOSCloudKeychainConstants.h"
55 #include "SOSCloudKeychainClient.h"
56 #include "SOSKVSKeys.h"
57 #include "SOSUserKeygen.h"
58 #include "SecOTRSession.h"
59 #include "SOSCloudKeychainLogging.h"
60
61 #include <os/activity.h>
62 #include <os/state_private.h>
63
64
65 static CFStringRef sErrorDomain = CFSTR("com.apple.security.sos.transport.error");
66
67 #define KVSLOGSTATE "kvsLogState"
68 #define SOSCKCSCOPE "sync"
69
70 // MARK: ---------- SOSCloudTransport ----------
71
72 /* SOSCloudTransport, a statically initialized transport singleton. */
73 static SOSCloudTransportRef sTransport = NULL;
74
75 static SOSCloudTransportRef SOSCloudTransportCreateXPCTransport(void);
76
77 void SOSCloudKeychainSetTransport(SOSCloudTransportRef transport) {
78 sTransport = transport;
79 }
80
81 void SOSCloudTransportGet(SOSCloudTransportRef transport, CFArrayRef keysToGet, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock);
82
83
84
85 /* Return the singleton cloud transport instance. */
86 CFDictionaryRef SOSCloudCopyKVSState(void) {
87 __block CFDictionaryRef retval = NULL;
88
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);
93 });
94
95 if (processQueue == NULL)
96 return NULL;
97
98 dispatch_semaphore_t waitSemaphore = NULL;
99
100 waitSemaphore = dispatch_semaphore_create(0);
101
102 CloudKeychainReplyBlock replyBlock = ^ (CFDictionaryRef returnedValues, CFErrorRef error) {
103 retval = returnedValues;
104 if (retval) CFRetain(retval);
105 dispatch_semaphore_signal(waitSemaphore);
106 };
107
108 SOSCloudKeychainGetAllObjectsFromCloud(processQueue, replyBlock);
109
110 dispatch_semaphore_wait(waitSemaphore, DISPATCH_TIME_FOREVER);
111 dispatch_release(waitSemaphore);
112
113 return retval;
114 }
115
116
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;
121
122 require_quiet(hints->osh_api == 3, errOut); // only grab on sysdiagnose or command lin
123
124 kvsdict = SOSCloudCopyKVSState();
125
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);
131
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");
136 errOut:
137 CFReleaseNull(kvsdict);
138 CFReleaseNull(serializedKVS);
139 return retval;
140 };
141
142
143 static SOSCloudTransportRef SOSCloudTransportDefaultTransport(void)
144 {
145 static dispatch_once_t sTransportOnce;
146 dispatch_once(&sTransportOnce, ^{
147 if (!sTransport)
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);
151 });
152 return sTransport;
153 }
154
155
156 // MARK: ----- utilities -----
157
158 static CFErrorRef makeError(CFIndex which)
159 {
160 CFDictionaryRef userInfo = NULL;
161 return CFErrorCreate(kCFAllocatorDefault, sErrorDomain, which, userInfo);
162 }
163
164 // MARK: ----- DEBUG Utilities -----
165
166 //------------------------------------------------------------------------------------------------
167 // DEBUG only
168 //------------------------------------------------------------------------------------------------
169
170 static void describeXPCObject(char *prefix, xpc_object_t object)
171 {
172 //#ifndef NDEBUG
173 // This is useful for debugging.
174 if (object)
175 {
176 char *desc = xpc_copy_description(object);
177 secdebug(SOSCKCSCOPE, "%s%s\n", prefix, desc);
178 free(desc);
179 }
180 else
181 secdebug(SOSCKCSCOPE, "%s<NULL>\n", prefix);
182 //#endif
183 }
184
185 static void describeXPCType(char *prefix, xpc_type_t xtype)
186 {
187 // Add others as necessary, e.g. XPC_TYPE_DOUBLE
188 #ifndef NDEBUG
189 // This is useful for debugging.
190 char msg[256]={0,};
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");
197 else
198 strcpy(msg, "<unknown>");
199
200 secdebug(SOSCKCSCOPE, "%s type:%s\n", prefix, msg);
201 #endif
202 }
203
204 // MARK: ---------- SOSXPCCloudTransport ----------
205
206 typedef struct SOSXPCCloudTransport *SOSXPCCloudTransportRef;
207 struct SOSXPCCloudTransport
208 {
209 struct SOSCloudTransport transport;
210 xpc_connection_t serviceConnection;
211 xpc_connection_t idsProxyServiceConnection;
212 dispatch_queue_t xpc_queue;
213 };
214
215 static bool xpc_event_filter(const xpc_connection_t peer, xpc_object_t event, CFErrorRef *error)
216 {
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)
222 {
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);
227 #if 0
228 if (error)
229 *error = makeError(kSOSOUnexpectedConnectionEvent); // FIX
230 assert(true);
231 #endif
232 }
233 else
234 if (XPC_TYPE_ERROR == xtype)
235 {
236 #ifndef NDEBUG
237 const char *estr = xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION);
238 #endif
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);
243 if (errStr)
244 CFDictionaryAddValue(userInfo, kCFErrorLocalizedDescriptionKey, errStr);
245 if (error)
246 *error = CFErrorCreate(kCFAllocatorDefault, sErrorDomain, kSOSOXPCErrorEvent, userInfo);
247 CFReleaseSafe(errStr);
248 CFReleaseSafe(userInfo);
249 #endif
250 }
251 else
252 if (XPC_TYPE_DICTIONARY == xtype)
253 {
254 secdebug(SOSCKCSCOPE, "received dictionary event %p\n", event);
255 return true;
256 }
257 else
258 {
259 secdebug(SOSCKCSCOPE, "default: unexpected connection event %p\n", event);
260 describeXPCObject("handle_xpc_event: obj : ", event);
261 if (error)
262 *error = makeError(kSOSOUnexpectedXPCEvent);
263 }
264 return false;
265 }
266
267 static void SOSXPCCloudTransportInit(SOSXPCCloudTransportRef transport)
268 {
269 secdebug(SOSCKCSCOPE, "initXPCConnection\n");
270
271 transport->xpc_queue = dispatch_queue_create(xpcServiceName, DISPATCH_QUEUE_SERIAL);
272
273 transport->serviceConnection = xpc_connection_create_mach_service(xpcServiceName, transport->xpc_queue, 0);
274
275
276 secdebug(SOSCKCSCOPE, "serviceConnection: %p\n", transport->serviceConnection);
277
278
279 xpc_connection_set_event_handler(transport->serviceConnection, ^(xpc_object_t event)
280 {
281 secdebug(SOSCKCSCOPE, "xpc_connection_set_event_handler\n");
282 });
283
284 xpc_connection_resume(transport->serviceConnection);
285 xpc_retain(transport->serviceConnection);
286
287 transport->idsProxyServiceConnection = xpc_connection_create_mach_service(xpcIDSServiceName, transport->xpc_queue, 0);
288
289 secdebug(SOSCKCSCOPE, "ids service connection: %p\n", transport->idsProxyServiceConnection);
290
291 xpc_connection_set_event_handler(transport->idsProxyServiceConnection, ^(xpc_object_t object) {
292 secdebug(SOSCKCSCOPE, "IDS Transport, xpc_connection_set_event_handler\n");
293 });
294 xpc_connection_resume(transport->idsProxyServiceConnection);
295 xpc_retain(transport->idsProxyServiceConnection);
296
297 }
298
299 static void talkWithIDS(SOSXPCCloudTransportRef transport, xpc_object_t message, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
300 {
301 CFErrorRef connectionError = NULL;
302
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);
307
308 xpc_connection_send_message_with_reply(transport->idsProxyServiceConnection, message, transport->xpc_queue, ^(xpc_object_t reply)
309 {
310 CFErrorRef serverError = NULL;
311 CFTypeRef object = NULL;
312 if (xpc_event_filter(transport->idsProxyServiceConnection, reply, &serverError) && reply)
313 {
314 describeXPCObject("IDS Proxy: reply : ", reply);
315 if (serverError)
316 secerror("Error from xpc_event_filter: %@", serverError);
317 xpc_object_t xrv = xpc_dictionary_get_value(reply, kMessageKeyValue);
318 if (xrv)
319 {
320 describeXPCObject("talkwithIDS: xrv: ", xrv);
321 /*
322 * The given XPC object must be one that was previously returned by
323 * _CFXPCCreateXPCMessageWithCFObject().
324 */
325 object = _CFXPCCreateCFObjectFromXPCObject(xrv); // CF object is retained; release in callback
326 secnotice("talkwithIDS", "converted CF object: %@", object);
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("talkwithIDS callback error: %@", serverError);
342 CFReleaseSafe(serverError);
343 }
344 dispatch_release(processQueue);
345 });
346 });
347 return;
348
349 xit:
350 secerror("talkWithIDS error: %@", connectionError);
351 dispatch_async(processQueue, ^{
352 if (replyBlock)
353 replyBlock(NULL, connectionError);
354 CFReleaseSafe(connectionError);
355 dispatch_release(processQueue);
356 });
357
358 os_activity_end(trace_activity);
359 }
360 static void talkWithKVS(SOSXPCCloudTransportRef transport, xpc_object_t message, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
361 {
362 CFErrorRef connectionError = NULL;
363
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);
368
369 xpc_connection_send_message_with_reply(transport->serviceConnection, message, transport->xpc_queue, ^(xpc_object_t reply)
370 {
371 CFErrorRef serverError = NULL;
372 CFTypeRef object = NULL;
373 if (xpc_event_filter(transport->serviceConnection, reply, &serverError) && reply)
374 {
375 describeXPCObject("getValuesFromKVS: reply : ", reply);
376 if (serverError)
377 secerror("Error from xpc_event_filter: %@", serverError);
378 xpc_object_t xrv = xpc_dictionary_get_value(reply, kMessageKeyValue);
379 if (xrv)
380 {
381 describeXPCObject("talkWithKVS: xrv: ", xrv);
382 /*
383 * The given XPC object must be one that was previously returned by
384 * _CFXPCCreateXPCMessageWithCFObject().
385 */
386 object = _CFXPCCreateCFObjectFromXPCObject(xrv); // CF object is retained; release in callback
387 secnotice("talkwithkvs", "converted CF object: %@", object);
388 }
389 else
390 secerror("missing value reply");
391
392 xpc_object_t xerror = xpc_dictionary_get_value(reply, kMessageKeyError);
393 if (xerror)
394 serverError = SecCreateCFErrorWithXPCObject(xerror); // use SecCFCreateErrorWithFormat?
395 }
396 dispatch_async(processQueue, ^{
397 if (replyBlock)
398 replyBlock(object, serverError);
399 CFReleaseSafe(object);
400 if (serverError)
401 {
402 secerror("callback error: %@", serverError);
403 CFReleaseSafe(serverError);
404 }
405 dispatch_release(processQueue);
406 });
407 });
408 return;
409
410 xit:
411 secerror("talkWithKVS error: %@", connectionError);
412 dispatch_async(processQueue, ^{
413 if (replyBlock)
414 replyBlock(NULL, connectionError);
415 CFReleaseSafe(connectionError);
416 dispatch_release(processQueue);
417 });
418
419 os_activity_end(trace_activity);
420 }
421
422 // MARK: ---------- SOSXPCCloudTransport Client Calls ----------
423
424 /* Concrete function backend implementations. */
425 static void SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportRef transport,
426 CloudItemsChangedBlock itemsChangedBlock) {
427 if (transport->itemsChangedBlock != itemsChangedBlock)
428 {
429 secnotice(SOSCKCSCOPE, "Changing itemsChangedBlock");
430 if (transport->itemsChangedBlock)
431 Block_release(transport->itemsChangedBlock);
432 transport->itemsChangedBlock = Block_copy(itemsChangedBlock);
433 }
434 }
435
436 /* Virtual function backend implementations. */
437 static void SOSCloudTransportPut(SOSCloudTransportRef transport, CFDictionaryRef values, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
438 {
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));
445
446 message = xpc_dictionary_create(NULL, NULL, 0);
447 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
448 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationPUTDictionary);
449
450 xobject = _CFXPCCreateXPCObjectFromCFObject(values);
451 require_action(xobject, xit, error = makeError(kSOSObjectCantBeConvertedToXPCObject));
452 xpc_dictionary_set_value(message, kMessageKeyValue, xobject);
453 xpc_release(xobject);
454
455 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
456 xpc_release(message);
457 return;
458
459 xit:
460 if (replyBlock)
461 replyBlock(NULL, error);
462 CFReleaseSafe(error);
463 }
464
465 /* Get from KVS */
466 void SOSCloudTransportGet(SOSCloudTransportRef transport, CFArrayRef keysToGet, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
467 {
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();
473
474 require_action(xkeysToGet, xit, error = makeError(kSOSObjectNotFoundError));
475
476 if (keysToGet) // don't add if nulll; will call getall
477 xpc_dictionary_set_value(xkeysOfInterest, kMessageKeyKeysToGet, xkeysToGet);
478
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);
483
484 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
485 xpc_release(xkeysToGet);
486 xpc_release(xkeysOfInterest);
487 xpc_release(message);
488 return;
489
490 xit:
491 if(xkeysOfInterest)
492 xpc_release(xkeysOfInterest);
493 if(xkeysToGet)
494 xpc_release(xkeysToGet);
495 if (replyBlock)
496 replyBlock(NULL, error);
497 CFReleaseSafe(error);
498 }
499
500 //
501 // Handles NULL by seting xpc_null.
502 static void SecXPCDictionarySetCFObject(xpc_object_t xdict, const char *key, CFTypeRef object)
503 {
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);
507 }
508
509 static void SOSCloudTransportGetIDSDeviceID(SOSCloudTransportRef transport, CloudKeychainReplyBlock replyBlock)
510 {
511 dispatch_queue_t processQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
512
513 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
514
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);
518
519 talkWithIDS(xpcTransport, message, processQueue, replyBlock);
520 xpc_release(message);
521 }
522
523 static void SOSCloudTransportSendFragmentedIDSMessage(SOSCloudTransportRef transport, CFDictionaryRef messageData, CFStringRef deviceName, CFStringRef peerID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock){
524
525 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
526 xpc_object_t xmessageData = _CFXPCCreateXPCObjectFromCFObject(messageData);
527
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);
531
532 xpc_dictionary_set_value(message, kMessageKeyValue, xmessageData);
533 SecXPCDictionarySetCFObject(message, kMessageKeyDeviceName, deviceName);
534 SecXPCDictionarySetCFObject(message, kMessageKeyPeerID, peerID);
535 talkWithIDS(xpcTransport, message, processQueue, replyBlock);
536
537 xpc_release(xmessageData);
538 xpc_release(message);
539 }
540
541 static void SOSCloudTransportSendIDSMessage(SOSCloudTransportRef transport, CFDictionaryRef messageData, CFStringRef deviceName, CFStringRef peerID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock){
542
543 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
544 xpc_object_t xmessageData = _CFXPCCreateXPCObjectFromCFObject(messageData);
545
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);
549
550 xpc_dictionary_set_value(message, kMessageKeyValue, xmessageData);
551 SecXPCDictionarySetCFObject(message, kMessageKeyDeviceName, deviceName);
552 SecXPCDictionarySetCFObject(message, kMessageKeyPeerID, peerID);
553 talkWithIDS(xpcTransport, message, processQueue, replyBlock);
554
555 xpc_release(xmessageData);
556 xpc_release(message);
557 }
558
559 static void SOSCloudTransportUpdateKeys(SOSCloudTransportRef transport,
560 CFDictionaryRef keys,
561 dispatch_queue_t processQueue,
562 CloudKeychainReplyBlock replyBlock)
563 {
564 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
565
566 xpc_object_t xkeysOfInterest = xpc_dictionary_create(NULL, NULL, 0);
567 SecXPCDictionarySetCFObject(xkeysOfInterest, kMessageAllKeys, keys);
568
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);
573
574 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
575 xpc_release(message);
576 xpc_release(xkeysOfInterest);
577 }
578
579 static void SOSCloudTransportGetAll(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
580 {
581 secdebug(SOSCKCSCOPE, "start");
582 SOSCloudTransportGet(transport, NULL, processQueue, replyBlock);
583 }
584
585 static void SOSCloudTransportSync(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
586 {
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);
594 }
595
596 static void SOSCloudTransportSyncAndWait(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
597 {
598 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
599 secnotice(SOSCKCSCOPE, "%s XPC request to CKD: %s", kWAIT2MINID, kOperationSynchronizeAndWait);
600
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);
604
605 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
606 xpc_release(message);
607 }
608
609 static void SOSCloudTransportClearAll(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
610 {
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);
618 }
619
620 static void SOSCloudTransportRequestSyncWithAllPeers(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
621 {
622 secdebug(SOSCKCSCOPE, "start");
623 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
624
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);
628
629 talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock);
630
631 xpc_release(xpcmessage);
632 }
633
634 static void SOSCloudTransportRequestEnsurePeerRegistration(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
635 {
636 secdebug(SOSCKCSCOPE, "start");
637 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
638
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);
642
643 talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock);
644
645 xpc_release(xpcmessage);
646 }
647
648 static void SOSCloudTransportFlush(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
649 {
650 secdebug(SOSCKCSCOPE, "start");
651 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
652
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);
656
657 talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock);
658
659 xpc_release(xpcmessage);
660 }
661
662 static void SOSCloudTransportCheckIDSDeviceIDAvailability(SOSCloudTransportRef transport, CFArrayRef ids, CFStringRef peerID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
663 {
664 secdebug(SOSCKCSCOPE, "start");
665 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
666
667 xpc_object_t xIDSArray = _CFXPCCreateXPCObjectFromCFObject(ids);
668
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);
672
673 SecXPCDictionarySetCFObject(message, kMessageKeyPeerID, peerID);
674 xpc_dictionary_set_value(message, kMessageKeyValue, xIDSArray);
675
676 talkWithIDS(xpcTransport, message, processQueue, replyBlock);
677
678 xpc_release(xIDSArray);
679 xpc_release(message);
680
681 }
682
683 static SOSCloudTransportRef SOSCloudTransportCreateXPCTransport(void)
684 {
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;
691
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);
704 assert(false);
705 return NULL;
706 });
707 SOSXPCCloudTransportInit(st);
708 return &st->transport;
709 }
710
711 // MARK: ---------- SOSCloudKeychain concrete client APIs ----------
712 void SOSCloudKeychainSetItemsChangedBlock(CloudItemsChangedBlock itemsChangedBlock)
713 {
714 secdebug(SOSCKCSCOPE, "start");
715 SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportDefaultTransport(),
716 itemsChangedBlock);
717 }
718
719 // MARK: ---------- SOSCloudKeychain virtual client APIs ----------
720
721 void SOSCloudKeychainPutObjectsInCloud(CFDictionaryRef objects, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
722 {
723 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
724 if (cTransportRef)
725 cTransportRef->put(cTransportRef, objects, processQueue, replyBlock);
726 }
727
728 void SOSCloudKeychainUpdateKeys(CFDictionaryRef keys, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
729 {
730 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
731 if (cTransportRef)
732 cTransportRef->updateKeys(cTransportRef, keys, processQueue, replyBlock);
733 }
734
735 void SOSCloudKeychainSendIDSMessage(CFDictionaryRef message, CFStringRef deviceName, CFStringRef peerID, dispatch_queue_t processQueue, CFBooleanRef fragmentation, CloudKeychainReplyBlock replyBlock)
736 {
737 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
738
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);
743
744 }
745 void SOSCloudKeychainGetIDSDeviceAvailability(CFArrayRef ids, CFStringRef peerID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock){
746
747 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
748
749 if (cTransportRef)
750 cTransportRef->getIDSDeviceAvailability(cTransportRef, ids, peerID, processQueue, replyBlock);
751 }
752 void SOSCloudKeychainGetIDSDeviceID(CloudKeychainReplyBlock replyBlock)
753 {
754 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
755 if (cTransportRef)
756 cTransportRef->getDeviceID(cTransportRef, replyBlock);
757
758 }
759
760 CF_RETURNS_RETAINED CFArrayRef SOSCloudKeychainHandleUpdateMessage(CFDictionaryRef updates)
761 {
762 CFArrayRef result = NULL;
763 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
764 if (cTransportRef->itemsChangedBlock)
765 result = ((CloudItemsChangedBlock)cTransportRef->itemsChangedBlock)(updates);
766 return result;
767 }
768
769 void SOSCloudKeychainGetObjectsFromCloud(CFArrayRef keysToGet, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
770 {
771 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
772 if (cTransportRef)
773 cTransportRef->get(cTransportRef, keysToGet, processQueue, replyBlock);
774 }
775
776 void SOSCloudKeychainGetAllObjectsFromCloud(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
777 {
778 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
779 if (cTransportRef)
780 cTransportRef->getAll(cTransportRef, processQueue, replyBlock);
781 }
782
783 void SOSCloudKeychainSynchronizeAndWait(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
784 {
785 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
786 if (cTransportRef)
787 cTransportRef->synchronizeAndWait(cTransportRef, processQueue, replyBlock);
788 }
789
790 //DEBUG ONLY
791 void SOSCloudKeychainSynchronize(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
792 {
793 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
794 if (cTransportRef)
795 cTransportRef->synchronize(cTransportRef, processQueue, replyBlock);
796 }
797
798 //DEBUG ONLY
799 void SOSCloudKeychainClearAll(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
800 {
801 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
802 if (cTransportRef)
803 cTransportRef->clearAll(cTransportRef, processQueue, replyBlock);
804 }
805
806 void SOSCloudKeychainRequestSyncWithAllPeers(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
807 {
808 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
809 if (cTransportRef)
810 cTransportRef->requestSyncWithAllPeers(cTransportRef, processQueue, replyBlock);
811 }
812
813 void SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
814 {
815 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
816 if (cTransportRef)
817 cTransportRef->requestEnsurePeerRegistration(cTransportRef, processQueue, replyBlock);
818 }
819
820 void SOSCloudKeychainFlush(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
821 {
822 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
823 if (cTransportRef)
824 cTransportRef->flush(cTransportRef, processQueue, replyBlock);
825 }