]> git.saurik.com Git - apple/security.git/blob - OSX/sec/ipc/client.c
Security-57337.20.44.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 <stdbool.h>
25 #include <sys/queue.h>
26 #include <syslog.h>
27 #include <vproc_priv.h>
28
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
35 #include <utilities/debugging.h>
36 #include <utilities/SecCFError.h>
37 #include <utilities/SecXPCError.h>
38 #include <utilities/SecCFWrappers.h>
39 #include <utilities/SecDispatchRelease.h>
40 #include <utilities/SecDb.h> // TODO Fixme this gets us SecError().
41 #include <ipc/securityd_client.h>
42
43 struct securityd *gSecurityd;
44
45 //
46 // MARK: XPC IPC.
47 //
48
49 /* Hardcoded Access Groups for the server itself */
50 static CFArrayRef SecServerCopyAccessGroups(void) {
51 return CFArrayCreateForCFTypes(kCFAllocatorDefault,
52 #if NO_SERVER
53 CFSTR("test"),
54 CFSTR("apple"),
55 CFSTR("lockdown-identities"),
56 #else
57 CFSTR("sync"),
58 #endif
59 CFSTR("com.apple.security.sos"),
60 CFSTR("com.apple.sbd"),
61 CFSTR("com.apple.lakitu"),
62 NULL);
63 }
64
65 static CFArrayRef gSecServerAccessGroups;
66 CFArrayRef SecAccessGroupsGetCurrent(void) {
67 static dispatch_once_t only_do_this_once;
68 dispatch_once(&only_do_this_once, ^{
69 gSecServerAccessGroups = SecServerCopyAccessGroups();
70 assert(gSecServerAccessGroups);
71 });
72 return gSecServerAccessGroups;
73 }
74
75 // Only for testing.
76 void SecAccessGroupsSetCurrent(CFArrayRef accessGroups);
77 void SecAccessGroupsSetCurrent(CFArrayRef accessGroups) {
78 // Not thread safe at all, but OK because it is meant to be used only by tests.
79 gSecServerAccessGroups = accessGroups;
80 }
81
82 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR))
83 static bool securityd_in_system_context(void) {
84 static bool runningInSystemContext;
85 static dispatch_once_t onceToken;
86 dispatch_once(&onceToken, ^{
87 runningInSystemContext = (getuid() == 0);
88 if (!runningInSystemContext) {
89 char *manager;
90 if (vproc_swap_string(NULL, VPROC_GSK_MGR_NAME, NULL, &manager) == NULL) {
91 runningInSystemContext = (!strcmp(manager, VPROCMGR_SESSION_SYSTEM) ||
92 !strcmp(manager, VPROCMGR_SESSION_LOGINWINDOW));
93 free(manager);
94 }
95 }
96 });
97 return runningInSystemContext;
98 }
99 #endif
100
101 static const char *securityd_service_name(void) {
102 return kSecuritydXPCServiceName;
103 }
104
105 static xpc_connection_t securityd_create_connection(const char *name, uint64_t flags) {
106 const char *serviceName = name;
107 if (!serviceName) {
108 serviceName = securityd_service_name();
109 }
110 xpc_connection_t connection;
111 connection = xpc_connection_create_mach_service(serviceName, NULL, flags);
112 xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
113 const char *description = xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION);
114 secnotice("xpc", "got event: %s", description);
115 });
116 xpc_connection_resume(connection);
117 return connection;
118 }
119
120 static xpc_connection_t sSecuritydConnection;
121 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR))
122 static xpc_connection_t sTrustdConnection;
123 #endif
124
125 static xpc_connection_t securityd_connection(void) {
126 static dispatch_once_t once;
127 dispatch_once(&once, ^{
128 sSecuritydConnection = securityd_create_connection(kSecuritydXPCServiceName, 0);
129 });
130 return sSecuritydConnection;
131 }
132
133 static xpc_connection_t trustd_connection(void) {
134 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR))
135 static dispatch_once_t once;
136 dispatch_once(&once, ^{
137 bool sysCtx = securityd_in_system_context();
138 uint64_t flags = (sysCtx) ? XPC_CONNECTION_MACH_SERVICE_PRIVILEGED : 0;
139 const char *serviceName = (sysCtx) ? kTrustdXPCServiceName : kTrustdAgentXPCServiceName;
140 sTrustdConnection = securityd_create_connection(serviceName, flags);
141 });
142 return sTrustdConnection;
143 #else
144 // on iOS all operations are still handled by securityd
145 return securityd_connection();
146 #endif
147 }
148
149 static xpc_connection_t securityd_connection_for_operation(enum SecXPCOperation op) {
150 bool isTrustOp;
151 switch (op) {
152 case sec_trust_store_contains_id:
153 case sec_trust_store_set_trust_settings_id:
154 case sec_trust_store_remove_certificate_id:
155 case sec_trust_evaluate_id:
156 isTrustOp = true;
157 break;
158 default:
159 isTrustOp = false;
160 break;
161 }
162 #if SECTRUST_VERBOSE_DEBUG
163 {
164 bool sysCtx = securityd_in_system_context();
165 const char *serviceName = (sysCtx) ? kTrustdXPCServiceName : kTrustdAgentXPCServiceName;
166 syslog(LOG_ERR, "Will connect to: %s (op=%d)",
167 (isTrustOp) ? serviceName : kSecuritydXPCServiceName, (int)op);
168 }
169 #endif
170 return (isTrustOp) ? trustd_connection() : securityd_connection();
171 }
172
173 // NOTE: This is not thread safe, but this SPI is for testing only.
174 void SecServerSetMachServiceName(const char *name) {
175 // Make sure sSecXPCServer.queue exists.
176 securityd_connection();
177
178 xpc_connection_t oldConection = sSecuritydConnection;
179 sSecuritydConnection = securityd_create_connection(name, 0);
180 if (oldConection)
181 xpc_release(oldConection);
182 }
183
184 xpc_object_t
185 securityd_message_with_reply_sync(xpc_object_t message, CFErrorRef *error)
186 {
187 xpc_object_t reply = NULL;
188 uint64_t operation = xpc_dictionary_get_uint64(message, kSecXPCKeyOperation);
189 xpc_connection_t connection = securityd_connection_for_operation((enum SecXPCOperation)operation);
190
191 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.
192
193 unsigned int tries_left = max_tries;
194 do {
195 if (reply) xpc_release(reply);
196 reply = xpc_connection_send_message_with_reply_sync(connection, message);
197 } while (reply == XPC_ERROR_CONNECTION_INTERRUPTED && --tries_left > 0);
198
199 if (xpc_get_type(reply) == XPC_TYPE_ERROR) {
200 CFIndex code = 0;
201 if (reply == XPC_ERROR_CONNECTION_INTERRUPTED || reply == XPC_ERROR_CONNECTION_INVALID) {
202 code = kSecXPCErrorConnectionFailed;
203 seccritical("Failed to talk to secd after %d attempts.", max_tries);
204 } else if (reply == XPC_ERROR_TERMINATION_IMMINENT)
205 code = kSecXPCErrorUnknown;
206 else
207 code = kSecXPCErrorUnknown;
208
209 char *conn_desc = xpc_copy_description(connection);
210 const char *description = xpc_dictionary_get_string(reply, XPC_ERROR_KEY_DESCRIPTION);
211 SecCFCreateErrorWithFormat(code, sSecXPCErrorDomain, NULL, error, NULL, CFSTR("%s: %s"), conn_desc, description);
212 free(conn_desc);
213 xpc_release(reply);
214 reply = NULL;
215 }
216
217 return reply;
218 }
219
220 xpc_object_t securityd_create_message(enum SecXPCOperation op, CFErrorRef* error)
221 {
222 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
223 if (message) {
224 xpc_dictionary_set_uint64(message, kSecXPCKeyOperation, op);
225 } else {
226 SecCFCreateError(kSecXPCErrorConnectionFailed, sSecXPCErrorDomain,
227 CFSTR("xpc_dictionary_create returned NULL"), NULL, error);
228 }
229 return message;
230 }
231
232 // Return true if there is no error in message, return false and set *error if there is.
233 bool securityd_message_no_error(xpc_object_t message, CFErrorRef *error) {
234 xpc_object_t xpc_error = xpc_dictionary_get_value(message, kSecXPCKeyError);
235 if (xpc_error == NULL)
236 return true;
237
238 if (error) {
239 *error = SecCreateCFErrorWithXPCObject(xpc_error);
240 }
241 return false;
242 }
243
244 bool securityd_send_sync_and_do(enum SecXPCOperation op, CFErrorRef *error,
245 bool (^add_to_message)(xpc_object_t message, CFErrorRef* error),
246 bool (^handle_response)(xpc_object_t response, CFErrorRef* error)) {
247 xpc_object_t message = securityd_create_message(op, error);
248 bool ok = false;
249 if (message) {
250 if (!add_to_message || add_to_message(message, error)) {
251 xpc_object_t response = securityd_message_with_reply_sync(message, error);
252 if (response) {
253 if (securityd_message_no_error(response, error)) {
254 ok = (!handle_response || handle_response(response, error));
255 }
256 xpc_release(response);
257 }
258 }
259 xpc_release(message);
260 }
261
262 return ok;
263 }
264
265
266 /* vi:set ts=4 sw=4 et: */