]> git.saurik.com Git - apple/securityd.git/blob - securityd_service/securityd_service/main.c
18283a816595f7f2ea15d24e8d0b99ff6757112a
[apple/securityd.git] / securityd_service / securityd_service / main.c
1 /* Copyright (c) 2013 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 <stdio.h>
15 #include <errno.h>
16 #include <assert.h>
17 #include <syslog.h>
18 #include <unistd.h>
19 #include <pwd.h>
20 #include <uuid/uuid.h>
21 #include <bsm/libbsm.h>
22 #include <copyfile.h>
23 #include <AssertMacros.h>
24 #include <Security/Security.h>
25 #include <Security/SecKeychainPriv.h>
26
27 #include <IOKit/IOKitLib.h>
28 #include <Kernel/IOKit/crypto/AppleFDEKeyStoreDefs.h>
29
30 #if DEBUG
31 #define LOG(...) syslog(LOG_NOTICE, ##__VA_ARGS__);
32 #else
33 #define LOG(...)
34 #endif
35
36 // exported from libaks.a
37 kern_return_t _aks_stash_create_internal(keybag_handle_t handle, bool stage_key, const void * passcode, int length);
38 kern_return_t _aks_stash_load_internal(keybag_handle_t handle, bool verify, uint8_t * data, size_t length, keybag_handle_t * handle_out);
39 kern_return_t _aks_stash_destroy_internal(void);
40 kern_return_t _aks_stash_commit_internal(void ** data, int * length);
41
42 const char * kb_home_path = "Library/Keychains";
43 const char * kb_user_bag = "user.kb";
44 const char * kb_stash_bag = "stash.kb";
45
46 typedef struct {
47 uid_t uid;
48 gid_t gid;
49 char * name;
50 char * home;
51 } service_user_record_t;
52
53 typedef enum {
54 kb_bag_type_user,
55 kb_bag_type_stash
56 } kb_bag_type_t;
57
58 static io_connect_t
59 openiodev(void)
60 {
61 io_registry_entry_t service;
62 io_connect_t conn;
63 kern_return_t kr;
64
65 service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(kAppleFDEKeyStoreServiceName));
66 if (service == IO_OBJECT_NULL)
67 return IO_OBJECT_NULL;
68
69 kr = IOServiceOpen(service, mach_task_self(), 0, &conn);
70 if (kr != KERN_SUCCESS)
71 return IO_OBJECT_NULL;
72
73 kr = IOConnectCallMethod(conn, kAppleFDEKeyStoreUserClientOpen, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL);
74 if (kr != KERN_SUCCESS) {
75 IOServiceClose(conn);
76 return IO_OBJECT_NULL;
77 }
78
79 return conn;
80 }
81
82 static void
83 closeiodev(io_connect_t conn)
84 {
85 kern_return_t kr;
86 kr = IOConnectCallMethod(conn, kAppleFDEKeyStoreUserClientClose, NULL, 0, NULL, 0, NULL, NULL, NULL, NULL);
87 if (kr != KERN_SUCCESS)
88 return;
89 IOServiceClose(conn);
90 }
91
92 static dispatch_queue_t
93 _kb_service_get_dispatch_queue()
94 {
95 static dispatch_once_t onceToken = 0;
96 static dispatch_queue_t connection_queue = NULL;
97
98 dispatch_once(&onceToken, ^{
99 connection_queue = dispatch_queue_create("kb-service-queue", DISPATCH_QUEUE_SERIAL);
100 });
101
102 return connection_queue;
103 }
104
105 static service_user_record_t * get_user_record(uid_t uid)
106 {
107 service_user_record_t * ur = NULL;
108 long bufsize = 0;
109 if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) {
110 bufsize = 4096;
111 }
112 char buf[bufsize];
113 struct passwd pwbuf, *pw = NULL;
114 if ((getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0) && pw != NULL) {
115 ur = calloc(1u, sizeof(service_user_record_t));
116 require(ur, done);
117 ur->uid = pw->pw_uid;
118 ur->gid = pw->pw_gid;
119 ur->home = strdup(pw->pw_dir);
120 ur->name = strdup(pw->pw_name);
121 } else {
122 syslog(LOG_ERR, "failed to lookup user record for uid: %d", uid);
123 }
124
125 done:
126 return ur;
127 }
128
129 static void free_user_record(service_user_record_t * ur)
130 {
131 if (ur != NULL) {
132 if (ur->home) {
133 free(ur->home);
134 }
135 if (ur->name) {
136 free(ur->name);
137 }
138 free(ur);
139 }
140 }
141
142 static const char * get_host_uuid()
143 {
144 static uuid_string_t hostuuid = {};
145 static dispatch_once_t onceToken;
146 dispatch_once(&onceToken, ^{
147 struct timespec timeout = {30, 0};
148 uuid_t uuid = {};
149 if (gethostuuid(uuid, &timeout) == 0) {
150 uuid_unparse(uuid, hostuuid);
151 } else {
152 syslog(LOG_ERR, "failed to get host uuid");
153 }
154 });
155
156 return hostuuid;
157 }
158
159 static char *
160 _kb_copy_bag_filename(service_user_record_t * ur, kb_bag_type_t type)
161 {
162 char * bag_file = NULL;
163 const char * name = NULL;
164
165 require(ur, done);
166 switch(type) {
167 case kb_bag_type_user:
168 name = kb_user_bag;
169 break;
170 case kb_bag_type_stash:
171 name = kb_stash_bag;
172 break;
173 default:
174 goto done;
175 }
176
177 bag_file = calloc(1u, PATH_MAX);
178 require(bag_file, done);
179
180 snprintf(bag_file, PATH_MAX, "%s/%s/%s/%s", ur->home, kb_home_path, get_host_uuid(), name);
181
182 done:
183 return bag_file;
184 }
185
186 static bool
187 _kb_verify_create_path(service_user_record_t * ur)
188 {
189 bool created = false;
190 struct stat st_info = {};
191 char new_path[PATH_MAX] = {};
192 char kb_path[PATH_MAX] = {};
193 snprintf(kb_path, sizeof(kb_path), "%s/%s/%s", ur->home, kb_home_path, get_host_uuid());
194 if (lstat(kb_path, &st_info) == 0) {
195 if (S_ISDIR(st_info.st_mode)) {
196 created = true;
197 } else {
198 syslog(LOG_ERR, "invalid directory at '%s' moving aside", kb_path);
199 snprintf(new_path, sizeof(new_path), "%s-invalid", kb_path);
200 unlink(new_path);
201 if (rename(kb_path, new_path) != 0) {
202 syslog(LOG_ERR, "failed to rename file: %s (%s)", kb_path, strerror(errno));
203 goto done;
204 }
205 }
206 }
207 if (!created) {
208 require_action(mkpath_np(kb_path, 0700) == 0, done, syslog(LOG_ERR, "could not create path: %s (%s)", kb_path, strerror(errno)));
209 created = true;
210 }
211
212 done:
213 return created;
214 }
215
216 static void
217 _set_thread_credentials(service_user_record_t * ur)
218 {
219 int rc = pthread_setugid_np(ur->uid, ur->gid);
220 if (rc) { syslog(LOG_ERR, "failed to set thread credential: %i (%s)", errno, strerror(errno)); }
221
222 rc = initgroups(ur->name, ur->gid);
223 if (rc) { syslog(LOG_ERR, "failed to initgroups: %i", rc); }
224 }
225
226 static void
227 _clear_thread_credentials()
228 {
229 int rc = pthread_setugid_np(KAUTH_UID_NONE, KAUTH_GID_NONE);
230 if (rc) { syslog(LOG_ERR, "failed to reset thread credential: %i (%s)", errno, strerror(errno)); }
231 }
232
233 static bool
234 _kb_bag_exists(service_user_record_t * ur, const char * bag_file)
235 {
236 bool exists = false;
237 struct stat st_info = {};
238 char new_file[PATH_MAX] = {};
239
240 require(ur, done);
241
242 _set_thread_credentials(ur);
243 if (lstat(bag_file, &st_info) == 0) {
244 if (S_ISREG(st_info.st_mode)) {
245 exists = true;
246 } else {
247 syslog(LOG_ERR, "invalid file at '%s' moving aside", bag_file);
248 snprintf(new_file, sizeof(new_file), "%s-invalid", bag_file);
249 unlink(new_file);
250 if (rename(bag_file, new_file) != 0) {
251 syslog(LOG_ERR, "failed to rename file: %s (%s)", bag_file, strerror(errno));
252 }
253 }
254 }
255
256 done:
257 _clear_thread_credentials();
258 return exists;
259 }
260
261 static bool
262 _kb_save_bag_to_disk(service_user_record_t * ur, const char * bag_file, void * data, size_t length)
263 {
264 bool result = false;
265 int fd = -1;
266
267 require(bag_file, done);
268
269 _set_thread_credentials(ur);
270 require(_kb_verify_create_path(ur), done);
271
272 fd = open(bag_file, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0600);
273 require_action(fd != -1, done, syslog(LOG_ERR, "could not create file: %s (%s)", bag_file, strerror(errno)));
274 require_action(write(fd, data, length) != -1, done, syslog(LOG_ERR, "failed to write keybag to disk %s", strerror(errno)));
275
276 result = true;
277
278 done:
279 if (fd != -1) { close(fd); }
280 _clear_thread_credentials();
281 return result;
282 }
283
284 static bool
285 _kb_load_bag_from_disk(service_user_record_t * ur, const char * bag_file, uint8_t ** data, size_t * length)
286 {
287 bool result = false;
288 int fd = -1;
289 uint8_t * buf = NULL;
290 size_t buf_size = 0;
291 struct stat st_info = {};
292
293 require(bag_file, done);
294
295 _set_thread_credentials(ur);
296 require(_kb_verify_create_path(ur), done);
297 require_quiet(lstat(bag_file, &st_info) == 0, done);
298 require_action(S_ISREG(st_info.st_mode), done, syslog(LOG_ERR, "failed to load, not a file: %s", bag_file));
299 buf_size = (size_t)st_info.st_size;
300
301 fd = open(bag_file, O_RDONLY | O_NOFOLLOW);
302 require_action(fd != -1, done, syslog(LOG_ERR, "could not open file: %s (%s)", bag_file, strerror(errno)));
303
304 buf = (uint8_t *)calloc(1u, buf_size);
305 require(buf != NULL, done);
306 require(read(fd, buf, buf_size) == buf_size, done);
307
308 *data = buf;
309 *length = buf_size;
310 buf = NULL;
311 result = true;
312
313 done:
314 if (fd != -1) { close(fd); }
315 if (buf) { free(buf); }
316 _clear_thread_credentials();
317 return result;
318 }
319
320 static void
321 _kb_rename_bag_on_disk(service_user_record_t * ur, const char * bag_file)
322 {
323 char new_file[PATH_MAX] = {};
324 if (bag_file) {
325 _set_thread_credentials(ur);
326 snprintf(new_file, sizeof(new_file), "%s-invalid", bag_file);
327 unlink(new_file);
328 rename(bag_file, new_file);
329 _clear_thread_credentials();
330 }
331 }
332
333 static void
334 _kb_delete_bag_on_disk(service_user_record_t * ur, const char * bag_file)
335 {
336 if (bag_file) {
337 _set_thread_credentials(ur);
338 unlink(bag_file);
339 _clear_thread_credentials();
340 }
341 }
342
343 static void
344 _kb_migrate_old_bag_if_exists(service_user_record_t * ur)
345 {
346 char session_file[PATH_MAX] = {};
347 struct stat st_info = {};
348 char * bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user);
349
350 if (bag_file) {
351 snprintf(session_file, sizeof(session_file), "/var/keybags/%i.kb", ur->uid);
352
353 // if the bag_file does not exist
354 // check for the session_file and copy it into place
355 if (!_kb_bag_exists(ur, bag_file)) {
356 if (lstat(session_file, &st_info) == 0 && (S_ISREG(st_info.st_mode))) {
357 lchmod("/var/keybags", 0777);
358 lchmod(session_file, 0666);
359 _set_thread_credentials(ur);
360 _kb_verify_create_path(ur);
361 syslog(LOG_ERR, "migrating %s to %s", session_file, bag_file);
362 copyfile(session_file, bag_file, NULL, COPYFILE_ALL | COPYFILE_MOVE | COPYFILE_NOFOLLOW | COPYFILE_EXCL);
363 lchmod(bag_file, 0600);
364 _clear_thread_credentials();
365 }
366 }
367 free(bag_file);
368 }
369 }
370
371 static int
372 _kb_get_session_handle(service_context_t * context, keybag_handle_t * handle_out)
373 {
374 int rc = KB_BagNotLoaded;
375 keybag_handle_t session_handle = bad_keybag_handle;
376 require_noerr_quiet(aks_get_system(context->s_uid, &session_handle), done);
377
378 *handle_out = session_handle;
379 rc = KB_Success;
380
381 done:
382 return rc;
383 }
384
385 static int
386 service_kb_create(service_context_t * context, const void * secret, int secret_len)
387 {
388 __block int rc = KB_GeneralError;
389
390 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
391 uint8_t * buf = NULL;
392 size_t buf_size = 0;
393 keybag_handle_t session_handle = bad_keybag_handle;
394 service_user_record_t * ur = get_user_record(context->s_uid);
395 char * bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user);
396
397 require(bag_file, done);
398
399 // check for the existance of the bagfile
400 require_action(!_kb_bag_exists(ur, bag_file), done, rc = KB_BagExists);
401
402 require_noerr(rc = aks_create_bag(secret, secret_len, kAppleKeyStoreDeviceBag, &session_handle), done);
403 require_noerr(rc = aks_save_bag(session_handle, (void**)&buf, (int*)&buf_size), done);
404 require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done, rc = KB_BagError);
405 require_noerr(rc = aks_set_system(session_handle, context->s_uid), done);
406 aks_unload_bag(session_handle);
407 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
408
409 if (secret && rc == KB_Success) {
410 aks_unlock_bag(session_handle, secret, secret_len);
411 }
412
413 done:
414 if (buf) free(buf);
415 if (bag_file) { free(bag_file); }
416 if (ur) free_user_record(ur);
417 });
418
419 return rc;
420 }
421
422 static int
423 service_kb_load(service_context_t * context)
424 {
425 __block int rc = KB_GeneralError;
426
427 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
428 uint8_t * buf = NULL;
429 size_t buf_size = 0;
430 keybag_handle_t session_handle = bad_keybag_handle;
431 service_user_record_t * ur = NULL;
432 char * bag_file = NULL;
433
434 rc = aks_get_system(context->s_uid, &session_handle);
435 if (rc == kIOReturnNotFound) {
436 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
437 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError);
438 require_action_quiet(_kb_load_bag_from_disk(ur, bag_file, &buf, &buf_size), done, rc = KB_BagNotFound);
439 rc = aks_load_bag(buf, (int)buf_size, &session_handle);
440 if (rc == kIOReturnNotPermitted) {
441 syslog(LOG_ERR, "error loading keybag for uid (%i) in session (%i)", context->s_uid, context->s_id);
442 _kb_rename_bag_on_disk(ur, bag_file);
443 rc = KB_BagNotFound;
444 }
445 require_noerr(rc, done);
446 require_noerr(rc = aks_set_system(session_handle, context->s_uid), done);
447 aks_unload_bag(session_handle);
448 }
449 require(rc == KB_Success, done);
450
451 done:
452 if (buf) free(buf);
453 if (ur) free_user_record(ur);
454 if (bag_file) free(bag_file);
455 });
456
457 return rc;
458 }
459
460
461 static int
462 service_kb_unlock(service_context_t * context, const void * secret, int secret_len)
463 {
464 int rc = KB_GeneralError;
465 keybag_handle_t session_handle;
466 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
467
468 rc = aks_unlock_bag(session_handle, secret, secret_len);
469
470 done:
471 return rc;
472 }
473
474 static int
475 service_kb_lock(service_context_t * context)
476 {
477 int rc = KB_GeneralError;
478 keybag_handle_t session_handle;
479 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
480
481 rc = aks_lock_bag(session_handle);
482
483 done:
484 return rc;
485 }
486
487 static int
488 service_kb_change_secret(service_context_t * context, const void * secret, int secret_len, const void * new_secret, int new_secret_len)
489 {
490 __block int rc = KB_GeneralError;
491 keybag_handle_t session_handle;
492 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
493
494 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
495 uint8_t * buf = NULL;
496 size_t buf_size = 0;
497 service_user_record_t * ur = NULL;
498 char * bag_file = NULL;
499
500 require_noerr(rc = aks_change_secret(session_handle, secret, secret_len, new_secret, new_secret_len), done);
501 require_noerr(rc = aks_save_bag(session_handle, (void**)&buf, (int*)&buf_size), done);
502 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
503 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError);
504 require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done, rc = KB_BagError);
505
506 rc = KB_Success;
507
508 done:
509 if (buf) free(buf);
510 if (ur) free_user_record(ur);
511 if (bag_file) free(bag_file);
512 return;
513 });
514
515 done:
516 return rc;
517 }
518
519 static int
520 service_kb_reset(service_context_t * context, const void * secret, int secret_len)
521 {
522 __block int rc = KB_GeneralError;
523 service_user_record_t * ur = NULL;
524 char * bag_file = NULL;
525
526 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
527 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_user), done, rc = KB_GeneralError);
528
529 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
530 uint8_t * buf = NULL;
531 size_t buf_size = 0;
532 keybag_handle_t session_handle = bad_keybag_handle;
533
534 syslog(LOG_ERR, "resetting keybag for uid (%i) in session (%i)", context->s_uid, context->s_id);
535 _kb_rename_bag_on_disk(ur, bag_file);
536
537 require_noerr(rc = aks_create_bag(secret, secret_len, kAppleKeyStoreDeviceBag, &session_handle), done);
538 require_noerr(rc = aks_save_bag(session_handle, (void**)&buf, (int*)&buf_size), done);
539 require_action(_kb_save_bag_to_disk(ur, bag_file, buf, buf_size), done, rc = KB_BagError);
540 require_noerr(rc = aks_set_system(session_handle, context->s_uid), done);
541 aks_unload_bag(session_handle);
542 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
543
544 if (secret && rc == KB_Success) {
545 aks_unlock_bag(session_handle, secret, secret_len);
546 }
547
548 done:
549 if (buf) free(buf);
550 return;
551 });
552
553 done:
554 if (ur) free_user_record(ur);
555 if (bag_file) free(bag_file);
556 return rc;
557 }
558
559 static int
560 service_kb_is_locked(service_context_t * context, xpc_object_t reply)
561 {
562 int rc = KB_GeneralError;
563 keybag_state_t state;
564 keybag_handle_t session_handle;
565 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
566
567 require_noerr(rc = aks_get_lock_state(session_handle, &state), done);
568
569 xpc_dictionary_set_bool(reply, SERVICE_XPC_LOCKED, state & keybag_state_locked);
570 xpc_dictionary_set_bool(reply, SERVICE_XPC_NO_PIN, state & keybag_state_no_pin);
571
572 done:
573 return rc;
574 }
575
576 static int
577 service_kb_stash_create(service_context_t * context, const void * key, unsigned key_size)
578 {
579 int rc = KB_GeneralError;
580 char * bag_file = NULL;
581 keybag_handle_t session_handle;
582 service_user_record_t * ur = NULL;
583 void * stashbag = NULL;
584 unsigned stashbag_size = 0;
585 __block bool saved = false;
586
587 require(key, done);
588 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
589 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
590 require_noerr(rc = _aks_stash_create_internal(session_handle, false, key, key_size), done);
591 require_noerr(rc = _aks_stash_commit_internal((void**)&stashbag, (int*)&stashbag_size), done);
592
593 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_stash), done, rc = KB_GeneralError);
594
595 // sync writing the bag to disk
596 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
597 saved = _kb_save_bag_to_disk(ur, bag_file, stashbag, stashbag_size);
598 });
599 require_action(saved, done, rc = KB_BagError);
600 rc = KB_Success;
601
602 done:
603 if (stashbag) { free(stashbag); }
604 if (bag_file) { free(bag_file); }
605 if (ur) free_user_record(ur);
606 return rc;
607 }
608
609 static int
610 service_kb_stash_load(service_context_t * context, const void * key, unsigned key_size)
611 {
612 __block int rc = KB_GeneralError;
613 char * bag_file = NULL;
614 keybag_handle_t session_handle;
615 service_user_record_t * ur = NULL;
616 __block uint8_t * stashbag = NULL;
617 __block size_t stashbag_size = 0;
618
619 require(key, done);
620 require_noerr(rc = _kb_get_session_handle(context, &session_handle), done);
621 require_action(ur = get_user_record(context->s_uid), done, rc = KB_GeneralError);
622 require_action(bag_file = _kb_copy_bag_filename(ur, kb_bag_type_stash), done, rc = KB_GeneralError);
623
624 // sync loading the bag from disk
625 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
626 if (!_kb_load_bag_from_disk(ur, bag_file, &stashbag, &stashbag_size)) {
627 rc = KB_BagError;
628 }
629 });
630 require_noerr(rc, done);
631
632 require_noerr(rc = _aks_stash_create_internal(session_handle, true, key, key_size), done);
633 require_noerr(rc = _aks_stash_load_internal(session_handle, false, stashbag, stashbag_size, NULL), done);
634 rc = KB_Success;
635
636 done:
637 if (stashbag) { free(stashbag); }
638 if (bag_file) {
639 _kb_delete_bag_on_disk(ur, bag_file);
640 free(bag_file);
641 }
642 if (ur) free_user_record(ur);
643 return rc;
644 }
645
646 //
647 // Get the keychain master key from the AppleFDEKeyStore.
648 // Note that this is a one-time call - the master key is
649 // removed from the keystore after it is returned.
650 // Requires the entitlement: com.apple.private.securityd.keychain
651 //
652 OSStatus service_stash_get_key(service_context_t * context, xpc_object_t event, xpc_object_t reply)
653 {
654 getStashKey_InStruct_t inStruct;
655 getStashKey_OutStruct_t outStruct;
656 size_t outSize = sizeof(outStruct);
657 kern_return_t kr = KERN_INVALID_ARGUMENT;
658
659 io_connect_t conn = openiodev();
660 require(conn, done);
661 inStruct.type = kAppleFDEKeyStoreStash_master;
662
663 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_getStashKey,
664 NULL, 0,
665 &inStruct, sizeof(inStruct),
666 NULL, NULL,
667 &outStruct, &outSize);
668
669 if (kr == KERN_SUCCESS) {
670 xpc_dictionary_set_data(reply, SERVICE_XPC_KEY, outStruct.outBuf.key.key, outStruct.outBuf.key.keysize);
671 service_kb_stash_load(context, outStruct.outBuf.key.key, outStruct.outBuf.key.keysize);
672 }
673
674 done:
675 if (conn)
676 closeiodev(conn);
677
678 return kr;
679 }
680
681 //
682 // Stash the keychain master key in the AppleFDEKeyStore and
683 // flag it as the keychain master key to be added to the
684 // reboot NVRAM blob.
685 // This requires two calls to the AKS: the first to store the
686 // key and get its uuid. The second uses the uuid to flag the
687 // key for blob inclusion.
688 //
689 OSStatus service_stash_set_key(service_context_t * context, xpc_object_t event, xpc_object_t reply)
690 {
691 kern_return_t kr = KERN_INVALID_ARGUMENT;
692 size_t keydata_len = 0;
693 size_t len;
694
695 io_connect_t conn = openiodev();
696 require(conn, done);
697
698 // Store the key in the keystore and get its uuid
699 setKeyGetUUID_InStruct_t inStruct1;
700 uuid_OutStruct_t outStruct1;
701
702
703 const uint8_t *keydata = xpc_dictionary_get_data(event, SERVICE_XPC_KEY, &keydata_len);
704 require(keydata, done);
705
706 memcpy(&inStruct1.inKey.key.key, keydata, keydata_len);
707 inStruct1.inKey.key.keysize = (cryptosize_t) keydata_len;
708 len = sizeof(outStruct1);
709 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_setKeyGetUUID,
710 NULL, 0,
711 &inStruct1, sizeof(inStruct1),
712 NULL, NULL,
713 &outStruct1, &len);
714 require(kr == KERN_SUCCESS, done);
715
716 // Now using the uuid stash it as the master key
717 setStashKey_InStruct_t inStruct2;
718 memcpy(&inStruct2.uuid, &outStruct1.uuid, sizeof(outStruct1.uuid));
719 inStruct2.type = kAppleFDEKeyStoreStash_master;
720
721 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_setStashKey,
722 NULL, 0,
723 &inStruct2, sizeof(inStruct2),
724 NULL, NULL,
725 NULL, NULL);
726
727 if (kr == KERN_SUCCESS) {
728 service_kb_stash_create(context, keydata, (unsigned)keydata_len);
729 }
730 done:
731 if (conn)
732 closeiodev(conn);
733
734 return kr;
735 }
736
737 //
738 // Signal the AppleFDEKeyStore to take the tagged FDE key
739 // and keychain master key, stash them in an encrypted
740 // blob structure and write the blob to NVRAM. The random
741 // encryption key is written to the SMC.
742 //
743 #if DEBUG
744 OSStatus service_stash_blob(xpc_object_t event, xpc_object_t reply)
745 {
746 kern_return_t kr = KERN_INVALID_ARGUMENT;
747
748 io_connect_t conn = openiodev();
749 require(conn, done);
750
751 kr = IOConnectCallMethod(conn, kAppleFDEKeyStore_commitStash,
752 NULL, 0,
753 NULL, 0,
754 NULL, NULL,
755 NULL, NULL);
756 done:
757 if (conn)
758 closeiodev(conn);
759
760 return kr;
761 }
762 #endif
763
764 bool peer_has_entitlement(xpc_connection_t peer, const char * entitlement)
765 {
766 bool entitled = false;
767
768 xpc_object_t value = xpc_connection_copy_entitlement_value(peer, entitlement);
769 if (value && (xpc_get_type(value) == XPC_TYPE_BOOL)) {
770 entitled = xpc_bool_get_value(value);
771 }
772
773 if (value) xpc_release(value);
774 return entitled;
775 }
776
777 void service_peer_event_handler(xpc_connection_t connection, xpc_object_t event)
778 {
779 xpc_type_t type = xpc_get_type(event);
780
781 if (type == XPC_TYPE_ERROR) {
782 if (event == XPC_ERROR_CONNECTION_INVALID) {
783 }
784 } else {
785 assert(type == XPC_TYPE_DICTIONARY);
786
787 int rc = KB_GeneralError;
788 uint64_t request = 0;
789 const uint8_t * secret = NULL, * new_secret = NULL;
790 size_t secret_len = 0, new_secret_len = 0, data_len = 0;
791 service_context_t * context = NULL;
792 const void * data;
793
794 xpc_object_t reply = xpc_dictionary_create_reply(event);
795
796 data = xpc_dictionary_get_data(event, SERVICE_XPC_CONTEXT, &data_len);
797 require(data, done);
798 require(data_len == sizeof(service_context_t), done);
799 context = (service_context_t*)data;
800
801 request = xpc_dictionary_get_uint64(event, SERVICE_XPC_REQUEST);
802
803 require_action(context->s_id != AU_DEFAUDITSID, done, rc = KB_InvalidSession);
804 require_action(context->s_uid != AU_DEFAUDITID, done, rc = KB_InvalidSession); // we only want to work in actual user sessions.
805
806 switch (request) {
807 case SERVICE_KB_CREATE:
808 // if (kb_service_has_entitlement(peer, "com.apple.keystore.device")) {
809 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
810 rc = service_kb_create(context, secret, (int)secret_len);
811 // }
812 break;
813 case SERVICE_KB_LOAD:
814 rc = service_kb_load(context);
815 break;
816 case SERVICE_KB_UNLOCK:
817 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
818 rc = service_kb_unlock(context, secret, (int)secret_len);
819 break;
820 case SERVICE_KB_LOCK:
821 rc = service_kb_lock(context);
822 break;
823 case SERVICE_KB_CHANGE_SECRET:
824 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
825 new_secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET_NEW, &new_secret_len);
826 rc = service_kb_change_secret(context, secret, (int)secret_len, new_secret, (int)new_secret_len);
827 break;
828 case SERVICE_KB_RESET:
829 secret = xpc_dictionary_get_data(event, SERVICE_XPC_SECRET, &secret_len);
830 rc = service_kb_reset(context, secret, (int)secret_len);
831 break;
832 case SERVICE_KB_IS_LOCKED:
833 rc = service_kb_is_locked(context, reply);
834 break;
835 case SERVICE_STASH_GET_KEY:
836 rc = service_stash_get_key(context, event, reply);
837 break;
838 case SERVICE_STASH_SET_KEY:
839 rc = service_stash_set_key(context, event, reply);
840 break;
841 #if DEBUG
842 case SERVICE_STASH_BLOB:
843 rc = service_stash_blob(event, reply);
844 break;
845 #endif
846 default:
847 LOG("unknown service type");
848 break;
849 }
850
851 done:
852 LOG("selector: %llu, error: %x, secret_len: %zu, new_secret_len: %zu, sid: %d, suid: %d)", request, rc, secret_len, new_secret_len, context ? context->s_id : 0, context ? context->s_uid : 0);
853 xpc_dictionary_set_int64(reply, SERVICE_XPC_RC, rc);
854 xpc_connection_send_message(connection, reply);
855 xpc_release(reply);
856 }
857 }
858
859 bool check_signature(xpc_connection_t connection)
860 {
861 CFStringRef reqStr = CFSTR("identifier com.apple.securityd and anchor apple");
862 SecRequirementRef requirement = NULL;
863 SecCodeRef codeRef = NULL;
864 CFMutableDictionaryRef codeDict = NULL;
865 CFNumberRef codePid = NULL;
866 pid_t pid = xpc_connection_get_pid(connection);
867
868 OSStatus status = SecRequirementCreateWithString(reqStr, kSecCSDefaultFlags, &requirement);
869 require_action(status == errSecSuccess, done, LOG("failed to create requirement"));
870
871 codeDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
872 codePid = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &pid);
873 CFDictionarySetValue(codeDict, kSecGuestAttributePid, codePid);
874 status = SecCodeCopyGuestWithAttributes(NULL, codeDict, kSecCSDefaultFlags, &codeRef);
875 require_action(status == errSecSuccess, done, LOG("failed to get code ref"));
876
877 status = SecCodeCheckValidity(codeRef, kSecCSDefaultFlags,
878 #if DEBUG || RC_BUILDIT_YES
879 NULL);
880 #else
881 requirement);
882 #endif
883 require_action(status == errSecSuccess, done, syslog(LOG_ERR, "pid %d, does not satisfy code requirment (%d)", pid, status));
884
885 done:
886 if (codeRef) CFRelease(codeRef);
887 if (requirement) CFRelease(requirement);
888 if (codeDict) CFRelease(codeDict);
889 if (codePid) CFRelease(codePid);
890
891 return (status == errSecSuccess);
892 }
893
894 int main(int argc, const char * argv[])
895 {
896 char * errorbuf;
897 if (sandbox_init(SECURITYD_SERVICE_NAME, SANDBOX_NAMED, &errorbuf) != 0) {
898 syslog(LOG_ERR, "sandbox_init failed %s", errorbuf);
899 sandbox_free_error(errorbuf);
900 #ifndef DEBUG
901 abort();
902 #endif
903 }
904
905 xpc_connection_t listener = xpc_connection_create_mach_service(SECURITYD_SERVICE_NAME, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
906 xpc_connection_set_event_handler(listener, ^(xpc_object_t peer) {
907 // It is safe to cast 'peer' to xpc_connection_t assuming
908 // we have a correct configuration in our launchd.plist.
909
910 if (xpc_connection_get_euid(peer) != 0) {
911 xpc_connection_cancel(peer);
912 return;
913 }
914
915 if (!check_signature(peer)) {
916 xpc_connection_cancel(peer);
917 return;
918 }
919
920 xpc_connection_set_event_handler(peer, ^(xpc_object_t event) {
921 vproc_transaction_t transaction = vproc_transaction_begin(NULL);
922 service_peer_event_handler(peer, event);
923 vproc_transaction_end(NULL, transaction);
924 });
925 xpc_connection_resume(peer);
926 });
927 xpc_connection_resume(listener);
928
929 dispatch_main();
930 exit(EXIT_FAILURE);
931 }
932