2 * Copyright (c) 2007-2009,2012-2015 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <sys/queue.h>
27 #include <vproc_priv.h>
29 #include <CoreFoundation/CoreFoundation.h>
30 #include <Security/SecItem.h>
31 #include <Security/SecBasePriv.h>
32 #include <Security/SecInternal.h>
33 #include <Security/SecuritydXPC.h>
34 #include <Security/SecTask.h>
35 #include <Security/SecItemPriv.h>
37 #include <utilities/debugging.h>
38 #include <utilities/SecCFError.h>
39 #include <utilities/SecXPCError.h>
40 #include <utilities/SecCFWrappers.h>
41 #include <utilities/SecDispatchRelease.h>
42 #include <utilities/SecDb.h> // TODO Fixme this gets us SecError().
43 #include <ipc/securityd_client.h>
45 struct securityd
*gSecurityd
;
51 /* Hardcoded Access Groups for the server itself */
52 static CFArrayRef
SecServerCopyAccessGroups(void) {
53 return CFArrayCreateForCFTypes(kCFAllocatorDefault
,
57 CFSTR("lockdown-identities"),
61 CFSTR("com.apple.security.sos"),
62 CFSTR("com.apple.sbd"),
63 CFSTR("com.apple.lakitu"),
67 static SecurityClient gClient
;
71 SecSecuritySetMusrMode(bool mode
, uid_t uid
, int activeUser
)
73 gClient
.inMultiUser
= mode
;
75 gClient
.activeUser
= activeUser
;
80 SecSecurityClientGet(void)
82 static dispatch_once_t onceToken
;
83 dispatch_once(&onceToken
, ^{
85 gClient
.accessGroups
= SecServerCopyAccessGroups();
86 gClient
.allowSystemKeychain
= true;
87 gClient
.allowSyncBubbleKeychain
= true;
88 gClient
.isNetworkExtension
= false;
90 gClient
.inMultiUser
= false;
91 gClient
.activeUser
= 501;
97 CFArrayRef
SecAccessGroupsGetCurrent(void) {
98 SecurityClient
*client
= SecSecurityClientGet();
99 assert(client
&& client
->accessGroups
);
100 return client
->accessGroups
;
104 void SecAccessGroupsSetCurrent(CFArrayRef accessGroups
);
105 void SecAccessGroupsSetCurrent(CFArrayRef accessGroups
) {
106 // Not thread safe at all, but OK because it is meant to be used only by tests.
107 gClient
.accessGroups
= accessGroups
;
110 #if !TARGET_OS_IPHONE
111 static bool securityd_in_system_context(void) {
112 static bool runningInSystemContext
;
113 static dispatch_once_t onceToken
;
114 dispatch_once(&onceToken
, ^{
115 runningInSystemContext
= (getuid() == 0);
116 if (!runningInSystemContext
) {
118 if (vproc_swap_string(NULL
, VPROC_GSK_MGR_NAME
, NULL
, &manager
) == NULL
) {
119 runningInSystemContext
= (!strcmp(manager
, VPROCMGR_SESSION_SYSTEM
) ||
120 !strcmp(manager
, VPROCMGR_SESSION_LOGINWINDOW
));
125 return runningInSystemContext
;
129 static const char *securityd_service_name(void) {
130 return kSecuritydXPCServiceName
;
133 static xpc_connection_t
securityd_create_connection(const char *name
, uint64_t flags
) {
134 const char *serviceName
= name
;
136 serviceName
= securityd_service_name();
138 xpc_connection_t connection
;
139 connection
= xpc_connection_create_mach_service(serviceName
, NULL
, flags
);
140 xpc_connection_set_event_handler(connection
, ^(xpc_object_t event
) {
141 const char *description
= xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
);
142 secnotice("xpc", "got event: %s", description
);
144 xpc_connection_resume(connection
);
148 static xpc_connection_t sSecuritydConnection
;
149 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR))
150 static xpc_connection_t sTrustdConnection
;
153 static xpc_connection_t
securityd_connection(void) {
154 static dispatch_once_t once
;
155 dispatch_once(&once
, ^{
156 sSecuritydConnection
= securityd_create_connection(kSecuritydXPCServiceName
, 0);
158 return sSecuritydConnection
;
161 static xpc_connection_t
trustd_connection(void) {
162 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR))
163 static dispatch_once_t once
;
164 dispatch_once(&once
, ^{
165 bool sysCtx
= securityd_in_system_context();
166 uint64_t flags
= (sysCtx
) ? XPC_CONNECTION_MACH_SERVICE_PRIVILEGED
: 0;
167 const char *serviceName
= (sysCtx
) ? kTrustdXPCServiceName
: kTrustdAgentXPCServiceName
;
168 sTrustdConnection
= securityd_create_connection(serviceName
, flags
);
170 return sTrustdConnection
;
172 // on iOS all operations are still handled by securityd
173 return securityd_connection();
177 static xpc_connection_t
securityd_connection_for_operation(enum SecXPCOperation op
) {
180 case sec_trust_store_contains_id
:
181 case sec_trust_store_set_trust_settings_id
:
182 case sec_trust_store_remove_certificate_id
:
183 case sec_trust_evaluate_id
:
190 #if SECTRUST_VERBOSE_DEBUG
192 bool sysCtx
= securityd_in_system_context();
193 const char *serviceName
= (sysCtx
) ? kTrustdXPCServiceName
: kTrustdAgentXPCServiceName
;
194 syslog(LOG_ERR
, "Will connect to: %s (op=%d)",
195 (isTrustOp
) ? serviceName
: kSecuritydXPCServiceName
, (int)op
);
198 return (isTrustOp
) ? trustd_connection() : securityd_connection();
201 // NOTE: This is not thread safe, but this SPI is for testing only.
202 void SecServerSetMachServiceName(const char *name
) {
203 // Make sure sSecXPCServer.queue exists.
204 securityd_connection();
206 xpc_connection_t oldConection
= sSecuritydConnection
;
207 sSecuritydConnection
= securityd_create_connection(name
, 0);
209 xpc_release(oldConection
);
213 securityd_message_with_reply_sync(xpc_object_t message
, CFErrorRef
*error
)
215 xpc_object_t reply
= NULL
;
216 uint64_t operation
= xpc_dictionary_get_uint64(message
, kSecXPCKeyOperation
);
217 xpc_connection_t connection
= securityd_connection_for_operation((enum SecXPCOperation
)operation
);
219 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.
221 unsigned int tries_left
= max_tries
;
223 if (reply
) xpc_release(reply
);
224 reply
= xpc_connection_send_message_with_reply_sync(connection
, message
);
225 } while (reply
== XPC_ERROR_CONNECTION_INTERRUPTED
&& --tries_left
> 0);
227 if (xpc_get_type(reply
) == XPC_TYPE_ERROR
) {
229 if (reply
== XPC_ERROR_CONNECTION_INTERRUPTED
|| reply
== XPC_ERROR_CONNECTION_INVALID
) {
230 code
= kSecXPCErrorConnectionFailed
;
231 seccritical("Failed to talk to secd after %d attempts.", max_tries
);
232 } else if (reply
== XPC_ERROR_TERMINATION_IMMINENT
)
233 code
= kSecXPCErrorUnknown
;
235 code
= kSecXPCErrorUnknown
;
237 char *conn_desc
= xpc_copy_description(connection
);
238 const char *description
= xpc_dictionary_get_string(reply
, XPC_ERROR_KEY_DESCRIPTION
);
239 SecCFCreateErrorWithFormat(code
, sSecXPCErrorDomain
, NULL
, error
, NULL
, CFSTR("%s: %s"), conn_desc
, description
);
248 xpc_object_t
securityd_create_message(enum SecXPCOperation op
, CFErrorRef
* error
)
250 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
252 xpc_dictionary_set_uint64(message
, kSecXPCKeyOperation
, op
);
254 SecCFCreateError(kSecXPCErrorConnectionFailed
, sSecXPCErrorDomain
,
255 CFSTR("xpc_dictionary_create returned NULL"), NULL
, error
);
260 // Return true if there is no error in message, return false and set *error if there is.
261 bool securityd_message_no_error(xpc_object_t message
, CFErrorRef
*error
) {
262 xpc_object_t xpc_error
= xpc_dictionary_get_value(message
, kSecXPCKeyError
);
263 if (xpc_error
== NULL
)
267 *error
= SecCreateCFErrorWithXPCObject(xpc_error
);
272 bool securityd_send_sync_and_do(enum SecXPCOperation op
, CFErrorRef
*error
,
273 bool (^add_to_message
)(xpc_object_t message
, CFErrorRef
* error
),
274 bool (^handle_response
)(xpc_object_t response
, CFErrorRef
* error
)) {
275 xpc_object_t message
= securityd_create_message(op
, error
);
278 if (!add_to_message
|| add_to_message(message
, error
)) {
279 xpc_object_t response
= securityd_message_with_reply_sync(message
, error
);
281 if (securityd_message_no_error(response
, error
)) {
282 ok
= (!handle_response
|| handle_response(response
, error
));
284 xpc_release(response
);
287 xpc_release(message
);
295 _SecSecuritydCopyWhoAmI(CFErrorRef
*error
)
297 CFDictionaryRef reply
= NULL
;
298 xpc_object_t message
= securityd_create_message(kSecXPCOpWhoAmI
, error
);
300 xpc_object_t response
= securityd_message_with_reply_sync(message
, error
);
302 reply
= _CFXPCCreateCFObjectFromXPCObject(response
);
303 xpc_release(response
);
305 securityd_message_no_error(response
, error
);
307 xpc_release(message
);
313 _SecSyncBubbleTransfer(CFArrayRef services
, uid_t uid
, CFErrorRef
*error
)
315 xpc_object_t message
;
318 message
= securityd_create_message(kSecXPCOpTransmogrifyToSyncBubble
, error
);
320 xpc_dictionary_set_int64(message
, "uid", uid
);
321 if (SecXPCDictionarySetPList(message
, "services", services
, error
)) {
322 xpc_object_t response
= securityd_message_with_reply_sync(message
, error
);
324 reply
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
326 securityd_message_no_error(response
, error
);
327 xpc_release(response
);
329 xpc_release(message
);
336 _SecSystemKeychainTransfer(CFErrorRef
*error
)
338 xpc_object_t message
;
341 message
= securityd_create_message(kSecXPCOpTransmogrifyToSystemKeychain
, error
);
343 xpc_object_t response
= securityd_message_with_reply_sync(message
, error
);
345 reply
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
347 securityd_message_no_error(response
, error
);
348 xpc_release(response
);
350 xpc_release(message
);
356 _SecSyncDeleteUserViews(uid_t uid
, CFErrorRef
*error
)
358 xpc_object_t message
;
361 message
= securityd_create_message(kSecXPCOpDeleteUserView
, error
);
363 xpc_dictionary_set_int64(message
, "uid", uid
);
365 xpc_object_t response
= securityd_message_with_reply_sync(message
, error
);
367 reply
= xpc_dictionary_get_bool(response
, kSecXPCKeyResult
);
369 securityd_message_no_error(response
, error
);
370 xpc_release(response
);
372 xpc_release(message
);
379 /* vi:set ts=4 sw=4 et: */