]> git.saurik.com Git - apple/security.git/blob - Security/sec/ipc/client.c
Security-57031.1.35.tar.gz
[apple/security.git] / Security / sec / ipc / client.c
1 /*
2 * Copyright (c) 2007-2009,2012-2014 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
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>
33
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>
41
42 struct securityd *gSecurityd;
43
44 //
45 // MARK: XPC IPC.
46 //
47
48 /* Hardcoded Access Groups for the server itself */
49 static CFArrayRef SecServerCopyAccessGroups(void) {
50 return CFArrayCreateForCFTypes(kCFAllocatorDefault,
51 #if NO_SERVER
52 CFSTR("test"),
53 CFSTR("apple"),
54 CFSTR("lockdown-identities"),
55 #else
56 CFSTR("sync"),
57 #endif
58 CFSTR("com.apple.security.sos"),
59 NULL);
60 }
61
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);
68 });
69 return gSecServerAccessGroups;
70 }
71
72 static xpc_connection_t securityd_create_connection(const char *name) {
73 if (!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);
80 });
81 xpc_connection_resume(connection);
82 return connection;
83 }
84
85 static xpc_connection_t sSecuritydConnection;
86
87 static xpc_connection_t securityd_connection(void) {
88 static dispatch_once_t once;
89 dispatch_once(&once, ^{
90 sSecuritydConnection = securityd_create_connection(NULL);
91 });
92 return sSecuritydConnection;
93 }
94
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();
99
100 xpc_connection_t oldConection = sSecuritydConnection;
101 sSecuritydConnection = securityd_create_connection(name);
102 if (oldConection)
103 xpc_release(oldConection);
104 }
105
106 xpc_object_t
107 securityd_message_with_reply_sync(xpc_object_t message, CFErrorRef *error)
108 {
109 xpc_object_t reply = NULL;
110 xpc_connection_t connection = securityd_connection();
111
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.
113
114 unsigned int tries_left = max_tries;
115 do {
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);
119
120 if (xpc_get_type(reply) == XPC_TYPE_ERROR) {
121 CFIndex code = 0;
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;
127 else
128 code = kSecXPCErrorUnknown;
129
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);
133 free(conn_desc);
134 xpc_release(reply);
135 reply = NULL;
136 }
137
138 return reply;
139 }
140
141 xpc_object_t securityd_create_message(enum SecXPCOperation op, CFErrorRef* error)
142 {
143 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
144 if (message) {
145 xpc_dictionary_set_uint64(message, kSecXPCKeyOperation, op);
146 } else {
147 SecCFCreateError(kSecXPCErrorConnectionFailed, sSecXPCErrorDomain,
148 CFSTR("xpc_dictionary_create returned NULL"), NULL, error);
149 }
150 return message;
151 }
152
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)
157 return true;
158
159 if (error) {
160 *error = SecCreateCFErrorWithXPCObject(xpc_error);
161 }
162 return false;
163 }
164
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);
169 bool ok = false;
170 if (message) {
171 if (!add_to_message || add_to_message(message, error)) {
172 xpc_object_t response = securityd_message_with_reply_sync(message, error);
173 if (response) {
174 if (securityd_message_no_error(response, error)) {
175 ok = (!handle_response || handle_response(response, error));
176 }
177 xpc_release(response);
178 }
179 }
180 xpc_release(message);
181 }
182
183 return ok;
184 }
185
186
187 /* vi:set ts=4 sw=4 et: */