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