2 * Copyright (c) 2007-2009,2012-2014 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>
28 #include <CoreFoundation/CoreFoundation.h>
29 #include <Security/SecItem.h>
30 #include <Security/SecBasePriv.h>
31 #include <Security/SecInternal.h>
32 #include <Security/SecuritydXPC.h>
34 #include <utilities/debugging.h>
35 #include <utilities/SecCFError.h>
36 #include <utilities/SecXPCError.h>
37 #include <utilities/SecCFWrappers.h>
38 #include <utilities/SecDispatchRelease.h>
39 #include <utilities/SecDb.h> // TODO Fixme this gets us SecError().
40 #include <ipc/securityd_client.h>
42 struct securityd
*gSecurityd
;
48 /* Hardcoded Access Groups for the server itself */
49 static CFArrayRef
SecServerCopyAccessGroups(void) {
50 return CFArrayCreateForCFTypes(kCFAllocatorDefault
,
54 CFSTR("lockdown-identities"),
58 CFSTR("com.apple.security.sos"),
62 CFArrayRef
SecAccessGroupsGetCurrent(void) {
63 static CFArrayRef gSecServerAccessGroups
;
64 static dispatch_once_t only_do_this_once
;
65 dispatch_once(&only_do_this_once
, ^{
66 gSecServerAccessGroups
= SecServerCopyAccessGroups();
67 assert(gSecServerAccessGroups
);
69 return gSecServerAccessGroups
;
72 static xpc_connection_t
securityd_create_connection(const char *name
) {
74 name
= kSecuritydXPCServiceName
;
75 xpc_connection_t connection
;
76 connection
= xpc_connection_create_mach_service(name
, NULL
, 0);
77 xpc_connection_set_event_handler(connection
, ^(xpc_object_t event
) {
78 const char *description
= xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
);
79 secnotice("xpc", "got event: %s", description
);
81 xpc_connection_resume(connection
);
85 static xpc_connection_t sSecuritydConnection
;
87 static xpc_connection_t
securityd_connection(void) {
88 static dispatch_once_t once
;
89 dispatch_once(&once
, ^{
90 sSecuritydConnection
= securityd_create_connection(NULL
);
92 return sSecuritydConnection
;
95 // NOTE: This is not thread safe, but this SPI is for testing only.
96 void SecServerSetMachServiceName(const char *name
) {
97 // Make sure sSecXPCServer.queue exists.
98 securityd_connection();
100 xpc_connection_t oldConection
= sSecuritydConnection
;
101 sSecuritydConnection
= securityd_create_connection(name
);
103 xpc_release(oldConection
);
107 securityd_message_with_reply_sync(xpc_object_t message
, CFErrorRef
*error
)
109 xpc_object_t reply
= NULL
;
110 xpc_connection_t connection
= securityd_connection();
112 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.
114 unsigned int tries_left
= max_tries
;
116 if (reply
) xpc_release(reply
);
117 reply
= xpc_connection_send_message_with_reply_sync(connection
, message
);
118 } while (reply
== XPC_ERROR_CONNECTION_INTERRUPTED
&& --tries_left
> 0);
120 if (xpc_get_type(reply
) == XPC_TYPE_ERROR
) {
122 if (reply
== XPC_ERROR_CONNECTION_INTERRUPTED
|| reply
== XPC_ERROR_CONNECTION_INVALID
) {
123 code
= kSecXPCErrorConnectionFailed
;
124 seccritical("Failed to talk to secd after %d attempts.", max_tries
);
125 } else if (reply
== XPC_ERROR_TERMINATION_IMMINENT
)
126 code
= kSecXPCErrorUnknown
;
128 code
= kSecXPCErrorUnknown
;
130 char *conn_desc
= xpc_copy_description(connection
);
131 const char *description
= xpc_dictionary_get_string(reply
, XPC_ERROR_KEY_DESCRIPTION
);
132 SecCFCreateErrorWithFormat(code
, sSecXPCErrorDomain
, NULL
, error
, NULL
, CFSTR("%s: %s"), conn_desc
, description
);
141 xpc_object_t
securityd_create_message(enum SecXPCOperation op
, CFErrorRef
* error
)
143 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
145 xpc_dictionary_set_uint64(message
, kSecXPCKeyOperation
, op
);
147 SecCFCreateError(kSecXPCErrorConnectionFailed
, sSecXPCErrorDomain
,
148 CFSTR("xpc_dictionary_create returned NULL"), NULL
, error
);
153 // Return true if there is no error in message, return false and set *error if there is.
154 bool securityd_message_no_error(xpc_object_t message
, CFErrorRef
*error
) {
155 xpc_object_t xpc_error
= xpc_dictionary_get_value(message
, kSecXPCKeyError
);
156 if (xpc_error
== NULL
)
160 *error
= SecCreateCFErrorWithXPCObject(xpc_error
);
165 bool securityd_send_sync_and_do(enum SecXPCOperation op
, CFErrorRef
*error
,
166 bool (^add_to_message
)(xpc_object_t message
, CFErrorRef
* error
),
167 bool (^handle_response
)(xpc_object_t response
, CFErrorRef
* error
)) {
168 xpc_object_t message
= securityd_create_message(op
, error
);
171 if (!add_to_message
|| add_to_message(message
, error
)) {
172 xpc_object_t response
= securityd_message_with_reply_sync(message
, error
);
174 if (securityd_message_no_error(response
, error
)) {
175 ok
= (!handle_response
|| handle_response(response
, error
));
177 xpc_release(response
);
180 xpc_release(message
);
187 /* vi:set ts=4 sw=4 et: */