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