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