client.c
1 /* 2 * Copyright (c) 2007-2009,2012-2020 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 #include <TargetConditionals.h> 25 26 // client.c is from the iOS world and must compile with an iOS view of the headers 27 #ifndef SEC_IOS_ON_OSX 28 #define SEC_IOS_ON_OSX 1 29 #endif // SEC_IOS_ON_OSX 30 31 #if TARGET_OS_OSX 32 #ifndef SECITEM_SHIM_OSX 33 #define SECITEM_SHIM_OSX 1 34 #endif // SECITEM_SHIM_OSX 35 #endif // TARGET_OS_OSX 36 37 #include <stdbool.h> 38 #include <sys/queue.h> 39 #include <syslog.h> 40 #include <vproc_priv.h> 41 #include <xpc/xpc.h> 42 #include <xpc/private.h> 43 #include <os/feature_private.h> 44 45 #include <CoreFoundation/CoreFoundation.h> 46 #include <Security/SecItem.h> 47 #include <Security/SecBasePriv.h> 48 #include <Security/SecInternal.h> 49 #include <Security/SecuritydXPC.h> 50 #include <Security/SecTask.h> 51 #include <Security/SecItemPriv.h> 52 53 #include <utilities/debugging.h> 54 #include <utilities/SecCFError.h> 55 #include <utilities/SecXPCError.h> 56 #include <utilities/SecCFWrappers.h> 57 #include <utilities/SecDispatchRelease.h> 58 #include <utilities/SecDb.h> // TODO Fixme this gets us SecError(). 59 #include <utilities/SecAKSWrappers.h> 60 #include <ipc/securityd_client.h> 61 62 #include "server_security_helpers.h" 63 64 struct securityd *gSecurityd; 65 struct trustd *gTrustd; 66 67 // 68 // MARK: XPC IPC. 69 // 70 71 /* Hardcoded Access Groups for the server itself */ 72 static CFArrayRef SecServerCopyAccessGroups(void) { 73 CFArrayRef accessGroups = CFArrayCreateForCFTypes(kCFAllocatorDefault, 74 #if NO_SERVER 75 CFSTR("test"), 76 CFSTR("apple"), 77 CFSTR("lockdown-identities"), 78 CFSTR("123456.test.group"), 79 CFSTR("123456.test.group2"), 80 CFSTR("com.apple.cfnetwork"), 81 CFSTR("com.apple.bluetooth"), 82 #endif 83 CFSTR("sync"), 84 CFSTR("com.apple.security.sos"), 85 CFSTR("com.apple.security.ckks"), 86 CFSTR("com.apple.security.octagon"), 87 CFSTR("com.apple.security.egoIdentities"), 88 CFSTR("com.apple.security.sos-usercredential"), 89 CFSTR("com.apple.sbd"), 90 CFSTR("com.apple.lakitu"), 91 CFSTR("com.apple.security.securityd"), 92 NULL); 93 if (os_feature_enabled(CryptoTokenKit, UseTokens)) { 94 CFMutableArrayRef mutableGroups = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, accessGroups); 95 CFArrayAppendValue(mutableGroups, kSecAttrAccessGroupToken); 96 CFAssignRetained(accessGroups, mutableGroups); 97 } 98 99 return accessGroups; 100 } 101 102 static SecurityClient gClient; 103 104 #if TARGET_OS_IOS 105 void 106 SecSecuritySetMusrMode(bool mode, uid_t uid, int activeUser) 107 { 108 gClient.inMultiUser = mode; 109 gClient.uid = uid; 110 gClient.activeUser = activeUser; 111 } 112 113 void 114 SecSecuritySetPersonaMusr(CFStringRef uuid) 115 { 116 if (gClient.inMultiUser) { 117 abort(); 118 } 119 CFReleaseNull(gClient.musr); 120 if (uuid) { 121 CFUUIDRef u = CFUUIDCreateFromString(NULL, uuid); 122 if (u == NULL) { 123 abort(); 124 } 125 CFUUIDBytes ubytes = CFUUIDGetUUIDBytes(u); 126 CFReleaseNull(u); 127 gClient.musr = CFDataCreate(NULL, (const void *)&ubytes, sizeof(ubytes)); 128 } 129 } 130 #endif 131 132 SecurityClient * 133 SecSecurityClientGet(void) 134 { 135 static dispatch_once_t onceToken; 136 dispatch_once(&onceToken, ^{ 137 gClient.task = NULL; 138 gClient.accessGroups = SecServerCopyAccessGroups(); 139 gClient.allowSystemKeychain = true; 140 gClient.allowSyncBubbleKeychain = true; 141 gClient.isNetworkExtension = false; 142 #if TARGET_OS_IPHONE 143 gClient.inMultiUser = false; 144 gClient.activeUser = 501; 145 gClient.musr = NULL; 146 #endif 147 gClient.applicationIdentifier = NULL; 148 gClient.isAppClip = false; 149 }); 150 return &gClient; 151 } 152 153 CFArrayRef SecAccessGroupsGetCurrent(void) { 154 SecurityClient *client = SecSecurityClientGet(); 155 assert(client && client->accessGroups); 156 return client->accessGroups; 157 } 158 159 // Only for testing. 160 void SecAccessGroupsSetCurrent(CFArrayRef accessGroups) { 161 // Not thread safe at all, but OK because it is meant to be used only by tests. 162 SecurityClient* client = SecSecurityClientGet(); 163 CFReleaseNull(client->accessGroups); 164 client->accessGroups = CFRetainSafe(accessGroups); 165 } 166 167 // Testing 168 void SecSecurityClientRegularToAppClip(void) { 169 SecurityClient* client = SecSecurityClientGet(); 170 client->isAppClip = true; 171 } 172 173 // Testing 174 void SecSecurityClientAppClipToRegular(void) { 175 SecurityClient* client = SecSecurityClientGet(); 176 client->isAppClip = false; 177 } 178 179 // Testing 180 void SecSecurityClientSetApplicationIdentifier(CFStringRef identifier) { 181 SecurityClient* client = SecSecurityClientGet(); 182 CFReleaseNull(client->applicationIdentifier); 183 if (identifier) { 184 client->applicationIdentifier = CFRetain(identifier); 185 } 186 } 187 188 #if !TARGET_OS_IPHONE 189 static bool securityd_in_system_context(void) { 190 static bool runningInSystemContext; 191 static dispatch_once_t onceToken; 192 dispatch_once(&onceToken, ^{ 193 runningInSystemContext = (getuid() == 0); 194 if (!runningInSystemContext) { 195 char *manager; 196 if (vproc_swap_string(NULL, VPROC_GSK_MGR_NAME, NULL, &manager) == NULL) { 197 runningInSystemContext = (!strcmp(manager, VPROCMGR_SESSION_SYSTEM) || 198 !strcmp(manager, VPROCMGR_SESSION_LOGINWINDOW)); 199 free(manager); 200 } 201 } 202 }); 203 return runningInSystemContext; 204 } 205 #endif 206 207 static const char *securityd_service_name(void) { 208 return kSecuritydXPCServiceName; 209 } 210 211 #define SECURITY_TARGET_UID_UNSET ((uid_t)-1) 212 static uid_t securityd_target_uid = SECURITY_TARGET_UID_UNSET; 213 214 void 215 _SecSetSecuritydTargetUID(uid_t uid) 216 { 217 securityd_target_uid = uid; 218 } 219 220 221 static xpc_connection_t securityd_create_connection(const char *name, uid_t target_uid, uint64_t flags) { 222 const char *serviceName = name; 223 if (!serviceName) { 224 serviceName = securityd_service_name(); 225 } 226 xpc_connection_t connection; 227 connection = xpc_connection_create_mach_service(serviceName, NULL, flags); 228 xpc_connection_set_event_handler(connection, ^(xpc_object_t event) { 229 const char *description = xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION); 230 secnotice("xpc", "got event: %s", description); 231 }); 232 if (target_uid != SECURITY_TARGET_UID_UNSET) { 233 xpc_connection_set_target_uid(connection, target_uid); 234 } 235 xpc_connection_resume(connection); 236 return connection; 237 } 238 239 static bool is_trust_operation(enum SecXPCOperation op) { 240 switch (op) { 241 case sec_trust_store_contains_id: 242 case sec_trust_store_set_trust_settings_id: 243 case sec_trust_store_remove_certificate_id: 244 case sec_trust_evaluate_id: 245 case sec_trust_store_copy_all_id: 246 case sec_trust_store_copy_usage_constraints_id: 247 case sec_ocsp_cache_flush_id: 248 case sec_ota_pki_trust_store_version_id: 249 case sec_ota_pki_asset_version_id: 250 case kSecXPCOpOTAGetEscrowCertificates: 251 case kSecXPCOpOTAPKIGetNewAsset: 252 case kSecXPCOpOTASecExperimentGetNewAsset: 253 case kSecXPCOpOTASecExperimentGetAsset: 254 case kSecXPCOpOTAPKICopyTrustedCTLogs: 255 case kSecXPCOpOTAPKICopyCTLogForKeyID: 256 case kSecXPCOpNetworkingAnalyticsReport: 257 case kSecXPCOpSetCTExceptions: 258 case kSecXPCOpCopyCTExceptions: 259 case sec_trust_get_exception_reset_count_id: 260 case sec_trust_increment_exception_reset_count_id: 261 case kSecXPCOpSetCARevocationAdditions: 262 case kSecXPCOpCopyCARevocationAdditions: 263 case kSecXPCOpValidUpdate: 264 case kSecXPCOpSetTransparentConnectionPins: 265 case kSecXPCOpCopyTransparentConnectionPins: 266 return true; 267 default: 268 break; 269 } 270 return false; 271 } 272 273 // sSC* manage a pool of xpc_connection_t objects to securityd 274 static dispatch_queue_t sSecuritydConnectionsQueue; 275 static CFMutableArrayRef sSecuritydConnectionsPool; 276 static unsigned sSecuritydConnectionsCount; // connections in circulation 277 #define MAX_SECURITYD_CONNECTIONS 5 278 279 static xpc_connection_t _securityd_connection(void) { 280 static dispatch_once_t onceToken; 281 dispatch_once(&onceToken, ^{ 282 sSecuritydConnectionsCount = 0; 283 sSecuritydConnectionsQueue = dispatch_queue_create("com.apple.security.securityd_connections", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); 284 sSecuritydConnectionsPool = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); 285 }); 286 287 __block xpc_connection_t ret = NULL; 288 dispatch_sync(sSecuritydConnectionsQueue, ^{ 289 if (CFArrayGetCount(sSecuritydConnectionsPool) > 0) { 290 ret = (xpc_connection_t)CFArrayGetValueAtIndex(sSecuritydConnectionsPool, 0); 291 CFArrayRemoveValueAtIndex(sSecuritydConnectionsPool, 0); 292 } else if (sSecuritydConnectionsCount < MAX_SECURITYD_CONNECTIONS) { 293 ret = securityd_create_connection(kSecuritydXPCServiceName, securityd_target_uid, 0); 294 ++sSecuritydConnectionsCount; 295 secnotice("xpc", "Adding securityd connection to pool, total now %d", sSecuritydConnectionsCount); 296 } // No connection available and no room in the pool for a new one, touch luck! 297 }); 298 return ret; 299 } 300 301 static xpc_connection_t securityd_connection(void) { 302 unsigned tries = 0; 303 xpc_connection_t ret = NULL; 304 do { 305 ret = _securityd_connection(); 306 if (!ret) { 307 usleep(2500); 308 } 309 ++tries; 310 if (tries % 100 == 0) { // 1/4 second is a long time to wait, but maybe you're overdoing it also? 311 secwarning("xpc: have been trying %d times to get a securityd connection", tries); 312 } 313 } while (!ret); 314 return ret; 315 } 316 317 static void return_securityd_connection_to_pool(enum SecXPCOperation op, xpc_connection_t conn) { 318 if (!is_trust_operation(op)) { 319 dispatch_sync(sSecuritydConnectionsQueue, ^{ 320 if (CFArrayGetCount(sSecuritydConnectionsPool) >= MAX_SECURITYD_CONNECTIONS) { 321 xpc_connection_cancel(conn); 322 secerror("xpc: Unable to re-enqueue securityd connection because already at limit"); 323 if (sSecuritydConnectionsCount < MAX_SECURITYD_CONNECTIONS) { 324 secerror("xpc: connection pool full but tracker does not agree (%d vs %ld)", sSecuritydConnectionsCount, CFArrayGetCount(sSecuritydConnectionsPool)); 325 } 326 abort(); // We've miscalculated? 327 } 328 CFArrayAppendValue(sSecuritydConnectionsPool, conn); 329 }); 330 } 331 } 332 333 static xpc_connection_t sTrustdConnection; 334 static xpc_connection_t trustd_connection(void) { 335 #if TARGET_OS_OSX 336 static dispatch_once_t once; 337 dispatch_once(&once, ^{ 338 bool sysCtx = securityd_in_system_context(); 339 uint64_t flags = (sysCtx) ? XPC_CONNECTION_MACH_SERVICE_PRIVILEGED : 0; 340 const char *serviceName = (sysCtx) ? kTrustdXPCServiceName : kTrustdAgentXPCServiceName; 341 sTrustdConnection = securityd_create_connection(serviceName, SECURITY_TARGET_UID_UNSET, flags); 342 }); 343 return sTrustdConnection; 344 #else 345 static dispatch_once_t once; 346 dispatch_once(&once, ^{ 347 sTrustdConnection = securityd_create_connection(kTrustdXPCServiceName, SECURITY_TARGET_UID_UNSET, 0); 348 }); 349 return sTrustdConnection; 350 #endif 351 } 352 353 static xpc_connection_t securityd_connection_for_operation(enum SecXPCOperation op) { 354 bool isTrustOp = is_trust_operation(op); 355 #if SECTRUST_VERBOSE_DEBUG 356 { 357 bool sysCtx = securityd_in_system_context(); 358 const char *serviceName = (sysCtx) ? kTrustdXPCServiceName : kTrustdAgentXPCServiceName; 359 syslog(LOG_ERR, "Will connect to: %s (op=%d)", 360 (isTrustOp) ? serviceName : kSecuritydXPCServiceName, (int)op); 361 } 362 #endif 363 return (isTrustOp) ? trustd_connection() : securityd_connection(); 364 } 365 366 // NOTE: This is not thread safe, but this SPI is for testing only. 367 void SecServerSetTrustdMachServiceName(const char *name) { 368 // Make sure sSecXPCServer.queue exists. 369 trustd_connection(); 370 371 xpc_connection_t oldConection = sTrustdConnection; 372 sTrustdConnection = securityd_create_connection(name, SECURITY_TARGET_UID_UNSET, 0); 373 if (oldConection) 374 xpc_release(oldConection); 375 } 376 377 378 #define SECURITYD_MAX_XPC_TRIES 4 379 // Per <rdar://problem/17829836> N61/12A342: Audio Playback... for why this needs to be at least 3, so we made it 4. 380 381 static bool 382 _securityd_process_message_reply(xpc_object_t *reply, 383 CFErrorRef *error, 384 xpc_connection_t connection, 385 uint64_t operation) 386 { 387 if (xpc_get_type(*reply) != XPC_TYPE_ERROR) { 388 return true; 389 } 390 CFIndex code = 0; 391 if (*reply == XPC_ERROR_CONNECTION_INTERRUPTED || *reply == XPC_ERROR_CONNECTION_INVALID) { 392 code = kSecXPCErrorConnectionFailed; 393 seccritical("Failed to talk to %s after %d attempts.", 394 (is_trust_operation((enum SecXPCOperation)operation)) ? "trustd" : 395 #if TARGET_OS_IPHONE 396 "securityd", 397 #else 398 "secd", 399 #endif 400 SECURITYD_MAX_XPC_TRIES); 401 } else if (*reply == XPC_ERROR_TERMINATION_IMMINENT) { 402 code = kSecXPCErrorUnknown; 403 } else { 404 code = kSecXPCErrorUnknown; 405 } 406 407 char *conn_desc = xpc_copy_description(connection); 408 const char *description = xpc_dictionary_get_string(*reply, XPC_ERROR_KEY_DESCRIPTION); 409 SecCFCreateErrorWithFormat(code, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("%s: %s"), conn_desc, description); 410 free(conn_desc); 411 xpc_release(*reply); 412 *reply = NULL; 413 return false; 414 } 415 416 417 XPC_RETURNS_RETAINED 418 xpc_object_t 419 securityd_message_with_reply_sync(xpc_object_t message, CFErrorRef *error) 420 { 421 xpc_object_t reply = NULL; 422 uint64_t operation = xpc_dictionary_get_uint64(message, kSecXPCKeyOperation); 423 xpc_connection_t connection = securityd_connection_for_operation((enum SecXPCOperation)operation); 424 425 const int max_tries = SECURITYD_MAX_XPC_TRIES; 426 427 unsigned int tries_left = max_tries; 428 do { 429 if (reply) xpc_release(reply); 430 reply = xpc_connection_send_message_with_reply_sync(connection, message); 431 } while (reply == XPC_ERROR_CONNECTION_INTERRUPTED && --tries_left > 0); 432 433 _securityd_process_message_reply(&reply, error, connection, operation); 434 435 return_securityd_connection_to_pool((enum SecXPCOperation)operation, connection); 436 437 return reply; 438 } 439 440 static void 441 _securityd_message_with_reply_async_inner(xpc_object_t message, 442 dispatch_queue_t replyq, 443 securityd_handler_t handler, 444 uint32_t tries_left) 445 { 446 uint64_t operation = xpc_dictionary_get_uint64(message, kSecXPCKeyOperation); 447 xpc_connection_t connection = securityd_connection_for_operation((enum SecXPCOperation)operation); 448 449 xpc_retain(message); 450 dispatch_retain(replyq); 451 securityd_handler_t handlerCopy = Block_copy(handler); 452 xpc_connection_send_message_with_reply(connection, message, replyq, ^(xpc_object_t _Nonnull reply) { 453 if (reply == XPC_ERROR_CONNECTION_INTERRUPTED && tries_left > 0) { 454 _securityd_message_with_reply_async_inner(message, replyq, handlerCopy, tries_left - 1); 455 } else { 456 CFErrorRef error = NULL; 457 _securityd_process_message_reply(&reply, &error, connection, operation); 458 handlerCopy(reply, error); 459 CFReleaseNull(error); 460 } 461 xpc_release(message); 462 dispatch_release(replyq); 463 Block_release(handlerCopy); 464 }); 465 return_securityd_connection_to_pool((enum SecXPCOperation)operation, connection); 466 } 467 468 void 469 securityd_message_with_reply_async(xpc_object_t message, 470 dispatch_queue_t replyq, 471 securityd_handler_t handler) 472 { 473 _securityd_message_with_reply_async_inner(message, replyq, handler, SECURITYD_MAX_XPC_TRIES); 474 } 475 476 XPC_RETURNS_RETAINED 477 xpc_object_t 478 securityd_create_message(enum SecXPCOperation op, CFErrorRef* error) 479 { 480 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0); 481 if (message) { 482 xpc_dictionary_set_uint64(message, kSecXPCKeyOperation, op); 483 } else { 484 SecCFCreateError(kSecXPCErrorConnectionFailed, sSecXPCErrorDomain, 485 CFSTR("xpc_dictionary_create returned NULL"), NULL, error); 486 } 487 return message; 488 } 489 490 // Return true if there is no error in message, return false and set *error if there is. 491 bool securityd_message_no_error(xpc_object_t message, CFErrorRef *error) { 492 xpc_object_t xpc_error = NULL; 493 if (message == NULL) 494 return false; 495 496 xpc_error = xpc_dictionary_get_value(message, kSecXPCKeyError); 497 if (xpc_error == NULL) 498 return true; 499 500 CFErrorRef localError = SecCreateCFErrorWithXPCObject(xpc_error); 501 502 #if TARGET_OS_IPHONE 503 secdebug("xpc", "Talking to securityd failed with error: %@", localError); 504 #else 505 #if !defined(NDEBUG) 506 uint64_t operation = xpc_dictionary_get_uint64(message, kSecXPCKeyOperation); 507 #endif 508 secdebug("xpc", "Talking to %s failed with error: %@", 509 (is_trust_operation((enum SecXPCOperation)operation)) ? "trustd" : "secd", localError); 510 #endif 511 512 if (error) { 513 *error = localError; 514 } else { 515 CFReleaseSafe(localError); 516 } 517 return false; 518 } 519 520 bool securityd_send_sync_and_do(enum SecXPCOperation op, CFErrorRef *error, 521 bool (^add_to_message)(xpc_object_t message, CFErrorRef* error), 522 bool (^handle_response)(xpc_object_t _Nonnull response, CFErrorRef* error)) { 523 xpc_object_t message = securityd_create_message(op, error); 524 bool ok = false; 525 if (message) { 526 if (!add_to_message || add_to_message(message, error)) { 527 xpc_object_t response = securityd_message_with_reply_sync(message, error); 528 if (response) { 529 if (securityd_message_no_error(response, error)) { 530 ok = (!handle_response || handle_response(response, error)); 531 } 532 xpc_release(response); 533 } 534 } 535 xpc_release(message); 536 } 537 538 return ok; 539 } 540 541 void securityd_send_async_and_do(enum SecXPCOperation op, dispatch_queue_t replyq, 542 bool (^add_to_message)(xpc_object_t message, CFErrorRef* error), 543 securityd_handler_t handler) { 544 CFErrorRef error = NULL; 545 xpc_object_t message = securityd_create_message(op, &error); 546 if (message == NULL) { 547 handler(NULL, error); 548 CFReleaseNull(error); 549 return; 550 } 551 552 if (add_to_message != NULL) { 553 if (!add_to_message(message, &error)) { 554 handler(NULL, error); 555 xpc_release(message); 556 CFReleaseNull(error); 557 return; 558 } 559 } 560 561 securityd_message_with_reply_async(message, replyq, ^(xpc_object_t reply, CFErrorRef error2) { 562 if (error2 != NULL) { 563 handler(NULL, error2); 564 return; 565 } 566 CFErrorRef error3 = NULL; 567 if (!securityd_message_no_error(reply, &error3)) { 568 handler(NULL, error3); 569 CFReleaseNull(error3); 570 return; 571 } 572 handler(reply, NULL); 573 }); 574 xpc_release(message); 575 } 576 577 578 CFDictionaryRef 579 _SecSecuritydCopyWhoAmI(CFErrorRef *error) 580 { 581 CFDictionaryRef reply = NULL; 582 xpc_object_t message = securityd_create_message(kSecXPCOpWhoAmI, error); 583 if (message) { 584 xpc_object_t response = securityd_message_with_reply_sync(message, error); 585 if (response) { 586 reply = _CFXPCCreateCFObjectFromXPCObject(response); 587 xpc_release(response); 588 } else { 589 secerror("Securityd failed getting whoamid with error: %@", 590 error ? *error : NULL); 591 } 592 xpc_release(message); 593 } 594 return reply; 595 } 596 597 bool 598 _SecSyncBubbleTransfer(CFArrayRef services, uid_t uid, CFErrorRef *error) 599 { 600 xpc_object_t message; 601 bool reply = false; 602 603 message = securityd_create_message(kSecXPCOpTransmogrifyToSyncBubble, error); 604 if (message) { 605 xpc_dictionary_set_int64(message, "uid", uid); 606 if (SecXPCDictionarySetPList(message, "services", services, error)) { 607 xpc_object_t response = securityd_message_with_reply_sync(message, error); 608 if (response) { 609 reply = xpc_dictionary_get_bool(response, kSecXPCKeyResult); 610 if (!reply) 611 securityd_message_no_error(response, error); 612 xpc_release(response); 613 } 614 xpc_release(message); 615 } 616 } 617 return reply; 618 } 619 620 bool 621 _SecSystemKeychainTransfer(CFErrorRef *error) 622 { 623 xpc_object_t message; 624 bool reply = false; 625 626 message = securityd_create_message(kSecXPCOpTransmogrifyToSystemKeychain, error); 627 if (message) { 628 xpc_object_t response = securityd_message_with_reply_sync(message, error); 629 if (response) { 630 reply = xpc_dictionary_get_bool(response, kSecXPCKeyResult); 631 if (!reply) 632 securityd_message_no_error(response, error); 633 xpc_release(response); 634 } 635 xpc_release(message); 636 } 637 return reply; 638 } 639 640 bool 641 _SecSyncDeleteUserViews(uid_t uid, CFErrorRef *error) 642 { 643 xpc_object_t message; 644 bool reply = false; 645 646 message = securityd_create_message(kSecXPCOpDeleteUserView, error); 647 if (message) { 648 xpc_dictionary_set_int64(message, "uid", uid); 649 650 xpc_object_t response = securityd_message_with_reply_sync(message, error); 651 if (response) { 652 reply = xpc_dictionary_get_bool(response, kSecXPCKeyResult); 653 if (!reply) 654 securityd_message_no_error(response, error); 655 xpc_release(response); 656 } 657 xpc_release(message); 658 } 659 return reply; 660 } 661 662 XPC_RETURNS_RETAINED xpc_endpoint_t 663 _SecSecuritydCopyEndpoint(enum SecXPCOperation op, CFErrorRef *error) 664 { 665 xpc_endpoint_t endpoint = NULL; 666 xpc_object_t message = securityd_create_message(op, error); 667 if (message) { 668 xpc_object_t response = securityd_message_with_reply_sync(message, error); 669 if (response) { 670 endpoint = xpc_dictionary_get_value(response, kSecXPCKeyEndpoint); 671 if (endpoint) { 672 if(xpc_get_type(endpoint) != XPC_TYPE_ENDPOINT) { 673 secerror("endpoint was not an endpoint"); 674 endpoint = NULL; 675 } else { 676 xpc_retain(endpoint); 677 } 678 } else { 679 secerror("endpoint was null"); 680 } 681 xpc_release(response); 682 } else { 683 secerror("Securityd failed getting endpoint with error: %@", error ? *error : NULL); 684 } 685 xpc_release(message); 686 } 687 return endpoint; 688 } 689 690 691 XPC_RETURNS_RETAINED xpc_endpoint_t 692 _SecSecuritydCopyCKKSEndpoint(CFErrorRef *error) 693 { 694 return NULL; 695 } 696 697 XPC_RETURNS_RETAINED xpc_endpoint_t 698 _SecSecuritydCopyKeychainControlEndpoint(CFErrorRef* error) 699 { 700 return _SecSecuritydCopyEndpoint(kSecXPCOpKeychainControlEndpoint, error); 701 } 702 703 XPC_RETURNS_RETAINED xpc_endpoint_t 704 _SecSecuritydCopySFKeychainEndpoint(CFErrorRef* error) 705 { 706 return _SecSecuritydCopyEndpoint(kSecXPCOpSFKeychainEndpoint, error); 707 }