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 55static 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. */ 62static SOSCloudTransportRef sTransport = NULL; 63 64static SOSCloudTransportRef SOSCloudTransportCreateXPCTransport(void); 65 66void SOSCloudKeychainSetTransport(SOSCloudTransportRef transport) { 67 sTransport = transport; 68} 69 70/* Return the singleton cloud transport instance. */ 71static 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 84static 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 96static 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 111static 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 132typedef struct SOSXPCCloudTransport *SOSXPCCloudTransportRef; 133struct SOSXPCCloudTransport 134{ 135 struct SOSCloudTransport transport; 136 xpc_connection_t serviceConnection; 137 dispatch_queue_t xpc_queue; 138}; 139 140static 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 192static 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 227static 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 247static 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 298xit: 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. */ 308static 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. */ 319static 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 341xit: 342 if (replyBlock) 343 replyBlock(NULL, error); 344 CFReleaseSafe(error); 345} 346 347/* Get from KVS */ 348static 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 372xit: 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 382static 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. 404static 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 411static 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 453static 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 472static void SOSCloudTransportGetAll(SOSCloudTransportRef transport, dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock) 473{ 474 secdebug(SOSCKCSCOPE, "start"); 475 SOSCloudTransportGet(transport, NULL, processQueue, replyBlock); 476} 477 478static 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 489static 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 511static 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 522static 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 545xit: 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 555static 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 577static 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 595static 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 609static 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 ---------- 631void SOSCloudKeychainSetItemsChangedBlock(CloudItemsChangedBlock itemsChangedBlock) 632{ 633 secdebug(SOSCKCSCOPE, "start"); 634 SOSCloudTransportSetItemsChangedBlock(SOSCloudTransportDefaultTransport(), 635 itemsChangedBlock); 636} 637 638// MARK: ---------- SOSCloudKeychain virtual client APIs ---------- 639 640void 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 647void 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 654bool 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 667void 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 674void SOSCloudKeychainHandleUpdate(CFDictionaryRef updates) 675{ 676 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport(); 677 if (cTransportRef->itemsChangedBlock) 678 ((CloudItemsChangedBlock)cTransportRef->itemsChangedBlock)(updates); 679} 680 681void 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 688void SOSCloudKeychainGetAllObjectsFromCloud(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock) 689{ 690 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport(); 691 if (cTransportRef) 692 cTransportRef->getAll(cTransportRef, processQueue, replyBlock); 693} 694 695void 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 703void 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 711void SOSCloudKeychainClearAll(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock) 712{ 713 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport(); 714 if (cTransportRef) 715 cTransportRef->clearAll(cTransportRef, processQueue, replyBlock); 716} 717 718void 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 725void 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 732void 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 739void SOSCloudKeychainRequestSyncWithAllPeers(dispatch_queue_t processQueue, CloudKeychainReplyBlock replyBlock) 740{ 741 SOSCloudTransportRef cTransportRef = SOSCloudTransportDefaultTransport(); 742 if (cTransportRef) 743 cTransportRef->requestSyncWithAllPeers(cTransportRef, processQueue, replyBlock); 744} 745 746void 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} 758