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