]> git.saurik.com Git - apple/security.git/blob - OSX/sec/ipc/client.c
Security-58286.230.21.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.sos-usercredential"),
86 CFSTR("com.apple.sbd"),
87 CFSTR("com.apple.lakitu"),
88 CFSTR("com.apple.security.securityd"),
89 kSecAttrAccessGroupToken,
90 NULL);
91 }
92
93 static SecurityClient gClient;
94
95 #if TARGET_OS_IOS
96 void
97 SecSecuritySetMusrMode(bool mode, uid_t uid, int activeUser)
98 {
99 gClient.inMultiUser = mode;
100 gClient.uid = uid;
101 gClient.activeUser = activeUser;
102 }
103 #endif
104
105 SecurityClient *
106 SecSecurityClientGet(void)
107 {
108 static dispatch_once_t onceToken;
109 dispatch_once(&onceToken, ^{
110 gClient.task = NULL;
111 gClient.accessGroups = SecServerCopyAccessGroups();
112 gClient.allowSystemKeychain = true;
113 gClient.allowSyncBubbleKeychain = true;
114 gClient.isNetworkExtension = false;
115 #if TARGET_OS_IPHONE
116 gClient.inMultiUser = false;
117 gClient.activeUser = 501;
118 #endif
119 });
120 return &gClient;
121 }
122
123 CFArrayRef SecAccessGroupsGetCurrent(void) {
124 SecurityClient *client = SecSecurityClientGet();
125 assert(client && client->accessGroups);
126 return client->accessGroups;
127 }
128
129 // Only for testing.
130 void SecAccessGroupsSetCurrent(CFArrayRef accessGroups) {
131 // Not thread safe at all, but OK because it is meant to be used only by tests.
132 gClient.accessGroups = accessGroups;
133 }
134
135 #if !TARGET_OS_IPHONE
136 static bool securityd_in_system_context(void) {
137 static bool runningInSystemContext;
138 static dispatch_once_t onceToken;
139 dispatch_once(&onceToken, ^{
140 runningInSystemContext = (getuid() == 0);
141 if (!runningInSystemContext) {
142 char *manager;
143 if (vproc_swap_string(NULL, VPROC_GSK_MGR_NAME, NULL, &manager) == NULL) {
144 runningInSystemContext = (!strcmp(manager, VPROCMGR_SESSION_SYSTEM) ||
145 !strcmp(manager, VPROCMGR_SESSION_LOGINWINDOW));
146 free(manager);
147 }
148 }
149 });
150 return runningInSystemContext;
151 }
152 #endif
153
154 static const char *securityd_service_name(void) {
155 return kSecuritydXPCServiceName;
156 }
157
158 #define SECURITY_TARGET_UID_UNSET ((uid_t)-1)
159 static uid_t securityd_target_uid = SECURITY_TARGET_UID_UNSET;
160
161 void
162 _SecSetSecuritydTargetUID(uid_t uid)
163 {
164 securityd_target_uid = uid;
165 }
166
167
168 static xpc_connection_t securityd_create_connection(const char *name, uid_t target_uid, uint64_t flags) {
169 const char *serviceName = name;
170 if (!serviceName) {
171 serviceName = securityd_service_name();
172 }
173 xpc_connection_t connection;
174 connection = xpc_connection_create_mach_service(serviceName, NULL, flags);
175 xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
176 const char *description = xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION);
177 secnotice("xpc", "got event: %s", description);
178 });
179 if (target_uid != SECURITY_TARGET_UID_UNSET) {
180 xpc_connection_set_target_uid(connection, target_uid);
181 }
182 xpc_connection_resume(connection);
183 return connection;
184 }
185
186 static xpc_connection_t sSecuritydConnection;
187 static xpc_connection_t sTrustdConnection;
188
189 static xpc_connection_t securityd_connection(void) {
190 static dispatch_once_t once;
191 dispatch_once(&once, ^{
192 sSecuritydConnection = securityd_create_connection(kSecuritydXPCServiceName, securityd_target_uid, 0);
193 });
194 return sSecuritydConnection;
195 }
196
197 static xpc_connection_t trustd_connection(void) {
198 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR))
199 static dispatch_once_t once;
200 dispatch_once(&once, ^{
201 bool sysCtx = securityd_in_system_context();
202 uint64_t flags = (sysCtx) ? XPC_CONNECTION_MACH_SERVICE_PRIVILEGED : 0;
203 const char *serviceName = (sysCtx) ? kTrustdXPCServiceName : kTrustdAgentXPCServiceName;
204 sTrustdConnection = securityd_create_connection(serviceName, SECURITY_TARGET_UID_UNSET, flags);
205 });
206 return sTrustdConnection;
207 #else
208 static dispatch_once_t once;
209 dispatch_once(&once, ^{
210 sTrustdConnection = securityd_create_connection(kTrustdXPCServiceName, SECURITY_TARGET_UID_UNSET, 0);
211 });
212 return sTrustdConnection;
213 #endif
214 }
215
216 static bool is_trust_operation(enum SecXPCOperation op) {
217 switch (op) {
218 case sec_trust_store_contains_id:
219 case sec_trust_store_set_trust_settings_id:
220 case sec_trust_store_remove_certificate_id:
221 case sec_trust_evaluate_id:
222 case sec_trust_store_copy_all_id:
223 case sec_trust_store_copy_usage_constraints_id:
224 case sec_ocsp_cache_flush_id:
225 case sec_ota_pki_trust_store_version_id:
226 case sec_ota_pki_asset_version_id:
227 case kSecXPCOpOTAGetEscrowCertificates:
228 case kSecXPCOpOTAPKIGetNewAsset:
229 case kSecXPCOpNetworkingAnalyticsReport:
230 case kSecXPCOpSetCTExceptions:
231 case kSecXPCOpCopyCTExceptions:
232 return true;
233 default:
234 break;
235 }
236 return false;
237 }
238
239 static xpc_connection_t securityd_connection_for_operation(enum SecXPCOperation op) {
240 bool isTrustOp = is_trust_operation(op);
241 #if SECTRUST_VERBOSE_DEBUG
242 {
243 bool sysCtx = securityd_in_system_context();
244 const char *serviceName = (sysCtx) ? kTrustdXPCServiceName : kTrustdAgentXPCServiceName;
245 syslog(LOG_ERR, "Will connect to: %s (op=%d)",
246 (isTrustOp) ? serviceName : kSecuritydXPCServiceName, (int)op);
247 }
248 #endif
249 return (isTrustOp) ? trustd_connection() : securityd_connection();
250 }
251
252 // NOTE: This is not thread safe, but this SPI is for testing only.
253 void SecServerSetTrustdMachServiceName(const char *name) {
254 // Make sure sSecXPCServer.queue exists.
255 trustd_connection();
256
257 xpc_connection_t oldConection = sTrustdConnection;
258 sTrustdConnection = securityd_create_connection(name, SECURITY_TARGET_UID_UNSET, 0);
259 if (oldConection)
260 xpc_release(oldConection);
261 }
262
263
264 #define SECURITYD_MAX_XPC_TRIES 4
265 // Per <rdar://problem/17829836> N61/12A342: Audio Playback... for why this needs to be at least 3, so we made it 4.
266
267 static bool
268 _securityd_process_message_reply(xpc_object_t *reply,
269 CFErrorRef *error,
270 xpc_connection_t connection,
271 uint64_t operation)
272 {
273 if (xpc_get_type(*reply) != XPC_TYPE_ERROR) {
274 return true;
275 }
276 CFIndex code = 0;
277 if (*reply == XPC_ERROR_CONNECTION_INTERRUPTED || *reply == XPC_ERROR_CONNECTION_INVALID) {
278 code = kSecXPCErrorConnectionFailed;
279 seccritical("Failed to talk to %s after %d attempts.",
280 (is_trust_operation((enum SecXPCOperation)operation)) ? "trustd" :
281 #if TARGET_OS_IPHONE
282 "securityd",
283 #else
284 "secd",
285 #endif
286 SECURITYD_MAX_XPC_TRIES);
287 } else if (*reply == XPC_ERROR_TERMINATION_IMMINENT) {
288 code = kSecXPCErrorUnknown;
289 } else {
290 code = kSecXPCErrorUnknown;
291 }
292
293 char *conn_desc = xpc_copy_description(connection);
294 const char *description = xpc_dictionary_get_string(*reply, XPC_ERROR_KEY_DESCRIPTION);
295 SecCFCreateErrorWithFormat(code, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("%s: %s"), conn_desc, description);
296 free(conn_desc);
297 xpc_release(*reply);
298 *reply = NULL;
299 return false;
300 }
301
302
303 XPC_RETURNS_RETAINED
304 xpc_object_t
305 securityd_message_with_reply_sync(xpc_object_t message, CFErrorRef *error)
306 {
307 xpc_object_t reply = NULL;
308 uint64_t operation = xpc_dictionary_get_uint64(message, kSecXPCKeyOperation);
309 xpc_connection_t connection = securityd_connection_for_operation((enum SecXPCOperation)operation);
310
311 const int max_tries = SECURITYD_MAX_XPC_TRIES;
312
313 unsigned int tries_left = max_tries;
314 do {
315 if (reply) xpc_release(reply);
316 reply = xpc_connection_send_message_with_reply_sync(connection, message);
317 } while (reply == XPC_ERROR_CONNECTION_INTERRUPTED && --tries_left > 0);
318
319 _securityd_process_message_reply(&reply, error, connection, operation);
320
321 return reply;
322 }
323
324 static void
325 _securityd_message_with_reply_async_inner(xpc_object_t message,
326 dispatch_queue_t replyq,
327 securityd_handler_t handler,
328 uint32_t tries_left)
329 {
330 uint64_t operation = xpc_dictionary_get_uint64(message, kSecXPCKeyOperation);
331 xpc_connection_t connection = securityd_connection_for_operation((enum SecXPCOperation)operation);
332
333 xpc_retain(message);
334 dispatch_retain(replyq);
335 securityd_handler_t handlerCopy = Block_copy(handler);
336 xpc_connection_send_message_with_reply(connection, message, replyq, ^(xpc_object_t _Nonnull reply) {
337 if (reply == XPC_ERROR_CONNECTION_INTERRUPTED && tries_left > 0) {
338 _securityd_message_with_reply_async_inner(message, replyq, handlerCopy, tries_left - 1);
339 } else {
340 CFErrorRef error = NULL;
341 _securityd_process_message_reply(&reply, &error, connection, operation);
342 handlerCopy(reply, error);
343 CFReleaseNull(error);
344 }
345 xpc_release(message);
346 dispatch_release(replyq);
347 Block_release(handlerCopy);
348 });
349 }
350
351 void
352 securityd_message_with_reply_async(xpc_object_t message,
353 dispatch_queue_t replyq,
354 securityd_handler_t handler)
355 {
356 _securityd_message_with_reply_async_inner(message, replyq, handler, SECURITYD_MAX_XPC_TRIES);
357 }
358
359 XPC_RETURNS_RETAINED
360 xpc_object_t
361 securityd_create_message(enum SecXPCOperation op, CFErrorRef* error)
362 {
363 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
364 if (message) {
365 xpc_dictionary_set_uint64(message, kSecXPCKeyOperation, op);
366 } else {
367 SecCFCreateError(kSecXPCErrorConnectionFailed, sSecXPCErrorDomain,
368 CFSTR("xpc_dictionary_create returned NULL"), NULL, error);
369 }
370 return message;
371 }
372
373 // Return true if there is no error in message, return false and set *error if there is.
374 bool securityd_message_no_error(xpc_object_t message, CFErrorRef *error) {
375 xpc_object_t xpc_error = NULL;
376 if (message == NULL)
377 return false;
378
379 xpc_error = xpc_dictionary_get_value(message, kSecXPCKeyError);
380 if (xpc_error == NULL)
381 return true;
382
383 CFErrorRef localError = SecCreateCFErrorWithXPCObject(xpc_error);
384
385 #if TARGET_OS_IPHONE
386 secdebug("xpc", "Talking to securityd failed with error: %@", localError);
387 #else
388 #if !defined(NDEBUG)
389 uint64_t operation = xpc_dictionary_get_uint64(message, kSecXPCKeyOperation);
390 #endif
391 secdebug("xpc", "Talking to %s failed with error: %@",
392 (is_trust_operation((enum SecXPCOperation)operation)) ? "trustd" : "secd", localError);
393 #endif
394
395 if (error) {
396 *error = localError;
397 } else {
398 CFReleaseSafe(localError);
399 }
400 return false;
401 }
402
403 bool securityd_send_sync_and_do(enum SecXPCOperation op, CFErrorRef *error,
404 bool (^add_to_message)(xpc_object_t message, CFErrorRef* error),
405 bool (^handle_response)(xpc_object_t _Nonnull response, CFErrorRef* error)) {
406 xpc_object_t message = securityd_create_message(op, error);
407 bool ok = false;
408 if (message) {
409 if (!add_to_message || add_to_message(message, error)) {
410 xpc_object_t response = securityd_message_with_reply_sync(message, error);
411 if (response) {
412 if (securityd_message_no_error(response, error)) {
413 ok = (!handle_response || handle_response(response, error));
414 }
415 xpc_release(response);
416 }
417 }
418 xpc_release(message);
419 }
420
421 return ok;
422 }
423
424 void securityd_send_async_and_do(enum SecXPCOperation op, dispatch_queue_t replyq,
425 bool (^add_to_message)(xpc_object_t message, CFErrorRef* error),
426 securityd_handler_t handler) {
427 CFErrorRef error = NULL;
428 xpc_object_t message = securityd_create_message(op, &error);
429 if (message == NULL) {
430 handler(NULL, error);
431 CFReleaseNull(error);
432 return;
433 }
434
435 if (add_to_message != NULL) {
436 if (!add_to_message(message, &error)) {
437 handler(NULL, error);
438 xpc_release(message);
439 CFReleaseNull(error);
440 return;
441 }
442 }
443
444 securityd_message_with_reply_async(message, replyq, ^(xpc_object_t reply, CFErrorRef error2) {
445 if (error2 != NULL) {
446 handler(NULL, error2);
447 return;
448 }
449 CFErrorRef error3 = NULL;
450 if (!securityd_message_no_error(reply, &error3)) {
451 handler(NULL, error3);
452 CFReleaseNull(error3);
453 return;
454 }
455 handler(reply, NULL);
456 });
457 xpc_release(message);
458 }
459
460
461 CFDictionaryRef
462 _SecSecuritydCopyWhoAmI(CFErrorRef *error)
463 {
464 CFDictionaryRef reply = NULL;
465 xpc_object_t message = securityd_create_message(kSecXPCOpWhoAmI, error);
466 if (message) {
467 xpc_object_t response = securityd_message_with_reply_sync(message, error);
468 if (response) {
469 reply = _CFXPCCreateCFObjectFromXPCObject(response);
470 xpc_release(response);
471 } else {
472 secerror("Securityd failed getting whoamid with error: %@",
473 error ? *error : NULL);
474 }
475 xpc_release(message);
476 }
477 return reply;
478 }
479
480 bool
481 _SecSyncBubbleTransfer(CFArrayRef services, uid_t uid, CFErrorRef *error)
482 {
483 xpc_object_t message;
484 bool reply = false;
485
486 message = securityd_create_message(kSecXPCOpTransmogrifyToSyncBubble, error);
487 if (message) {
488 xpc_dictionary_set_int64(message, "uid", uid);
489 if (SecXPCDictionarySetPList(message, "services", services, error)) {
490 xpc_object_t response = securityd_message_with_reply_sync(message, error);
491 if (response) {
492 reply = xpc_dictionary_get_bool(response, kSecXPCKeyResult);
493 if (!reply)
494 securityd_message_no_error(response, error);
495 xpc_release(response);
496 }
497 xpc_release(message);
498 }
499 }
500 return reply;
501 }
502
503 bool
504 _SecSystemKeychainTransfer(CFErrorRef *error)
505 {
506 xpc_object_t message;
507 bool reply = false;
508
509 message = securityd_create_message(kSecXPCOpTransmogrifyToSystemKeychain, error);
510 if (message) {
511 xpc_object_t response = securityd_message_with_reply_sync(message, error);
512 if (response) {
513 reply = xpc_dictionary_get_bool(response, kSecXPCKeyResult);
514 if (!reply)
515 securityd_message_no_error(response, error);
516 xpc_release(response);
517 }
518 xpc_release(message);
519 }
520 return reply;
521 }
522
523 bool
524 _SecSyncDeleteUserViews(uid_t uid, CFErrorRef *error)
525 {
526 xpc_object_t message;
527 bool reply = false;
528
529 message = securityd_create_message(kSecXPCOpDeleteUserView, error);
530 if (message) {
531 xpc_dictionary_set_int64(message, "uid", uid);
532
533 xpc_object_t response = securityd_message_with_reply_sync(message, error);
534 if (response) {
535 reply = xpc_dictionary_get_bool(response, kSecXPCKeyResult);
536 if (!reply)
537 securityd_message_no_error(response, error);
538 xpc_release(response);
539 }
540 xpc_release(message);
541 }
542 return reply;
543 }
544
545 XPC_RETURNS_RETAINED xpc_endpoint_t
546 _SecSecuritydCopyEndpoint(enum SecXPCOperation op, CFErrorRef *error)
547 {
548 xpc_endpoint_t endpoint = NULL;
549 xpc_object_t message = securityd_create_message(op, error);
550 if (message) {
551 xpc_object_t response = securityd_message_with_reply_sync(message, error);
552 if (response) {
553 endpoint = xpc_dictionary_get_value(response, kSecXPCKeyEndpoint);
554 if (endpoint) {
555 if(xpc_get_type(endpoint) != XPC_TYPE_ENDPOINT) {
556 secerror("endpoint was not an endpoint");
557 endpoint = NULL;
558 } else {
559 xpc_retain(endpoint);
560 }
561 } else {
562 secerror("endpoint was null");
563 }
564 xpc_release(response);
565 } else {
566 secerror("Securityd failed getting endpoint with error: %@", error ? *error : NULL);
567 }
568 xpc_release(message);
569 }
570 return endpoint;
571 }
572
573
574 XPC_RETURNS_RETAINED xpc_endpoint_t
575 _SecSecuritydCopyCKKSEndpoint(CFErrorRef *error)
576 {
577 return NULL;
578 }
579
580 XPC_RETURNS_RETAINED xpc_endpoint_t
581 _SecSecuritydCopyKeychainControlEndpoint(CFErrorRef* error)
582 {
583 return _SecSecuritydCopyEndpoint(kSecXPCOpKeychainControlEndpoint, error);
584 }
585
586 XPC_RETURNS_RETAINED xpc_endpoint_t
587 _SecSecuritydCopySFKeychainEndpoint(CFErrorRef* error)
588 {
589 return _SecSecuritydCopyEndpoint(kSecXPCOpSFKeychainEndpoint, error);
590 }