2 * Copyright (c) 2007-2017 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 #undef SECUREOBJECTSYNC
27 #undef SHAREDWEBCREDENTIALS
30 #include <os/transaction_private.h>
31 #include <os/variant_private.h>
33 #include <corecrypto/ccec.h>
34 #include "keychain/SecureObjectSync/SOSPeerInfoDER.h"
35 #include <Security/SecureObjectSync/SOSCloudCircle.h>
36 #include <Security/SecureObjectSync/SOSCloudCircleInternal.h>
37 #include "keychain/SecureObjectSync/SOSInternal.h"
38 #include "keychain/SecureObjectSync/SOSPeerInfoCollections.h"
39 #include "keychain/SecureObjectSync/SOSControlServer.h"
40 #include <Security/SecBase.h>
41 #include <Security/SecBasePriv.h>
42 #include <Security/SecCertificatePriv.h>
43 #include <Security/SecEntitlements.h>
44 #include <Security/SecInternal.h>
45 #include <Security/SecItem.h>
46 #include <Security/SecItemPriv.h>
47 #include <Security/SecPolicy.h>
48 #include <Security/SecPolicyInternal.h>
49 #include <Security/SecTask.h>
50 #include <Security/SecTrustInternal.h>
51 #include <Security/SecuritydXPC.h>
52 #include "trust/trustd/OTATrustUtilities.h"
53 #include "keychain/securityd/SOSCloudCircleServer.h"
54 #include "keychain/securityd/SecItemBackupServer.h"
55 #include "keychain/securityd/SecItemServer.h"
56 #include "keychain/securityd/SecLogSettingsServer.h"
57 #include "keychain/securityd/SecOTRRemote.h"
58 #include "trust/trustd/SecTrustServer.h"
59 #include "trust/trustd/SecTrustStoreServer.h"
60 #include "keychain/securityd/iCloudTrace.h"
61 #include "keychain/securityd/spi.h"
62 #include <utilities/SecAKSWrappers.h>
63 #include <utilities/SecCFError.h>
64 #include <utilities/SecCFWrappers.h>
65 #include <utilities/SecCoreAnalytics.h>
66 #include <utilities/SecDb.h>
67 #include <utilities/SecIOFormat.h>
68 #include <utilities/SecXPCError.h>
69 #include <utilities/debugging.h>
70 #include <utilities/SecInternalReleasePriv.h>
71 #include <utilities/der_plist_internal.h>
72 #include <utilities/der_plist.h>
73 #include "trust/trustd/personalization.h"
74 #include "trust/trustd/SecPinningDb.h"
75 #include "keychain/securityd/SFKeychainControlManager.h"
77 #include <keychain/ckks/CKKS.h>
78 #include <keychain/ckks/CKKSControlServer.h>
79 #include "keychain/ot/OctagonControlServer.h"
81 #include "keychain/securityd/SFKeychainServer.h"
83 #include "keychain/securityd/PolicyReporter.h"
86 #include <AssertMacros.h>
87 #include <CoreFoundation/CFXPCBridge.h>
88 #include <CoreFoundation/CoreFoundation.h>
89 // <rdar://problem/22425706> 13B104+Roots:Device never moved past spinner after using approval to ENABLE icdp
92 #include <Security/SecTaskPriv.h>
93 #include <login/SessionAgentStatusCom.h>
96 #include <bsm/libbsm.h>
97 #include <ipc/securityd_client.h>
98 #include <libkern/OSAtomic.h>
99 #include <mach/mach.h>
100 #include <mach/message.h>
103 #include <sys/queue.h>
104 #include <sys/sysctl.h>
106 #include <xpc/private.h>
109 #include <ipc/server_security_helpers.h>
110 #include <ipc/server_entitlement_helpers.h>
112 #include "keychain/ot/OT.h"
113 #include "keychain/escrowrequest/EscrowRequestXPCServer.h"
114 #include "keychain/escrowrequest/EscrowRequestServerHelpers.h"
124 static void refresh_prng(void)
126 aks_ref_key_t ref
= NULL
;
128 int fd
= open("/dev/random", O_WRONLY
);
130 secerror("failed to open /dev/random (%d)", errno
);
134 /* create class F ref-key, and use its public key as an entropy source */
135 int err
= aks_ref_key_create(bad_keybag_handle
, key_class_f
, key_type_asym_ec_p256
, NULL
, 0, &ref
);
136 if (err
!= kAKSReturnSuccess
) {
137 secerror("failed to create refkey (%d)", err
);
141 size_t pub_key_len
= 0;
142 const uint8_t *pub_key
= aks_ref_key_get_public_key(ref
, &pub_key_len
);
143 if (pub_key_len
> ccec_export_pub_size_cp(ccec_cp_256())) {
144 secerror("invalid pub key (%zu)", pub_key_len
);
148 while (pub_key_len
> 0) {
149 ssize_t n
= write(fd
, pub_key
, pub_key_len
);
151 secerror("failed to write /dev/random (%d)", errno
);
161 aks_ref_key_free(&ref
);
173 _xpc_dictionary_copy_CFString(xpc_object_t xdict
, const char *key
)
175 CFStringRef result
= NULL
;
176 const char *str
= xpc_dictionary_get_string(xdict
, key
);
178 result
= CFStringCreateWithCString(kCFAllocatorDefault
, str
, kCFStringEncodingUTF8
);
185 _xpc_dictionary_copy_CFDataNoCopy(xpc_object_t xdict
, const char *key
)
187 CFDataRef result
= NULL
;
189 const void *ptr
= xpc_dictionary_get_data(xdict
, key
, &len
);
191 result
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, ptr
, len
, kCFAllocatorNull
);
196 static void with_label_and_password(xpc_object_t message
, void (^action
)(CFStringRef label
, CFDataRef password
)) {
197 CFStringRef user_label
= _xpc_dictionary_copy_CFString(message
, kSecXPCKeyUserLabel
);
198 CFDataRef user_password
= _xpc_dictionary_copy_CFDataNoCopy(message
, kSecXPCKeyUserPassword
);
200 if (user_label
!= NULL
&& user_password
!= NULL
) {
201 action(user_label
, user_password
);
204 CFReleaseNull(user_label
);
205 CFReleaseNull(user_password
);
208 static void with_label_and_password_and_dsid(xpc_object_t message
, void (^action
)(CFStringRef label
, CFDataRef password
, CFStringRef dsid
)) {
209 CFStringRef user_label
= _xpc_dictionary_copy_CFString(message
, kSecXPCKeyUserLabel
);
210 CFDataRef user_password
= _xpc_dictionary_copy_CFDataNoCopy(message
, kSecXPCKeyUserPassword
);
211 CFStringRef dsid
= _xpc_dictionary_copy_CFString(message
, kSecXPCKeyDSID
);
213 /* dsid is optional */
214 if (user_label
!= NULL
&& user_password
!= NULL
) {
215 action(user_label
, user_password
, dsid
);
218 CFReleaseNull(user_label
);
219 CFReleaseNull(user_password
);
223 static void with_view_and_action(xpc_object_t message
, void (^action
)(CFStringRef view_name
, uint64_t view_action_code
)) {
224 CFStringRef view
= _xpc_dictionary_copy_CFString(message
, kSecXPCKeyViewName
);
225 const int64_t number
= xpc_dictionary_get_int64(message
, kSecXPCKeyViewActionCode
);
228 action(view
, number
);
234 static CFArrayRef
SecXPCDictionaryCopyPeerInfoArray(xpc_object_t dictionary
, const char *key
, CFErrorRef
*error
) {
235 return CreateArrayOfPeerInfoWithXPCObject(xpc_dictionary_get_value(dictionary
, key
), error
);
238 static CFDataRef
SecXPCDictionaryCopyCFDataRef(xpc_object_t message
, const char *key
, CFErrorRef
*error
) {
239 CFDataRef retval
= NULL
;
240 const uint8_t *bytes
= NULL
;
243 bytes
= xpc_dictionary_get_data(message
, key
, &len
);
244 require_action_quiet(bytes
, errOut
, SOSCreateError(kSOSErrorBadKey
, CFSTR("missing CFDataRef info"), NULL
, error
));
245 retval
= CFDataCreate(NULL
, bytes
, len
);
246 require_action_quiet(retval
, errOut
, SOSCreateError(kSOSErrorBadKey
, CFSTR("could not allocate CFDataRef info"), NULL
, error
));
251 static CFSetRef
CreateCFSetRefFromXPCObject(xpc_object_t xpcSetDER
, CFErrorRef
* error
) {
252 CFSetRef retval
= NULL
;
253 require_action_quiet(xpcSetDER
, errOut
, SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedNull
, sSecXPCErrorDomain
, NULL
, error
, NULL
, CFSTR("Unexpected Null Set to decode")));
255 require_action_quiet(xpc_get_type(xpcSetDER
) == XPC_TYPE_DATA
, errOut
, SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType
, sSecXPCErrorDomain
, NULL
, error
, NULL
, CFSTR("xpcSetDER not data, got %@"), xpcSetDER
));
257 const uint8_t* der
= xpc_data_get_bytes_ptr(xpcSetDER
);
258 const uint8_t* der_end
= der
+ xpc_data_get_length(xpcSetDER
);
259 der
= der_decode_set(kCFAllocatorDefault
, &retval
, error
, der
, der_end
);
260 if (der
!= der_end
) {
261 SecError(errSecDecode
, error
, CFSTR("trailing garbage at end of SecAccessControl data"));
266 CFReleaseNull(retval
);
270 static SOSPeerInfoRef
SecXPCDictionaryCopyPeerInfo(xpc_object_t message
, const char *key
, CFErrorRef
*error
) {
272 const uint8_t *der
= xpc_dictionary_get_data(message
, key
, &length
);
274 return SecRequirementError(der
!= NULL
, error
, CFSTR("No data for key %s"), key
) ? SOSPeerInfoCreateFromDER(kCFAllocatorDefault
, error
, &der
, der
+ length
) : NULL
;
277 static CFSetRef
SecXPCSetCreateFromXPCDictionaryElement(xpc_object_t event
, const char *key
) {
278 CFErrorRef error
= NULL
;
279 xpc_object_t object
= xpc_dictionary_get_value(event
, key
);
280 CFSetRef retval
= NULL
;
281 if(object
) retval
= CreateCFSetRefFromXPCObject(object
, &error
);
282 CFReleaseNull(error
);
287 void xpc_dictionary_set_and_consume_CFArray(xpc_object_t xdict
, const char *key
, CF_CONSUMED CFArrayRef cf_array
) {
289 xpc_object_t xpc_array
= _CFXPCCreateXPCObjectFromCFObject(cf_array
);
290 xpc_dictionary_set_value(xdict
, key
, xpc_array
);
291 xpc_release(xpc_array
);
293 CFReleaseNull(cf_array
);
297 bool xpc_dictionary_set_and_consume_PeerInfoArray(xpc_object_t xdict
, const char *key
, CF_CONSUMED CFArrayRef cf_array
, CFErrorRef
*error
) {
300 xpc_object_t xpc_array
= CreateXPCObjectWithArrayOfPeerInfo(cf_array
, error
);
302 xpc_dictionary_set_value(xdict
, key
, xpc_array
);
303 xpc_release(xpc_array
);
308 CFReleaseNull(cf_array
);
312 #endif /* SECUREOBJECTSYNC */
315 SecDataCopyMmapFileDescriptor(int fd
, void **mem
, size_t *size
, CFErrorRef
*error
)
318 if (fstat(fd
, &sb
) < 0) {
322 *size
= (size_t)sb
.st_size
;
323 if ((off_t
)*size
!= sb
.st_size
) {
327 *mem
= mmap(NULL
, *size
, PROT_READ
, MAP_SHARED
, fd
, 0);
328 if (*mem
== MAP_FAILED
) {
332 return CFDataCreateWithBytesNoCopy(NULL
, *mem
, *size
, kCFAllocatorNull
);
336 SecDataWriteFileDescriptor(int fd
, CFDataRef data
)
338 CFIndex count
= CFDataGetLength(data
);
339 const uint8_t *ptr
= CFDataGetBytePtr(data
);
340 bool writeResult
= false;
343 ssize_t ret
= write(fd
, ptr
, count
);
355 // Returns error if entitlement isn't present.
357 EntitlementPresentAndTrue(uint64_t op
, SecTaskRef clientTask
, CFStringRef entitlement
, CFErrorRef
*error
)
359 if (!SecTaskGetBooleanValueForEntitlement(clientTask
, entitlement
)) {
360 SecError(errSecMissingEntitlement
, error
, CFSTR("%@: %@ lacks entitlement %@"), SOSCCGetOperationDescription((enum SecXPCOperation
)op
), clientTask
, entitlement
);
367 EntitlementAbsentOrFalse(uint64_t op
, SecTaskRef clientTask
, CFStringRef entitlement
, CFErrorRef
*error
)
369 if (SecTaskGetBooleanValueForEntitlement(clientTask
, entitlement
)) {
370 SecError(errSecNotAvailable
, error
, CFSTR("%@: %@ has entitlement %@"), SOSCCGetOperationDescription((enum SecXPCOperation
) op
), clientTask
, entitlement
);
376 static void securityd_xpc_dictionary_handler(const xpc_connection_t connection
, xpc_object_t event
) {
377 xpc_type_t type
= xpc_get_type(event
);
378 __block CFErrorRef error
= NULL
;
379 xpc_object_t xpcError
= NULL
;
380 xpc_object_t replyMessage
= NULL
;
381 CFDataRef clientAuditToken
= NULL
;
382 CFArrayRef domains
= NULL
;
383 SecurityClient client
= {
385 .accessGroups
= NULL
,
387 .uid
= xpc_connection_get_euid(connection
),
388 .allowSystemKeychain
= false,
389 .allowSyncBubbleKeychain
= false,
390 .isNetworkExtension
= false,
391 .canAccessNetworkExtensionAccessGroups
= false,
392 .applicationIdentifier
= NULL
,
396 secdebug("serverxpc", "entering");
397 if (type
== XPC_TYPE_DICTIONARY
) {
398 // TODO: Find out what we're dispatching.
399 replyMessage
= xpc_dictionary_create_reply(event
);
401 uint64_t operation
= xpc_dictionary_get_uint64(event
, kSecXPCKeyOperation
);
403 audit_token_t auditToken
= {};
404 xpc_connection_get_audit_token(connection
, &auditToken
);
405 clientAuditToken
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)&auditToken
, sizeof(auditToken
));
407 if (!fill_security_client(&client
, xpc_connection_get_euid(connection
), auditToken
)) {
408 CFReleaseNull(clientAuditToken
);
409 xpc_connection_send_message(connection
, replyMessage
);
410 xpc_release(replyMessage
);
415 if (operation
== sec_add_shared_web_credential_id
|| operation
== sec_copy_shared_web_credential_id
) {
416 domains
= SecTaskCopySharedWebCredentialDomains(client
.task
);
419 secinfo("serverxpc", "XPC [%@] operation: %@ (%" PRIu64
")", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), operation
);
423 case sec_item_add_id
:
425 if (EntitlementAbsentOrFalse(sec_item_add_id
, client
.task
, kSecEntitlementKeychainDeny
, &error
)) {
426 CFDictionaryRef query
= SecXPCDictionaryCopyDictionary(event
, kSecXPCKeyQuery
, &error
);
428 // Check for any entitlement-required attributes
429 bool entitlementsCorrect
= true;
430 if(CFDictionaryGetValue(query
, kSecAttrDeriveSyncIDFromItemAttributes
) ||
431 CFDictionaryGetValue(query
, kSecAttrPCSPlaintextServiceIdentifier
) ||
432 CFDictionaryGetValue(query
, kSecAttrPCSPlaintextPublicKey
) ||
433 CFDictionaryGetValue(query
, kSecAttrPCSPlaintextPublicIdentity
)) {
434 entitlementsCorrect
= EntitlementPresentAndTrue(sec_item_add_id
, client
.task
, kSecEntitlementPrivateCKKSPlaintextFields
, &error
);
436 if(entitlementsCorrect
&&
437 (CFDictionaryGetValue(query
, kSecDataInetExtraNotes
) ||
438 CFDictionaryGetValue(query
, kSecDataInetExtraHistory
) ||
439 CFDictionaryGetValue(query
, kSecDataInetExtraClientDefined0
) ||
440 CFDictionaryGetValue(query
, kSecDataInetExtraClientDefined1
) ||
441 CFDictionaryGetValue(query
, kSecDataInetExtraClientDefined2
) ||
442 CFDictionaryGetValue(query
, kSecDataInetExtraClientDefined3
))) {
443 entitlementsCorrect
= EntitlementPresentAndTrue(sec_item_add_id
, client
.task
, kSecEntitlementPrivateInetExpansionFields
, &error
);
446 if (entitlementsCorrect
&& CFDictionaryGetValue(query
, kSecAttrSysBound
)) {
447 entitlementsCorrect
= EntitlementPresentAndTrue(sec_item_add_id
, client
.task
, kSecEntitlementPrivateSysBound
, &error
);
450 CFTypeRef result
= NULL
;
451 if(entitlementsCorrect
) {
452 if (_SecItemAdd(query
, &client
, &result
, &error
) && result
) {
453 SecXPCDictionarySetPList(replyMessage
, kSecXPCKeyResult
, result
, &error
);
454 CFReleaseNull(result
);
457 CFReleaseNull(query
);
462 case sec_item_copy_matching_id
:
464 if (EntitlementAbsentOrFalse(sec_item_add_id
, client
.task
, kSecEntitlementKeychainDeny
, &error
)) {
465 CFDictionaryRef query
= SecXPCDictionaryCopyDictionary(event
, kSecXPCKeyQuery
, &error
);
467 CFTypeRef result
= NULL
;
468 if (_SecItemCopyMatching(query
, &client
, &result
, &error
) && result
) {
469 SecXPCDictionarySetPListWithRepair(replyMessage
, kSecXPCKeyResult
, result
, true, &error
);
470 CFReleaseNull(result
);
472 CFReleaseNull(query
);
477 case sec_item_update_id
:
479 if (EntitlementAbsentOrFalse(sec_item_update_id
, client
.task
, kSecEntitlementKeychainDeny
, &error
)) {
480 CFDictionaryRef query
= SecXPCDictionaryCopyDictionary(event
, kSecXPCKeyQuery
, &error
);
482 CFDictionaryRef attributesToUpdate
= SecXPCDictionaryCopyDictionary(event
, kSecXPCKeyAttributesToUpdate
, &error
);
483 if (attributesToUpdate
) {
484 // Check for any entitlement-required attributes
485 bool entitlementsCorrect
= true;
486 if(CFDictionaryGetValue(query
, kSecAttrDeriveSyncIDFromItemAttributes
) ||
487 CFDictionaryGetValue(attributesToUpdate
, kSecAttrPCSPlaintextServiceIdentifier
) ||
488 CFDictionaryGetValue(attributesToUpdate
, kSecAttrPCSPlaintextPublicKey
) ||
489 CFDictionaryGetValue(attributesToUpdate
, kSecAttrPCSPlaintextPublicIdentity
)) {
490 entitlementsCorrect
= EntitlementPresentAndTrue(sec_item_update_id
, client
.task
, kSecEntitlementPrivateCKKSPlaintextFields
, &error
);
492 if(entitlementsCorrect
&&
493 (CFDictionaryGetValue(attributesToUpdate
, kSecDataInetExtraNotes
) ||
494 CFDictionaryGetValue(attributesToUpdate
, kSecDataInetExtraHistory
) ||
495 CFDictionaryGetValue(attributesToUpdate
, kSecDataInetExtraClientDefined0
) ||
496 CFDictionaryGetValue(attributesToUpdate
, kSecDataInetExtraClientDefined1
) ||
497 CFDictionaryGetValue(attributesToUpdate
, kSecDataInetExtraClientDefined2
) ||
498 CFDictionaryGetValue(attributesToUpdate
, kSecDataInetExtraClientDefined3
))) {
499 entitlementsCorrect
= EntitlementPresentAndTrue(sec_item_update_id
, client
.task
, kSecEntitlementPrivateInetExpansionFields
, &error
);
501 if (entitlementsCorrect
&& CFDictionaryGetValue(query
, kSecAttrSysBound
)) {
502 entitlementsCorrect
= EntitlementPresentAndTrue(sec_item_update_id
, client
.task
, kSecEntitlementPrivateSysBound
, &error
);
505 if(entitlementsCorrect
) {
506 bool result
= _SecItemUpdate(query
, attributesToUpdate
, &client
, &error
);
507 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, result
);
509 CFReleaseNull(attributesToUpdate
);
511 CFReleaseNull(query
);
516 case sec_item_delete_id
:
518 if (EntitlementAbsentOrFalse(sec_item_add_id
, client
.task
, kSecEntitlementKeychainDeny
, &error
)) {
519 CFDictionaryRef query
= SecXPCDictionaryCopyDictionary(event
, kSecXPCKeyQuery
, &error
);
521 bool result
= _SecItemDelete(query
, &client
, &error
);
522 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, result
);
523 CFReleaseNull(query
);
528 case sec_item_update_token_items_for_access_groups_id
:
530 if (EntitlementAbsentOrFalse(sec_item_update_token_items_for_access_groups_id
, client
.task
, kSecEntitlementKeychainDeny
, &error
) &&
531 EntitlementPresentAndTrue(sec_item_update_token_items_for_access_groups_id
, client
.task
, kSecEntitlementUpdateTokenItems
, &error
)) {
532 CFStringRef tokenID
= SecXPCDictionaryCopyString(event
, kSecXPCKeyString
, &error
);
533 CFArrayRef accessGroups
= SecXPCDictionaryCopyArray(event
, kSecXPCKeyArray
, &error
);
534 CFArrayRef tokenItems
= SecXPCDictionaryCopyArray(event
, kSecXPCKeyQuery
, &error
);
536 bool result
= _SecItemUpdateTokenItemsForAccessGroups(tokenID
, accessGroups
, tokenItems
, &client
, &error
);
537 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, result
);
539 CFReleaseNull(tokenID
);
540 CFReleaseNull(accessGroups
);
541 CFReleaseNull(tokenItems
);
545 case sec_delete_all_id
:
549 /* buddy is temporary allowed to do this */
550 CFStringRef applicationIdentifier
= SecTaskCopyApplicationIdentifier(client
.task
);
551 bool isBuddy
= applicationIdentifier
&&
552 CFEqual(applicationIdentifier
, CFSTR("com.apple.purplebuddy"));
553 CFReleaseNull(applicationIdentifier
);
555 if (isBuddy
|| EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementPrivateDeleteAll
, &error
))
557 retval
= _SecItemDeleteAll(&error
);
560 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, retval
);
563 case sec_keychain_backup_id
:
565 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementRestoreKeychain
, &error
)) {
566 CFDataRef keybag
= NULL
, passcode
= NULL
;
567 if (SecXPCDictionaryCopyDataOptional(event
, kSecXPCKeyKeybag
, &keybag
, &error
)) {
568 if (SecXPCDictionaryCopyDataOptional(event
, kSecXPCKeyUserPassword
, &passcode
, &error
)) {
569 bool emcs
= SecXPCDictionaryGetBool(event
, kSecXPCKeyEMCSBackup
, NULL
);
570 CFDataRef backup
= _SecServerKeychainCreateBackup(&client
, keybag
, passcode
, emcs
, &error
);
572 int fd
= SecXPCDictionaryDupFileDescriptor(event
, kSecXPCKeyFileDescriptor
, NULL
);
574 SecXPCDictionarySetData(replyMessage
, kSecXPCKeyResult
, backup
, &error
);
576 bool writeResult
= SecDataWriteFileDescriptor(fd
, backup
);
580 SecError(errSecIO
, &error
, CFSTR("Failed to write backup file: %d"), errno
);
581 SecXPCDictionarySetBool(replyMessage
, kSecXPCKeyResult
, writeResult
, NULL
);
585 CFReleaseSafe(passcode
);
587 CFReleaseSafe(keybag
);
592 case sec_keychain_restore_id
:
594 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementRestoreKeychain
, &error
)) {
595 CFDataRef backup
= NULL
;
599 int fd
= SecXPCDictionaryDupFileDescriptor(event
, kSecXPCKeyFileDescriptor
, NULL
);
601 backup
= SecDataCopyMmapFileDescriptor(fd
, &mem
, &size
, &error
);
603 backup
= SecXPCDictionaryCopyData(event
, kSecXPCKeyBackup
, &error
);
606 CFDataRef keybag
= SecXPCDictionaryCopyData(event
, kSecXPCKeyKeybag
, &error
);
608 CFDataRef passcode
= NULL
;
609 if (SecXPCDictionaryCopyDataOptional(event
, kSecXPCKeyUserPassword
, &passcode
, &error
)) {
610 bool result
= _SecServerKeychainRestore(backup
, &client
, keybag
, passcode
, &error
);
611 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, result
);
612 CFReleaseSafe(passcode
);
615 CFReleaseNull(keybag
);
617 CFReleaseNull(backup
);
626 case sec_keychain_backup_keybag_uuid_id
:
628 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementRestoreKeychain
, &error
)) {
629 CFDataRef backup
= NULL
;
630 CFStringRef uuid
= NULL
;
634 int fd
= SecXPCDictionaryDupFileDescriptor(event
, kSecXPCKeyFileDescriptor
, NULL
);
636 backup
= SecDataCopyMmapFileDescriptor(fd
, &mem
, &size
, &error
);
638 uuid
= _SecServerBackupCopyUUID(backup
, &error
);
641 SecXPCDictionarySetString(replyMessage
, kSecXPCKeyResult
, uuid
, &error
);
643 CFReleaseNull(backup
);
654 case sec_keychain_sync_update_message_id
:
656 CFDictionaryRef updates
= SecXPCDictionaryCopyDictionary(event
, kSecXPCKeyQuery
, &error
);
658 CFArrayRef result
= _SecServerKeychainSyncUpdateMessage(updates
, &error
);
659 SecXPCDictionarySetPList(replyMessage
, kSecXPCKeyResult
, result
, &error
);
660 CFReleaseNull(result
);
662 CFReleaseNull(updates
);
665 case sec_keychain_backup_syncable_id
:
667 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementRestoreKeychain
, &error
)) {
668 CFDictionaryRef oldbackup
= NULL
;
669 if (SecXPCDictionaryCopyDictionaryOptional(event
, kSecXPCKeyBackup
, &oldbackup
, &error
)) {
670 CFDataRef keybag
= SecXPCDictionaryCopyData(event
, kSecXPCKeyKeybag
, &error
);
672 CFDataRef passcode
= NULL
;
673 if (SecXPCDictionaryCopyDataOptional(event
, kSecXPCKeyUserPassword
, &passcode
, &error
)) {
674 CFDictionaryRef newbackup
= _SecServerBackupSyncable(oldbackup
, keybag
, passcode
, &error
);
676 SecXPCDictionarySetPList(replyMessage
, kSecXPCKeyResult
, newbackup
, &error
);
677 CFRelease(newbackup
);
679 CFReleaseSafe(passcode
);
681 CFReleaseNull(keybag
);
683 CFReleaseSafe(oldbackup
);
688 case sec_keychain_restore_syncable_id
:
690 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementRestoreKeychain
, &error
)) {
691 CFDictionaryRef backup
= SecXPCDictionaryCopyDictionary(event
, kSecXPCKeyBackup
, &error
);
693 CFDataRef keybag
= SecXPCDictionaryCopyData(event
, kSecXPCKeyKeybag
, &error
);
695 CFDataRef passcode
= NULL
;
696 if (SecXPCDictionaryCopyDataOptional(event
, kSecXPCKeyUserPassword
, &passcode
, &error
)) {
697 bool result
= _SecServerRestoreSyncable(backup
, keybag
, passcode
, &error
);
698 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, result
);
699 CFReleaseSafe(passcode
);
701 CFReleaseNull(keybag
);
703 CFReleaseNull(backup
);
708 case sec_item_backup_copy_names_id
:
710 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementRestoreKeychain
, &error
)) {
711 CFArrayRef names
= SecServerItemBackupCopyNames(&error
);
712 SecXPCDictionarySetPListOptional(replyMessage
, kSecXPCKeyResult
, names
, &error
);
713 CFReleaseSafe(names
);
717 case sec_item_backup_ensure_copy_view_id
:
719 if(EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementRestoreKeychain
, &error
)) {
720 CFStringRef viewName
= NULL
;
721 if (SecXPCDictionaryCopyStringOptional(event
, kSecXPCKeyString
, &viewName
, &error
)) {
722 CFStringRef name
= SecServerItemBackupEnsureCopyView(viewName
, &error
);
723 SecXPCDictionarySetString(replyMessage
, kSecXPCKeyResult
, name
, &error
);
729 case sec_item_backup_handoff_fd_id
:
731 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementRestoreKeychain
, &error
)) {
732 CFStringRef backupName
= SecXPCDictionaryCopyString(event
, kSecXPCKeyBackup
, &error
);
735 fd
= SecServerItemBackupHandoffFD(backupName
, &error
);
736 CFRelease(backupName
);
738 SecXPCDictionarySetFileDescriptor(replyMessage
, kSecXPCKeyResult
, fd
, &error
);
744 case sec_item_backup_set_confirmed_manifest_id
:
746 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementRestoreKeychain
, &error
)) {
747 CFDataRef keybagDigest
= NULL
;
748 if (SecXPCDictionaryCopyDataOptional(event
, kSecXPCKeyKeybag
, &keybagDigest
, &error
)) {
749 CFDataRef manifest
= NULL
;
750 if (SecXPCDictionaryCopyDataOptional(event
, kSecXPCData
, &manifest
, &error
)) {
751 CFStringRef backupName
= SecXPCDictionaryCopyString(event
, kSecXPCKeyBackup
, &error
);
753 bool result
= SecServerItemBackupSetConfirmedManifest(backupName
, keybagDigest
, manifest
, &error
);
754 CFRelease(backupName
);
755 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, result
);
757 CFReleaseSafe(manifest
);
760 CFReleaseNull(keybagDigest
);
764 case sec_item_backup_restore_id
:
766 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementRestoreKeychain
, &error
)) {
768 CFStringRef backupName
= SecXPCDictionaryCopyString(event
, kSecXPCKeyBackup
, &error
);
770 CFStringRef peerID
= NULL
;
771 if (SecXPCDictionaryCopyStringOptional(event
, kSecXPCKeyDigest
, &peerID
, &error
)) {
772 CFDataRef keybag
= SecXPCDictionaryCopyData(event
, kSecXPCKeyKeybag
, &error
);
774 CFDataRef secret
= SecXPCDictionaryCopyData(event
, kSecXPCKeyUserPassword
, &error
);
776 CFDataRef backup
= SecXPCDictionaryCopyData(event
, kSecXPCData
, &error
);
778 result
= SecServerItemBackupRestore(backupName
, peerID
, keybag
, secret
, backup
, &error
);
785 CFReleaseSafe(peerID
);
787 CFRelease(backupName
);
789 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, result
);
793 case sec_add_shared_web_credential_id
:
795 #if SHAREDWEBCREDENTIALS
796 CFDictionaryRef query
= SecXPCDictionaryCopyDictionary(event
, kSecXPCKeyQuery
, &error
);
798 CFTypeRef result
= NULL
;
800 CFStringRef appID
= (client
.task
) ? SecTaskCopyApplicationIdentifier(client
.task
) : NULL
;
801 if (_SecAddSharedWebCredential(query
, &client
, &auditToken
, appID
, domains
, &result
, &error
) && result
) {
802 SecXPCDictionarySetPList(replyMessage
, kSecXPCKeyResult
, result
, &error
);
803 CFReleaseNull(result
);
805 CFReleaseSafe(appID
);
806 CFReleaseNull(query
);
809 SecXPCDictionarySetPList(replyMessage
, kSecXPCKeyResult
, kCFBooleanFalse
, &error
);
813 case sec_copy_shared_web_credential_id
:
815 #if SHAREDWEBCREDENTIALS
816 CFDictionaryRef query
= SecXPCDictionaryCopyDictionary(event
, kSecXPCKeyQuery
, &error
);
818 CFTypeRef result
= NULL
;
819 CFStringRef appID
= (client
.task
) ? SecTaskCopyApplicationIdentifier(client
.task
) : NULL
;
820 if (_SecCopySharedWebCredential(query
, &client
, &auditToken
, appID
, domains
, &result
, &error
) && result
) {
821 SecXPCDictionarySetPList(replyMessage
, kSecXPCKeyResult
, result
, &error
);
822 CFReleaseNull(result
);
824 CFReleaseSafe(appID
);
825 CFReleaseNull(query
);
828 SecXPCDictionarySetPList(replyMessage
, kSecXPCKeyResult
, kCFBooleanFalse
, &error
);
832 case sec_get_log_settings_id
:
834 CFPropertyListRef currentList
= SecCopyLogSettings_Server(&error
);
836 SecXPCDictionarySetPList(replyMessage
, kSecXPCKeyResult
, currentList
, &error
);
838 CFReleaseSafe(currentList
);
841 case sec_set_xpc_log_settings_id
:
843 CFPropertyListRef newSettings
= SecXPCDictionaryCopyPList(event
, kSecXPCKeyQuery
, &error
);
845 SecSetXPCLogSettings_Server(newSettings
, &error
);
847 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, true);
848 CFReleaseNull(newSettings
);
851 case sec_set_circle_log_settings_id
:
853 CFPropertyListRef newSettings
= SecXPCDictionaryCopyPList(event
, kSecXPCKeyQuery
, &error
);
855 SecSetCircleLogSettings_Server(newSettings
, &error
);
857 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, true);
858 CFReleaseNull(newSettings
);
861 case sec_otr_session_create_remote_id
:
863 CFDataRef publicPeerId
= NULL
;
864 if (SecXPCDictionaryCopyDataOptional(event
, kSecXPCPublicPeerId
, &publicPeerId
, &error
)) {
865 CFDataRef otrSession
= _SecOTRSessionCreateRemote(publicPeerId
, &error
);
867 SecXPCDictionarySetData(replyMessage
, kSecXPCKeyResult
, otrSession
, &error
);
868 CFReleaseNull(otrSession
);
870 CFReleaseSafe(publicPeerId
);
874 case sec_otr_session_process_packet_remote_id
:
876 CFDataRef sessionData
= NULL
, inputPacket
= NULL
, outputSessionData
= NULL
, outputPacket
= NULL
;
877 bool readyForMessages
= false;
878 if (SecXPCDictionaryCopyDataOptional(event
, kSecXPCOTRSession
, &sessionData
, &error
)) {
879 if (SecXPCDictionaryCopyDataOptional(event
, kSecXPCData
, &inputPacket
, &error
)) {
880 bool result
= _SecOTRSessionProcessPacketRemote(sessionData
, inputPacket
, &outputSessionData
, &outputPacket
, &readyForMessages
, &error
);
882 SecXPCDictionarySetData(replyMessage
, kSecXPCOTRSession
, outputSessionData
, &error
);
883 SecXPCDictionarySetData(replyMessage
, kSecXPCData
, outputPacket
, &error
);
884 xpc_dictionary_set_bool(replyMessage
, kSecXPCOTRReady
, readyForMessages
);
885 CFReleaseNull(outputSessionData
);
886 CFReleaseNull(outputPacket
);
888 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, result
);
890 CFReleaseSafe(inputPacket
);
892 CFReleaseSafe(sessionData
);
896 case kSecXPCOpTryUserCredentials
:
897 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
898 with_label_and_password_and_dsid(event
, ^(CFStringRef label
, CFDataRef password
, CFStringRef dsid
) {
899 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
900 SOSCCTryUserCredentials_Server(label
, password
, dsid
, &error
));
904 case kSecXPCOpSetUserCredentials
:
905 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
906 with_label_and_password(event
, ^(CFStringRef label
, CFDataRef password
) {
907 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
908 SOSCCSetUserCredentials_Server(label
, password
, &error
));
912 case kSecXPCOpSetUserCredentialsAndDSID
:
913 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
914 with_label_and_password_and_dsid(event
, ^(CFStringRef label
, CFDataRef password
, CFStringRef dsid
) {
915 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
916 SOSCCSetUserCredentialsAndDSID_Server(label
, password
, dsid
, &error
));
921 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
922 with_view_and_action(event
, ^(CFStringRef view
, uint64_t actionCode
) {
923 xpc_dictionary_set_int64(replyMessage
, kSecXPCKeyResult
,
924 SOSCCView_Server(view
, (SOSViewActionCode
)actionCode
, &error
));
928 case kSecXPCOpViewSet
:
929 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
930 CFSetRef enabledViews
= SecXPCSetCreateFromXPCDictionaryElement(event
, kSecXPCKeyEnabledViewsKey
);
931 CFSetRef disabledViews
= SecXPCSetCreateFromXPCDictionaryElement(event
, kSecXPCKeyDisabledViewsKey
);
932 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, SOSCCViewSet_Server(enabledViews
, disabledViews
));
933 CFReleaseNull(enabledViews
);
934 CFReleaseNull(disabledViews
);
937 case kSecXPCOpCanAuthenticate
:
938 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
939 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
940 SOSCCCanAuthenticate_Server(&error
));
943 case kSecXPCOpPurgeUserCredentials
:
944 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
945 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
946 SOSCCPurgeUserCredentials_Server(&error
));
949 case kSecXPCOpDeviceInCircle
:
950 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
951 xpc_dictionary_set_int64(replyMessage
, kSecXPCKeyResult
,
952 SOSCCThisDeviceIsInCircle_Server(&error
));
955 case kSecXPCOpRequestToJoin
:
956 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
957 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
958 SOSCCRequestToJoinCircle_Server(&error
));
961 case kSecXPCOpAccountHasPublicKey
:
962 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
963 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
964 SOSCCAccountHasPublicKey_Server(&error
));
968 case kSecXPCOpRequestToJoinAfterRestore
:
969 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
970 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
971 SOSCCRequestToJoinCircleAfterRestore_Server(&error
));
974 case kSecXPCOpRequestDeviceID
:
975 case kSecXPCOpSetDeviceID
:
976 case kSecXPCOpHandleIDSMessage
:
977 case kSecXPCOpSyncWithIDSPeer
:
978 case kSecXPCOpSendIDSMessage
:
979 case kSecXPCOpPingTest
:
980 case kSecXPCOpIDSDeviceID
:
981 case kSecXPCOpSyncWithKVSPeerIDOnly
:{
982 xpc_dictionary_set_int64(replyMessage
, kSecXPCKeyError
, errSecUnimplemented
);
985 case kSecXPCOpAccountSetToNew
:
986 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
987 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, SOSCCAccountSetToNew_Server(&error
));
990 case kSecXPCOpResetToOffering
:
991 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
992 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
993 SOSCCResetToOffering_Server(&error
));
996 case kSecXPCOpResetToEmpty
:
997 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
998 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
999 SOSCCResetToEmpty_Server(&error
));
1002 case kSecXPCOpRemoveThisDeviceFromCircle
:
1003 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1004 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
1005 SOSCCRemoveThisDeviceFromCircle_Server(&error
));
1008 case kSecXPCOpRemovePeersFromCircle
:
1009 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1010 CFArrayRef applicants
= SecXPCDictionaryCopyPeerInfoArray(event
, kSecXPCKeyPeerInfoArray
, &error
);
1011 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
1012 SOSCCRemovePeersFromCircle_Server(applicants
, &error
));
1013 CFReleaseNull(applicants
);
1016 case kSecXPCOpLoggedIntoAccount
:
1017 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1018 SOSCCNotifyLoggedIntoAccount_Server();
1019 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
1023 case kSecXPCOpLoggedOutOfAccount
:
1024 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1025 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
1026 SOSCCLoggedOutOfAccount_Server(&error
));
1029 case kSecXPCOpAcceptApplicants
:
1030 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1031 xpc_object_t xapplicants
= xpc_dictionary_get_value(event
, kSecXPCKeyPeerInfoArray
);
1032 // CreateArrayOfPeerInfoWithXPCObject enforces that xapplicants is a non-NULL xpc data object
1033 CFArrayRef applicants
= CreateArrayOfPeerInfoWithXPCObject(xapplicants
, &error
); //(CFArrayRef)(_CFXPCCreateCFObjectFromXPCObject(xapplicants));
1034 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
1035 (applicants
&& SOSCCAcceptApplicants_Server(applicants
, &error
)));
1036 CFReleaseSafe(applicants
);
1039 case kSecXPCOpRejectApplicants
:
1040 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1041 xpc_object_t xapplicants
= xpc_dictionary_get_value(event
, kSecXPCKeyPeerInfoArray
);
1042 // CreateArrayOfPeerInfoWithXPCObject enforces that xapplicants is a non-NULL xpc data object
1043 CFArrayRef applicants
= CreateArrayOfPeerInfoWithXPCObject(xapplicants
, &error
); //(CFArrayRef)(_CFXPCCreateCFObjectFromXPCObject(xapplicants));
1044 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
1045 (applicants
&& SOSCCRejectApplicants_Server(applicants
, &error
)));
1046 CFReleaseSafe(applicants
);
1049 case kSecXPCOpSetNewPublicBackupKey
:
1051 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementRestoreKeychain
, &error
)) {
1052 CFDataRef publicBackupKey
= SecXPCDictionaryCopyData(event
, kSecXPCKeyNewPublicBackupKey
, &error
);
1053 if (publicBackupKey
!= NULL
) {
1054 SOSPeerInfoRef peerInfo
= SOSCCSetNewPublicBackupKey_Server(publicBackupKey
, &error
);
1055 CFDataRef peerInfoData
= peerInfo
? SOSPeerInfoCopyEncodedData(peerInfo
, kCFAllocatorDefault
, &error
) : NULL
;
1056 CFReleaseNull(peerInfo
);
1058 xpc_object_t xpc_object
= _CFXPCCreateXPCObjectFromCFObject(peerInfoData
);
1059 xpc_dictionary_set_value(replyMessage
, kSecXPCKeyResult
, xpc_object
);
1060 xpc_release(xpc_object
);
1062 CFReleaseNull(peerInfoData
);
1063 CFReleaseSafe(publicBackupKey
);
1068 case kSecXPCOpRegisterRecoveryPublicKey
:
1070 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementRestoreKeychain
, &error
)) {
1071 CFDataRef recovery_key
= SecXPCDictionaryCopyData(event
, kSecXPCKeyRecoveryPublicKey
, &error
);
1072 if (recovery_key
!= NULL
) {
1074 CFDataRef nullData
= CFDataCreate(kCFAllocatorDefault
, &zero
, 1); // token we send if we really wanted to send NULL
1075 if(CFEqual(recovery_key
, nullData
)) {
1076 CFReleaseNull(recovery_key
);
1078 CFReleaseNull(nullData
);
1079 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, SOSCCRegisterRecoveryPublicKey_Server(recovery_key
, &error
));
1080 CFReleaseNull(recovery_key
);
1085 case kSecXPCOpGetRecoveryPublicKey
:
1087 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementRestoreKeychain
, &error
)) {
1088 xpc_object_t xpc_recovery_object
= NULL
;
1089 CFDataRef recovery
= SOSCCCopyRecoveryPublicKey(&error
);
1091 xpc_recovery_object
= _CFXPCCreateXPCObjectFromCFObject(recovery
);
1093 xpc_dictionary_set_value(replyMessage
, kSecXPCKeyResult
, xpc_recovery_object
);
1094 CFReleaseNull(recovery
);
1098 case kSecXPCOpSetBagForAllSlices
:
1100 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementRestoreKeychain
, &error
)) {
1101 CFDataRef backupSlice
= SecXPCDictionaryCopyData(event
, kSecXPCKeyKeybag
, &error
); // NULL checked below
1102 bool includeV0
= xpc_dictionary_get_bool(event
, kSecXPCKeyIncludeV0
); // false is ok, so it's safe for this paramter to be unset or incorrect type
1103 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, backupSlice
&& SOSCCRegisterSingleRecoverySecret_Server(backupSlice
, includeV0
, &error
));
1104 CFReleaseSafe(backupSlice
);
1108 case kSecXPCOpCopyApplicantPeerInfo
:
1109 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1110 xpc_dictionary_set_and_consume_PeerInfoArray(replyMessage
, kSecXPCKeyResult
,
1111 SOSCCCopyApplicantPeerInfo_Server(&error
),
1115 case kSecXPCOpCopyValidPeerPeerInfo
:
1116 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1117 xpc_dictionary_set_and_consume_PeerInfoArray(replyMessage
, kSecXPCKeyResult
,
1118 SOSCCCopyValidPeerPeerInfo_Server(&error
),
1122 case kSecXPCOpValidateUserPublic
:
1123 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1124 bool trusted
= SOSCCValidateUserPublic_Server(&error
);
1125 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, trusted
);
1128 case kSecXPCOpCopyNotValidPeerPeerInfo
:
1129 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1130 xpc_dictionary_set_and_consume_PeerInfoArray(replyMessage
, kSecXPCKeyResult
,
1131 SOSCCCopyNotValidPeerPeerInfo_Server(&error
),
1135 case kSecXPCOpCopyGenerationPeerInfo
:
1136 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1137 xpc_dictionary_set_and_consume_CFArray(replyMessage
, kSecXPCKeyResult
,
1138 SOSCCCopyGenerationPeerInfo_Server(&error
));
1141 case kSecXPCOpCopyRetirementPeerInfo
:
1142 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1143 xpc_dictionary_set_and_consume_PeerInfoArray(replyMessage
, kSecXPCKeyResult
,
1144 SOSCCCopyRetirementPeerInfo_Server(&error
),
1148 case kSecXPCOpCopyViewUnawarePeerInfo
:
1149 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1150 xpc_dictionary_set_and_consume_PeerInfoArray(replyMessage
, kSecXPCKeyResult
,
1151 SOSCCCopyViewUnawarePeerInfo_Server(&error
),
1155 case kSecXPCOpCopyEngineState
:
1157 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1158 CFArrayRef array
= SOSCCCopyEngineState_Server(&error
);
1159 CFDataRef derData
= NULL
;
1161 require_quiet(array
, done
);
1162 derData
= CFPropertyListCreateDERData(kCFAllocatorDefault
, array
, &error
);
1164 require_quiet(derData
, done
);
1165 xpc_dictionary_set_data(replyMessage
, kSecXPCKeyResult
, CFDataGetBytePtr(derData
),CFDataGetLength(derData
));
1167 CFReleaseNull(derData
);
1168 CFReleaseNull(array
);
1172 case kSecXPCOpCopyPeerPeerInfo
:
1173 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1174 xpc_dictionary_set_and_consume_PeerInfoArray(replyMessage
, kSecXPCKeyResult
,
1175 SOSCCCopyPeerPeerInfo_Server(&error
),
1179 case kSecXPCOpCopyConcurringPeerPeerInfo
:
1180 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1181 xpc_dictionary_set_and_consume_PeerInfoArray(replyMessage
, kSecXPCKeyResult
,
1182 SOSCCCopyConcurringPeerPeerInfo_Server(&error
),
1186 case kSecXPCOpCopyMyPeerInfo
:
1187 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1188 SOSPeerInfoRef peerInfo
= SOSCCCopyMyPeerInfo_Server(&error
);
1189 CFDataRef peerInfoData
= peerInfo
? SOSPeerInfoCopyEncodedData(peerInfo
, kCFAllocatorDefault
, &error
) : NULL
;
1190 CFReleaseNull(peerInfo
);
1192 xpc_object_t xpc_object
= _CFXPCCreateXPCObjectFromCFObject(peerInfoData
);
1193 xpc_dictionary_set_value(replyMessage
, kSecXPCKeyResult
, xpc_object
);
1194 xpc_release(xpc_object
);
1196 CFReleaseNull(peerInfoData
);
1199 case kSecXPCOpGetLastDepartureReason
:
1200 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1201 xpc_dictionary_set_int64(replyMessage
, kSecXPCKeyResult
,
1202 SOSCCGetLastDepartureReason_Server(&error
));
1205 case kSecXPCOpSetLastDepartureReason
:
1206 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1207 // 0 is a legitimate reason (kSOSDepartureReasonError), so it's safe for this parameter to be unset or incorrect type
1208 int32_t reason
= (int32_t) xpc_dictionary_get_int64(event
, kSecXPCKeyReason
);
1209 xpc_dictionary_set_int64(replyMessage
, kSecXPCKeyResult
,
1210 SOSCCSetLastDepartureReason_Server(reason
, &error
));
1213 case kSecXPCOpProcessSyncWithPeers
:
1214 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainSyncUpdates
, &error
)) {
1215 CFSetRef peers
= SecXPCDictionaryCopySet(event
, kSecXPCKeySet
, &error
);
1216 CFSetRef backupPeers
= SecXPCDictionaryCopySet(event
, kSecXPCKeySet2
, &error
);
1217 if (peers
&& backupPeers
) {
1218 CFSetRef result
= SOSCCProcessSyncWithPeers_Server(peers
, backupPeers
, &error
);
1220 SecXPCDictionarySetPList(replyMessage
, kSecXPCKeyResult
, result
, &error
);
1222 CFReleaseNull(result
);
1224 CFReleaseNull(peers
);
1225 CFReleaseNull(backupPeers
);
1228 case kSecXPCOpProcessSyncWithAllPeers
:
1229 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainSyncUpdates
, &error
)) {
1230 xpc_dictionary_set_int64(replyMessage
, kSecXPCKeyResult
,
1231 SOSCCProcessSyncWithAllPeers_Server(&error
));
1234 case soscc_EnsurePeerRegistration_id
:
1235 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainSyncUpdates
, &error
)) {
1236 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
1237 SOSCCProcessEnsurePeerRegistration_Server(&error
));
1240 case kSecXPCOpRollKeys
:
1242 // false is valid, so it's safe for this parameter to be unset or incorrect type
1243 bool force
= xpc_dictionary_get_bool(event
, "force");
1244 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
1245 _SecServerRollKeys(force
, &client
, &error
));
1248 case kSecXPCOpWaitForInitialSync
:
1249 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1250 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
1251 SOSCCWaitForInitialSync_Server(&error
));
1254 case kSecXPCOpPeersHaveViewsEnabled
:
1256 CFArrayRef viewSet
= SecXPCDictionaryCopyArray(event
, kSecXPCKeyArray
, &error
);
1258 CFBooleanRef result
= SOSCCPeersHaveViewsEnabled_Server(viewSet
, &error
);
1259 if (result
!= NULL
) {
1260 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, result
!= kCFBooleanFalse
);
1263 CFReleaseNull(viewSet
);
1267 case kSecXPCOpWhoAmI
:
1270 xpc_dictionary_set_data(replyMessage
, "musr", CFDataGetBytePtr(client
.musr
), CFDataGetLength(client
.musr
));
1271 xpc_dictionary_set_bool(replyMessage
, "system-keychain", client
.allowSystemKeychain
);
1272 xpc_dictionary_set_bool(replyMessage
, "syncbubble-keychain", client
.allowSyncBubbleKeychain
);
1273 xpc_dictionary_set_bool(replyMessage
, "network-extension", client
.isNetworkExtension
);
1274 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, true);
1277 case kSecXPCOpTransmogrifyToSyncBubble
:
1279 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementPrivateKeychainSyncBubble
, &error
)) {
1281 uid_t uid
= (uid_t
)xpc_dictionary_get_int64(event
, "uid");
1282 CFArrayRef services
= SecXPCDictionaryCopyArray(event
, "services", &error
);
1284 if (uid
&& services
) {
1285 res
= _SecServerTransmogrifyToSyncBubble(services
, uid
, &client
, &error
);
1287 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, res
);
1288 CFReleaseNull(services
);
1290 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, false);
1295 case kSecXPCOpTransmogrifyToSystemKeychain
:
1297 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementPrivateKeychainMigrateSystemKeychain
, &error
)) {
1299 bool res
= _SecServerTransmogrifyToSystemKeychain(&client
, &error
);
1300 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, res
);
1302 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, false);
1308 case kSecXPCOpDeleteUserView
:
1310 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementPrivateKeychainMigrateSystemKeychain
, &error
)) {
1313 uid_t uid
= (uid_t
)xpc_dictionary_get_int64(event
, "uid");
1315 res
= _SecServerDeleteMUSERViews(&client
, uid
, &error
);
1318 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, res
);
1323 case kSecXPCOpCopyApplication
:
1324 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementCircleJoin
, &error
)) {
1325 SOSPeerInfoRef peerInfo
= SOSCCCopyApplication_Server(&error
);
1326 CFDataRef peerInfoData
= peerInfo
? SOSPeerInfoCopyEncodedData(peerInfo
, kCFAllocatorDefault
, &error
) : NULL
;
1327 CFReleaseNull(peerInfo
);
1329 xpc_object_t xpc_object
= _CFXPCCreateXPCObjectFromCFObject(peerInfoData
);
1330 xpc_dictionary_set_value(replyMessage
, kSecXPCKeyResult
, xpc_object
);
1331 xpc_release(xpc_object
);
1333 CFReleaseNull(peerInfoData
);
1336 case kSecXPCOpCopyCircleJoiningBlob
:
1337 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementCircleJoin
, &error
)) {
1338 CFDataRef appBlob
= SecXPCDictionaryCopyCFDataRef(event
, kSecXPCData
, &error
);
1339 if (appBlob
!= NULL
) {
1340 SOSPeerInfoRef applicant
= SOSPeerInfoCreateFromData(kCFAllocatorDefault
, &error
, appBlob
);
1341 if (applicant
!= NULL
) {
1342 CFDataRef pbblob
= SOSCCCopyCircleJoiningBlob_Server(applicant
, &error
);
1344 xpc_object_t xpc_object
= _CFXPCCreateXPCObjectFromCFObject(pbblob
);
1345 xpc_dictionary_set_value(replyMessage
, kSecXPCKeyResult
, xpc_object
);
1346 xpc_release(xpc_object
);
1348 CFReleaseNull(pbblob
);
1349 CFReleaseNull(applicant
);
1351 CFReleaseNull(appBlob
);
1355 case kSecXPCOpCopyInitialSyncBlob
:
1356 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementCircleJoin
, &error
)) {
1357 uint64_t flags
= xpc_dictionary_get_uint64(event
, kSecXPCKeyFlags
); // 0 is a valid flags, so no error checking
1358 CFDataRef initialblob
= SOSCCCopyInitialSyncData_Server((uint32_t)flags
, &error
);
1360 xpc_object_t xpc_object
= _CFXPCCreateXPCObjectFromCFObject(initialblob
);
1361 xpc_dictionary_set_value(replyMessage
, kSecXPCKeyResult
, xpc_object
);
1362 xpc_release(xpc_object
);
1364 CFReleaseNull(initialblob
);
1367 case kSecXPCOpJoinWithCircleJoiningBlob
:
1368 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementCircleJoin
, &error
)) {
1369 CFDataRef joiningBlob
= SecXPCDictionaryCopyCFDataRef(event
, kSecXPCData
, &error
); // NULL checked below
1370 uint64_t version
= xpc_dictionary_get_uint64(event
, kSecXPCVersion
); // 0 is valid, so this parameter can be unset or incorrect type
1371 if (joiningBlob
!= NULL
) {
1372 bool retval
= SOSCCJoinWithCircleJoiningBlob_Server(joiningBlob
, (PiggyBackProtocolVersion
) version
, &error
);
1373 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, retval
);
1374 CFReleaseNull(joiningBlob
);
1378 case kSecXPCOpKVSKeyCleanup
:
1379 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainCloudCircle
, &error
)) {
1380 bool retval
= SOSCCCleanupKVSKeys_Server(&error
);
1381 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, retval
);
1384 case kSecXPCOpMessageFromPeerIsPending
:
1386 SOSPeerInfoRef peer
= SecXPCDictionaryCopyPeerInfo(event
, kSecXPCKeyPeerInfo
, &error
);
1388 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
1389 SOSCCMessageFromPeerIsPending_Server(peer
, &error
));
1391 CFReleaseNull(peer
);
1394 case kSecXPCOpSendToPeerIsPending
:
1396 SOSPeerInfoRef peer
= SecXPCDictionaryCopyPeerInfo(event
, kSecXPCKeyPeerInfo
, &error
);
1398 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
,
1399 SOSCCSendToPeerIsPending(peer
, &error
));
1401 CFReleaseNull(peer
);
1404 #endif /* !SECUREOBJECTSYNC */
1405 case sec_delete_items_with_access_groups_id
:
1407 bool retval
= false;
1408 #if TARGET_OS_IPHONE
1409 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementPrivateUninstallDeletion
, &error
)) {
1410 CFArrayRef accessGroups
= SecXPCDictionaryCopyArray(event
, kSecXPCKeyAccessGroups
, &error
);
1413 retval
= _SecItemServerDeleteAllWithAccessGroups(accessGroups
, &client
, &error
);
1415 CFReleaseNull(accessGroups
);
1418 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, retval
);
1421 case kSecXPCOpBackupKeybagAdd
: {
1422 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementBackupTableOperations
, &error
)) {
1423 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, false);
1427 case kSecXPCOpBackupKeybagDelete
: {
1428 if (EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementBackupTableOperations
, &error
)) {
1429 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, false);
1433 case kSecXPCOpKeychainControlEndpoint
: {
1434 if(EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementKeychainControl
, &error
)) {
1435 xpc_endpoint_t endpoint
= SecServerCreateKeychainControlEndpoint();
1437 xpc_dictionary_set_value(replyMessage
, kSecXPCKeyEndpoint
, endpoint
);
1438 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, true);
1439 xpc_release(endpoint
);
1441 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, false);
1446 case sec_item_copy_parent_certificates_id
: {
1447 CFArrayRef results
= NULL
;
1448 if(EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementPrivateCertificateAllAccess
, &error
)) {
1449 CFDataRef issuer
= SecXPCDictionaryCopyData(event
, kSecXPCKeyNormalizedIssuer
, &error
);
1450 CFArrayRef accessGroups
= SecXPCDictionaryCopyArray(event
, kSecXPCKeyAccessGroups
, &error
);
1451 if (issuer
&& accessGroups
) {
1452 results
= _SecItemCopyParentCertificates(issuer
, accessGroups
, &error
);
1454 CFReleaseNull(issuer
);
1455 CFReleaseNull(accessGroups
);
1457 SecXPCDictionarySetPListOptional(replyMessage
, kSecXPCKeyResult
, results
, &error
);
1458 CFReleaseNull(results
);
1461 case sec_item_certificate_exists_id
: {
1462 bool result
= false;
1463 if(EntitlementPresentAndTrue(operation
, client
.task
, kSecEntitlementPrivateCertificateAllAccess
, &error
)) {
1464 CFDataRef issuer
= SecXPCDictionaryCopyData(event
, kSecXPCKeyNormalizedIssuer
, &error
);
1465 CFDataRef serialNum
= SecXPCDictionaryCopyData(event
, kSecXPCKeySerialNumber
, &error
);
1466 CFArrayRef accessGroups
= SecXPCDictionaryCopyArray(event
, kSecXPCKeyAccessGroups
, &error
);
1467 if (issuer
&& serialNum
&& accessGroups
) {
1468 result
= _SecItemCertificateExists(issuer
, serialNum
, accessGroups
, &error
);
1470 CFReleaseNull(issuer
);
1471 CFReleaseNull(serialNum
);
1472 CFReleaseNull(accessGroups
);
1474 xpc_dictionary_set_bool(replyMessage
, kSecXPCKeyResult
, result
);
1483 if(SecErrorGetOSStatus(error
) == errSecItemNotFound
|| isSOSErrorCoded(error
, kSOSErrorPublicKeyAbsent
))
1484 secdebug("ipc", "%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
1485 else if (SecErrorGetOSStatus(error
) == errSecAuthNeeded
)
1486 secwarning("Authentication is needed %@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
1488 secerror("%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
1490 xpcError
= SecCreateXPCObjectWithCFError(error
);
1492 xpc_dictionary_set_value(replyMessage
, kSecXPCKeyError
, xpcError
);
1494 } else if (replyMessage
) {
1495 secdebug("ipc", "%@ %@ responding %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), replyMessage
);
1498 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType
, sSecXPCErrorDomain
, NULL
, &error
, 0, CFSTR("Messages expect to be xpc dictionary, got: %@"), event
);
1499 secerror("%@: returning error: %@", client
.task
, error
);
1500 xpcError
= SecCreateXPCObjectWithCFError(error
);
1501 replyMessage
= xpc_create_reply_with_format(event
, "{%string: %value}", kSecXPCKeyError
, xpcError
);
1505 xpc_connection_send_message(connection
, replyMessage
);
1506 xpc_release(replyMessage
);
1509 xpc_release(xpcError
);
1511 CFReleaseSafe(error
);
1512 CFReleaseSafe(client
.accessGroups
);
1513 CFReleaseSafe(client
.musr
);
1514 CFReleaseSafe(client
.task
);
1515 CFReleaseNull(client
.applicationIdentifier
);
1516 CFReleaseSafe(domains
);
1517 CFReleaseSafe(clientAuditToken
);
1520 static void securityd_xpc_init(const char *service_name
)
1522 secdebug("serverxpc", "start");
1523 xpc_connection_t listener
= xpc_connection_create_mach_service(service_name
, NULL
, XPC_CONNECTION_MACH_SERVICE_LISTENER
);
1525 seccritical("security failed to register xpc listener for %s, exiting", service_name
);
1529 xpc_connection_set_event_handler(listener
, ^(xpc_object_t connection
) {
1530 if (xpc_get_type(connection
) == XPC_TYPE_CONNECTION
) {
1531 xpc_connection_set_event_handler(connection
, ^(xpc_object_t event
) {
1532 if (xpc_get_type(event
) == XPC_TYPE_DICTIONARY
) {
1533 // Synchronous. The client has a connection pool so they can be somewhat re-entrant if they need.
1534 securityd_xpc_dictionary_handler(connection
, event
);
1537 xpc_connection_resume(connection
);
1540 xpc_connection_resume(listener
);
1543 xpc_activity_register("com.apple.securityd.daily", XPC_ACTIVITY_CHECK_IN
, ^(xpc_activity_t activity
) {
1544 xpc_activity_state_t activityState
= xpc_activity_get_state(activity
);
1545 if (activityState
== XPC_ACTIVITY_STATE_RUN
) {
1546 SecCKKS24hrNotification();
1547 SecOctagon24hrNotification();
1552 xpc_activity_register("com.apple.securityd.entropyhealth", XPC_ACTIVITY_CHECK_IN
, ^(xpc_activity_t activity
) {
1553 xpc_activity_state_t activityState
= xpc_activity_get_state(activity
);
1554 if (activityState
== XPC_ACTIVITY_STATE_RUN
) {
1555 SecCoreAnalyticsSendKernEntropyHealth();
1559 xpc_activity_register("com.apple.securityd.prng", XPC_ACTIVITY_CHECK_IN
, ^(xpc_activity_t activity
) {
1560 xpc_activity_state_t state
= xpc_activity_get_state(activity
);
1561 if (state
== XPC_ACTIVITY_STATE_RUN
) {
1566 #if OCTAGON && !TARGET_OS_BRIDGE
1567 // Kick off reporting tasks.
1568 if (os_variant_has_internal_diagnostics("com.apple.security") && !os_variant_is_recovery("securityd")) {
1569 InitPolicyReporter();
1575 // <rdar://problem/22425706> 13B104+Roots:Device never moved past spinner after using approval to ENABLE icdp
1577 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR && !TARGET_OS_BRIDGE
1578 static void securityd_soscc_lock_hack() {
1579 dispatch_queue_t soscc_lock_queue
= dispatch_queue_create("soscc_lock_queue", DISPATCH_QUEUE_PRIORITY_DEFAULT
);
1582 // <rdar://problem/22500239> Prevent securityd from quitting while holding a keychain assertion
1583 // FIXME: securityd isn't currently registering for any other notifyd events. If/when it does,
1584 // this code will need to be generalized / migrated away from just this specific purpose.
1585 xpc_set_event_stream_handler("com.apple.notifyd.matching", dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH
, 0), ^(xpc_object_t object
) {
1586 char *event_description
= xpc_copy_description(object
);
1587 secnotice("events", "%s", event_description
);
1588 free(event_description
);
1591 secnotice("lockassertion", "notify_register_dispatch(kSOSCCHoldLockForInitialSync)");
1592 notify_register_dispatch(kSOSCCHoldLockForInitialSync
, &soscc_tok
, soscc_lock_queue
, ^(int token __unused
) {
1593 secnotice("lockassertion", "kSOSCCHoldLockForInitialSync: grabbing the lock");
1594 CFErrorRef error
= NULL
;
1596 uint64_t one_minute
= 60ull;
1597 if(SecAKSUserKeybagHoldLockAssertion(one_minute
, &error
)){
1598 // <rdar://problem/22500239> Prevent securityd from quitting while holding a keychain assertion
1599 os_transaction_t transaction
= os_transaction_create("securityd-LockAssertedingHolder");
1601 dispatch_after(dispatch_time(DISPATCH_TIME_NOW
, one_minute
*NSEC_PER_SEC
), soscc_lock_queue
, ^{
1602 CFErrorRef localError
= NULL
;
1603 if(!SecAKSUserKeybagDropLockAssertion(&localError
))
1604 secerror("failed to unlock: %@", localError
);
1605 CFReleaseNull(localError
);
1606 os_release(transaction
);
1609 secerror("Failed to take device lock assertion: %@", error
);
1611 CFReleaseNull(error
);
1612 secnotice("lockassertion", "kSOSCCHoldLockForInitialSync => done");
1622 static char homeDir
[PATH_MAX
] = {};
1624 if (homeDir
[0] == '\0') {
1625 struct passwd
* pwd
= getpwuid(getuid());
1629 if (realpath(pwd
->pw_dir
, homeDir
) == NULL
) {
1630 strlcpy(homeDir
, pwd
->pw_dir
, sizeof(homeDir
));
1638 int main(int argc
, char *argv
[])
1640 DisableLocalization();
1642 char *wait4debugger
= getenv("WAIT4DEBUGGER");
1643 if (wait4debugger
&& !strcasecmp("YES", wait4debugger
)) {
1644 seccritical("SIGSTOPing self, awaiting debugger");
1645 kill(getpid(), SIGSTOP
);
1646 seccritical("Again, for good luck (or bad debuggers)");
1647 kill(getpid(), SIGSTOP
);
1650 /* <rdar://problem/15792007> Users with network home folders are unable to use/save password for Mail/Cal/Contacts/websites
1651 Secd doesn't realize DB connections get invalidated when network home directory users logout
1652 and their home gets unmounted. Exit secd, start fresh when user logs back in.
1655 int sessionstatechanged_tok
;
1656 notify_register_dispatch(kSA_SessionStateChangedNotification
, &sessionstatechanged_tok
, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(int token __unused
) {
1657 // we could be a process running as root.
1658 // However, since root never logs out this isn't an issue.
1659 if (SASSessionStateForUser(getuid()) == kSA_state_loggingout_pointofnoreturn
) {
1660 dispatch_after(dispatch_time(DISPATCH_TIME_NOW
, 3ull*NSEC_PER_SEC
), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
1661 xpc_transaction_exit_clean();
1667 signal(SIGTERM
, SIG_IGN
);
1668 static dispatch_source_t termSource
;
1669 termSource
= dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL
, SIGTERM
, 0, dispatch_get_global_queue(QOS_CLASS_USER_INITIATED
, 0));
1670 dispatch_source_set_event_handler(termSource
, ^{
1671 secnotice("signal", "SIGTERM, exiting when clean ✌️");
1672 xpc_transaction_exit_clean();
1674 dispatch_activate(termSource
);
1677 #define SECD_PROFILE_NAME "com.apple.secd"
1678 const char *homedir
= homedirPath();
1679 if (homedir
== NULL
) {
1680 errx(1, "failed to get home directory for secd");
1683 char *errorbuf
= NULL
;
1684 const char *sandbox_params
[] = {"_HOME", homedir
, NULL
};
1685 int32_t rc
= sandbox_init_with_parameters(SECD_PROFILE_NAME
, SANDBOX_NAMED
, sandbox_params
, &errorbuf
);
1687 errx(1, "Failed to instantiate sandbox: %d %s", rc
, errorbuf
);
1688 /* errx will quit the process */
1690 #endif /* TARGET_OS_OSX */
1692 const char *serviceName
= kSecuritydXPCServiceName
;
1694 // Mark our interest in running some features (before we bring the DB layer up)
1696 EscrowRequestServerSetEnabled(true);
1697 OctagonSetShouldPerformInitialization(true);
1701 /* setup SQDLite before some other component have a chance to create a database connection */
1702 _SecDbServerSetup();
1704 securityd_init_server();
1705 securityd_xpc_init(serviceName
);
1706 SecCreateSecuritydXPCServer();
1708 #if SECUREOBJECTSYNC
1709 SOSControlServerInitialize();
1713 CKKSControlServerInitialize();
1714 OctagonControlServerInitialize();
1715 EscrowRequestXPCServerInitialize();
1718 // <rdar://problem/22425706> 13B104+Roots:Device never moved past spinner after using approval to ENABLE icdp
1719 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR && !TARGET_OS_BRIDGE
1720 securityd_soscc_lock_hack();
1726 /* vi:set ts=4 sw=4 et: */