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