1 /* Copyright (c) 2013 Apple Inc. All rights reserved. */
3 #include "securityd_service.h"
4 #include "securityd_service_client.h"
10 #include <xpc/private.h>
11 #include <dispatch/dispatch.h>
12 #include <sys/types.h>
20 #include <uuid/uuid.h>
21 #include <bsm/libbsm.h>
23 #include <AssertMacros.h>
24 #include <Security/Security.h>
25 #include <Security/SecKeychainPriv.h>
27 #include <IOKit/IOKitLib.h>
28 #include <Kernel/IOKit/crypto/AppleFDEKeyStoreDefs.h>
31 #define LOG(...) syslog(LOG_NOTICE, ##__VA_ARGS__);
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
);
42 const char * kb_home_path
= "Library/Keychains";
43 const char * kb_user_bag
= "user.kb";
44 const char * kb_stash_bag
= "stash.kb";
51 } service_user_record_t
;
61 io_registry_entry_t service
;
65 service
= IOServiceGetMatchingService(kIOMasterPortDefault
, IOServiceMatching(kAppleFDEKeyStoreServiceName
));
66 if (service
== IO_OBJECT_NULL
)
67 return IO_OBJECT_NULL
;
69 kr
= IOServiceOpen(service
, mach_task_self(), 0, &conn
);
70 if (kr
!= KERN_SUCCESS
)
71 return IO_OBJECT_NULL
;
73 kr
= IOConnectCallMethod(conn
, kAppleFDEKeyStoreUserClientOpen
, NULL
, 0, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
74 if (kr
!= KERN_SUCCESS
) {
76 return IO_OBJECT_NULL
;
83 closeiodev(io_connect_t conn
)
86 kr
= IOConnectCallMethod(conn
, kAppleFDEKeyStoreUserClientClose
, NULL
, 0, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
87 if (kr
!= KERN_SUCCESS
)
92 static dispatch_queue_t
93 _kb_service_get_dispatch_queue()
95 static dispatch_once_t onceToken
= 0;
96 static dispatch_queue_t connection_queue
= NULL
;
98 dispatch_once(&onceToken
, ^{
99 connection_queue
= dispatch_queue_create("kb-service-queue", DISPATCH_QUEUE_SERIAL
);
102 return connection_queue
;
105 static service_user_record_t
* get_user_record(uid_t uid
)
107 service_user_record_t
* ur
= NULL
;
109 if ((bufsize
= sysconf(_SC_GETPW_R_SIZE_MAX
)) == -1) {
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
));
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
);
122 syslog(LOG_ERR
, "failed to lookup user record for uid: %d", uid
);
129 static void free_user_record(service_user_record_t
* ur
)
142 static const char * get_host_uuid()
144 static uuid_string_t hostuuid
= {};
145 static dispatch_once_t onceToken
;
146 dispatch_once(&onceToken
, ^{
147 struct timespec timeout
= {30, 0};
149 if (gethostuuid(uuid
, &timeout
) == 0) {
150 uuid_unparse(uuid
, hostuuid
);
152 syslog(LOG_ERR
, "failed to get host uuid");
160 _kb_copy_bag_filename(service_user_record_t
* ur
, kb_bag_type_t type
)
162 char * bag_file
= NULL
;
163 const char * name
= NULL
;
167 case kb_bag_type_user
:
170 case kb_bag_type_stash
:
177 bag_file
= calloc(1u, PATH_MAX
);
178 require(bag_file
, done
);
180 snprintf(bag_file
, PATH_MAX
, "%s/%s/%s/%s", ur
->home
, kb_home_path
, get_host_uuid(), name
);
187 _kb_verify_create_path(service_user_record_t
* ur
)
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
)) {
198 syslog(LOG_ERR
, "invalid directory at '%s' moving aside", kb_path
);
199 snprintf(new_path
, sizeof(new_path
), "%s-invalid", kb_path
);
201 if (rename(kb_path
, new_path
) != 0) {
202 syslog(LOG_ERR
, "failed to rename file: %s (%s)", kb_path
, strerror(errno
));
208 require_action(mkpath_np(kb_path
, 0700) == 0, done
, syslog(LOG_ERR
, "could not create path: %s (%s)", kb_path
, strerror(errno
)));
217 _set_thread_credentials(service_user_record_t
* ur
)
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
)); }
222 rc
= initgroups(ur
->name
, ur
->gid
);
223 if (rc
) { syslog(LOG_ERR
, "failed to initgroups: %i", rc
); }
227 _clear_thread_credentials()
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
)); }
234 _kb_bag_exists(service_user_record_t
* ur
, const char * bag_file
)
237 struct stat st_info
= {};
238 char new_file
[PATH_MAX
] = {};
242 _set_thread_credentials(ur
);
243 if (lstat(bag_file
, &st_info
) == 0) {
244 if (S_ISREG(st_info
.st_mode
)) {
247 syslog(LOG_ERR
, "invalid file at '%s' moving aside", bag_file
);
248 snprintf(new_file
, sizeof(new_file
), "%s-invalid", bag_file
);
250 if (rename(bag_file
, new_file
) != 0) {
251 syslog(LOG_ERR
, "failed to rename file: %s (%s)", bag_file
, strerror(errno
));
257 _clear_thread_credentials();
262 _kb_save_bag_to_disk(service_user_record_t
* ur
, const char * bag_file
, void * data
, size_t length
)
267 require(bag_file
, done
);
269 _set_thread_credentials(ur
);
270 require(_kb_verify_create_path(ur
), done
);
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
)));
279 if (fd
!= -1) { close(fd
); }
280 _clear_thread_credentials();
285 _kb_load_bag_from_disk(service_user_record_t
* ur
, const char * bag_file
, uint8_t ** data
, size_t * length
)
289 uint8_t * buf
= NULL
;
291 struct stat st_info
= {};
293 require(bag_file
, done
);
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
;
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
)));
304 buf
= (uint8_t *)calloc(1u, buf_size
);
305 require(buf
!= NULL
, done
);
306 require(read(fd
, buf
, buf_size
) == buf_size
, done
);
314 if (fd
!= -1) { close(fd
); }
315 if (buf
) { free(buf
); }
316 _clear_thread_credentials();
321 _kb_rename_bag_on_disk(service_user_record_t
* ur
, const char * bag_file
)
323 char new_file
[PATH_MAX
] = {};
325 _set_thread_credentials(ur
);
326 snprintf(new_file
, sizeof(new_file
), "%s-invalid", bag_file
);
328 rename(bag_file
, new_file
);
329 _clear_thread_credentials();
334 _kb_delete_bag_on_disk(service_user_record_t
* ur
, const char * bag_file
)
337 _set_thread_credentials(ur
);
339 _clear_thread_credentials();
344 _kb_migrate_old_bag_if_exists(service_user_record_t
* ur
)
346 char session_file
[PATH_MAX
] = {};
347 struct stat st_info
= {};
348 char * bag_file
= _kb_copy_bag_filename(ur
, kb_bag_type_user
);
351 snprintf(session_file
, sizeof(session_file
), "/var/keybags/%i.kb", ur
->uid
);
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();
372 _kb_get_session_handle(service_context_t
* context
, keybag_handle_t
* handle_out
)
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
);
378 *handle_out
= session_handle
;
386 service_kb_create(service_context_t
* context
, const void * secret
, int secret_len
)
388 __block
int rc
= KB_GeneralError
;
390 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
391 uint8_t * buf
= NULL
;
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
);
397 require(bag_file
, done
);
399 // check for the existance of the bagfile
400 require_action(!_kb_bag_exists(ur
, bag_file
), done
, rc
= KB_BagExists
);
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
);
409 if (secret
&& rc
== KB_Success
) {
410 aks_unlock_bag(session_handle
, secret
, secret_len
);
415 if (bag_file
) { free(bag_file
); }
416 if (ur
) free_user_record(ur
);
423 service_kb_load(service_context_t
* context
)
425 __block
int rc
= KB_GeneralError
;
427 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
428 uint8_t * buf
= NULL
;
430 keybag_handle_t session_handle
= bad_keybag_handle
;
431 service_user_record_t
* ur
= NULL
;
432 char * bag_file
= NULL
;
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
);
445 require_noerr(rc
, done
);
446 require_noerr(rc
= aks_set_system(session_handle
, context
->s_uid
), done
);
447 aks_unload_bag(session_handle
);
449 require(rc
== KB_Success
, done
);
453 if (ur
) free_user_record(ur
);
454 if (bag_file
) free(bag_file
);
462 service_kb_unlock(service_context_t
* context
, const void * secret
, int secret_len
)
464 int rc
= KB_GeneralError
;
465 keybag_handle_t session_handle
;
466 require_noerr(rc
= _kb_get_session_handle(context
, &session_handle
), done
);
468 rc
= aks_unlock_bag(session_handle
, secret
, secret_len
);
475 service_kb_lock(service_context_t
* context
)
477 int rc
= KB_GeneralError
;
478 keybag_handle_t session_handle
;
479 require_noerr(rc
= _kb_get_session_handle(context
, &session_handle
), done
);
481 rc
= aks_lock_bag(session_handle
);
488 service_kb_change_secret(service_context_t
* context
, const void * secret
, int secret_len
, const void * new_secret
, int new_secret_len
)
490 __block
int rc
= KB_GeneralError
;
491 keybag_handle_t session_handle
;
492 require_noerr(rc
= _kb_get_session_handle(context
, &session_handle
), done
);
494 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
495 uint8_t * buf
= NULL
;
497 service_user_record_t
* ur
= NULL
;
498 char * bag_file
= NULL
;
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
);
510 if (ur
) free_user_record(ur
);
511 if (bag_file
) free(bag_file
);
520 service_kb_reset(service_context_t
* context
, const void * secret
, int secret_len
)
522 __block
int rc
= KB_GeneralError
;
523 service_user_record_t
* ur
= NULL
;
524 char * bag_file
= NULL
;
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
);
529 dispatch_sync(_kb_service_get_dispatch_queue(), ^{
530 uint8_t * buf
= NULL
;
532 keybag_handle_t session_handle
= bad_keybag_handle
;
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
);
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
);
544 if (secret
&& rc
== KB_Success
) {
545 aks_unlock_bag(session_handle
, secret
, secret_len
);
554 if (ur
) free_user_record(ur
);
555 if (bag_file
) free(bag_file
);
560 service_kb_is_locked(service_context_t
* context
, xpc_object_t reply
)
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
);
567 require_noerr(rc
= aks_get_lock_state(session_handle
, &state
), done
);
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
);
577 service_kb_stash_create(service_context_t
* context
, const void * key
, unsigned key_size
)
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;
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
);
593 require_action(bag_file
= _kb_copy_bag_filename(ur
, kb_bag_type_stash
), done
, rc
= KB_GeneralError
);
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
);
599 require_action(saved
, done
, rc
= KB_BagError
);
603 if (stashbag
) { free(stashbag
); }
604 if (bag_file
) { free(bag_file
); }
605 if (ur
) free_user_record(ur
);
610 service_kb_stash_load(service_context_t
* context
, const void * key
, unsigned key_size
)
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;
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
);
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
)) {
630 require_noerr(rc
, done
);
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
);
637 if (stashbag
) { free(stashbag
); }
639 _kb_delete_bag_on_disk(ur
, bag_file
);
642 if (ur
) free_user_record(ur
);
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
652 OSStatus
service_stash_get_key(service_context_t
* context
, xpc_object_t event
, xpc_object_t reply
)
654 getStashKey_InStruct_t inStruct
;
655 getStashKey_OutStruct_t outStruct
;
656 size_t outSize
= sizeof(outStruct
);
657 kern_return_t kr
= KERN_INVALID_ARGUMENT
;
659 io_connect_t conn
= openiodev();
661 inStruct
.type
= kAppleFDEKeyStoreStash_master
;
663 kr
= IOConnectCallMethod(conn
, kAppleFDEKeyStore_getStashKey
,
665 &inStruct
, sizeof(inStruct
),
667 &outStruct
, &outSize
);
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
);
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.
689 OSStatus
service_stash_set_key(service_context_t
* context
, xpc_object_t event
, xpc_object_t reply
)
691 kern_return_t kr
= KERN_INVALID_ARGUMENT
;
692 size_t keydata_len
= 0;
695 io_connect_t conn
= openiodev();
698 // Store the key in the keystore and get its uuid
699 setKeyGetUUID_InStruct_t inStruct1
;
700 uuid_OutStruct_t outStruct1
;
703 const uint8_t *keydata
= xpc_dictionary_get_data(event
, SERVICE_XPC_KEY
, &keydata_len
);
704 require(keydata
, done
);
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
,
711 &inStruct1
, sizeof(inStruct1
),
714 require(kr
== KERN_SUCCESS
, done
);
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
;
721 kr
= IOConnectCallMethod(conn
, kAppleFDEKeyStore_setStashKey
,
723 &inStruct2
, sizeof(inStruct2
),
727 if (kr
== KERN_SUCCESS
) {
728 service_kb_stash_create(context
, keydata
, (unsigned)keydata_len
);
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.
744 OSStatus
service_stash_blob(xpc_object_t event
, xpc_object_t reply
)
746 kern_return_t kr
= KERN_INVALID_ARGUMENT
;
748 io_connect_t conn
= openiodev();
751 kr
= IOConnectCallMethod(conn
, kAppleFDEKeyStore_commitStash
,
764 bool peer_has_entitlement(xpc_connection_t peer
, const char * entitlement
)
766 bool entitled
= false;
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
);
773 if (value
) xpc_release(value
);
777 void service_peer_event_handler(xpc_connection_t connection
, xpc_object_t event
)
779 xpc_type_t type
= xpc_get_type(event
);
781 if (type
== XPC_TYPE_ERROR
) {
782 if (event
== XPC_ERROR_CONNECTION_INVALID
) {
785 assert(type
== XPC_TYPE_DICTIONARY
);
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
;
794 xpc_object_t reply
= xpc_dictionary_create_reply(event
);
796 data
= xpc_dictionary_get_data(event
, SERVICE_XPC_CONTEXT
, &data_len
);
798 require(data_len
== sizeof(service_context_t
), done
);
799 context
= (service_context_t
*)data
;
801 request
= xpc_dictionary_get_uint64(event
, SERVICE_XPC_REQUEST
);
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.
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
);
813 case SERVICE_KB_LOAD
:
814 rc
= service_kb_load(context
);
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
);
820 case SERVICE_KB_LOCK
:
821 rc
= service_kb_lock(context
);
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
);
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
);
832 case SERVICE_KB_IS_LOCKED
:
833 rc
= service_kb_is_locked(context
, reply
);
835 case SERVICE_STASH_GET_KEY
:
836 rc
= service_stash_get_key(context
, event
, reply
);
838 case SERVICE_STASH_SET_KEY
:
839 rc
= service_stash_set_key(context
, event
, reply
);
842 case SERVICE_STASH_BLOB
:
843 rc
= service_stash_blob(event
, reply
);
847 LOG("unknown service type");
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
);
859 bool check_signature(xpc_connection_t connection
)
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
);
868 OSStatus status
= SecRequirementCreateWithString(reqStr
, kSecCSDefaultFlags
, &requirement
);
869 require_action(status
== errSecSuccess
, done
, LOG("failed to create requirement"));
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"));
877 status
= SecCodeCheckValidity(codeRef
, kSecCSDefaultFlags
,
878 #if DEBUG || RC_BUILDIT_YES
883 require_action(status
== errSecSuccess
, done
, syslog(LOG_ERR
, "pid %d, does not satisfy code requirment (%d)", pid
, status
));
886 if (codeRef
) CFRelease(codeRef
);
887 if (requirement
) CFRelease(requirement
);
888 if (codeDict
) CFRelease(codeDict
);
889 if (codePid
) CFRelease(codePid
);
891 return (status
== errSecSuccess
);
894 int main(int argc
, const char * argv
[])
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
);
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.
910 if (xpc_connection_get_euid(peer
) != 0) {
911 xpc_connection_cancel(peer
);
915 if (!check_signature(peer
)) {
916 xpc_connection_cancel(peer
);
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
);
925 xpc_connection_resume(peer
);
927 xpc_connection_resume(listener
);