]> git.saurik.com Git - apple/security.git/blob - OSX/sec/ipc/client.c
Security-59754.41.1.tar.gz
[apple/security.git] / OSX / sec / ipc / 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 return true;
265 default:
266 break;
267 }
268 return false;
269 }
270
271 // sSC* manage a pool of xpc_connection_t objects to securityd
272 static dispatch_queue_t sSecuritydConnectionsQueue;
273 static CFMutableArrayRef sSecuritydConnectionsPool;
274 static unsigned sSecuritydConnectionsCount; // connections in circulation
275 #define MAX_SECURITYD_CONNECTIONS 5
276
277 static xpc_connection_t _securityd_connection(void) {
278 static dispatch_once_t onceToken;
279 dispatch_once(&onceToken, ^{
280 sSecuritydConnectionsCount = 0;
281 sSecuritydConnectionsQueue = dispatch_queue_create("com.apple.security.securityd_connections", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
282 sSecuritydConnectionsPool = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
283 });
284
285 __block xpc_connection_t ret = NULL;
286 dispatch_sync(sSecuritydConnectionsQueue, ^{
287 if (CFArrayGetCount(sSecuritydConnectionsPool) > 0) {
288 ret = (xpc_connection_t)CFArrayGetValueAtIndex(sSecuritydConnectionsPool, 0);
289 CFArrayRemoveValueAtIndex(sSecuritydConnectionsPool, 0);
290 } else if (sSecuritydConnectionsCount < MAX_SECURITYD_CONNECTIONS) {
291 ret = securityd_create_connection(kSecuritydXPCServiceName, securityd_target_uid, 0);
292 ++sSecuritydConnectionsCount;
293 secnotice("xpc", "Adding securityd connection to pool, total now %d", sSecuritydConnectionsCount);
294 } // No connection available and no room in the pool for a new one, touch luck!
295 });
296 return ret;
297 }
298
299 static xpc_connection_t securityd_connection(void) {
300 unsigned tries = 0;
301 xpc_connection_t ret = NULL;
302 do {
303 ret = _securityd_connection();
304 if (!ret) {
305 usleep(2500);
306 }
307 ++tries;
308 if (tries % 100 == 0) { // 1/4 second is a long time to wait, but maybe you're overdoing it also?
309 secwarning("xpc: have been trying %d times to get a securityd connection", tries);
310 }
311 } while (!ret);
312 return ret;
313 }
314
315 static void return_securityd_connection_to_pool(enum SecXPCOperation op, xpc_connection_t conn) {
316 if (!is_trust_operation(op)) {
317 dispatch_sync(sSecuritydConnectionsQueue, ^{
318 if (CFArrayGetCount(sSecuritydConnectionsPool) >= MAX_SECURITYD_CONNECTIONS) {
319 xpc_connection_cancel(conn);
320 secerror("xpc: Unable to re-enqueue securityd connection because already at limit");
321 if (sSecuritydConnectionsCount < MAX_SECURITYD_CONNECTIONS) {
322 secerror("xpc: connection pool full but tracker does not agree (%d vs %ld)", sSecuritydConnectionsCount, CFArrayGetCount(sSecuritydConnectionsPool));
323 }
324 abort(); // We've miscalculated?
325 }
326 CFArrayAppendValue(sSecuritydConnectionsPool, conn);
327 });
328 }
329 }
330
331 static xpc_connection_t sTrustdConnection;
332 static xpc_connection_t trustd_connection(void) {
333 #if TARGET_OS_OSX
334 static dispatch_once_t once;
335 dispatch_once(&once, ^{
336 bool sysCtx = securityd_in_system_context();
337 uint64_t flags = (sysCtx) ? XPC_CONNECTION_MACH_SERVICE_PRIVILEGED : 0;
338 const char *serviceName = (sysCtx) ? kTrustdXPCServiceName : kTrustdAgentXPCServiceName;
339 sTrustdConnection = securityd_create_connection(serviceName, SECURITY_TARGET_UID_UNSET, flags);
340 });
341 return sTrustdConnection;
342 #else
343 static dispatch_once_t once;
344 dispatch_once(&once, ^{
345 sTrustdConnection = securityd_create_connection(kTrustdXPCServiceName, SECURITY_TARGET_UID_UNSET, 0);
346 });
347 return sTrustdConnection;
348 #endif
349 }
350
351 static xpc_connection_t securityd_connection_for_operation(enum SecXPCOperation op) {
352 bool isTrustOp = is_trust_operation(op);
353 #if SECTRUST_VERBOSE_DEBUG
354 {
355 bool sysCtx = securityd_in_system_context();
356 const char *serviceName = (sysCtx) ? kTrustdXPCServiceName : kTrustdAgentXPCServiceName;
357 syslog(LOG_ERR, "Will connect to: %s (op=%d)",
358 (isTrustOp) ? serviceName : kSecuritydXPCServiceName, (int)op);
359 }
360 #endif
361 return (isTrustOp) ? trustd_connection() : securityd_connection();
362 }
363
364 // NOTE: This is not thread safe, but this SPI is for testing only.
365 void SecServerSetTrustdMachServiceName(const char *name) {
366 // Make sure sSecXPCServer.queue exists.
367 trustd_connection();
368
369 xpc_connection_t oldConection = sTrustdConnection;
370 sTrustdConnection = securityd_create_connection(name, SECURITY_TARGET_UID_UNSET, 0);
371 if (oldConection)
372 xpc_release(oldConection);
373 }
374
375
376 #define SECURITYD_MAX_XPC_TRIES 4
377 // Per <rdar://problem/17829836> N61/12A342: Audio Playback... for why this needs to be at least 3, so we made it 4.
378
379 static bool
380 _securityd_process_message_reply(xpc_object_t *reply,
381 CFErrorRef *error,
382 xpc_connection_t connection,
383 uint64_t operation)
384 {
385 if (xpc_get_type(*reply) != XPC_TYPE_ERROR) {
386 return true;
387 }
388 CFIndex code = 0;
389 if (*reply == XPC_ERROR_CONNECTION_INTERRUPTED || *reply == XPC_ERROR_CONNECTION_INVALID) {
390 code = kSecXPCErrorConnectionFailed;
391 seccritical("Failed to talk to %s after %d attempts.",
392 (is_trust_operation((enum SecXPCOperation)operation)) ? "trustd" :
393 #if TARGET_OS_IPHONE
394 "securityd",
395 #else
396 "secd",
397 #endif
398 SECURITYD_MAX_XPC_TRIES);
399 } else if (*reply == XPC_ERROR_TERMINATION_IMMINENT) {
400 code = kSecXPCErrorUnknown;
401 } else {
402 code = kSecXPCErrorUnknown;
403 }
404
405 char *conn_desc = xpc_copy_description(connection);
406 const char *description = xpc_dictionary_get_string(*reply, XPC_ERROR_KEY_DESCRIPTION);
407 SecCFCreateErrorWithFormat(code, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("%s: %s"), conn_desc, description);
408 free(conn_desc);
409 xpc_release(*reply);
410 *reply = NULL;
411 return false;
412 }
413
414
415 XPC_RETURNS_RETAINED
416 xpc_object_t
417 securityd_message_with_reply_sync(xpc_object_t message, CFErrorRef *error)
418 {
419 xpc_object_t reply = NULL;
420 uint64_t operation = xpc_dictionary_get_uint64(message, kSecXPCKeyOperation);
421 xpc_connection_t connection = securityd_connection_for_operation((enum SecXPCOperation)operation);
422
423 const int max_tries = SECURITYD_MAX_XPC_TRIES;
424
425 unsigned int tries_left = max_tries;
426 do {
427 if (reply) xpc_release(reply);
428 reply = xpc_connection_send_message_with_reply_sync(connection, message);
429 } while (reply == XPC_ERROR_CONNECTION_INTERRUPTED && --tries_left > 0);
430
431 _securityd_process_message_reply(&reply, error, connection, operation);
432
433 return_securityd_connection_to_pool((enum SecXPCOperation)operation, connection);
434
435 return reply;
436 }
437
438 static void
439 _securityd_message_with_reply_async_inner(xpc_object_t message,
440 dispatch_queue_t replyq,
441 securityd_handler_t handler,
442 uint32_t tries_left)
443 {
444 uint64_t operation = xpc_dictionary_get_uint64(message, kSecXPCKeyOperation);
445 xpc_connection_t connection = securityd_connection_for_operation((enum SecXPCOperation)operation);
446
447 xpc_retain(message);
448 dispatch_retain(replyq);
449 securityd_handler_t handlerCopy = Block_copy(handler);
450 xpc_connection_send_message_with_reply(connection, message, replyq, ^(xpc_object_t _Nonnull reply) {
451 if (reply == XPC_ERROR_CONNECTION_INTERRUPTED && tries_left > 0) {
452 _securityd_message_with_reply_async_inner(message, replyq, handlerCopy, tries_left - 1);
453 } else {
454 CFErrorRef error = NULL;
455 _securityd_process_message_reply(&reply, &error, connection, operation);
456 handlerCopy(reply, error);
457 CFReleaseNull(error);
458 }
459 xpc_release(message);
460 dispatch_release(replyq);
461 Block_release(handlerCopy);
462 });
463 return_securityd_connection_to_pool((enum SecXPCOperation)operation, connection);
464 }
465
466 void
467 securityd_message_with_reply_async(xpc_object_t message,
468 dispatch_queue_t replyq,
469 securityd_handler_t handler)
470 {
471 _securityd_message_with_reply_async_inner(message, replyq, handler, SECURITYD_MAX_XPC_TRIES);
472 }
473
474 XPC_RETURNS_RETAINED
475 xpc_object_t
476 securityd_create_message(enum SecXPCOperation op, CFErrorRef* error)
477 {
478 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
479 if (message) {
480 xpc_dictionary_set_uint64(message, kSecXPCKeyOperation, op);
481 } else {
482 SecCFCreateError(kSecXPCErrorConnectionFailed, sSecXPCErrorDomain,
483 CFSTR("xpc_dictionary_create returned NULL"), NULL, error);
484 }
485 return message;
486 }
487
488 // Return true if there is no error in message, return false and set *error if there is.
489 bool securityd_message_no_error(xpc_object_t message, CFErrorRef *error) {
490 xpc_object_t xpc_error = NULL;
491 if (message == NULL)
492 return false;
493
494 xpc_error = xpc_dictionary_get_value(message, kSecXPCKeyError);
495 if (xpc_error == NULL)
496 return true;
497
498 CFErrorRef localError = SecCreateCFErrorWithXPCObject(xpc_error);
499
500 #if TARGET_OS_IPHONE
501 secdebug("xpc", "Talking to securityd failed with error: %@", localError);
502 #else
503 #if !defined(NDEBUG)
504 uint64_t operation = xpc_dictionary_get_uint64(message, kSecXPCKeyOperation);
505 #endif
506 secdebug("xpc", "Talking to %s failed with error: %@",
507 (is_trust_operation((enum SecXPCOperation)operation)) ? "trustd" : "secd", localError);
508 #endif
509
510 if (error) {
511 *error = localError;
512 } else {
513 CFReleaseSafe(localError);
514 }
515 return false;
516 }
517
518 bool securityd_send_sync_and_do(enum SecXPCOperation op, CFErrorRef *error,
519 bool (^add_to_message)(xpc_object_t message, CFErrorRef* error),
520 bool (^handle_response)(xpc_object_t _Nonnull response, CFErrorRef* error)) {
521 xpc_object_t message = securityd_create_message(op, error);
522 bool ok = false;
523 if (message) {
524 if (!add_to_message || add_to_message(message, error)) {
525 xpc_object_t response = securityd_message_with_reply_sync(message, error);
526 if (response) {
527 if (securityd_message_no_error(response, error)) {
528 ok = (!handle_response || handle_response(response, error));
529 }
530 xpc_release(response);
531 }
532 }
533 xpc_release(message);
534 }
535
536 return ok;
537 }
538
539 void securityd_send_async_and_do(enum SecXPCOperation op, dispatch_queue_t replyq,
540 bool (^add_to_message)(xpc_object_t message, CFErrorRef* error),
541 securityd_handler_t handler) {
542 CFErrorRef error = NULL;
543 xpc_object_t message = securityd_create_message(op, &error);
544 if (message == NULL) {
545 handler(NULL, error);
546 CFReleaseNull(error);
547 return;
548 }
549
550 if (add_to_message != NULL) {
551 if (!add_to_message(message, &error)) {
552 handler(NULL, error);
553 xpc_release(message);
554 CFReleaseNull(error);
555 return;
556 }
557 }
558
559 securityd_message_with_reply_async(message, replyq, ^(xpc_object_t reply, CFErrorRef error2) {
560 if (error2 != NULL) {
561 handler(NULL, error2);
562 return;
563 }
564 CFErrorRef error3 = NULL;
565 if (!securityd_message_no_error(reply, &error3)) {
566 handler(NULL, error3);
567 CFReleaseNull(error3);
568 return;
569 }
570 handler(reply, NULL);
571 });
572 xpc_release(message);
573 }
574
575
576 CFDictionaryRef
577 _SecSecuritydCopyWhoAmI(CFErrorRef *error)
578 {
579 CFDictionaryRef reply = NULL;
580 xpc_object_t message = securityd_create_message(kSecXPCOpWhoAmI, error);
581 if (message) {
582 xpc_object_t response = securityd_message_with_reply_sync(message, error);
583 if (response) {
584 reply = _CFXPCCreateCFObjectFromXPCObject(response);
585 xpc_release(response);
586 } else {
587 secerror("Securityd failed getting whoamid with error: %@",
588 error ? *error : NULL);
589 }
590 xpc_release(message);
591 }
592 return reply;
593 }
594
595 bool
596 _SecSyncBubbleTransfer(CFArrayRef services, uid_t uid, CFErrorRef *error)
597 {
598 xpc_object_t message;
599 bool reply = false;
600
601 message = securityd_create_message(kSecXPCOpTransmogrifyToSyncBubble, error);
602 if (message) {
603 xpc_dictionary_set_int64(message, "uid", uid);
604 if (SecXPCDictionarySetPList(message, "services", services, error)) {
605 xpc_object_t response = securityd_message_with_reply_sync(message, error);
606 if (response) {
607 reply = xpc_dictionary_get_bool(response, kSecXPCKeyResult);
608 if (!reply)
609 securityd_message_no_error(response, error);
610 xpc_release(response);
611 }
612 xpc_release(message);
613 }
614 }
615 return reply;
616 }
617
618 bool
619 _SecSystemKeychainTransfer(CFErrorRef *error)
620 {
621 xpc_object_t message;
622 bool reply = false;
623
624 message = securityd_create_message(kSecXPCOpTransmogrifyToSystemKeychain, error);
625 if (message) {
626 xpc_object_t response = securityd_message_with_reply_sync(message, error);
627 if (response) {
628 reply = xpc_dictionary_get_bool(response, kSecXPCKeyResult);
629 if (!reply)
630 securityd_message_no_error(response, error);
631 xpc_release(response);
632 }
633 xpc_release(message);
634 }
635 return reply;
636 }
637
638 bool
639 _SecSyncDeleteUserViews(uid_t uid, CFErrorRef *error)
640 {
641 xpc_object_t message;
642 bool reply = false;
643
644 message = securityd_create_message(kSecXPCOpDeleteUserView, error);
645 if (message) {
646 xpc_dictionary_set_int64(message, "uid", uid);
647
648 xpc_object_t response = securityd_message_with_reply_sync(message, error);
649 if (response) {
650 reply = xpc_dictionary_get_bool(response, kSecXPCKeyResult);
651 if (!reply)
652 securityd_message_no_error(response, error);
653 xpc_release(response);
654 }
655 xpc_release(message);
656 }
657 return reply;
658 }
659
660 XPC_RETURNS_RETAINED xpc_endpoint_t
661 _SecSecuritydCopyEndpoint(enum SecXPCOperation op, CFErrorRef *error)
662 {
663 xpc_endpoint_t endpoint = NULL;
664 xpc_object_t message = securityd_create_message(op, error);
665 if (message) {
666 xpc_object_t response = securityd_message_with_reply_sync(message, error);
667 if (response) {
668 endpoint = xpc_dictionary_get_value(response, kSecXPCKeyEndpoint);
669 if (endpoint) {
670 if(xpc_get_type(endpoint) != XPC_TYPE_ENDPOINT) {
671 secerror("endpoint was not an endpoint");
672 endpoint = NULL;
673 } else {
674 xpc_retain(endpoint);
675 }
676 } else {
677 secerror("endpoint was null");
678 }
679 xpc_release(response);
680 } else {
681 secerror("Securityd failed getting endpoint with error: %@", error ? *error : NULL);
682 }
683 xpc_release(message);
684 }
685 return endpoint;
686 }
687
688
689 XPC_RETURNS_RETAINED xpc_endpoint_t
690 _SecSecuritydCopyCKKSEndpoint(CFErrorRef *error)
691 {
692 return NULL;
693 }
694
695 XPC_RETURNS_RETAINED xpc_endpoint_t
696 _SecSecuritydCopyKeychainControlEndpoint(CFErrorRef* error)
697 {
698 return _SecSecuritydCopyEndpoint(kSecXPCOpKeychainControlEndpoint, error);
699 }
700
701 XPC_RETURNS_RETAINED xpc_endpoint_t
702 _SecSecuritydCopySFKeychainEndpoint(CFErrorRef* error)
703 {
704 return _SecSecuritydCopyEndpoint(kSecXPCOpSFKeychainEndpoint, error);
705 }