]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/CKBridge/SOSCloudKeychainClient.c
Security-57336.1.9.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
49 #include <utilities/debugging.h>
50 #include <utilities/SecCFWrappers.h>
51 #include <utilities/SecXPCError.h>
52
53 #include "SOSCloudKeychainConstants.h"
54 #include "SOSCloudKeychainClient.h"
55
56 static CFStringRef sErrorDomain = CFSTR("com.apple.security.sos.transport.error");
57
58 #define SOSCKCSCOPE "sync"
59
60 // MARK: ---------- SOSCloudTransport ----------
61
62 /* SOSCloudTransport, a statically initialized transport singleton. */
63 static SOSCloudTransportRef sTransport = NULL;
64
65 static SOSCloudTransportRef SOSCloudTransportCreateXPCTransport(void);
66
67 void SOSCloudKeychainSetTransport(SOSCloudTransportRef transport) {
68 sTransport = transport;
69 }
70
71 /* Return the singleton cloud transport instance. */
72 static SOSCloudTransportRef SOSCloudTransportDefaultTransport(void)
73 {
74 static dispatch_once_t sTransportOnce;
75 dispatch_once(&sTransportOnce, ^{
76 if (!sTransport)
77 SOSCloudKeychainSetTransport(SOSCloudTransportCreateXPCTransport());
78 });
79 return sTransport;
80 }
81
82
83 // MARK: ----- utilities -----
84
85 static CFErrorRef makeError(CFIndex which)
86 {
87 CFDictionaryRef userInfo = NULL;
88 return CFErrorCreate(kCFAllocatorDefault, sErrorDomain, which, userInfo);
89 }
90
91 // MARK: ----- DEBUG Utilities -----
92
93 //------------------------------------------------------------------------------------------------
94 // DEBUG only
95 //------------------------------------------------------------------------------------------------
96
97 static void describeXPCObject(char *prefix, xpc_object_t object)
98 {
99 //#ifndef NDEBUG
100 // This is useful for debugging.
101 if (object)
102 {
103 char *desc = xpc_copy_description(object);
104 secdebug(SOSCKCSCOPE, "%s%s\n", prefix, desc);
105 free(desc);
106 }
107 else
108 secdebug(SOSCKCSCOPE, "%s<NULL>\n", prefix);
109 //#endif
110 }
111
112 static void describeXPCType(char *prefix, xpc_type_t xtype)
113 {
114 // Add others as necessary, e.g. XPC_TYPE_DOUBLE
115 #ifndef NDEBUG
116 // This is useful for debugging.
117 char msg[256]={0,};
118 if (XPC_TYPE_CONNECTION == xtype)
119 strcpy(msg, "XPC_TYPE_CONNECTION");
120 else if (XPC_TYPE_ERROR == xtype)
121 strcpy(msg, "XPC_TYPE_ERROR");
122 else if (XPC_TYPE_DICTIONARY == xtype)
123 strcpy(msg, "XPC_TYPE_DICTIONARY");
124 else
125 strcpy(msg, "<unknown>");
126
127 secdebug(SOSCKCSCOPE, "%s type:%s\n", prefix, msg);
128 #endif
129 }
130
131 // MARK: ---------- SOSXPCCloudTransport ----------
132
133 typedef struct SOSXPCCloudTransport *SOSXPCCloudTransportRef;
134 struct SOSXPCCloudTransport
135 {
136 struct SOSCloudTransport transport;
137 xpc_connection_t serviceConnection;
138 xpc_connection_t idsProxyServiceConnection;
139 dispatch_queue_t xpc_queue;
140 };
141
142 static bool xpc_event_filter(const xpc_connection_t peer, xpc_object_t event, CFErrorRef *error)
143 {
144 // return true if the type is XPC_TYPE_DICTIONARY (and therefore something more to process)
145 secdebug(SOSCKCSCOPE, "handle_connection_event\n");
146 xpc_type_t xtype = xpc_get_type(event);
147 describeXPCType("handle_xpc_event", xtype);
148 if (XPC_TYPE_CONNECTION == xtype)
149 {
150 secdebug(SOSCKCSCOPE, "handle_xpc_event: XPC_TYPE_CONNECTION (unexpected)");
151 // The client of an XPC service does not get connection events
152 // For now, we log this and keep going
153 describeXPCObject("handle_xpc_event: XPC_TYPE_CONNECTION, obj : ", event);
154 #if 0
155 if (error)
156 *error = makeError(kSOSOUnexpectedConnectionEvent); // FIX
157 assert(true);
158 #endif
159 }
160 else
161 if (XPC_TYPE_ERROR == xtype)
162 {
163 #ifndef NDEBUG
164 const char *estr = xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION);
165 #endif
166 secdebug(SOSCKCSCOPE, "default: xpc error: %s\n", estr);
167 #if 0 // just log for now
168 CFStringRef errStr = CFStringCreateWithCString(kCFAllocatorDefault, estr, kCFStringEncodingUTF8);
169 CFMutableDictionaryRef userInfo = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
170 if (errStr)
171 CFDictionaryAddValue(userInfo, kCFErrorLocalizedDescriptionKey, errStr);
172 if (error)
173 *error = CFErrorCreate(kCFAllocatorDefault, sErrorDomain, kSOSOXPCErrorEvent, userInfo);
174 CFReleaseSafe(errStr);
175 CFReleaseSafe(userInfo);
176 #endif
177 }
178 else
179 if (XPC_TYPE_DICTIONARY == xtype)
180 {
181 secdebug(SOSCKCSCOPE, "received dictionary event %p\n", event);
182 return true;
183 }
184 else
185 {
186 secdebug(SOSCKCSCOPE, "default: unexpected connection event %p\n", event);
187 describeXPCObject("handle_xpc_event: obj : ", event);
188 if (error)
189 *error = makeError(kSOSOUnexpectedXPCEvent);
190 }
191 return false;
192 }
193
194 static void SOSXPCCloudTransportInit(SOSXPCCloudTransportRef transport)
195 {
196 secdebug(SOSCKCSCOPE, "initXPCConnection\n");
197
198 transport->xpc_queue = dispatch_queue_create(xpcServiceName, DISPATCH_QUEUE_SERIAL);
199
200 transport->serviceConnection = xpc_connection_create_mach_service(xpcServiceName, transport->xpc_queue, 0);
201
202
203 secdebug(SOSCKCSCOPE, "serviceConnection: %p\n", transport->serviceConnection);
204
205
206 xpc_connection_set_event_handler(transport->serviceConnection, ^(xpc_object_t event)
207 {
208 secdebug(SOSCKCSCOPE, "xpc_connection_set_event_handler\n");
209 });
210
211 xpc_connection_resume(transport->serviceConnection);
212 xpc_retain(transport->serviceConnection);
213
214 transport->idsProxyServiceConnection = xpc_connection_create_mach_service(xpcIDSServiceName, transport->xpc_queue, 0);
215
216 secdebug(SOSCKCSCOPE, "ids service connection: %p\n", transport->idsProxyServiceConnection);
217
218 xpc_connection_set_event_handler(transport->idsProxyServiceConnection, ^(xpc_object_t object) {
219 secdebug(SOSCKCSCOPE, "IDS Transport, xpc_connection_set_event_handler\n");
220 });
221 xpc_connection_resume(transport->idsProxyServiceConnection);
222 xpc_retain(transport->idsProxyServiceConnection);
223 }
224
225 static void talkWithIDS(SOSXPCCloudTransportRef transport, xpc_object_t message, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
226 {
227 CFErrorRef connectionError = NULL;
228
229 os_activity_t trace_activity = os_activity_start("talkWithIDS", OS_ACTIVITY_FLAG_DEFAULT);
230 require_action(transport->idsProxyServiceConnection, xit, connectionError = makeError(kSOSConnectionNotOpen));
231 require_action(message, xit, connectionError = makeError(kSOSObjectNotFoundError));
232 dispatch_retain(processQueue);
233
234 xpc_connection_send_message_with_reply(transport->idsProxyServiceConnection, message, transport->xpc_queue, ^(xpc_object_t reply)
235 {
236 CFErrorRef serverError = NULL;
237 CFTypeRef object = NULL;
238 if (xpc_event_filter(transport->idsProxyServiceConnection, reply, &serverError) && reply)
239 {
240 describeXPCObject("IDS Proxy: reply : ", reply);
241 if (serverError)
242 secerror("Error from xpc_event_filter: %@", serverError);
243 xpc_object_t xrv = xpc_dictionary_get_value(reply, kMessageKeyValue);
244 if (xrv)
245 {
246 describeXPCObject("talkwithIDS: xrv: ", xrv);
247 /*
248 * The given XPC object must be one that was previously returned by
249 * _CFXPCCreateXPCMessageWithCFObject().
250 */
251 object = _CFXPCCreateCFObjectFromXPCObject(xrv); // CF object is retained; release in callback
252 secnotice("talkwithIDS", "converted CF object: %@", object);
253 }
254 else
255 secerror("missing value reply");
256
257 xpc_object_t xerror = xpc_dictionary_get_value(reply, kMessageKeyError);
258 if (xerror)
259 serverError = SecCreateCFErrorWithXPCObject(xerror); // use SecCFCreateErrorWithFormat?
260 }
261 dispatch_async(processQueue, ^{
262 if (replyBlock)
263 replyBlock(object, serverError);
264 CFReleaseSafe(object);
265 if (serverError)
266 {
267 secerror("talkwithIDS callback error: %@", serverError);
268 CFReleaseSafe(serverError);
269 }
270 dispatch_release(processQueue);
271 });
272 });
273 return;
274
275 xit:
276 secerror("talkWithIDS error: %@", connectionError);
277 dispatch_async(processQueue, ^{
278 if (replyBlock)
279 replyBlock(NULL, connectionError);
280 CFReleaseSafe(connectionError);
281 dispatch_release(processQueue);
282 });
283
284 os_activity_end(trace_activity);
285 }
286 static void talkWithKVS(SOSXPCCloudTransportRef transport, xpc_object_t message, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
287 {
288 CFErrorRef connectionError = NULL;
289
290 os_activity_t trace_activity = os_activity_start("talkWithKVS", OS_ACTIVITY_FLAG_DEFAULT);
291 require_action(transport->serviceConnection, xit, connectionError = makeError(kSOSConnectionNotOpen));
292 require_action(message, xit, connectionError = makeError(kSOSObjectNotFoundError));
293 dispatch_retain(processQueue);
294
295 xpc_connection_send_message_with_reply(transport->serviceConnection, message, transport->xpc_queue, ^(xpc_object_t reply)
296 {
297 CFErrorRef serverError = NULL;
298 CFTypeRef object = NULL;
299 if (xpc_event_filter(transport->serviceConnection, reply, &serverError) && reply)
300 {
301 describeXPCObject("getValuesFromKVS: reply : ", reply);
302 if (serverError)
303 secerror("Error from xpc_event_filter: %@", serverError);
304 xpc_object_t xrv = xpc_dictionary_get_value(reply, kMessageKeyValue);
305 if (xrv)
306 {
307 describeXPCObject("talkWithKVS: xrv: ", xrv);
308 /*
309 * The given XPC object must be one that was previously returned by
310 * _CFXPCCreateXPCMessageWithCFObject().
311 */
312 object = _CFXPCCreateCFObjectFromXPCObject(xrv); // CF object is retained; release in callback
313 secnotice("talkwithkvs", "converted CF object: %@", object);
314 }
315 else
316 secerror("missing value reply");
317
318 xpc_object_t xerror = xpc_dictionary_get_value(reply, kMessageKeyError);
319 if (xerror)
320 serverError = SecCreateCFErrorWithXPCObject(xerror); // use SecCFCreateErrorWithFormat?
321 }
322 dispatch_async(processQueue, ^{
323 if (replyBlock)
324 replyBlock(object, serverError);
325 CFReleaseSafe(object);
326 if (serverError)
327 {
328 secerror("callback error: %@", serverError);
329 CFReleaseSafe(serverError);
330 }
331 dispatch_release(processQueue);
332 });
333 });
334 return;
335
336 xit:
337 secerror("talkWithKVS error: %@", connectionError);
338 dispatch_async(processQueue, ^{
339 if (replyBlock)
340 replyBlock(NULL, connectionError);
341 CFReleaseSafe(connectionError);
342 dispatch_release(processQueue);
343 });
344
345 os_activity_end(trace_activity);
346 }
347
348 // MARK: ---------- SOSXPCCloudTransport Client Calls ----------
349
350 /* Concrete function backend implementations. */
351 static void SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportRef transport,
352 CloudItemsChangedBlock itemsChangedBlock) {
353 if (transport->itemsChangedBlock != itemsChangedBlock)
354 {
355 secnotice(SOSCKCSCOPE, "Changing itemsChangedBlock");
356 if (transport->itemsChangedBlock)
357 Block_release(transport->itemsChangedBlock);
358 transport->itemsChangedBlock = Block_copy(itemsChangedBlock);
359 }
360 }
361
362 /* Virtual function backend implementations. */
363 static void SOSCloudTransportPut(SOSCloudTransportRef transport, CFDictionaryRef values, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
364 {
365 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
366 secdebug(SOSCKCSCOPE, "%@", values);
367 CFErrorRef error = NULL;
368 xpc_object_t message = NULL;
369 xpc_object_t xobject = NULL;
370 require_action(values, xit, error = makeError(kSOSObjectNotFoundError));
371
372 message = xpc_dictionary_create(NULL, NULL, 0);
373 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
374 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationPUTDictionary);
375
376 xobject = _CFXPCCreateXPCObjectFromCFObject(values);
377 require_action(xobject, xit, error = makeError(kSOSObjectCantBeConvertedToXPCObject));
378 xpc_dictionary_set_value(message, kMessageKeyValue, xobject);
379 xpc_release(xobject);
380
381 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
382 xpc_release(message);
383 return;
384
385 xit:
386 if (replyBlock)
387 replyBlock(NULL, error);
388 CFReleaseSafe(error);
389 }
390
391 /* Get from KVS */
392 static void SOSCloudTransportGet(SOSCloudTransportRef transport, CFArrayRef keysToGet, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
393 {
394 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
395 secdebug(SOSCKCSCOPE, "%@", keysToGet);
396 CFErrorRef error = NULL;
397 xpc_object_t xkeysOfInterest = xpc_dictionary_create(NULL, NULL, 0);
398 xpc_object_t xkeysToGet = keysToGet ? _CFXPCCreateXPCObjectFromCFObject(keysToGet) : xpc_null_create();
399
400 require_action(xkeysToGet, xit, error = makeError(kSOSObjectNotFoundError));
401
402 if (keysToGet) // don't add if nulll; will call getall
403 xpc_dictionary_set_value(xkeysOfInterest, kMessageKeyKeysToGet, xkeysToGet);
404
405 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
406 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
407 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationGETv2);
408 xpc_dictionary_set_value(message, kMessageKeyValue, xkeysOfInterest);
409
410 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
411 xpc_release(xkeysToGet);
412 xpc_release(xkeysOfInterest);
413 xpc_release(message);
414 return;
415
416 xit:
417 if(xkeysOfInterest)
418 xpc_release(xkeysOfInterest);
419 if(xkeysToGet)
420 xpc_release(xkeysToGet);
421 if (replyBlock)
422 replyBlock(NULL, error);
423 CFReleaseSafe(error);
424 }
425
426 //
427 // Handles NULL by seting xpc_null.
428 static void SecXPCDictionarySetCFObject(xpc_object_t xdict, const char *key, CFTypeRef object)
429 {
430 xpc_object_t xpc_obj = object ? _CFXPCCreateXPCObjectFromCFObject(object) : xpc_null_create();
431 xpc_dictionary_set_value(xdict, key, xpc_obj);
432 xpc_release(xpc_obj);
433 }
434
435 static void SOSCloudTransportGetIDSDeviceID(SOSCloudTransportRef transport, CloudKeychainReplyBlock replyBlock)
436 {
437 dispatch_queue_t processQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
438
439 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
440
441 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
442 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
443 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationGetDeviceID);
444
445 talkWithIDS(xpcTransport, message, processQueue, replyBlock);
446 xpc_release(message);
447 }
448
449 static void SOSCloudTransportSendIDSMessage(SOSCloudTransportRef transport, CFDataRef messageData, CFStringRef deviceName, CFStringRef peerID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock){
450
451 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
452 xpc_object_t xmessageData = _CFXPCCreateXPCObjectFromCFObject(messageData);
453
454 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
455 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
456 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationSendIDSMessage);
457 xpc_dictionary_set_value(message, kMessageKeyValue, xmessageData);
458 SecXPCDictionarySetCFObject(message, kMessageKeyDeviceName, deviceName);
459 SecXPCDictionarySetCFObject(message, kMessageKeyPeerID, peerID);
460 talkWithIDS(xpcTransport, message, processQueue, replyBlock);
461
462 xpc_release(xmessageData);
463 xpc_release(message);
464 }
465
466 static void SOSCloudTransportUpdateKeys(SOSCloudTransportRef transport,
467 CFDictionaryRef keys,
468 dispatch_queue_t processQueue,
469 CloudKeychainReplyBlock replyBlock)
470 {
471 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
472
473 xpc_object_t xkeysOfInterest = xpc_dictionary_create(NULL, NULL, 0);
474 SecXPCDictionarySetCFObject(xkeysOfInterest, kMessageAllKeys, keys);
475
476 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
477 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
478 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationRegisterKeys);
479 xpc_dictionary_set_value(message, kMessageKeyValue, xkeysOfInterest);
480
481 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
482 xpc_release(message);
483 xpc_release(xkeysOfInterest);
484 }
485
486 static void SOSCloudTransportGetAll(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
487 {
488 secdebug(SOSCKCSCOPE, "start");
489 SOSCloudTransportGet(transport, NULL, processQueue, replyBlock);
490 }
491
492 static void SOSCloudTransportSync(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
493 {
494 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
495 secdebug(SOSCKCSCOPE, "start");
496 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
497 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
498 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationSynchronize);
499 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
500 xpc_release(message);
501 }
502
503 static void SOSCloudTransportSyncAndWait(SOSCloudTransportRef transport, CFArrayRef keysToGet, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
504 {
505 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
506 secdebug(SOSCKCSCOPE, "%@", keysToGet);
507 secnotice(SOSCKCSCOPE, "%s XPC request to CKD: %s", kWAIT2MINID, kOperationSynchronizeAndWait);
508 xpc_object_t xkeysOfInterest = xpc_dictionary_create(NULL, NULL, 0);
509
510 xpc_object_t xkeysToRegister = keysToGet ? _CFXPCCreateXPCObjectFromCFObject(keysToGet) : xpc_null_create();
511 xpc_dictionary_set_value(xkeysOfInterest, kMessageKeyKeysToGet, xkeysToRegister);
512 xpc_release(xkeysToRegister);
513 xkeysToRegister = NULL;
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, kOperationSynchronizeAndWait);
518 xpc_dictionary_set_value(message, kMessageKeyValue, xkeysOfInterest);
519 xpc_release(xkeysOfInterest);
520 xkeysOfInterest = NULL;
521
522 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
523 xpc_release(message);
524 }
525
526 static void SOSCloudTransportClearAll(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
527 {
528 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
529 secdebug(SOSCKCSCOPE, "start");
530 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
531 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
532 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationClearStore);
533 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
534 xpc_release(message);
535 }
536
537 static void SOSCloudTransportRemoveObjectForKey(SOSCloudTransportRef transport, CFStringRef keyToRemove, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
538 {
539 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
540 secdebug(SOSCKCSCOPE, "start");
541 CFErrorRef error = NULL;
542 xpc_object_t message = NULL;
543 xpc_object_t xkeytoremove = NULL;
544
545 require_action(keyToRemove, xit, error = makeError(kSOSObjectNotFoundError));
546
547 message = xpc_dictionary_create(NULL, NULL, 0);
548 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
549 xpc_dictionary_set_string(message, kMessageKeyOperation, kOperationRemoveObjectForKey);
550
551 xkeytoremove = _CFXPCCreateXPCObjectFromCFObject(keyToRemove);
552 require_action(xkeytoremove, xit, error = makeError(kSOSObjectCantBeConvertedToXPCObject));
553 xpc_dictionary_set_value(message, kMessageKeyKey, xkeytoremove);
554 xpc_release(xkeytoremove);
555
556 talkWithKVS(xpcTransport, message, processQueue, replyBlock);
557 xpc_release(message);
558 return;
559
560 xit:
561 if(xkeytoremove)
562 xpc_release(xkeytoremove);
563 if(message)
564 xpc_release(message);
565 if (replyBlock)
566 replyBlock(NULL, error);
567 CFReleaseSafe(error);
568 }
569 static void SOSCloudTransportLocalNotification(SOSCloudTransportRef transport, CFStringRef messageToUser, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
570 {
571 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
572 secdebug(SOSCKCSCOPE, "start");
573 xpc_object_t xLocalNotificationDict = xpc_dictionary_create(NULL, NULL, 0);
574 char *headerKey = CFStringToCString(kCFUserNotificationAlertHeaderKey);
575 char *message = CFStringToCString(messageToUser);
576 xpc_dictionary_set_string(xLocalNotificationDict, headerKey, message);
577
578 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
579 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
580 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationUILocalNotification);
581 xpc_dictionary_set_value (xpcmessage, kMessageKeyValue, xLocalNotificationDict);
582 xpc_release(xLocalNotificationDict);
583
584 talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock);
585
586 free(headerKey);
587 free(message);
588 xpc_release(xpcmessage);
589 }
590
591 static void SOSCloudTransportRequestSyncWithAllPeers(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
592 {
593 secdebug(SOSCKCSCOPE, "start");
594 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
595
596 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
597 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
598 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationRequestSyncWithAllPeers);
599
600 talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock);
601
602 xpc_release(xpcmessage);
603 }
604
605 static void SOSCloudTransportRequestEnsurePeerRegistration(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
606 {
607 secdebug(SOSCKCSCOPE, "start");
608 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
609
610 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
611 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
612 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationRequestEnsurePeerRegistration);
613
614 talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock);
615
616 xpc_release(xpcmessage);
617 }
618
619 static void SOSCloudTransportFlush(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
620 {
621 secdebug(SOSCKCSCOPE, "start");
622 SOSXPCCloudTransportRef xpcTransport = (SOSXPCCloudTransportRef)transport;
623
624 xpc_object_t xpcmessage = xpc_dictionary_create(NULL, NULL, 0);
625 xpc_dictionary_set_uint64(xpcmessage, kMessageKeyVersion, kCKDXPCVersion);
626 xpc_dictionary_set_string(xpcmessage, kMessageKeyOperation, kOperationFlush);
627
628 talkWithKVS(xpcTransport, xpcmessage, processQueue, replyBlock);
629
630 xpc_release(xpcmessage);
631 }
632
633 static SOSCloudTransportRef SOSCloudTransportCreateXPCTransport(void)
634 {
635 SOSXPCCloudTransportRef st;
636 st = calloc(1, sizeof(*st));
637 st->transport.put = SOSCloudTransportPut;
638 st->transport.updateKeys = SOSCloudTransportUpdateKeys;
639 st->transport.sendIDSMessage = SOSCloudTransportSendIDSMessage;
640 st->transport.getDeviceID = SOSCloudTransportGetIDSDeviceID;
641 st->transport.get = SOSCloudTransportGet;
642 st->transport.getAll = SOSCloudTransportGetAll;
643 st->transport.synchronize = SOSCloudTransportSync;
644 st->transport.synchronizeAndWait = SOSCloudTransportSyncAndWait;
645 st->transport.clearAll = SOSCloudTransportClearAll;
646 st->transport.removeObjectForKey = SOSCloudTransportRemoveObjectForKey;
647 st->transport.localNotification = SOSCloudTransportLocalNotification;
648 st->transport.requestSyncWithAllPeers = SOSCloudTransportRequestSyncWithAllPeers;
649 st->transport.requestEnsurePeerRegistration = SOSCloudTransportRequestEnsurePeerRegistration;
650 st->transport.flush = SOSCloudTransportFlush;
651 st->transport.itemsChangedBlock = Block_copy(^CFArrayRef(CFDictionaryRef changes) {
652 secerror("Calling default itemsChangedBlock - fatal: %@", changes);
653 assert(false);
654 return NULL;
655 });
656 SOSXPCCloudTransportInit(st);
657 return &st->transport;
658 }
659
660 // MARK: ---------- SOSCloudKeychain concrete client APIs ----------
661 void SOSCloudKeychainSetItemsChangedBlock(CloudItemsChangedBlock itemsChangedBlock)
662 {
663 secdebug(SOSCKCSCOPE, "start");
664 SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportDefaultTransport(),
665 itemsChangedBlock);
666 }
667
668 // MARK: ---------- SOSCloudKeychain virtual client APIs ----------
669
670 void SOSCloudKeychainPutObjectsInCloud(CFDictionaryRef objects, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
671 {
672 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
673 if (cTransportRef)
674 cTransportRef->put(cTransportRef, objects, processQueue, replyBlock);
675 }
676
677 void SOSCloudKeychainUpdateKeys(CFDictionaryRef keys, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
678 {
679 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
680 if (cTransportRef)
681 cTransportRef->updateKeys(cTransportRef, keys, processQueue, replyBlock);
682 }
683
684 void SOSCloudKeychainSendIDSMessage(CFDataRef message, CFStringRef deviceName, CFStringRef peerID, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
685 {
686 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
687 if(cTransportRef)
688 cTransportRef->sendIDSMessage(cTransportRef, message, deviceName, peerID, processQueue, replyBlock);
689
690 }
691 void SOSCloudKeychainGetIDSDeviceID(CloudKeychainReplyBlock replyBlock)
692 {
693 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
694 if (cTransportRef)
695 cTransportRef->getDeviceID(cTransportRef, replyBlock);
696
697 }
698
699 CF_RETURNS_RETAINED CFArrayRef SOSCloudKeychainHandleUpdateMessage(CFDictionaryRef updates)
700 {
701 CFArrayRef result = NULL;
702 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
703 if (cTransportRef->itemsChangedBlock)
704 result = ((CloudItemsChangedBlock)cTransportRef->itemsChangedBlock)(updates);
705 return result;
706 }
707
708 void SOSCloudKeychainGetObjectsFromCloud(CFArrayRef keysToGet, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
709 {
710 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
711 if (cTransportRef)
712 cTransportRef->get(cTransportRef, keysToGet, processQueue, replyBlock);
713 }
714
715 void SOSCloudKeychainGetAllObjectsFromCloud(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
716 {
717 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
718 if (cTransportRef)
719 cTransportRef->getAll(cTransportRef, processQueue, replyBlock);
720 }
721
722 void SOSCloudKeychainSynchronizeAndWait(CFArrayRef keysToGet, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
723 {
724 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
725 if (cTransportRef)
726 cTransportRef->synchronizeAndWait(cTransportRef, keysToGet, processQueue, replyBlock);
727 }
728
729 //DEBUG ONLY
730 void SOSCloudKeychainSynchronize(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
731 {
732 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
733 if (cTransportRef)
734 cTransportRef->synchronize(cTransportRef, processQueue, replyBlock);
735 }
736
737 //DEBUG ONLY
738 void SOSCloudKeychainClearAll(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
739 {
740 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
741 if (cTransportRef)
742 cTransportRef->clearAll(cTransportRef, processQueue, replyBlock);
743 }
744
745 void SOSCloudKeychainRemoveObjectForKey(CFStringRef keyToRemove, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
746 {
747 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
748 if (cTransportRef)
749 cTransportRef->removeObjectForKey(cTransportRef, keyToRemove, processQueue, replyBlock);
750 }
751
752 void SOSCloudKeychainRequestSyncWithAllPeers(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
753 {
754 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
755 if (cTransportRef)
756 cTransportRef->requestSyncWithAllPeers(cTransportRef, processQueue, replyBlock);
757 }
758
759 void SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
760 {
761 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
762 if (cTransportRef)
763 cTransportRef->requestEnsurePeerRegistration(cTransportRef, processQueue, replyBlock);
764 }
765
766 void SOSCloudKeychainFlush(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock)
767 {
768 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport();
769 if (cTransportRef)
770 cTransportRef->flush(cTransportRef, processQueue, replyBlock);
771 }