]> git.saurik.com Git - apple/security.git/blob - securityd/securityd_service/securityd_service/securityd_service_client.c
fa8f8a107db8d037f328d5af5cc8a1ca318fdf48
[apple/security.git] / securityd / securityd_service / securityd_service / securityd_service_client.c
1 /* Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. */
2
3 #include "securityd_service.h"
4 #include "securityd_service_client.h"
5 #include <xpc/xpc.h>
6 #include <dispatch/dispatch.h>
7 #include <syslog.h>
8 #include <AssertMacros.h>
9
10 static xpc_connection_t
11 _service_get_connection()
12 {
13 static dispatch_once_t onceToken;
14 static xpc_connection_t connection = NULL;
15
16 dispatch_once(&onceToken, ^{
17 connection = xpc_connection_create_mach_service(SECURITYD_SERVICE_NAME, NULL, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
18 require(connection, done);
19
20 xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
21 if (xpc_get_type(event) == XPC_TYPE_ERROR) {
22 if (event == XPC_ERROR_CONNECTION_INVALID) {
23 syslog(LOG_ERR, "securityd_service not available");
24 }
25 // XPC_ERROR_CONNECTION_INTERRUPTED
26 // XPC_ERROR_TERMINATION_IMMINENT
27 } else {
28 char * desc = xpc_copy_description(event);
29 syslog(LOG_ERR, "securityd_service should never get messages on this connection: %s", desc);
30 free(desc);
31 }
32 });
33
34 xpc_connection_resume(connection);
35 done:
36 return;
37 });
38
39 return connection;
40 }
41
42 static int
43 _service_send_msg(service_context_t *context, xpc_object_t message, xpc_object_t * reply_out)
44 {
45 int rc = KB_GeneralError;
46 xpc_object_t reply = NULL;
47 xpc_connection_t conn = NULL;
48
49 require(message, done);
50 conn = _service_get_connection();
51 require(conn, done);
52
53 if (context) {
54 xpc_dictionary_set_data(message, SERVICE_XPC_CONTEXT, context, sizeof(service_context_t));
55 }
56 reply = xpc_connection_send_message_with_reply_sync(conn, message);
57 require(reply, done);
58 require(xpc_get_type(reply) != XPC_TYPE_ERROR, done);
59
60 rc = (int)xpc_dictionary_get_int64(reply, SERVICE_XPC_RC);
61
62 if (reply_out) {
63 *reply_out = reply;
64 reply = NULL;
65 }
66
67 done:
68 if (reply) xpc_release(reply);
69 return rc;
70 }
71
72 int
73 _service_client_send_uid(service_context_t *context, uint64_t request, uid_t uid)
74 {
75 int rc = KB_GeneralError;
76 xpc_object_t message = NULL;
77
78 message = xpc_dictionary_create(NULL, NULL, 0);
79 require_quiet(message, done);
80
81 xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, request);
82 xpc_dictionary_set_uint64(message, SERVICE_XPC_UID, uid);
83
84 rc = _service_send_msg(context, message, NULL);
85
86 done:
87 if (message) xpc_release(message);
88 return rc;
89 }
90
91
92 int
93 _service_client_send_secret(service_context_t *context, uint64_t request, const void * secret, int secret_len, const void * new_secret, int new_secret_len)
94 {
95 int rc = KB_GeneralError;
96 xpc_object_t message = NULL;
97
98 message = xpc_dictionary_create(NULL, NULL, 0);
99 require_quiet(message, done);
100
101 xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, request);
102 if (secret) {
103 xpc_dictionary_set_data(message, SERVICE_XPC_SECRET, secret, secret_len);
104 }
105
106 if (new_secret) {
107 xpc_dictionary_set_data(message, SERVICE_XPC_SECRET_NEW, new_secret, new_secret_len);
108 }
109
110 rc = _service_send_msg(context, message, NULL);
111
112 done:
113 if (message) xpc_release(message);
114 return rc;
115 }
116
117 int
118 service_client_kb_create(service_context_t *context, const void * secret, int secret_len)
119 {
120 return _service_client_send_secret(context, SERVICE_KB_CREATE, secret, secret_len, NULL, 0);
121 }
122
123 int
124 service_client_kb_load(service_context_t *context)
125 {
126 return _service_client_send_secret(context, SERVICE_KB_LOAD, NULL, 0, NULL, 0);
127 }
128
129 int
130 service_client_kb_load_uid(uid_t uid)
131 {
132 return _service_client_send_uid(NULL, SERVICE_KB_LOAD_UID, uid);
133 }
134
135 int
136 service_client_kb_unload(service_context_t *context)
137 {
138 return _service_client_send_secret(context, SERVICE_KB_UNLOAD, NULL, 0, NULL, 0);
139 }
140
141 int
142 service_client_kb_save(service_context_t *context)
143 {
144 return _service_client_send_secret(context, SERVICE_KB_SAVE, NULL, 0, NULL, 0);
145 }
146
147 int
148 service_client_kb_unlock(service_context_t *context, const void * secret, int secret_len)
149 {
150 return _service_client_send_secret(context, SERVICE_KB_UNLOCK, secret, secret_len, NULL, 0);
151 }
152
153 int
154 service_client_kb_lock(service_context_t *context)
155 {
156 return _service_client_send_secret(context, SERVICE_KB_LOCK, NULL, 0, NULL, 0);
157 }
158
159 int
160 service_client_kb_change_secret(service_context_t *context, const void * secret, int secret_len, const void * new_secret, int new_secret_len)
161 {
162 return _service_client_send_secret(context, SERVICE_KB_CHANGE_SECRET, secret, secret_len, new_secret, new_secret_len);
163 }
164
165 int
166 service_client_kb_reset(service_context_t *context, const void * secret, int secret_len)
167 {
168 return _service_client_send_secret(context, SERVICE_KB_RESET, secret, secret_len, NULL, 0);
169 }
170
171 int service_client_kb_is_locked(service_context_t *context, bool *locked, bool *no_pin)
172 {
173 int rc = KB_GeneralError;
174 xpc_object_t message = NULL;
175 xpc_object_t reply = NULL;
176
177 if (locked) *locked = false;
178 if (no_pin) *no_pin = false;
179
180 message = xpc_dictionary_create(NULL, NULL, 0);
181 require_quiet(message, done);
182
183 xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, SERVICE_KB_IS_LOCKED);
184
185 rc = _service_send_msg(context, message, &reply);
186
187 if (rc == KB_Success) {
188 if (locked) {
189 *locked = xpc_dictionary_get_bool(reply, SERVICE_XPC_LOCKED);
190 }
191 if (no_pin) {
192 *no_pin = xpc_dictionary_get_bool(reply, SERVICE_XPC_NO_PIN);
193 }
194 }
195
196 done:
197 if (message) xpc_release(message);
198 if (reply) xpc_release(reply);
199 return rc;
200 }
201
202 int
203 service_client_kb_wrap_key(service_context_t *context, const void *key, int key_size, keyclass_t key_class, void **wrapped_key, int *wrapped_key_size, keyclass_t *wrapped_key_class)
204 {
205 int rc = KB_GeneralError;
206 xpc_object_t message = NULL;
207 xpc_object_t reply = NULL;
208 const void *data;
209 size_t data_len;
210
211 if (wrapped_key) *wrapped_key = NULL;
212 if (wrapped_key_size) *wrapped_key_size = 0;
213 if (wrapped_key_class) *wrapped_key_class = key_class_none;
214
215 message = xpc_dictionary_create(NULL, NULL, 0);
216 require_quiet(message, done);
217
218 xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, SERVICE_KB_WRAP_KEY);
219 xpc_dictionary_set_data(message, SERVICE_XPC_KEY, key, (size_t)key_size);
220 xpc_dictionary_set_int64(message, SERVICE_XPC_KEYCLASS, key_class);
221
222 rc = _service_send_msg(context, message, &reply);
223 if (rc == KB_Success) {
224 data = xpc_dictionary_get_data(reply, SERVICE_XPC_WRAPPED_KEY, &data_len);
225 if (data) {
226 if (wrapped_key) {
227 *wrapped_key = malloc(data_len);
228 memcpy(*wrapped_key, data, data_len);
229 }
230 if (wrapped_key_size) {
231 *wrapped_key_size = (int)data_len;
232 }
233 }
234
235 if (wrapped_key_class) {
236 *wrapped_key_class = (keyclass_t)xpc_dictionary_get_int64(reply, SERVICE_XPC_KEYCLASS);
237 }
238 }
239
240 done:
241 if (message) xpc_release(message);
242 if (reply) xpc_release(reply);
243 return rc;
244 }
245
246 int
247 service_client_kb_unwrap_key(service_context_t *context, const void *wrapped_key, int wrapped_key_size, keyclass_t wrapped_key_class, void **key, int *key_size)
248 {
249 int rc = KB_GeneralError;
250 xpc_object_t message = NULL;
251 xpc_object_t reply = NULL;
252 const void *data;
253 size_t data_len;
254
255 if (key) *key = NULL;
256 if (key_size) *key_size = 0;
257
258 message = xpc_dictionary_create(NULL, NULL, 0);
259 require_quiet(message, done);
260
261 xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, SERVICE_KB_UNWRAP_KEY);
262 xpc_dictionary_set_data(message, SERVICE_XPC_WRAPPED_KEY, wrapped_key, (size_t)wrapped_key_size);
263 xpc_dictionary_set_int64(message, SERVICE_XPC_KEYCLASS, wrapped_key_class);
264
265 rc = _service_send_msg(context, message, &reply);
266 if (rc == KB_Success) {
267 data = xpc_dictionary_get_data(reply, SERVICE_XPC_KEY, &data_len);
268 if (data) {
269 if (key) {
270 *key = malloc(data_len);
271 memcpy(*key, data, data_len);
272 }
273 if (key_size) {
274 *key_size = (int)data_len;
275 }
276 }
277 }
278
279 done:
280 if (message) xpc_release(message);
281 if (reply) xpc_release(reply);
282 return rc;
283 }
284
285 int
286 service_client_stash_set_key(service_context_t *context, const void * key, int key_len)
287 {
288 int rc = KB_GeneralError;
289 xpc_object_t message = NULL;
290
291 message = xpc_dictionary_create(NULL, NULL, 0);
292 require_quiet(message, done);
293
294 xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, SERVICE_STASH_SET_KEY);
295
296 if (key)
297 xpc_dictionary_set_data(message, SERVICE_XPC_KEY, key, key_len);
298
299 rc = _service_send_msg(context, message, NULL);
300
301 done:
302 if (message) xpc_release(message);
303 return rc;
304 }
305
306 int
307 service_client_stash_load_key(service_context_t *context, const void * key, int key_len)
308 {
309 int rc = KB_GeneralError;
310 xpc_object_t message = NULL;
311
312 message = xpc_dictionary_create(NULL, NULL, 0);
313 require_quiet(message, done);
314
315 xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, SERVICE_STASH_LOAD_KEY);
316
317 if (key)
318 xpc_dictionary_set_data(message, SERVICE_XPC_KEY, key, key_len);
319
320 rc = _service_send_msg(context, message, NULL);
321
322 done:
323 if (message) xpc_release(message);
324 return rc;
325 }
326
327 int
328 service_client_stash_get_key(service_context_t *context, void ** key, int * key_len)
329 {
330 int rc = KB_GeneralError;
331 xpc_object_t message = NULL;
332 xpc_object_t reply = NULL;
333
334 require(key, done);
335 require(key_len, done);
336
337 message = xpc_dictionary_create(NULL, NULL, 0);
338 require_quiet(message, done);
339
340 xpc_dictionary_set_uint64(message, SERVICE_XPC_REQUEST, SERVICE_STASH_GET_KEY);
341
342 rc = _service_send_msg(context, message, &reply);
343
344 if (rc == KB_Success) {
345 size_t data_len = 0;
346 const void * data = xpc_dictionary_get_data(reply, SERVICE_XPC_KEY, &data_len);
347 if (data) {
348 *key = calloc(1u, data_len);
349 memcpy(*key, data, data_len);
350 *key_len = (int)data_len;
351 }
352 }
353
354 done:
355 if (message) xpc_release(message);
356 if (reply) xpc_release(reply);
357 return rc;
358 }