]> git.saurik.com Git - apple/security.git/blob - securityd/securityd_service/securityd_service/main.c
28be2bed3fe8b0b6f6629821e35feb620ccf76e0
[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 <os/log.h>
16 #include <stdio.h>
17 #include <errno.h>
18 #include <assert.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 #include <MobileKeyBag/MobileKeyBag.h>
30
31 #include <IOKit/IOKitLib.h>
32 #include <Kernel/IOKit/crypto/AppleFDEKeyStoreDefs.h>
33
34 #define LOG(...) os_log_debug(OS_LOG_DEFAULT, ##__VA_ARGS__);
35
36 static bool check_signature(xpc_connection_t connection);
37
38 static pid_t get_caller_pid(audit_token_t * token)
39 {
40 pid_t pid = 0;
41 if (token) {
42 audit_token_to_au32(*token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL);
43 }
44 return pid;
45 }
46
47 // exported from libaks.a
48 kern_return_t aks_register_for_notifications(mach_port_t server_port, uintptr_t message_id);
49 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);
50
51 const char * kb_home_path = "Library/Keychains";
52 const char * kb_user_bag = "user.kb";
53 const char * kb_stash_bag = "stash.kb";
54
55 #define HEXBUF_LEN 2048
56
57 typedef struct {
58 uid_t uid;
59 gid_t gid;
60 char * name;
61 char * home;
62 } service_user_record_t;
63
64 typedef enum {
65 kb_bag_type_user,
66 kb_bag_type_stash
67 } kb_bag_type_t;
68
69 static io_connect_t
70 openiodev(void)
71 {
72 io_registry_entry_t service;
73 io_connect_t conn;
74 kern_return_t kr;
75
76 service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(kAppleFDEKeyStoreServiceName));
77 if (service == IO_OBJECT_NULL)
78 return IO_OBJECT_NULL;
79
80 kr = IOServiceOpen(service, mach_task_self(), 0, &conn);
81 if (kr != KERN_SUCCESS)
82 return IO_OBJECT_NULL;
83
84 kr = IOConnectCallMethod(conn, kAppleFDEKeyStoreUserClientOpen, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL);
85 if (kr != KERN_SUCCESS) {
86 IOServiceClose(conn);
87 return IO_OBJECT_NULL;
88 }
89
90 return conn;
91 }
92
93 static void
94 closeiodev(io_connect_t conn)
95 {
96 kern_return_t kr;
97 kr = IOConnectCallMethod(conn, kAppleFDEKeyStoreUserClientClose, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL);
98 if (kr != KERN_SUCCESS)
99 return;
100 IOServiceClose(conn);
101 }
102
103 static dispatch_queue_t
104 _kb_service_get_dispatch_queue()
105 {
106 static dispatch_once_t onceToken = 0;
107 static dispatch_queue_t connection_queue = NULL;
108
109 dispatch_once(&onceToken, ^{
110 connection_queue = dispatch_queue_create("kb-service-queue", DISPATCH_QUEUE_SERIAL);
111 });
112
113 return connection_queue;
114 }
115
116 static service_user_record_t * get_user_record(uid_t uid)
117 {
118 service_user_record_t * ur = NULL;
119 long bufsize = 0;
120 if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) {
121 bufsize = 4096;
122 }
123 char buf[bufsize];
124 struct passwd pwbuf, *pw = NULL;
125 int rc;
126 if (((rc = getpwuid_r(uid, &pwbuf, buf, bufsize, &pw)) == 0) && pw != NULL) {
127 ur = calloc(1u, sizeof(service_user_record_t));
128 require(ur, done);
129 ur->uid = pw->pw_uid;
130 ur->gid = pw->pw_gid;
131 ur->home = strdup(pw->pw_dir);
132 ur->name = strdup(pw->pw_name);
133 } else {
134 os_log(OS_LOG_DEFAULT, "failed (%d) to lookup user record for uid: %d", rc, uid);
135 }
136
137 done:
138 return ur;
139 }
140
141 static void free_user_record(service_user_record_t * ur)
142 {
143 if (ur != NULL) {
144 if (ur->home) {
145 free(ur->home);
146 }
147 if (ur->name) {
148 free(ur->name);
149 }
150 free(ur);
151 }
152 }
153
154 static const char * get_host_uuid()
155 {
156 static uuid_string_t hostuuid = {};
157 static dispatch_once_t onceToken;
158 dispatch_once(&onceToken, ^{
159 struct timespec timeout = {30, 0};
160 uuid_t uuid = {};
161 if (gethostuuid(uuid, &timeout) == 0) {
162 uuid_unparse(uuid, hostuuid);
163 } else {
164 os_log(OS_LOG_DEFAULT, "failed to get host uuid");
165 onceToken = 0;
166 }
167 });
168
169 return hostuuid;
170 }
171
172 static char *
173 _kb_copy_bag_filename(service_user_record_t * ur, kb_bag_type_t type)
174 {
175 char * bag_file = NULL;
176 const char * name = NULL;
177
178 require(ur, done);
179 switch(type) {
180 case kb_bag_type_user:
181 name = kb_user_bag;
182 break;
183 case kb_bag_type_stash:
184 name = kb_stash_bag;
185 break;
186 default:
187 goto done;
188 }
189
190 bag_file = calloc(1u, PATH_MAX);
191 require(bag_file, done);
192
193 snprintf(bag_file, PATH_MAX, "%s/%s/%s/%s", ur->home, kb_home_path, get_host_uuid(), name);
194
195 done:
196 return bag_file;
197 }
198
199 static bool
200 _kb_verify_create_path(service_user_record_t * ur)
201 {
202 bool created = false;
203 struct stat st_info = {};
204 char new_path[PATH_MAX] = {};
205 char kb_path[PATH_MAX] = {};
206 snprintf(kb_path, sizeof(kb_path), "%s/%s/%s", ur->home, kb_home_path, get_host_uuid());
207 if (lstat(kb_path, &st_info) == 0) {
208 if (S_ISDIR(st_info.st_mode)) {
209 created = true;
210 } else {
211 os_log(OS_LOG_DEFAULT, "invalid directory at '%s' moving aside", kb_path);
212 snprintf(new_path, sizeof(new_path), "%s-invalid", kb_path);
213 unlink(new_path);
214 if (rename(kb_path, new_path) != 0) {
215 os_log(OS_LOG_DEFAULT, "failed to rename file: %s (%s)", kb_path, strerror(errno));
216 goto done;
217 }
218 }
219 }
220 if (!created) {
221 require_action(mkpath_np(kb_path, 0700) == 0, done, os_log(OS_LOG_DEFAULT, "could not create path: %s (%s)", kb_path, strerror(errno)));
222 created = true;
223 }
224
225 done:
226 if (!created) {
227 os_log(OS_LOG_DEFAULT, "_kb_verify_create_path failed %s", kb_path);
228 }
229 return created;
230 }
231
232 static void
233 _set_thread_credentials(service_user_record_t * ur)
234 {
235 int rc = pthread_setugid_np(ur->uid, ur->gid);
236 if (rc) { os_log(OS_LOG_DEFAULT, "failed to set thread credential: %i (%s)", errno, strerror(errno)); }
237
238 rc = initgroups(ur->name, ur->gid);
239 if (rc) { os_log(OS_LOG_DEFAULT, "failed to initgroups: %i", rc); }
240 }
241
242 static void
243 _clear_thread_credentials()
244 {
245 int rc = pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE);
246 if (rc) { os_log(OS_LOG_DEFAULT, "failed to reset thread credential: %i (%s)", errno, strerror(errno)); }
247 }
248
249 static bool
250 _kb_bag_exists(service_user_record_t * ur, const char * bag_file)
251 {
252 bool exists = false;
253 struct stat st_info = {};
254 char new_file[PATH_MAX] = {};
255
256 require(ur, done);
257
258 _set_thread_credentials(ur);
259 if (lstat(bag_file, &st_info) == 0) {
260 if (S_ISREG(st_info.st_mode)) {
261 exists = true;
262 } else {
263 os_log(OS_LOG_DEFAULT, "invalid file at '%s' moving aside", bag_file);
264 snprintf(new_file, sizeof(new_file), "%s-invalid", bag_file);
265 unlink(new_file);
266 if (rename(bag_file, new_file) != 0) {
267 os_log(OS_LOG_DEFAULT, "failed to rename file: %s (%s)", bag_file, strerror(errno));
268 }
269 }
270 }
271
272 done:
273 _clear_thread_credentials();
274 return exists;
275 }
276
277 static bool
278 _kb_save_bag_to_disk(service_user_record_t * ur, const char * bag_file, void * data, size_t length)
279 {
280 bool result = false;
281 char tmp_bag[PATH_MAX];
282 int fd = -1;
283
284 require(bag_file, done);
285
286 _set_thread_credentials(ur);
287 require(_kb_verify_create_path(ur), done);
288
289 require_action(snprintf(tmp_bag, sizeof(tmp_bag), "%s.tmp", bag_file) < sizeof(tmp_bag), done, os_log(OS_LOG_DEFAULT, "path too large"));
290
291 fd = open(tmp_bag, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0600);
292 require_action(fd != -1, done, os_log(OS_LOG_DEFAULT, "could not create file: %s (%s)", tmp_bag, strerror(errno)));
293 require_action(write(fd, data, length) == length, done, os_log(OS_LOG_DEFAULT, "failed to write keybag to disk %s (%s)", tmp_bag, strerror(errno)));
294
295 /* try atomic swap (will fail if destination doesn't exist); if that fails, try regular rename */
296 if (renamex_np(tmp_bag, bag_file, RENAME_SWAP) != 0) {
297 os_log(OS_LOG_DEFAULT, "Warning: atomic swap failed");
298 require_noerr_action(rename(tmp_bag, bag_file), done, os_log(OS_LOG_DEFAULT, "could not save keybag file"));
299 } else {
300 (void)unlink(tmp_bag);
301 }
302
303 result = true;
304
305 done:
306 if (fd != -1) { close(fd); }
307 _clear_thread_credentials();
308 return result;
309 }
310
311 static bool
312 _kb_load_bag_from_disk(service_user_record_t * ur, const char * bag_file, uint8_t ** data, size_t * length)
313 {
314 bool result = false;
315 int fd = -1;
316 uint8_t * buf = NULL;
317 size_t buf_size = 0;
318 struct stat st_info = {};
319
320 require(bag_file, done);
321
322 _set_thread_credentials(ur);
323 require(_kb_verify_create_path(ur), done);
324 require_action_quiet(lstat(bag_file, &st_info) == 0, done, os_log(OS_LOG_DEFAULT, "failed to stat file: %s (%s)", bag_file, strerror(errno)));
325 require_action(S_ISREG(st_info.st_mode), done, os_log(OS_LOG_DEFAULT, "failed to load, not a file: %s", bag_file));
326 buf_size = (size_t)st_info.st_size;
327
328 fd = open(bag_file, O_RDONLY | O_NOFOLLOW);
329 require_action(fd != -1, done, os_log(OS_LOG_DEFAULT, "could not open file: %s (%s)", bag_file, strerror(errno)));
330
331 buf = (uint8_t *)calloc(1u, buf_size);
332 require(buf != NULL, done);
333 require(read(fd, buf, buf_size) == buf_size, done);
334
335 *data = buf;
336 *length = buf_size;
337 buf = NULL;
338 result = true;
339
340 done:
341 if (fd != -1) { close(fd); }
342 if (buf) { free(buf); }
343 _clear_thread_credentials();
344 return result;
345 }
346
347 static void
348 _kb_invalidate_bag(service_user_record_t *ur, const char * bag_file)
349 {
350 uint8_t *buf = NULL;
351 size_t buf_size = 0;
352
353 require(ur, out);
354
355 if (_kb_load_bag_from_disk(ur, bag_file, &buf, &buf_size)) {
356 require_action(buf && buf_size <= INT_MAX, out, os_log(OS_LOG_DEFAULT, "failed to read: %s", bag_file));
357 require_noerr_action(aks_invalidate_bag(buf, (int)buf_size), out, os_log(OS_LOG_DEFAULT, "failed to invalidate file: %s", bag_file));
358 } else {
359 os_log(OS_LOG_DEFAULT, "failed to read file: %s", bag_file);
360 }
361
362 out:
363 free(buf);
364 }
365
366 static void
367 _kb_rename_bag_on_disk(service_user_record_t * ur, const char * bag_file)
368 {
369 char new_file[PATH_MAX] = {};
370 if (bag_file) {
371 _set_thread_credentials(ur);
372 snprintf(new_file, sizeof(new_file), "%s-invalid", bag_file);
373 unlink(new_file);
374 rename(bag_file, new_file);
375 _kb_invalidate_bag(ur, new_file);
376 _clear_thread_credentials();
377 }
378 }
379
380 static void
381 _kb_delete_bag_on_disk(service_user_record_t * ur, const char * bag_file)
382 {
383 if (bag_file) {
384 _set_thread_credentials(ur);
385 _kb_invalidate_bag(ur, bag_file);
386 unlink(bag_file);
387 _clear_thread_credentials();
388 }
389 }
390
391 static int service_kb_load(service_context_t *context);
392 static int service_kb_load_uid(uid_t s_uid);
393
394 #ifndef AKS_MACOS_ROOT_HANDLE
395 #define AKS_MACOS_ROOT_HANDLE 4 //temporary define to avoid dependency on AKS change, filed rdar://problem/30542034
396 #endif /* AKS_MACOS_ROOT_HANDLE */
397
398 static int
399 _service_kb_set_system(keybag_handle_t handle, keybag_handle_t special_handle)
400 {
401 //Use reserved root handle for root sessions, since 0 clashes with device_keybag_handle in AKS
402 return aks_set_system(handle, (special_handle == 0) ? AKS_MACOS_ROOT_HANDLE : special_handle);
403 }
404
405 static int
406 _service_kb_get_system(keybag_handle_t special_handle, keybag_handle_t * handle_out)
407 {
408 //Use reserved root handle for root sessions, since 0 clashes with device_keybag_handle in AKS
409 return aks_get_system((special_handle == 0) ? AKS_MACOS_ROOT_HANDLE : special_handle, handle_out);
410 }
411
412 static int
413 _kb_get_session_handle(service_context_t * context, keybag_handle_t * handle_out)
414 {
415 int rc = KB_BagNotLoaded;
416 require_noerr_quiet(_service_kb_get_system(context->s_uid, handle_out), done);
417
418 rc = KB_Success;
419
420 done:
421 if (rc == KB_BagNotLoaded) {
422 if (service_kb_load(context) == KB_Success) {
423 if (_service_kb_get_system(context->s_uid, handle_out) == kIOReturnSuccess) {
424 rc = KB_Success;
425 }
426 }
427 }
428 return rc;
429 }
430
431 static void update_keybag_handle(keybag_handle_t handle)
432 {
433 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
434 uid_t uid = abs(handle);
435 uint8_t * buf = NULL;
436 size_t buf_size = 0;
437 service_user_record_t * ur = NULL;
438 char * bag_file = NULL;
439
440 require_noerr(aks_save_bag(handle, (void**)&buf, (int*)&buf_size), done);
441 require(ur = get_user_record(uid), done);
442 require(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done);
443 require(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done);
444
445 os_log(OS_LOG_DEFAULT, "successfully updated handle %d", handle);
446
447 done:
448 if (buf) free(buf);
449 if (ur) free_user_record(ur);
450 if (bag_file) free(bag_file);
451 });
452 }
453
454 static int
455 _kb_get_options_for_uid(uid_t uid, CFMutableDictionaryRef *options_out)
456 {
457 int result = KB_GeneralError;
458 CFMutableDictionaryRef options = NULL;
459 CFNumberRef cf_uid = NULL;
460
461 require(options_out, out);
462
463 require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), out);
464 require(cf_uid = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &uid), out);
465 CFDictionaryAddValue(options, kKeyBagDeviceHandle, cf_uid);
466
467 *options_out = options;
468 options = NULL;
469
470 result = KB_Success;
471 out:
472 if (options) { CFRelease(options); }
473 if (cf_uid) { CFRelease(cf_uid); }
474
475 return result;
476 }
477
478 static int
479 _kb_set_properties(service_context_t * context, const void * secret, int secret_len)
480 {
481 int result = KB_GeneralError;
482 CFMutableDictionaryRef options = NULL;
483 CFDataRef passcode = NULL;
484
485 require_noerr(_kb_get_options_for_uid(context->s_uid, &options), done);
486
487 /* set user uuid, if not already set */
488 passcode = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, secret, secret_len, kCFAllocatorNull);
489 if (MKBKeyBagSetUserUUID(options, passcode)) {
490 os_log(OS_LOG_DEFAULT, "set user uuid failed");
491 }
492
493 #ifdef MKB_SUPPORTS_BIND_KEK
494 if (MKBKeyBagBindKEK(options, passcode)) {
495 os_log(OS_LOG_DEFAULT, "KEK bind failed");
496 }
497 #else
498 os_log(OS_LOG_DEFAULT, "Not bindinig KEK, update SDK");
499 #endif
500
501 result = KB_Success;
502 done:
503 if (options) { CFRelease(options); }
504 if (passcode) { CFRelease(passcode); }
505 return result;
506 }
507
508 static int
509 service_kb_create(service_context_t * context, const void * secret, int secret_len)
510 {
511 __block int rc = KB_GeneralError;
512
513 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
514 uint8_t * buf = NULL;
515 size_t buf_size = 0;
516 keybag_handle_t private_handle = bad_keybag_handle, session_handle = bad_keybag_handle;
517 service_user_record_t * ur = get_user_record(context->s_uid);
518 char * bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user);
519
520 require(bag_file, done);
521
522 // check for the existance of the bagfile
523 require_action(!_kb_bag_exists(ur, bag_file), done, rc = KB_BagExists);
524
525 require_noerr(rc = aks_create_bag(secret, secret_len, kAppleKeyStoreDeviceBag, &private_handle), done);
526 require_noerr(rc = aks_save_bag(private_handle, (void**)&buf, (int*)&buf_size), done);
527 require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done, rc = KB_BagError);
528 require_noerr(rc = _service_kb_set_system(private_handle, context->s_uid), done);
529 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
530
531 if (secret && rc == KB_Success) {
532 aks_unlock_bag(session_handle, secret, secret_len);
533 }
534
535 if (rc == KB_Success) {
536 _kb_set_properties(context, secret, secret_len);
537 }
538
539 done:
540 if (private_handle != bad_keybag_handle) {
541 aks_unload_bag(private_handle);
542 }
543 if (buf) free(buf);
544 if (bag_file) { free(bag_file); }
545 if (ur) free_user_record(ur);
546 });
547
548 return rc;
549 }
550
551 /* Load s_uid's keybag, unless already loaded */
552 static int
553 _service_kb_load_uid(uid_t s_uid)
554 {
555 __block int rc = KB_GeneralError;
556
557 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
558 uint8_t * buf = NULL;
559 size_t buf_size = 0;
560 keybag_handle_t private_handle = bad_keybag_handle, session_handle = bad_keybag_handle;
561 service_user_record_t * ur = NULL;
562 char * bag_file = NULL;
563 int _stage = 0;
564
565 rc = _service_kb_get_system(s_uid, &session_handle);
566 if (rc == kIOReturnNotFound) {
567 require_action(ur = get_user_record(s_uid), done, rc = KB_GeneralError; _stage = 1);
568 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError; _stage = 2);
569 require_action_quiet(_kb_load_bag_from_disk(ur, bag_file, &buf, &buf_size), done, rc = KB_BagNotFound; _stage = 3);
570 rc = aks_load_bag(buf, (int)buf_size, &private_handle);
571 switch (rc) {
572 case kAKSReturnBadDeviceKey:
573 case kAKSReturnBadSignature:
574 case kAKSReturnDecodeError:
575 case kAKSReturnPolicyInvalid:
576 os_log(OS_LOG_DEFAULT, "bag load failed 0x%x for uid (%i), discarding", rc, s_uid);
577 _kb_rename_bag_on_disk(ur, bag_file);
578 rc = KB_BagNotFound;
579 break;
580 case kAKSReturnSuccess:
581 /* nothing to do */
582 break;
583 default:
584 os_log(OS_LOG_DEFAULT, "bag load failed 0x%x for uid (%i)", rc, s_uid);
585 break;
586 }
587 require_noerr_action(rc, done, _stage = 4);
588 require_noerr_action(rc = _service_kb_set_system(private_handle, s_uid), done, _stage = 5);
589 }
590 require(rc == KB_Success, done);
591
592 done:
593 if (private_handle != bad_keybag_handle) {
594 aks_unload_bag(private_handle);
595 }
596 // this function should never fail unless bootstrapping the user for the first time, or rare conditions from aks_load_bag
597 if (rc != KB_Success) {
598 os_log(OS_LOG_DEFAULT, "%d: error %d loading keybag for uid (%i) at path: %s", _stage, rc, s_uid, bag_file);
599 }
600 if (buf) free(buf);
601 if (ur) free_user_record(ur);
602 if (bag_file) free(bag_file);
603 });
604
605 return rc;
606 }
607
608 static int
609 service_kb_load_uid(uid_t s_uid)
610 {
611 return _service_kb_load_uid(s_uid);
612 }
613
614 static int
615 service_kb_load(service_context_t * context)
616 {
617 return _service_kb_load_uid(context->s_uid);
618 }
619
620 static int
621 service_kb_unload(service_context_t *context)
622 {
623 __block int rc = KB_GeneralError;
624
625 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
626 keybag_handle_t session_handle = bad_keybag_handle;
627
628 rc = _service_kb_get_system(context->s_uid, &session_handle);
629 if (rc == kIOReturnNotFound) {
630 // No session bag, nothing to do
631 rc = KB_Success;
632 return;
633 } else if (rc != kIOReturnSuccess) {
634 os_log(OS_LOG_DEFAULT, "error locating session keybag for uid (%i) in session (%i)", context->s_uid, context->s_id);
635 rc = KB_BagError;
636 return;
637 }
638
639 rc = aks_unload_bag(session_handle);
640 if (rc != kAKSReturnSuccess) {
641 os_log(OS_LOG_DEFAULT, "error unloading keybag for uid (%i) in session (%i)", context->s_uid, context->s_id);
642 rc = KB_BagError;
643 } else {
644 os_log(OS_LOG_DEFAULT, "successfully unloaded keybag (%ld) for uid (%i) in session (%i)", (long)session_handle, context->s_uid, context->s_id);
645 }
646 });
647
648 return rc;
649 }
650
651 static int
652 service_kb_save(service_context_t * context)
653 {
654 __block int rc = KB_GeneralError;
655 keybag_handle_t session_handle;
656 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
657
658 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
659 uint8_t * buf = NULL;
660 size_t buf_size = 0;
661 service_user_record_t * ur = NULL;
662 char * bag_file = NULL;
663
664 require_noerr(rc = aks_save_bag(session_handle, (void**)&buf, (int*)&buf_size), done);
665 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
666 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError);
667 require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done, rc = KB_BagError);
668
669 rc = KB_Success;
670
671 done:
672 if (buf) free(buf);
673 if (ur) free_user_record(ur);
674 if (bag_file) free(bag_file);
675 return;
676 });
677
678 done:
679 return rc;
680 }
681
682 static int
683 service_kb_unlock(service_context_t * context, const void * secret, int secret_len)
684 {
685 int rc = KB_GeneralError;
686 keybag_handle_t session_handle;
687 CFDataRef passcode = NULL;
688 CFMutableDictionaryRef options = NULL;
689
690 require_noerr(_kb_get_options_for_uid(context->s_uid, &options), done);
691
692 /* technically, session_handle is not needed. Call this to handle lazy keybag loading */
693 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
694
695 require(passcode = CFDataCreateWithBytesNoCopy(NULL, secret, secret_len, kCFAllocatorNull), done);
696
697 rc = MKBUnlockDevice(passcode, options);
698 os_log(OS_LOG_DEFAULT, "MKBUnlockDevice result: (%ld)", (long)rc);
699
700 done:
701 if (options) { CFRelease(options); }
702 if (passcode) { CFRelease(passcode); }
703 return rc;
704 }
705
706 static int
707 service_kb_lock(service_context_t * context)
708 {
709 // this call has been disabled
710 return -1;
711 }
712
713 static int
714 service_kb_change_secret(service_context_t * context, const void * secret, int secret_len, const void * new_secret, int new_secret_len)
715 {
716 __block int rc = KB_GeneralError;
717 keybag_handle_t session_handle;
718 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
719
720 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
721 uint8_t * buf = NULL;
722 size_t buf_size = 0;
723 service_user_record_t * ur = NULL;
724 char * bag_file = NULL;
725
726 require_noerr(rc = aks_change_secret(session_handle, secret, secret_len, new_secret, new_secret_len, generation_noop, NULL), done);
727 require_noerr(rc = aks_save_bag(session_handle, (void**)&buf, (int*)&buf_size), done);
728 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
729 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError);
730 require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done, rc = KB_BagError);
731
732 rc = KB_Success;
733
734 done:
735 if (buf) free(buf);
736 if (ur) free_user_record(ur);
737 if (bag_file) free(bag_file);
738 return;
739 });
740
741 done:
742 return rc;
743 }
744
745 static int
746 service_kb_reset(service_context_t * context, const void * secret, int secret_len)
747 {
748 __block int rc = KB_GeneralError;
749 service_user_record_t * ur = NULL;
750 char * bag_file = NULL;
751
752 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
753 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError);
754
755 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
756 uint8_t * buf = NULL;
757 size_t buf_size = 0;
758 keybag_handle_t private_handle = bad_keybag_handle, session_handle = bad_keybag_handle;
759
760 os_log(OS_LOG_DEFAULT, "resetting keybag for uid (%i) in session (%i)", context->s_uid, context->s_id);
761 _kb_rename_bag_on_disk(ur, bag_file);
762
763 require_noerr(rc = aks_create_bag(secret, secret_len, kAppleKeyStoreDeviceBag, &private_handle), done);
764 require_noerr(rc = aks_save_bag(private_handle, (void**)&buf, (int*)&buf_size), done);
765 require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done, rc = KB_BagError);
766 require_noerr(rc = _service_kb_set_system(private_handle, context->s_uid), done);
767 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
768
769 if (secret && rc == KB_Success) {
770 aks_unlock_bag(session_handle, secret, secret_len);
771 }
772
773 if (rc == KB_Success) {
774 _kb_set_properties(context, secret, secret_len);
775 }
776
777 done:
778 if (private_handle != bad_keybag_handle) {
779 aks_unload_bag(private_handle);
780 }
781 if (buf) free(buf);
782 return;
783 });
784
785 done:
786 if (ur) free_user_record(ur);
787 if (bag_file) free(bag_file);
788 return rc;
789 }
790
791 static int
792 service_kb_is_locked(service_context_t * context, xpc_object_t reply)
793 {
794 int rc = KB_GeneralError;
795 keybag_state_t state;
796 keybag_handle_t session_handle;
797 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
798
799 require_noerr(rc = aks_get_lock_state(session_handle, &state), done);
800
801 xpc_dictionary_set_bool(reply, SERVICE_XPC_LOCKED, state & keybag_state_locked);
802 xpc_dictionary_set_bool(reply, SERVICE_XPC_NO_PIN, state & keybag_state_no_pin);
803
804 done:
805 return rc;
806 }
807
808 static int
809 service_kb_wrap_key(service_context_t *context, xpc_object_t event, xpc_object_t reply)
810 {
811 int rc = KB_GeneralError;
812 size_t sz;
813 const void *key;
814 int key_size;
815 keyclass_t key_class;
816 keybag_handle_t session_handle;
817 void *wrapped_key = NULL;
818 int wrapped_key_size;
819 keyclass_t wrapped_key_class;
820
821 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
822
823 key = xpc_dictionary_get_data(event, SERVICE_XPC_KEY, &sz);
824 require_action(key != NULL, done, rc = KB_GeneralError);
825 require_action(sz <= APPLE_KEYSTORE_MAX_KEY_LEN, done, rc = KB_GeneralError);
826 key_size = (int)sz;
827 key_class = (keyclass_t)xpc_dictionary_get_int64(event, SERVICE_XPC_KEYCLASS);
828
829 wrapped_key_size = APPLE_KEYSTORE_MAX_ASYM_WRAPPED_KEY_LEN;
830 wrapped_key = calloc(1, wrapped_key_size);
831
832 rc = aks_wrap_key(key, key_size, key_class, session_handle, wrapped_key, &wrapped_key_size, &wrapped_key_class);
833 if (rc == KB_Success) {
834 xpc_dictionary_set_data(reply, SERVICE_XPC_WRAPPED_KEY, wrapped_key, wrapped_key_size);
835 xpc_dictionary_set_int64(reply, SERVICE_XPC_KEYCLASS, wrapped_key_class);
836 }
837
838 done:
839 free(wrapped_key);
840 return rc;
841 }
842
843 static int
844 service_kb_unwrap_key(service_context_t *context, xpc_object_t event, xpc_object_t reply)
845 {
846 int rc = KB_GeneralError;
847 size_t sz;
848 const void *wrapped_key;
849 int wrapped_key_size;
850 keyclass_t wrapped_key_class;
851 keybag_handle_t session_handle;
852 void *key = NULL;
853 int key_size;
854
855 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
856
857 wrapped_key = xpc_dictionary_get_data(event, SERVICE_XPC_WRAPPED_KEY, &sz);
858 require_action(wrapped_key != NULL, done, rc = KB_GeneralError);
859 require_action(sz <= APPLE_KEYSTORE_MAX_ASYM_WRAPPED_KEY_LEN, done, rc = KB_GeneralError);
860 wrapped_key_size = (int)sz;
861 wrapped_key_class = (keyclass_t)xpc_dictionary_get_int64(event, SERVICE_XPC_KEYCLASS);
862
863 key_size = APPLE_KEYSTORE_MAX_KEY_LEN;
864 key = calloc(1, key_size);
865
866 rc = aks_unwrap_key(wrapped_key, wrapped_key_size, wrapped_key_class, session_handle, key, &key_size);
867 if (rc == KB_Success) {
868 xpc_dictionary_set_data(reply, SERVICE_XPC_KEY, key, key_size);
869 }
870
871 done:
872 free(key);
873 return rc;
874 }
875
876 static int
877 service_kb_stash_create(service_context_t * context, const void * key, unsigned key_size)
878 {
879 int rc = KB_GeneralError;
880 char * bag_file = NULL;
881 keybag_handle_t session_handle;
882 service_user_record_t * ur = NULL;
883 void * stashbag = NULL;
884 int stashbag_size = 0;
885 __block bool saved = false;
886
887 require(key, done);
888 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
889 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
890 require_noerr(rc = aks_stash_escrow(session_handle, true, key, key_size, NULL, 0, (void**)&stashbag, &stashbag_size), done);
891 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_stash), done, rc = KB_GeneralError);
892
893 // sync writing the bag to disk
894 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
895 saved = _kb_save_bag_to_disk(ur, bag_file, stashbag, stashbag_size);
896 });
897 require_action(saved, done, rc = KB_BagError);
898 rc = KB_Success;
899
900 done:
901 if (stashbag) { free(stashbag); }
902 if (bag_file) { free(bag_file); }
903 if (ur) free_user_record(ur);
904 return rc;
905 }
906
907 static int
908 service_kb_stash_load(service_context_t * context, const void * key, unsigned key_size, bool nondestructive)
909 {
910 __block int rc = KB_GeneralError;
911 char * bag_file = NULL;
912 keybag_handle_t session_handle;
913 service_user_record_t * ur = NULL;
914 __block uint8_t * stashbag = NULL;
915 __block size_t stashbag_size = 0;
916
917 require(key, done);
918 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
919 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
920 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_stash), done, rc = KB_GeneralError);
921
922 // sync loading the bag from disk
923 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
924 if (!_kb_load_bag_from_disk(ur, bag_file, &stashbag, &stashbag_size)) {
925 rc = KB_BagError;
926 }
927 });
928 require_noerr(rc, done);
929
930 require_noerr(rc = aks_stash_escrow(session_handle, false, key, key_size, stashbag, (int)stashbag_size, NULL, NULL), done);
931 rc = KB_Success;
932
933 done:
934 if (stashbag) { free(stashbag); }
935 if ((bag_file) && (!nondestructive)) {
936 _kb_delete_bag_on_disk(ur, bag_file);
937 free(bag_file);
938 }
939 if (ur) free_user_record(ur);
940 return rc;
941 }
942
943 //
944 // Get the keychain master key from the AppleFDEKeyStore.
945 // Note that this is a one-time call - the master key is
946 // removed from the keystore after it is returned.
947 // Requires the entitlement: com.apple.private.securityd.keychain
948 //
949 OSStatus service_stash_get_key(service_context_t * context, xpc_object_t event, xpc_object_t reply)
950 {
951 getStashKey_InStruct_t inStruct;
952 getStashKey_OutStruct_t outStruct;
953 size_t outSize = sizeof(outStruct);
954 kern_return_t kr = KERN_INVALID_ARGUMENT;
955
956 io_connect_t conn = openiodev();
957 require(conn, done);
958 inStruct.type = kAppleFDEKeyStoreStash_master;
959
960 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_getStashKey,
961 NULL, 0,
962 &inStruct, sizeof(inStruct),
963 NULL, NULL,
964 &outStruct, &outSize);
965
966 if (kr == KERN_SUCCESS) {
967 xpc_dictionary_set_data(reply, SERVICE_XPC_KEY, outStruct.outBuf.key.key, outStruct.outBuf.key.keysize);
968 service_kb_stash_load(context, outStruct.outBuf.key.key, outStruct.outBuf.key.keysize, false);
969 } else {
970 os_log(OS_LOG_DEFAULT, "failed to get stash key: %d", (int)kr);
971 }
972
973 done:
974 if (conn)
975 closeiodev(conn);
976
977 return kr;
978 }
979
980 //
981 // Stash the keychain master key in the AppleFDEKeyStore and
982 // flag it as the keychain master key to be added to the
983 // reboot NVRAM blob.
984 // This requires two calls to the AKS: the first to store the
985 // key and get its uuid. The second uses the uuid to flag the
986 // key for blob inclusion.
987 //
988 OSStatus service_stash_set_key(service_context_t * context, xpc_object_t event, xpc_object_t reply)
989 {
990 kern_return_t kr = KERN_INVALID_ARGUMENT;
991 io_connect_t conn = IO_OBJECT_NULL;
992 size_t keydata_len = 0;
993 size_t len;
994
995 keybag_state_t state;
996 keybag_handle_t session_handle;
997 require_noerr(_kb_get_session_handle(context, &session_handle), done);
998 require_noerr(aks_get_lock_state(session_handle, &state), done);
999 require_action(!(state & keybag_lock_locked), done, kr = CSSMERR_CSP_OS_ACCESS_DENIED; LOG("stash failed keybag locked"));
1000
1001 conn = openiodev();
1002 require(conn, done);
1003
1004 // Store the key in the keystore and get its uuid
1005 setKeyGetUUID_InStruct_t inStruct1;
1006 uuid_OutStruct_t outStruct1;
1007
1008
1009 const uint8_t *keydata = xpc_dictionary_get_data(event, SERVICE_XPC_KEY, &keydata_len);
1010 require(keydata, done);
1011
1012 memcpy(&inStruct1.inKey.key.key, keydata, keydata_len);
1013 inStruct1.inKey.key.keysize = (cryptosize_t) keydata_len;
1014 len = sizeof(outStruct1);
1015 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_setKeyGetUUID,
1016 NULL, 0,
1017 &inStruct1, sizeof(inStruct1),
1018 NULL, NULL,
1019 &outStruct1, &len);
1020 require(kr == KERN_SUCCESS, done);
1021
1022 // Now using the uuid stash it as the master key
1023 setStashKey_InStruct_t inStruct2;
1024 memcpy(&inStruct2.uuid, &outStruct1.uuid, sizeof(outStruct1.uuid));
1025 inStruct2.type = kAppleFDEKeyStoreStash_master;
1026
1027 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_setStashKey,
1028 NULL, 0,
1029 &inStruct2, sizeof(inStruct2),
1030 NULL, NULL,
1031 NULL, NULL);
1032
1033 if (kr == KERN_SUCCESS) {
1034 service_kb_stash_create(context, keydata, (unsigned)keydata_len);
1035 }
1036 done:
1037 os_log(OS_LOG_DEFAULT, "set stashkey %d", (int)kr);
1038
1039 if (conn)
1040 closeiodev(conn);
1041
1042 return kr;
1043 }
1044
1045 //
1046 // Load the master stash key
1047 //
1048 OSStatus service_stash_load_key(service_context_t * context, xpc_object_t event, xpc_object_t reply)
1049 {
1050 kern_return_t kr = KERN_SUCCESS;
1051 size_t keydata_len = 0;
1052
1053 const uint8_t *keydata = xpc_dictionary_get_data(event, SERVICE_XPC_KEY, &keydata_len);
1054 require(keydata, done);
1055
1056 kr = service_kb_stash_load(context, keydata, (cryptosize_t) keydata_len, true);
1057 done:
1058
1059 return kr;
1060 }
1061
1062 //
1063 // Signal the AppleFDEKeyStore to take the tagged FDE key
1064 // and keychain master key, stash them in an encrypted
1065 // blob structure and write the blob to NVRAM. The random
1066 // encryption key is written to the SMC.
1067 //
1068 #if DEBUG
1069 OSStatus service_stash_blob(xpc_object_t event, xpc_object_t reply)
1070 {
1071 kern_return_t kr = KERN_INVALID_ARGUMENT;
1072
1073 io_connect_t conn = openiodev();
1074 require(conn, done);
1075
1076 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_commitStash,
1077 NULL, 0,
1078 NULL, 0,
1079 NULL, NULL,
1080 NULL, NULL);
1081 done:
1082 if (conn)
1083 closeiodev(conn);
1084
1085 return kr;
1086 }
1087 #endif
1088
1089 bool peer_has_entitlement(xpc_connection_t peer, const char * entitlement)
1090 {
1091 bool entitled = false;
1092
1093 xpc_object_t value = xpc_connection_copy_entitlement_value(peer, entitlement);
1094 if (value && (xpc_get_type(value) == XPC_TYPE_BOOL)) {
1095 entitled = xpc_bool_get_value(value);
1096 }
1097
1098 if (value) xpc_release(value);
1099 return entitled;
1100 }
1101
1102 static char * sel_to_char(uint64_t sel)
1103 {
1104 switch (sel) {
1105 case SERVICE_STASH_SET_KEY:
1106 return "set_key";
1107 case SERVICE_STASH_GET_KEY:
1108 return "get_key";
1109 case SERVICE_STASH_BLOB:
1110 return "stash_blob";
1111 case SERVICE_KB_LOAD:
1112 return "kb_load";
1113 case SERVICE_KB_SAVE:
1114 return "kb_save";
1115 case SERVICE_KB_UNLOCK:
1116 return "kb_unlock";
1117 case SERVICE_KB_LOCK:
1118 return "kb_lock";
1119 case SERVICE_KB_CHANGE_SECRET:
1120 return "kb_change_secret";
1121 case SERVICE_KB_CREATE:
1122 return "kb_create";
1123 case SERVICE_KB_IS_LOCKED:
1124 return "kb_is_locked";
1125 case SERVICE_KB_RESET:
1126 return "kb_reset";
1127 case SERVICE_KB_UNLOAD:
1128 return "kb_unload";
1129 case SERVICE_KB_LOAD_UID:
1130 return "kb_load_uid";
1131 case SERVICE_KB_WRAP_KEY:
1132 return "kb_wrap_key";
1133 case SERVICE_KB_UNWRAP_KEY:
1134 return "kb_unwrap_key";
1135 default:
1136 return "unknown";
1137 }
1138 }
1139
1140 static char * err_to_char(int err)
1141 {
1142 switch (err) {
1143 case KB_Success:
1144 return "success";
1145 case KB_GeneralError:
1146 return "general error";
1147 case KB_BagNotFound:
1148 return "bag not found";
1149 case KB_BagError:
1150 return "bag error";
1151 case KB_BagNotLoaded:
1152 return "bag not loaded";
1153 case KB_BagExists:
1154 return "bag exists";
1155 case KB_InvalidSession:
1156 return "invalid session";
1157 default:
1158 return "";
1159 }
1160 }
1161
1162 void service_peer_event_handler(xpc_connection_t connection, xpc_object_t event)
1163 {
1164 xpc_type_t type = xpc_get_type(event);
1165 uid_t uid;
1166
1167 if (type == XPC_TYPE_ERROR) {
1168 if (event == XPC_ERROR_CONNECTION_INVALID) {
1169 }
1170 } else {
1171 assert(type == XPC_TYPE_DICTIONARY);
1172
1173 int rc = KB_GeneralError;
1174 uint64_t request = 0;
1175 const uint8_t * secret = NULL, * new_secret = NULL;
1176 size_t secret_len = 0, new_secret_len = 0, data_len = 0;
1177 service_context_t * context = NULL;
1178 bool free_context = false;
1179 const void * data;
1180 const char *entitlement;
1181
1182 xpc_object_t reply = xpc_dictionary_create_reply(event);
1183
1184 request = xpc_dictionary_get_uint64(event, SERVICE_XPC_REQUEST);
1185
1186
1187 // For SERVICE_KB_{UNLOAD,LOAD} only, allow non-securityd, non-root but
1188 // entitled callers.
1189 if (request == SERVICE_KB_UNLOAD || request == SERVICE_KB_LOAD_UID) {
1190 switch (request) {
1191 case SERVICE_KB_UNLOAD:
1192 entitlement = "com.apple.private.securityd.keybag-unload";
1193 break;
1194 case SERVICE_KB_LOAD_UID:
1195 entitlement = "com.apple.private.securityd.keybag-load";
1196 break;
1197 }
1198 if (!peer_has_entitlement(connection, entitlement) && !peer_has_entitlement(connection, "com.apple.keystore.device")) {
1199 xpc_connection_cancel(connection);
1200 return;
1201 }
1202 } else {
1203 if (xpc_connection_get_euid(connection) != 0) {
1204 xpc_connection_cancel(connection);
1205 return;
1206 }
1207 if (!check_signature(connection)) {
1208 xpc_connection_cancel(connection);
1209 return;
1210 }
1211 }
1212
1213 data = xpc_dictionary_get_data(event, SERVICE_XPC_CONTEXT, &data_len);
1214 require_action(data || request == SERVICE_KB_UNLOAD || request == SERVICE_KB_LOAD_UID, done, rc = KB_GeneralError);
1215 if (data) {
1216 require(data_len == sizeof(service_context_t), done);
1217 context = (service_context_t*)data;
1218 } else {
1219 audit_token_t audit_token = { 0 };
1220 xpc_connection_get_audit_token(connection, &audit_token);
1221 context = calloc(1, sizeof(service_context_t));
1222 context->s_id = xpc_connection_get_asid(connection);
1223 context->s_uid = xpc_connection_get_euid(connection);
1224 context->procToken = audit_token;
1225 free_context = true;
1226 }
1227
1228 require_action(context->s_id != AU_DEFAUDITSID, done, rc = KB_InvalidSession);
1229 require_action(context->s_uid != AU_DEFAUDITID, done, rc = KB_InvalidSession); // we only want to work in actual user sessions.
1230
1231 switch (request) {
1232 case SERVICE_KB_CREATE:
1233 // if (kb_service_has_entitlement(peer, "com.apple.keystore.device")) {
1234 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
1235 rc = service_kb_create(context, secret, (int)secret_len);
1236 // }
1237 break;
1238 case SERVICE_KB_LOAD:
1239 rc = service_kb_load(context);
1240 break;
1241 case SERVICE_KB_UNLOAD:
1242 rc = service_kb_unload(context);
1243 break;
1244 case SERVICE_KB_SAVE:
1245 rc = service_kb_save(context);
1246 break;
1247 case SERVICE_KB_UNLOCK:
1248 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
1249 rc = service_kb_unlock(context, secret, (int)secret_len);
1250 break;
1251 case SERVICE_KB_LOCK:
1252 rc = service_kb_lock(context);
1253 break;
1254 case SERVICE_KB_CHANGE_SECRET:
1255 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
1256 new_secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET_NEW, &new_secret_len);
1257 rc = service_kb_change_secret(context, secret, (int)secret_len, new_secret, (int)new_secret_len);
1258 break;
1259 case SERVICE_KB_RESET:
1260 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
1261 rc = service_kb_reset(context, secret, (int)secret_len);
1262 break;
1263 case SERVICE_KB_IS_LOCKED:
1264 rc = service_kb_is_locked(context, reply);
1265 break;
1266 case SERVICE_STASH_GET_KEY:
1267 rc = service_stash_get_key(context, event, reply);
1268 break;
1269 case SERVICE_STASH_SET_KEY:
1270 rc = service_stash_set_key(context, event, reply);
1271 break;
1272 case SERVICE_STASH_LOAD_KEY:
1273 rc = service_stash_load_key(context, event, reply);
1274 break;
1275 case SERVICE_KB_LOAD_UID:
1276 uid = (uid_t)xpc_dictionary_get_uint64(event, SERVICE_XPC_UID);
1277 rc = service_kb_load_uid(uid);
1278 break;
1279 case SERVICE_KB_WRAP_KEY:
1280 rc = service_kb_wrap_key(context, event, reply);
1281 break;
1282 case SERVICE_KB_UNWRAP_KEY:
1283 rc = service_kb_unwrap_key(context, event, reply);
1284 break;
1285 #if DEBUG
1286 case SERVICE_STASH_BLOB:
1287 rc = service_stash_blob(event, reply);
1288 break;
1289 #endif
1290 default:
1291 LOG("unknown service type");
1292 break;
1293 }
1294
1295 done:
1296 #if DEBUG
1297 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);
1298 #else
1299 if (rc != 0) {
1300 os_log(OS_LOG_DEFAULT, "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);
1301 }
1302 #endif
1303 xpc_dictionary_set_int64(reply, SERVICE_XPC_RC, rc);
1304 xpc_connection_send_message(connection, reply);
1305 xpc_release(reply);
1306 if (free_context) {
1307 free(context);
1308 }
1309 }
1310 }
1311
1312 bool check_signature(xpc_connection_t connection)
1313 {
1314 #if !(DEBUG || RC_BUILDIT_YES)
1315 audit_token_t token;
1316
1317 xpc_connection_get_audit_token(connection, &token);
1318
1319 SecTaskRef task = SecTaskCreateWithAuditToken(NULL, token);
1320 if (task == NULL) {
1321 os_log(OS_LOG_DEFAULT, "failed getting SecTaskRef of the client");
1322 return false;
1323 }
1324
1325 uint32_t flags = SecTaskGetCodeSignStatus(task);
1326 /* check if valid and platform binary, but not platform path */
1327 if ((flags & (CS_VALID | CS_PLATFORM_BINARY | CS_PLATFORM_PATH)) != (CS_VALID | CS_PLATFORM_BINARY)) {
1328 os_log(OS_LOG_DEFAULT, "client is not a platform binary: %0x08x", flags);
1329 CFRelease(task);
1330 return false;
1331 }
1332
1333 CFStringRef signingIdentity = SecTaskCopySigningIdentifier(task, NULL);
1334 CFRelease(task);
1335 if (signingIdentity == NULL) {
1336 os_log(OS_LOG_DEFAULT, "client have no code sign identity");
1337 return false;
1338 }
1339
1340 bool res = CFEqual(signingIdentity, CFSTR("com.apple.securityd"));
1341 CFRelease(signingIdentity);
1342
1343 if (!res)
1344 os_log(OS_LOG_DEFAULT, "client is not not securityd");
1345
1346 return res;
1347 #else
1348 return true;
1349 #endif
1350 }
1351
1352 static void register_for_notifications()
1353 {
1354 __block kern_return_t kr;
1355 static mach_port_t mp = MACH_PORT_NULL;
1356
1357 static dispatch_once_t onceToken = 0;
1358 dispatch_once(&onceToken, ^{
1359 kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
1360 if (kr == KERN_SUCCESS) {
1361 dispatch_source_t mach_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
1362 dispatch_source_set_event_handler(mach_src, ^{
1363 mach_msg_return_t mr;
1364 uint8_t buf[sizeof(aks_notification_msg_t) + MAX_TRAILER_SIZE] = {};
1365 aks_notification_msg_t * msg = (aks_notification_msg_t*)buf;
1366 mr = mach_msg((mach_msg_header_t*)&buf, MACH_RCV_MSG, 0, sizeof(buf), mp, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
1367 if (mr == MACH_MSG_SUCCESS && msg->hdr.msgh_id == AKS_NOTIFICATION_MSGID) {
1368 // ignored for now
1369 } else if (mr == MACH_MSG_SUCCESS && msg->hdr.msgh_id == AKS_NOTIFICATION_WRITE_SYSTEM_KEYBAG) {
1370 os_log(OS_LOG_DEFAULT, "request to update handle %d", msg->handle);
1371 update_keybag_handle(msg->handle);
1372 } else {
1373 os_log(OS_LOG_DEFAULT, "mach_msg error: %x", mr);
1374 }
1375 });
1376 dispatch_resume(mach_src);
1377 } else {
1378 os_log(OS_LOG_DEFAULT, "failed to create notification port");
1379 }
1380
1381 });
1382
1383 kr = aks_register_for_notifications(mp, AKS_NOTIFICATION_WRITE_SYSTEM_KEYBAG);
1384 if (kr == KERN_SUCCESS) {
1385 os_log(OS_LOG_DEFAULT, "registered for notifications");
1386 } else {
1387 os_log(OS_LOG_DEFAULT, "failed to register for notifications %d", kr);
1388 }
1389 }
1390
1391 int main(int argc, const char * argv[])
1392 {
1393 char * errorbuf;
1394 if (sandbox_init(SECURITYD_SERVICE_NAME, SANDBOX_NAMED, &errorbuf) != 0) {
1395 os_log(OS_LOG_DEFAULT, "sandbox_init failed %s", errorbuf);
1396 sandbox_free_error(errorbuf);
1397 #ifndef DEBUG
1398 abort();
1399 #endif
1400 }
1401
1402 register_for_notifications();
1403
1404 xpc_connection_t listener = xpc_connection_create_mach_service(SECURITYD_SERVICE_NAME, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
1405 xpc_connection_set_event_handler(listener, ^(xpc_object_t peer) {
1406 // It is safe to cast 'peer' to xpc_connection_t assuming
1407 // we have a correct configuration in our launchd.plist.
1408 xpc_connection_set_event_handler(peer, ^(xpc_object_t event) {
1409 vproc_transaction_t transaction = vproc_transaction_begin(NULL);
1410 service_peer_event_handler(peer, event);
1411 vproc_transaction_end(NULL, transaction);
1412 });
1413 xpc_connection_resume(peer);
1414 });
1415 xpc_connection_resume(listener);
1416
1417 dispatch_main();
1418 }
1419