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