]> git.saurik.com Git - apple/security.git/blob - securityd/securityd_service/securityd_service/main.c
df04c16b7c90055a39ba69e340a2a47aaa18d1ea
[apple/security.git] / securityd / securityd_service / securityd_service / main.c
1 /* Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. */
2
3 #include "securityd_service.h"
4 #include "securityd_service_client.h"
5 #include <libaks.h>
6
7 #include <sandbox.h>
8 #include <vproc.h>
9 #include <xpc/xpc.h>
10 #include <xpc/private.h>
11 #include <dispatch/dispatch.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <sys/codesign.h>
15 #include <stdio.h>
16 #include <errno.h>
17 #include <assert.h>
18 #include <syslog.h>
19 #include <unistd.h>
20 #include <pwd.h>
21 #include <uuid/uuid.h>
22 #include <bsm/libbsm.h>
23 #include <copyfile.h>
24 #include <AssertMacros.h>
25 #include <Security/Security.h>
26 #include <Security/SecTask.h>
27 #include <Security/SecTaskPriv.h>
28 #include <Security/SecKeychainPriv.h>
29
30 #include <IOKit/IOKitLib.h>
31 #include <Kernel/IOKit/crypto/AppleFDEKeyStoreDefs.h>
32
33 #if DEBUG
34 #define LOG(...) syslog(LOG_ERR, ##__VA_ARGS__);
35 #else
36 #define LOG(...)
37 #endif
38
39 static bool check_signature(xpc_connection_t connection);
40
41 static pid_t get_caller_pid(audit_token_t * token)
42 {
43 pid_t pid = 0;
44 if (token) {
45 audit_token_to_au32(*token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL);
46 }
47 return pid;
48 }
49
50 // exported from libaks.a
51 kern_return_t aks_register_for_notifications(mach_port_t server_port, uintptr_t message_id);
52 kern_return_t aks_stash_escrow(keybag_handle_t handle, bool create, const void * secret, int secret_len, const void * in_data, int in_data_len, void ** out_data, int * out_data_len);
53
54 const char * kb_home_path = "Library/Keychains";
55 const char * kb_user_bag = "user.kb";
56 const char * kb_stash_bag = "stash.kb";
57
58 #define HEXBUF_LEN 2048
59
60 typedef struct {
61 uid_t uid;
62 gid_t gid;
63 char * name;
64 char * home;
65 } service_user_record_t;
66
67 typedef enum {
68 kb_bag_type_user,
69 kb_bag_type_stash
70 } kb_bag_type_t;
71
72 static io_connect_t
73 openiodev(void)
74 {
75 io_registry_entry_t service;
76 io_connect_t conn;
77 kern_return_t kr;
78
79 service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(kAppleFDEKeyStoreServiceName));
80 if (service == IO_OBJECT_NULL)
81 return IO_OBJECT_NULL;
82
83 kr = IOServiceOpen(service, mach_task_self(), 0, &conn);
84 if (kr != KERN_SUCCESS)
85 return IO_OBJECT_NULL;
86
87 kr = IOConnectCallMethod(conn, kAppleFDEKeyStoreUserClientOpen, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL);
88 if (kr != KERN_SUCCESS) {
89 IOServiceClose(conn);
90 return IO_OBJECT_NULL;
91 }
92
93 return conn;
94 }
95
96 static void
97 closeiodev(io_connect_t conn)
98 {
99 kern_return_t kr;
100 kr = IOConnectCallMethod(conn, kAppleFDEKeyStoreUserClientClose, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL);
101 if (kr != KERN_SUCCESS)
102 return;
103 IOServiceClose(conn);
104 }
105
106 static dispatch_queue_t
107 _kb_service_get_dispatch_queue()
108 {
109 static dispatch_once_t onceToken = 0;
110 static dispatch_queue_t connection_queue = NULL;
111
112 dispatch_once(&onceToken, ^{
113 connection_queue = dispatch_queue_create("kb-service-queue", DISPATCH_QUEUE_SERIAL);
114 });
115
116 return connection_queue;
117 }
118
119 static service_user_record_t * get_user_record(uid_t uid)
120 {
121 service_user_record_t * ur = NULL;
122 long bufsize = 0;
123 if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) {
124 bufsize = 4096;
125 }
126 char buf[bufsize];
127 struct passwd pwbuf, *pw = NULL;
128 if ((getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0) && pw != NULL) {
129 ur = calloc(1u, sizeof(service_user_record_t));
130 require(ur, done);
131 ur->uid = pw->pw_uid;
132 ur->gid = pw->pw_gid;
133 ur->home = strdup(pw->pw_dir);
134 ur->name = strdup(pw->pw_name);
135 } else {
136 syslog(LOG_ERR, "failed to lookup user record for uid: %d", uid);
137 }
138
139 done:
140 return ur;
141 }
142
143 static void free_user_record(service_user_record_t * ur)
144 {
145 if (ur != NULL) {
146 if (ur->home) {
147 free(ur->home);
148 }
149 if (ur->name) {
150 free(ur->name);
151 }
152 free(ur);
153 }
154 }
155
156 static const char * get_host_uuid()
157 {
158 static uuid_string_t hostuuid = {};
159 static dispatch_once_t onceToken;
160 dispatch_once(&onceToken, ^{
161 struct timespec timeout = {30, 0};
162 uuid_t uuid = {};
163 if (gethostuuid(uuid, &timeout) == 0) {
164 uuid_unparse(uuid, hostuuid);
165 } else {
166 syslog(LOG_ERR, "failed to get host uuid");
167 }
168 });
169
170 return hostuuid;
171 }
172
173 static char *
174 _kb_copy_bag_filename(service_user_record_t * ur, kb_bag_type_t type)
175 {
176 char * bag_file = NULL;
177 const char * name = NULL;
178
179 require(ur, done);
180 switch(type) {
181 case kb_bag_type_user:
182 name = kb_user_bag;
183 break;
184 case kb_bag_type_stash:
185 name = kb_stash_bag;
186 break;
187 default:
188 goto done;
189 }
190
191 bag_file = calloc(1u, PATH_MAX);
192 require(bag_file, done);
193
194 snprintf(bag_file, PATH_MAX, "%s/%s/%s/%s", ur->home, kb_home_path, get_host_uuid(), name);
195
196 done:
197 return bag_file;
198 }
199
200 static bool
201 _kb_verify_create_path(service_user_record_t * ur)
202 {
203 bool created = false;
204 struct stat st_info = {};
205 char new_path[PATH_MAX] = {};
206 char kb_path[PATH_MAX] = {};
207 snprintf(kb_path, sizeof(kb_path), "%s/%s/%s", ur->home, kb_home_path, get_host_uuid());
208 if (lstat(kb_path, &st_info) == 0) {
209 if (S_ISDIR(st_info.st_mode)) {
210 created = true;
211 } else {
212 syslog(LOG_ERR, "invalid directory at '%s' moving aside", kb_path);
213 snprintf(new_path, sizeof(new_path), "%s-invalid", kb_path);
214 unlink(new_path);
215 if (rename(kb_path, new_path) != 0) {
216 syslog(LOG_ERR, "failed to rename file: %s (%s)", kb_path, strerror(errno));
217 goto done;
218 }
219 }
220 }
221 if (!created) {
222 require_action(mkpath_np(kb_path, 0700) == 0, done, syslog(LOG_ERR, "could not create path: %s (%s)", kb_path, strerror(errno)));
223 created = true;
224 }
225
226 done:
227 return created;
228 }
229
230 static void
231 _set_thread_credentials(service_user_record_t * ur)
232 {
233 int rc = pthread_setugid_np(ur->uid, ur->gid);
234 if (rc) { syslog(LOG_ERR, "failed to set thread credential: %i (%s)", errno, strerror(errno)); }
235
236 rc = initgroups(ur->name, ur->gid);
237 if (rc) { syslog(LOG_ERR, "failed to initgroups: %i", rc); }
238 }
239
240 static void
241 _clear_thread_credentials()
242 {
243 int rc = pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE);
244 if (rc) { syslog(LOG_ERR, "failed to reset thread credential: %i (%s)", errno, strerror(errno)); }
245 }
246
247 static bool
248 _kb_bag_exists(service_user_record_t * ur, const char * bag_file)
249 {
250 bool exists = false;
251 struct stat st_info = {};
252 char new_file[PATH_MAX] = {};
253
254 require(ur, done);
255
256 _set_thread_credentials(ur);
257 if (lstat(bag_file, &st_info) == 0) {
258 if (S_ISREG(st_info.st_mode)) {
259 exists = true;
260 } else {
261 syslog(LOG_ERR, "invalid file at '%s' moving aside", bag_file);
262 snprintf(new_file, sizeof(new_file), "%s-invalid", bag_file);
263 unlink(new_file);
264 if (rename(bag_file, new_file) != 0) {
265 syslog(LOG_ERR, "failed to rename file: %s (%s)", bag_file, strerror(errno));
266 }
267 }
268 }
269
270 done:
271 _clear_thread_credentials();
272 return exists;
273 }
274
275 static bool
276 _kb_save_bag_to_disk(service_user_record_t * ur, const char * bag_file, void * data, size_t length)
277 {
278 bool result = false;
279 int fd = -1;
280
281 require(bag_file, done);
282
283 _set_thread_credentials(ur);
284 require(_kb_verify_create_path(ur), done);
285
286 fd = open(bag_file, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0600);
287 require_action(fd != -1, done, syslog(LOG_ERR, "could not create file: %s (%s)", bag_file, strerror(errno)));
288 require_action(write(fd, data, length) != -1, done, syslog(LOG_ERR, "failed to write keybag to disk %s", strerror(errno)));
289
290 result = true;
291
292 done:
293 if (fd != -1) { close(fd); }
294 _clear_thread_credentials();
295 return result;
296 }
297
298 static bool
299 _kb_load_bag_from_disk(service_user_record_t * ur, const char * bag_file, uint8_t ** data, size_t * length)
300 {
301 bool result = false;
302 int fd = -1;
303 uint8_t * buf = NULL;
304 size_t buf_size = 0;
305 struct stat st_info = {};
306
307 require(bag_file, done);
308
309 _set_thread_credentials(ur);
310 require(_kb_verify_create_path(ur), done);
311 require_quiet(lstat(bag_file, &st_info) == 0, done);
312 require_action(S_ISREG(st_info.st_mode), done, syslog(LOG_ERR, "failed to load, not a file: %s", bag_file));
313 buf_size = (size_t)st_info.st_size;
314
315 fd = open(bag_file, O_RDONLY | O_NOFOLLOW);
316 require_action(fd != -1, done, syslog(LOG_ERR, "could not open file: %s (%s)", bag_file, strerror(errno)));
317
318 buf = (uint8_t *)calloc(1u, buf_size);
319 require(buf != NULL, done);
320 require(read(fd, buf, buf_size) == buf_size, done);
321
322 *data = buf;
323 *length = buf_size;
324 buf = NULL;
325 result = true;
326
327 done:
328 if (fd != -1) { close(fd); }
329 if (buf) { free(buf); }
330 _clear_thread_credentials();
331 return result;
332 }
333
334 static void
335 _kb_rename_bag_on_disk(service_user_record_t * ur, const char * bag_file)
336 {
337 char new_file[PATH_MAX] = {};
338 if (bag_file) {
339 _set_thread_credentials(ur);
340 snprintf(new_file, sizeof(new_file), "%s-invalid", bag_file);
341 unlink(new_file);
342 rename(bag_file, new_file);
343 _clear_thread_credentials();
344 }
345 }
346
347 static void
348 _kb_delete_bag_on_disk(service_user_record_t * ur, const char * bag_file)
349 {
350 if (bag_file) {
351 _set_thread_credentials(ur);
352 unlink(bag_file);
353 _clear_thread_credentials();
354 }
355 }
356
357 static int
358 _kb_get_session_handle(service_context_t * context, keybag_handle_t * handle_out)
359 {
360 int rc = KB_BagNotLoaded;
361 keybag_handle_t session_handle = bad_keybag_handle;
362 require_noerr_quiet(aks_get_system(context->s_uid, &session_handle), done);
363
364 *handle_out = session_handle;
365 rc = KB_Success;
366
367 done:
368 return rc;
369 }
370
371 static void update_keybag_handle(keybag_handle_t handle)
372 {
373 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
374 uid_t uid = abs(handle);
375 uint8_t * buf = NULL;
376 size_t buf_size = 0;
377 service_user_record_t * ur = NULL;
378 char * bag_file = NULL;
379
380 require_noerr(aks_save_bag(handle, (void**)&buf, (int*)&buf_size), done);
381 require(ur = get_user_record(uid), done);
382 require(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done);
383 require(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done);
384
385 syslog(LOG_NOTICE, "successfully updated handle %d", handle);
386
387 done:
388 if (buf) free(buf);
389 if (ur) free_user_record(ur);
390 if (bag_file) free(bag_file);
391 });
392 }
393
394 static int
395 service_kb_create(service_context_t * context, const void * secret, int secret_len)
396 {
397 __block int rc = KB_GeneralError;
398
399 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
400 uint8_t * buf = NULL;
401 size_t buf_size = 0;
402 keybag_handle_t session_handle = bad_keybag_handle;
403 service_user_record_t * ur = get_user_record(context->s_uid);
404 char * bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user);
405
406 require(bag_file, done);
407
408 // check for the existance of the bagfile
409 require_action(!_kb_bag_exists(ur, bag_file), done, rc = KB_BagExists);
410
411 require_noerr(rc = aks_create_bag(secret, secret_len, kAppleKeyStoreDeviceBag, &session_handle), done);
412 require_noerr(rc = aks_save_bag(session_handle, (void**)&buf, (int*)&buf_size), done);
413 require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done, rc = KB_BagError);
414 require_noerr(rc = aks_set_system(session_handle, context->s_uid), done);
415 aks_unload_bag(session_handle);
416 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
417
418 if (secret && rc == KB_Success) {
419 aks_unlock_bag(session_handle, secret, secret_len);
420 }
421
422 done:
423 if (buf) free(buf);
424 if (bag_file) { free(bag_file); }
425 if (ur) free_user_record(ur);
426 });
427
428 return rc;
429 }
430
431 static int
432 service_kb_load(service_context_t * context)
433 {
434 __block int rc = KB_GeneralError;
435
436 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
437 uint8_t * buf = NULL;
438 size_t buf_size = 0;
439 keybag_handle_t session_handle = bad_keybag_handle;
440 service_user_record_t * ur = NULL;
441 char * bag_file = NULL;
442
443 rc = aks_get_system(context->s_uid, &session_handle);
444 if (rc == kIOReturnNotFound) {
445 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
446 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError);
447 require_action_quiet(_kb_load_bag_from_disk(ur, bag_file, &buf, &buf_size), done, rc = KB_BagNotFound);
448 rc = aks_load_bag(buf, (int)buf_size, &session_handle);
449 if (rc == kIOReturnNotPermitted) {
450 syslog(LOG_ERR, "error loading keybag for uid (%i) in session (%i)", context->s_uid, context->s_id);
451 _kb_rename_bag_on_disk(ur, bag_file);
452 rc = KB_BagNotFound;
453 }
454 require_noerr(rc, done);
455 require_noerr(rc = aks_set_system(session_handle, context->s_uid), done);
456 aks_unload_bag(session_handle);
457 }
458 require(rc == KB_Success, done);
459
460 done:
461 if (buf) free(buf);
462 if (ur) free_user_record(ur);
463 if (bag_file) free(bag_file);
464 });
465
466 return rc;
467 }
468
469 static int
470 service_kb_unload(service_context_t *context)
471 {
472 __block int rc = KB_GeneralError;
473
474 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
475 keybag_handle_t session_handle = bad_keybag_handle;
476
477 rc = aks_get_system(context->s_uid, &session_handle);
478 if (rc == kIOReturnNotFound) {
479 // No session bag, nothing to do
480 rc = KB_Success;
481 return;
482 } else if (rc != kIOReturnSuccess) {
483 syslog(LOG_ERR, "error locating session keybag for uid (%i) in session (%i)", context->s_uid, context->s_id);
484 rc = KB_BagError;
485 return;
486 }
487
488 rc = aks_unload_bag(session_handle);
489 if (rc != kAKSReturnSuccess) {
490 syslog(LOG_ERR, "error unloading keybag for uid (%i) in session (%i)", context->s_uid, context->s_id);
491 rc = KB_BagError;
492 } else {
493 syslog(LOG_ERR, "successfully unloaded keybag (%ld) for uid (%i) in session (%i)", (long)session_handle, context->s_uid, context->s_id);
494 }
495 });
496
497 return rc;
498 }
499
500 static int
501 service_kb_save(service_context_t * context)
502 {
503 __block int rc = KB_GeneralError;
504 keybag_handle_t session_handle;
505 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
506
507 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
508 uint8_t * buf = NULL;
509 size_t buf_size = 0;
510 service_user_record_t * ur = NULL;
511 char * bag_file = NULL;
512
513 require_noerr(rc = aks_save_bag(session_handle, (void**)&buf, (int*)&buf_size), done);
514 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
515 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError);
516 require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done, rc = KB_BagError);
517
518 rc = KB_Success;
519
520 done:
521 if (buf) free(buf);
522 if (ur) free_user_record(ur);
523 if (bag_file) free(bag_file);
524 return;
525 });
526
527 done:
528 return rc;
529 }
530
531 static int
532 service_kb_unlock(service_context_t * context, const void * secret, int secret_len)
533 {
534 int rc = KB_GeneralError;
535 keybag_handle_t session_handle;
536 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
537
538 rc = aks_unlock_bag(session_handle, secret, secret_len);
539
540 done:
541 return rc;
542 }
543
544 static int
545 service_kb_lock(service_context_t * context)
546 {
547 // this call has been disabled
548 return -1;
549 }
550
551 static int
552 service_kb_change_secret(service_context_t * context, const void * secret, int secret_len, const void * new_secret, int new_secret_len)
553 {
554 __block int rc = KB_GeneralError;
555 keybag_handle_t session_handle;
556 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
557
558 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
559 uint8_t * buf = NULL;
560 size_t buf_size = 0;
561 service_user_record_t * ur = NULL;
562 char * bag_file = NULL;
563
564 require_noerr(rc = aks_change_secret(session_handle, secret, secret_len, new_secret, new_secret_len, NULL, NULL), done);
565 require_noerr(rc = aks_save_bag(session_handle, (void**)&buf, (int*)&buf_size), done);
566 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
567 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError);
568 require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done, rc = KB_BagError);
569
570 rc = KB_Success;
571
572 done:
573 if (buf) free(buf);
574 if (ur) free_user_record(ur);
575 if (bag_file) free(bag_file);
576 return;
577 });
578
579 done:
580 return rc;
581 }
582
583 static int
584 service_kb_reset(service_context_t * context, const void * secret, int secret_len)
585 {
586 __block int rc = KB_GeneralError;
587 service_user_record_t * ur = NULL;
588 char * bag_file = NULL;
589
590 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
591 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError);
592
593 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
594 uint8_t * buf = NULL;
595 size_t buf_size = 0;
596 keybag_handle_t session_handle = bad_keybag_handle;
597
598 syslog(LOG_ERR, "resetting keybag for uid (%i) in session (%i)", context->s_uid, context->s_id);
599 _kb_rename_bag_on_disk(ur, bag_file);
600
601 require_noerr(rc = aks_create_bag(secret, secret_len, kAppleKeyStoreDeviceBag, &session_handle), done);
602 require_noerr(rc = aks_save_bag(session_handle, (void**)&buf, (int*)&buf_size), done);
603 require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done, rc = KB_BagError);
604 require_noerr(rc = aks_set_system(session_handle, context->s_uid), done);
605 aks_unload_bag(session_handle);
606 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
607
608 if (secret && rc == KB_Success) {
609 aks_unlock_bag(session_handle, secret, secret_len);
610 }
611
612 done:
613 if (buf) free(buf);
614 return;
615 });
616
617 done:
618 if (ur) free_user_record(ur);
619 if (bag_file) free(bag_file);
620 return rc;
621 }
622
623 static int
624 service_kb_is_locked(service_context_t * context, xpc_object_t reply)
625 {
626 int rc = KB_GeneralError;
627 keybag_state_t state;
628 keybag_handle_t session_handle;
629 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
630
631 require_noerr(rc = aks_get_lock_state(session_handle, &state), done);
632
633 xpc_dictionary_set_bool(reply, SERVICE_XPC_LOCKED, state & keybag_state_locked);
634 xpc_dictionary_set_bool(reply, SERVICE_XPC_NO_PIN, state & keybag_state_no_pin);
635
636 done:
637 return rc;
638 }
639
640 static int
641 service_kb_stash_create(service_context_t * context, const void * key, unsigned key_size)
642 {
643 int rc = KB_GeneralError;
644 char * bag_file = NULL;
645 keybag_handle_t session_handle;
646 service_user_record_t * ur = NULL;
647 void * stashbag = NULL;
648 int stashbag_size = 0;
649 __block bool saved = false;
650
651 require(key, done);
652 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
653 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
654 require_noerr(rc = aks_stash_escrow(session_handle, true, key, key_size, NULL, 0, (void**)&stashbag, &stashbag_size), done);
655 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_stash), done, rc = KB_GeneralError);
656
657 // sync writing the bag to disk
658 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
659 saved = _kb_save_bag_to_disk(ur, bag_file, stashbag, stashbag_size);
660 });
661 require_action(saved, done, rc = KB_BagError);
662 rc = KB_Success;
663
664 done:
665 if (stashbag) { free(stashbag); }
666 if (bag_file) { free(bag_file); }
667 if (ur) free_user_record(ur);
668 return rc;
669 }
670
671 static int
672 service_kb_stash_load(service_context_t * context, const void * key, unsigned key_size, bool nondestructive)
673 {
674 __block int rc = KB_GeneralError;
675 char * bag_file = NULL;
676 keybag_handle_t session_handle;
677 service_user_record_t * ur = NULL;
678 __block uint8_t * stashbag = NULL;
679 __block size_t stashbag_size = 0;
680
681 require(key, done);
682 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
683 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
684 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_stash), done, rc = KB_GeneralError);
685
686 // sync loading the bag from disk
687 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
688 if (!_kb_load_bag_from_disk(ur, bag_file, &stashbag, &stashbag_size)) {
689 rc = KB_BagError;
690 }
691 });
692 require_noerr(rc, done);
693
694 require_noerr(rc = aks_stash_escrow(session_handle, false, key, key_size, stashbag, (int)stashbag_size, NULL, NULL), done);
695 rc = KB_Success;
696
697 done:
698 if (stashbag) { free(stashbag); }
699 if ((bag_file) && (!nondestructive)) {
700 _kb_delete_bag_on_disk(ur, bag_file);
701 free(bag_file);
702 }
703 if (ur) free_user_record(ur);
704 return rc;
705 }
706
707 //
708 // Get the keychain master key from the AppleFDEKeyStore.
709 // Note that this is a one-time call - the master key is
710 // removed from the keystore after it is returned.
711 // Requires the entitlement: com.apple.private.securityd.keychain
712 //
713 OSStatus service_stash_get_key(service_context_t * context, xpc_object_t event, xpc_object_t reply)
714 {
715 getStashKey_InStruct_t inStruct;
716 getStashKey_OutStruct_t outStruct;
717 size_t outSize = sizeof(outStruct);
718 kern_return_t kr = KERN_INVALID_ARGUMENT;
719
720 io_connect_t conn = openiodev();
721 require(conn, done);
722 inStruct.type = kAppleFDEKeyStoreStash_master;
723
724 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_getStashKey,
725 NULL, 0,
726 &inStruct, sizeof(inStruct),
727 NULL, NULL,
728 &outStruct, &outSize);
729
730 if (kr == KERN_SUCCESS) {
731 xpc_dictionary_set_data(reply, SERVICE_XPC_KEY, outStruct.outBuf.key.key, outStruct.outBuf.key.keysize);
732 service_kb_stash_load(context, outStruct.outBuf.key.key, outStruct.outBuf.key.keysize, false);
733 }
734
735 done:
736 if (conn)
737 closeiodev(conn);
738
739 return kr;
740 }
741
742 //
743 // Stash the keychain master key in the AppleFDEKeyStore and
744 // flag it as the keychain master key to be added to the
745 // reboot NVRAM blob.
746 // This requires two calls to the AKS: the first to store the
747 // key and get its uuid. The second uses the uuid to flag the
748 // key for blob inclusion.
749 //
750 OSStatus service_stash_set_key(service_context_t * context, xpc_object_t event, xpc_object_t reply)
751 {
752 kern_return_t kr = KERN_INVALID_ARGUMENT;
753 io_connect_t conn = IO_OBJECT_NULL;
754 size_t keydata_len = 0;
755 size_t len;
756
757 keybag_state_t state;
758 keybag_handle_t session_handle;
759 require_noerr(_kb_get_session_handle(context, &session_handle), done);
760 require_noerr(aks_get_lock_state(session_handle, &state), done);
761 require_action(!(state & keybag_lock_locked), done, kr = CSSMERR_CSP_OS_ACCESS_DENIED; LOG("stash failed keybag locked"));
762
763 conn = openiodev();
764 require(conn, done);
765
766 // Store the key in the keystore and get its uuid
767 setKeyGetUUID_InStruct_t inStruct1;
768 uuid_OutStruct_t outStruct1;
769
770
771 const uint8_t *keydata = xpc_dictionary_get_data(event, SERVICE_XPC_KEY, &keydata_len);
772 require(keydata, done);
773
774 memcpy(&inStruct1.inKey.key.key, keydata, keydata_len);
775 inStruct1.inKey.key.keysize = (cryptosize_t) keydata_len;
776 len = sizeof(outStruct1);
777 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_setKeyGetUUID,
778 NULL, 0,
779 &inStruct1, sizeof(inStruct1),
780 NULL, NULL,
781 &outStruct1, &len);
782 require(kr == KERN_SUCCESS, done);
783
784 // Now using the uuid stash it as the master key
785 setStashKey_InStruct_t inStruct2;
786 memcpy(&inStruct2.uuid, &outStruct1.uuid, sizeof(outStruct1.uuid));
787 inStruct2.type = kAppleFDEKeyStoreStash_master;
788
789 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_setStashKey,
790 NULL, 0,
791 &inStruct2, sizeof(inStruct2),
792 NULL, NULL,
793 NULL, NULL);
794
795 if (kr == KERN_SUCCESS) {
796 service_kb_stash_create(context, keydata, (unsigned)keydata_len);
797 }
798 done:
799 if (conn)
800 closeiodev(conn);
801
802 return kr;
803 }
804
805 //
806 // Load the master stash key
807 //
808 OSStatus service_stash_load_key(service_context_t * context, xpc_object_t event, xpc_object_t reply)
809 {
810 kern_return_t kr = KERN_SUCCESS;
811 size_t keydata_len = 0;
812
813 const uint8_t *keydata = xpc_dictionary_get_data(event, SERVICE_XPC_KEY, &keydata_len);
814 require(keydata, done);
815
816 kr = service_kb_stash_load(context, keydata, (cryptosize_t) keydata_len, true);
817 done:
818
819 return kr;
820 }
821
822 //
823 // Signal the AppleFDEKeyStore to take the tagged FDE key
824 // and keychain master key, stash them in an encrypted
825 // blob structure and write the blob to NVRAM. The random
826 // encryption key is written to the SMC.
827 //
828 #if DEBUG
829 OSStatus service_stash_blob(xpc_object_t event, xpc_object_t reply)
830 {
831 kern_return_t kr = KERN_INVALID_ARGUMENT;
832
833 io_connect_t conn = openiodev();
834 require(conn, done);
835
836 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_commitStash,
837 NULL, 0,
838 NULL, 0,
839 NULL, NULL,
840 NULL, NULL);
841 done:
842 if (conn)
843 closeiodev(conn);
844
845 return kr;
846 }
847 #endif
848
849 bool peer_has_entitlement(xpc_connection_t peer, const char * entitlement)
850 {
851 bool entitled = false;
852
853 xpc_object_t value = xpc_connection_copy_entitlement_value(peer, entitlement);
854 if (value && (xpc_get_type(value) == XPC_TYPE_BOOL)) {
855 entitled = xpc_bool_get_value(value);
856 }
857
858 if (value) xpc_release(value);
859 return entitled;
860 }
861
862 static char * sel_to_char(uint64_t sel)
863 {
864 switch (sel) {
865 case SERVICE_STASH_SET_KEY:
866 return "set_key";
867 case SERVICE_STASH_GET_KEY:
868 return "get_key";
869 case SERVICE_STASH_BLOB:
870 return "stash_blob";
871 case SERVICE_KB_LOAD:
872 return "kb_load";
873 case SERVICE_KB_SAVE:
874 return "kb_save";
875 case SERVICE_KB_UNLOCK:
876 return "kb_unlock";
877 case SERVICE_KB_LOCK:
878 return "kb_lock";
879 case SERVICE_KB_CHANGE_SECRET:
880 return "kb_change_secret";
881 case SERVICE_KB_CREATE:
882 return "kb_create";
883 case SERVICE_KB_IS_LOCKED:
884 return "kb_is_locked";
885 case SERVICE_KB_RESET:
886 return "kb_reset";
887 case SERVICE_KB_UNLOAD:
888 return "kb_unload";
889 default:
890 return "unknown";
891 }
892 }
893
894 static char * err_to_char(int err)
895 {
896 switch (err) {
897 case KB_Success:
898 return "success";
899 case KB_GeneralError:
900 return "general error";
901 case KB_BagNotFound:
902 return "bag not found";
903 case KB_BagError:
904 return "bag error";
905 case KB_BagNotLoaded:
906 return "bag not loaded";
907 case KB_BagExists:
908 return "bag exists";
909 case KB_InvalidSession:
910 return "invalid session";
911 default:
912 return "";
913 }
914 }
915
916 void service_peer_event_handler(xpc_connection_t connection, xpc_object_t event)
917 {
918 xpc_type_t type = xpc_get_type(event);
919
920 if (type == XPC_TYPE_ERROR) {
921 if (event == XPC_ERROR_CONNECTION_INVALID) {
922 }
923 } else {
924 assert(type == XPC_TYPE_DICTIONARY);
925
926 int rc = KB_GeneralError;
927 uint64_t request = 0;
928 const uint8_t * secret = NULL, * new_secret = NULL;
929 size_t secret_len = 0, new_secret_len = 0, data_len = 0;
930 service_context_t * context = NULL;
931 bool free_context = false;
932 const void * data;
933
934 xpc_object_t reply = xpc_dictionary_create_reply(event);
935
936 request = xpc_dictionary_get_uint64(event, SERVICE_XPC_REQUEST);
937
938 // For SERVICE_KB_UNLOAD only, allow non-securityd, non-root but
939 // entitled callers.
940 if (request == SERVICE_KB_UNLOAD) {
941 if (!peer_has_entitlement(connection, "com.apple.private.securityd.keybag-unload")) {
942 xpc_connection_cancel(connection);
943 return;
944 }
945 } else {
946 if (xpc_connection_get_euid(connection) != 0) {
947 xpc_connection_cancel(connection);
948 return;
949 }
950 if (!check_signature(connection)) {
951 xpc_connection_cancel(connection);
952 return;
953 }
954 }
955
956 data = xpc_dictionary_get_data(event, SERVICE_XPC_CONTEXT, &data_len);
957 require_action(data || request == SERVICE_KB_UNLOAD, done, rc = KB_GeneralError);
958 if (data) {
959 require(data_len == sizeof(service_context_t), done);
960 context = (service_context_t*)data;
961 } else {
962 audit_token_t audit_token = { 0 };
963 xpc_connection_get_audit_token(connection, &audit_token);
964 context = calloc(1, sizeof(service_context_t));
965 context->s_id = xpc_connection_get_asid(connection);
966 context->s_uid = xpc_connection_get_euid(connection);
967 context->procToken = audit_token;
968 free_context = true;
969 }
970
971 require_action(context->s_id != AU_DEFAUDITSID, done, rc = KB_InvalidSession);
972 require_action(context->s_uid != AU_DEFAUDITID, done, rc = KB_InvalidSession); // we only want to work in actual user sessions.
973
974 switch (request) {
975 case SERVICE_KB_CREATE:
976 // if (kb_service_has_entitlement(peer, "com.apple.keystore.device")) {
977 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
978 rc = service_kb_create(context, secret, (int)secret_len);
979 // }
980 break;
981 case SERVICE_KB_LOAD:
982 rc = service_kb_load(context);
983 break;
984 case SERVICE_KB_UNLOAD:
985 rc = service_kb_unload(context);
986 break;
987 case SERVICE_KB_SAVE:
988 rc = service_kb_save(context);
989 break;
990 case SERVICE_KB_UNLOCK:
991 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
992 rc = service_kb_unlock(context, secret, (int)secret_len);
993 break;
994 case SERVICE_KB_LOCK:
995 rc = service_kb_lock(context);
996 break;
997 case SERVICE_KB_CHANGE_SECRET:
998 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
999 new_secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET_NEW, &new_secret_len);
1000 rc = service_kb_change_secret(context, secret, (int)secret_len, new_secret, (int)new_secret_len);
1001 break;
1002 case SERVICE_KB_RESET:
1003 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
1004 rc = service_kb_reset(context, secret, (int)secret_len);
1005 break;
1006 case SERVICE_KB_IS_LOCKED:
1007 rc = service_kb_is_locked(context, reply);
1008 break;
1009 case SERVICE_STASH_GET_KEY:
1010 rc = service_stash_get_key(context, event, reply);
1011 break;
1012 case SERVICE_STASH_SET_KEY:
1013 rc = service_stash_set_key(context, event, reply);
1014 break;
1015 case SERVICE_STASH_LOAD_KEY:
1016 rc = service_stash_load_key(context, event, reply);
1017 break;
1018 #if DEBUG
1019 case SERVICE_STASH_BLOB:
1020 rc = service_stash_blob(event, reply);
1021 break;
1022 #endif
1023 default:
1024 LOG("unknown service type");
1025 break;
1026 }
1027
1028 done:
1029 #if DEBUG
1030 LOG("selector: %s (%llu), error: %s (%x), sid: %d, suid: %d, pid: %d", sel_to_char(request), request, err_to_char(rc), rc, context ? context->s_id : 0, context ? context->s_uid : 0, context ? get_caller_pid(&context->procToken) : 0);
1031 #else
1032 if (rc != 0) {
1033 syslog(LOG_NOTICE, "selector: %s (%llu), error: %s (%x), sid: %d, suid: %d, pid: %d", sel_to_char(request), request, err_to_char(rc), rc, context ? context->s_id : 0, context ? context->s_uid : 0, context ? get_caller_pid(&context->procToken) : 0);
1034 }
1035 #endif
1036 xpc_dictionary_set_int64(reply, SERVICE_XPC_RC, rc);
1037 xpc_connection_send_message(connection, reply);
1038 xpc_release(reply);
1039 if (free_context) {
1040 free(context);
1041 }
1042 }
1043 }
1044
1045 bool check_signature(xpc_connection_t connection)
1046 {
1047 #if !(DEBUG || RC_BUILDIT_YES)
1048 audit_token_t token;
1049
1050 xpc_connection_get_audit_token(connection, &token);
1051
1052 SecTaskRef task = SecTaskCreateWithAuditToken(NULL, token);
1053 if (task == NULL) {
1054 syslog(LOG_NOTICE, "failed getting SecTaskRef of the client");
1055 return false;
1056 }
1057
1058 uint32_t flags = SecTaskGetCodeSignStatus(task);
1059 /* check if valid and platform binary, but not platform path */
1060 if ((flags & (CS_VALID | CS_PLATFORM_BINARY | CS_PLATFORM_PATH)) != (CS_VALID | CS_PLATFORM_BINARY)) {
1061 syslog(LOG_NOTICE, "client is not a platform binary: %0x08x", flags);
1062 CFRelease(task);
1063 return false;
1064 }
1065
1066 CFStringRef signingIdentity = SecTaskCopySigningIdentifier(task, NULL);
1067 CFRelease(task);
1068 if (signingIdentity == NULL) {
1069 syslog(LOG_NOTICE, "client have no code sign identity");
1070 return false;
1071 }
1072
1073 bool res = CFEqual(signingIdentity, CFSTR("com.apple.securityd"));
1074 CFRelease(signingIdentity);
1075
1076 if (!res)
1077 syslog(LOG_NOTICE, "client is not not securityd");
1078
1079 return res;
1080 #else
1081 return true;
1082 #endif
1083 }
1084
1085 static void register_for_notifications()
1086 {
1087 __block kern_return_t kr;
1088 static mach_port_t mp = MACH_PORT_NULL;
1089
1090 static dispatch_once_t onceToken = 0;
1091 dispatch_once(&onceToken, ^{
1092 kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
1093 if (kr == KERN_SUCCESS) {
1094 dispatch_source_t mach_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
1095 dispatch_source_set_event_handler(mach_src, ^{
1096 mach_msg_return_t mr;
1097 uint8_t buf[sizeof(aks_notification_msg_t) + MAX_TRAILER_SIZE] = {};
1098 aks_notification_msg_t * msg = (aks_notification_msg_t*)buf;
1099 mr = mach_msg((mach_msg_header_t*)&buf, MACH_RCV_MSG, 0, sizeof(buf), mp, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
1100 if (mr == MACH_MSG_SUCCESS && msg->hdr.msgh_id == AKS_NOTIFICATION_MSGID) {
1101 // ignored for now
1102 } else if (mr == MACH_MSG_SUCCESS && msg->hdr.msgh_id == AKS_NOTIFICATION_WRITE_SYSTEM_KEYBAG) {
1103 syslog(LOG_NOTICE, "request to update handle %d", msg->handle);
1104 update_keybag_handle(msg->handle);
1105 } else {
1106 syslog(LOG_ERR, "mach_msg error: %x", mr);
1107 }
1108 });
1109 dispatch_resume(mach_src);
1110 } else {
1111 syslog(LOG_NOTICE, "failed to create notification port");
1112 }
1113
1114 });
1115
1116 kr = aks_register_for_notifications(mp, AKS_NOTIFICATION_WRITE_SYSTEM_KEYBAG);
1117 if (kr == KERN_SUCCESS) {
1118 syslog(LOG_NOTICE, "registered for notifications");
1119 } else {
1120 syslog(LOG_NOTICE, "failed to register for notifications %d", kr);
1121 }
1122 }
1123
1124 int main(int argc, const char * argv[])
1125 {
1126 char * errorbuf;
1127 if (sandbox_init(SECURITYD_SERVICE_NAME, SANDBOX_NAMED, &errorbuf) != 0) {
1128 syslog(LOG_ERR, "sandbox_init failed %s", errorbuf);
1129 sandbox_free_error(errorbuf);
1130 #ifndef DEBUG
1131 abort();
1132 #endif
1133 }
1134
1135 register_for_notifications();
1136
1137 xpc_connection_t listener = xpc_connection_create_mach_service(SECURITYD_SERVICE_NAME, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
1138 xpc_connection_set_event_handler(listener, ^(xpc_object_t peer) {
1139 // It is safe to cast 'peer' to xpc_connection_t assuming
1140 // we have a correct configuration in our launchd.plist.
1141 xpc_connection_set_event_handler(peer, ^(xpc_object_t event) {
1142 vproc_transaction_t transaction = vproc_transaction_begin(NULL);
1143 service_peer_event_handler(peer, event);
1144 vproc_transaction_end(NULL, transaction);
1145 });
1146 xpc_connection_resume(peer);
1147 });
1148 xpc_connection_resume(listener);
1149
1150 dispatch_main();
1151 exit(EXIT_FAILURE);
1152 }
1153