2 * Copyright (c) 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@
24 #include <AssertMacros.h>
26 #include <dirhelper_priv.h>
28 #include <sys/types.h>
31 #include <xpc/private.h>
33 #include <CoreFoundation/CFStream.h>
35 #include <Security/SecuritydXPC.h>
36 #include <Security/SecTrustStore.h>
37 #include <Security/SecCertificateInternal.h>
38 #include <Security/SecEntitlements.h>
39 #include <Security/SecTrustInternal.h>
40 #include <Security/SecItem.h>
41 #include <Security/SecItemPriv.h>
43 #include <ipc/securityd_client.h>
44 #include <ipc/server_entitlement_helpers.h>
45 #include <utilities/SecCFWrappers.h>
46 #include <utilities/SecDb.h>
47 #include <utilities/SecFileLocations.h>
48 #include <utilities/debugging.h>
49 #include <utilities/SecXPCError.h>
50 #include <securityd/SecTrustStoreServer.h>
51 #include <securityd/SecPinningDb.h>
52 #include <securityd/SecPolicyServer.h>
53 #include <securityd/SecRevocationDb.h>
54 #include <securityd/SecTrustServer.h>
55 #include <securityd/spi.h>
58 #include <Security/SecTaskPriv.h>
59 #include <login/SessionAgentStatusCom.h>
60 #include <trustd/macOS/SecTrustOSXEntryPoints.h>
63 #include "OTATrustUtilities.h"
65 static struct trustd trustd_spi
= {
66 .sec_trust_store_for_domain
= SecTrustStoreForDomainName
,
67 .sec_trust_store_contains
= SecTrustStoreContainsCertificateWithDigest
,
68 .sec_trust_store_set_trust_settings
= _SecTrustStoreSetTrustSettings
,
69 .sec_trust_store_remove_certificate
= SecTrustStoreRemoveCertificateWithDigest
,
70 .sec_truststore_remove_all
= _SecTrustStoreRemoveAll
,
71 .sec_trust_evaluate
= SecTrustServerEvaluate
,
72 .sec_ota_pki_asset_version
= SecOTAPKIGetCurrentAssetVersion
,
73 .ota_CopyEscrowCertificates
= SecOTAPKICopyCurrentEscrowCertificates
,
74 .sec_ota_pki_get_new_asset
= SecOTAPKISignalNewAsset
,
75 .sec_trust_store_copy_all
= _SecTrustStoreCopyAll
,
76 .sec_trust_store_copy_usage_constraints
= _SecTrustStoreCopyUsageConstraints
,
79 static bool SecXPCDictionarySetChainOptional(xpc_object_t message
, const char *key
, SecCertificatePathRef path
, CFErrorRef
*error
) {
82 xpc_object_t xpc_chain
= SecCertificatePathCopyXPCArray(path
, error
);
86 xpc_dictionary_set_value(message
, key
, xpc_chain
);
87 xpc_release(xpc_chain
);
91 static SecCertificateRef
SecXPCDictionaryCopyCertificate(xpc_object_t message
, const char *key
, CFErrorRef
*error
) {
93 const void *bytes
= xpc_dictionary_get_data(message
, key
, &length
);
95 SecCertificateRef certificate
= SecCertificateCreateWithBytes(kCFAllocatorDefault
, bytes
, length
);
98 SecError(errSecDecode
, error
, CFSTR("object for key %s failed to create certificate from data"), key
);
100 SecError(errSecParam
, error
, CFSTR("object for key %s missing"), key
);
105 static bool SecXPCDictionaryCopyCertificates(xpc_object_t message
, const char *key
, CFArrayRef
*certificates
, CFErrorRef
*error
) {
106 xpc_object_t xpc_certificates
= xpc_dictionary_get_value(message
, key
);
107 if (!xpc_certificates
)
108 return SecError(errSecAllocate
, error
, CFSTR("no certs for key %s"), key
);
109 *certificates
= SecCertificateXPCArrayCopyArray(xpc_certificates
, error
);
110 return *certificates
;
113 static bool SecXPCDictionaryCopyCertificatesOptional(xpc_object_t message
, const char *key
, CFArrayRef
*certificates
, CFErrorRef
*error
) {
114 xpc_object_t xpc_certificates
= xpc_dictionary_get_value(message
, key
);
115 if (!xpc_certificates
) {
116 *certificates
= NULL
;
119 *certificates
= SecCertificateXPCArrayCopyArray(xpc_certificates
, error
);
120 return *certificates
;
123 static bool SecXPCDictionaryCopyPoliciesOptional(xpc_object_t message
, const char *key
, CFArrayRef
*policies
, CFErrorRef
*error
) {
124 xpc_object_t xpc_policies
= xpc_dictionary_get_value(message
, key
);
130 *policies
= SecPolicyXPCArrayCopyArray(xpc_policies
, error
);
131 return *policies
!= NULL
;
134 // Returns error if entitlement isn't present.
136 EntitlementPresentAndTrue(uint64_t op
, SecTaskRef clientTask
, CFStringRef entitlement
, CFErrorRef
*error
)
138 if (!SecTaskGetBooleanValueForEntitlement(clientTask
, entitlement
)) {
139 SecError(errSecMissingEntitlement
, error
, CFSTR("%@: %@ lacks entitlement %@"), SOSCCGetOperationDescription((enum SecXPCOperation
)op
), clientTask
, entitlement
);
145 static SecTrustStoreRef
SecXPCDictionaryGetTrustStore(xpc_object_t message
, const char *key
, CFErrorRef
*error
) {
146 SecTrustStoreRef ts
= NULL
;
147 CFStringRef domain
= SecXPCDictionaryCopyString(message
, key
, error
);
149 ts
= SecTrustStoreForDomainName(domain
, error
);
155 static bool SecXPCTrustStoreContains(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
157 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
159 CFDataRef digest
= SecXPCDictionaryCopyData(event
, kSecXPCKeyDigest
, error
);
162 if (SecTrustStoreContainsCertificateWithDigest(ts
, digest
, &contains
, error
)) {
163 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, contains
);
166 CFReleaseNull(digest
);
172 static bool SecXPCTrustStoreSetTrustSettings(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
173 bool noError
= false;
174 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
176 SecCertificateRef certificate
= SecXPCDictionaryCopyCertificate(event
, kSecXPCKeyCertificate
, error
);
178 CFTypeRef trustSettingsDictOrArray
= NULL
;
179 if (SecXPCDictionaryCopyPListOptional(event
, kSecXPCKeySettings
, &trustSettingsDictOrArray
, error
)) {
180 bool result
= _SecTrustStoreSetTrustSettings(ts
, certificate
, trustSettingsDictOrArray
, error
);
181 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, result
);
183 CFReleaseSafe(trustSettingsDictOrArray
);
185 CFReleaseNull(certificate
);
191 static bool SecXPCTrustStoreRemoveCertificate(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
192 bool noError
= false;
193 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
195 CFDataRef digest
= SecXPCDictionaryCopyData(event
, kSecXPCKeyDigest
, error
);
197 bool result
= SecTrustStoreRemoveCertificateWithDigest(ts
, digest
, error
);
198 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, result
);
200 CFReleaseNull(digest
);
206 static bool SecXPCTrustStoreCopyAll(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
208 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
210 CFArrayRef trustStoreContents
= NULL
;
211 if(_SecTrustStoreCopyAll(ts
, &trustStoreContents
, error
) && trustStoreContents
) {
212 SecXPCDictionarySetPList(reply
, kSecXPCKeyResult
, trustStoreContents
, error
);
213 CFReleaseNull(trustStoreContents
);
220 static bool SecXPCTrustStoreCopyUsageConstraints(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
222 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
224 CFDataRef digest
= SecXPCDictionaryCopyData(event
, kSecXPCKeyDigest
, error
);
226 CFArrayRef usageConstraints
= NULL
;
227 if(_SecTrustStoreCopyUsageConstraints(ts
, digest
, &usageConstraints
, error
) && usageConstraints
) {
228 SecXPCDictionarySetPList(reply
, kSecXPCKeyResult
, usageConstraints
, error
);
229 CFReleaseNull(usageConstraints
);
232 CFReleaseNull(digest
);
238 static bool SecXPC_OTAPKI_GetAssetVersion(xpc_object_t __unused event
, xpc_object_t reply
, CFErrorRef
*error
) {
239 xpc_dictionary_set_int64(reply
, kSecXPCKeyResult
, SecOTAPKIGetCurrentAssetVersion(error
));
243 static bool SecXPC_OTAPKI_GetEscrowCertificates(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
245 uint32_t escrowRootType
= (uint32_t)xpc_dictionary_get_uint64(event
, "escrowType");
246 CFArrayRef array
= SecOTAPKICopyCurrentEscrowCertificates(escrowRootType
, error
);
248 xpc_object_t xpc_array
= _CFXPCCreateXPCObjectFromCFObject(array
);
249 xpc_dictionary_set_value(reply
, kSecXPCKeyResult
, xpc_array
);
250 xpc_release(xpc_array
);
253 CFReleaseNull(array
);
257 static bool SecXPC_OTAPKI_GetNewAsset(xpc_object_t __unused event
, xpc_object_t reply
, CFErrorRef
*error
) {
258 xpc_dictionary_set_int64(reply
, kSecXPCKeyResult
, SecOTAPKISignalNewAsset(error
));
262 typedef bool(*SecXPCOperationHandler
)(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
);
265 CFStringRef entitlement
;
266 SecXPCOperationHandler handler
;
267 } SecXPCServerOperation
;
269 struct trustd_operations
{
270 SecXPCServerOperation trust_store_contains
;
271 SecXPCServerOperation trust_store_set_trust_settings
;
272 SecXPCServerOperation trust_store_remove_certificate
;
273 SecXPCServerOperation trust_store_copy_all
;
274 SecXPCServerOperation trust_store_copy_usage_constraints
;
275 SecXPCServerOperation ota_pki_asset_version
;
276 SecXPCServerOperation ota_pki_get_escrow_certs
;
277 SecXPCServerOperation ota_pki_get_new_asset
;
280 static struct trustd_operations trustd_ops
= {
281 .trust_store_contains
= { NULL
, SecXPCTrustStoreContains
},
282 .trust_store_set_trust_settings
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreSetTrustSettings
},
283 .trust_store_remove_certificate
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreRemoveCertificate
},
284 .trust_store_copy_all
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreCopyAll
},
285 .trust_store_copy_usage_constraints
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreCopyUsageConstraints
},
286 .ota_pki_asset_version
= { NULL
, SecXPC_OTAPKI_GetAssetVersion
},
287 .ota_pki_get_escrow_certs
= { NULL
, SecXPC_OTAPKI_GetEscrowCertificates
},
288 .ota_pki_get_new_asset
= { NULL
, SecXPC_OTAPKI_GetNewAsset
},
291 static void trustd_xpc_dictionary_handler(const xpc_connection_t connection
, xpc_object_t event
) {
292 xpc_type_t type
= xpc_get_type(event
);
293 __block CFErrorRef error
= NULL
;
294 xpc_object_t xpcError
= NULL
;
295 xpc_object_t replyMessage
= NULL
;
296 CFDataRef clientAuditToken
= NULL
;
297 CFArrayRef domains
= NULL
;
298 SecurityClient client
= {
300 .accessGroups
= NULL
,
302 .uid
= xpc_connection_get_euid(connection
),
303 .allowSystemKeychain
= true,
304 .allowSyncBubbleKeychain
= false,
305 .isNetworkExtension
= false,
306 .canAccessNetworkExtensionAccessGroups
= false,
308 .inMultiUser
= false,
312 secdebug("serverxpc", "entering");
313 if (type
== XPC_TYPE_DICTIONARY
) {
314 // TODO: Find out what we're dispatching.
315 replyMessage
= xpc_dictionary_create_reply(event
);
318 uint64_t operation
= xpc_dictionary_get_uint64(event
, kSecXPCKeyOperation
);
320 audit_token_t auditToken
= {};
321 xpc_connection_get_audit_token(connection
, &auditToken
);
323 client
.task
= SecTaskCreateWithAuditToken(kCFAllocatorDefault
, auditToken
);
324 clientAuditToken
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)&auditToken
, sizeof(auditToken
));
325 client
.accessGroups
= SecTaskCopyAccessGroups(client
.task
);
327 secinfo("serverxpc", "XPC [%@] operation: %@ (%" PRIu64
")", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), operation
);
329 if (operation
== sec_trust_evaluate_id
) {
330 CFArrayRef certificates
= NULL
, anchors
= NULL
, policies
= NULL
, responses
= NULL
, scts
= NULL
, trustedLogs
= NULL
, exceptions
= NULL
;
331 bool anchorsOnly
= xpc_dictionary_get_bool(event
, kSecTrustAnchorsOnlyKey
);
332 bool keychainsAllowed
= xpc_dictionary_get_bool(event
, kSecTrustKeychainsAllowedKey
);
334 if (SecXPCDictionaryCopyCertificates(event
, kSecTrustCertificatesKey
, &certificates
, &error
) &&
335 SecXPCDictionaryCopyCertificatesOptional(event
, kSecTrustAnchorsKey
, &anchors
, &error
) &&
336 SecXPCDictionaryCopyPoliciesOptional(event
, kSecTrustPoliciesKey
, &policies
, &error
) &&
337 SecXPCDictionaryCopyCFDataArrayOptional(event
, kSecTrustResponsesKey
, &responses
, &error
) &&
338 SecXPCDictionaryCopyCFDataArrayOptional(event
, kSecTrustSCTsKey
, &scts
, &error
) &&
339 SecXPCDictionaryCopyArrayOptional(event
, kSecTrustTrustedLogsKey
, &trustedLogs
, &error
) &&
340 SecXPCDictionaryGetDouble(event
, kSecTrustVerifyDateKey
, &verifyTime
, &error
) &&
341 SecXPCDictionaryCopyArrayOptional(event
, kSecTrustExceptionsKey
, &exceptions
, &error
)) {
342 // If we have no error yet, capture connection and reply in block and properly retain them.
343 xpc_retain(connection
);
344 CFRetainSafe(client
.task
);
345 CFRetainSafe(clientAuditToken
);
347 // Clear replyMessage so we don't send a synchronous reply.
348 xpc_object_t asyncReply
= replyMessage
;
351 SecTrustServerEvaluateBlock(clientAuditToken
, certificates
, anchors
, anchorsOnly
, keychainsAllowed
, policies
,
352 responses
, scts
, trustedLogs
, verifyTime
, client
.accessGroups
, exceptions
,
353 ^(SecTrustResultType tr
, CFArrayRef details
, CFDictionaryRef info
, SecCertificatePathRef chain
,
354 CFErrorRef replyError
) {
355 // Send back reply now
357 CFRetain(replyError
);
359 xpc_dictionary_set_int64(asyncReply
, kSecTrustResultKey
, tr
);
360 SecXPCDictionarySetPListOptional(asyncReply
, kSecTrustDetailsKey
, details
, &replyError
) &&
361 SecXPCDictionarySetPListOptional(asyncReply
, kSecTrustInfoKey
, info
, &replyError
) &&
362 SecXPCDictionarySetChainOptional(asyncReply
, kSecTrustChainKey
, chain
, &replyError
);
365 secdebug("ipc", "%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), replyError
);
366 xpc_object_t xpcReplyError
= SecCreateXPCObjectWithCFError(replyError
);
368 xpc_dictionary_set_value(asyncReply
, kSecXPCKeyError
, xpcReplyError
);
369 xpc_release(xpcReplyError
);
371 CFReleaseNull(replyError
);
373 secdebug("ipc", "%@ %@ responding %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), asyncReply
);
376 xpc_connection_send_message(connection
, asyncReply
);
377 xpc_release(asyncReply
);
378 xpc_release(connection
);
379 CFReleaseSafe(client
.task
);
380 CFReleaseSafe(clientAuditToken
);
383 CFReleaseSafe(policies
);
384 CFReleaseSafe(anchors
);
385 CFReleaseSafe(certificates
);
386 CFReleaseSafe(responses
);
388 CFReleaseSafe(trustedLogs
);
389 CFReleaseSafe(exceptions
);
391 SecXPCServerOperation
*server_op
= NULL
;
393 case sec_trust_store_contains_id
:
394 server_op
= &trustd_ops
.trust_store_contains
;
396 case sec_trust_store_set_trust_settings_id
:
397 server_op
= &trustd_ops
.trust_store_set_trust_settings
;
399 case sec_trust_store_remove_certificate_id
:
400 server_op
= &trustd_ops
.trust_store_remove_certificate
;
402 case sec_trust_store_copy_all_id
:
403 server_op
= &trustd_ops
.trust_store_copy_all
;
405 case sec_trust_store_copy_usage_constraints_id
:
406 server_op
= &trustd_ops
.trust_store_copy_usage_constraints
;
408 case sec_ota_pki_asset_version_id
:
409 server_op
= &trustd_ops
.ota_pki_asset_version
;
411 case kSecXPCOpOTAGetEscrowCertificates
:
412 server_op
= &trustd_ops
.ota_pki_get_escrow_certs
;
414 case kSecXPCOpOTAPKIGetNewAsset
:
415 server_op
= &trustd_ops
.ota_pki_get_new_asset
;
420 if (server_op
&& server_op
->handler
) {
421 bool entitled
= true;
422 if (server_op
->entitlement
) {
423 entitled
= EntitlementPresentAndTrue(operation
, client
.task
, server_op
->entitlement
, &error
);
426 (void)server_op
->handler(event
, replyMessage
, &error
);
433 if(SecErrorGetOSStatus(error
) == errSecItemNotFound
)
434 secdebug("ipc", "%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
435 else if (SecErrorGetOSStatus(error
) == errSecAuthNeeded
)
436 secwarning("Authentication is needed %@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
438 secerror("%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
440 xpcError
= SecCreateXPCObjectWithCFError(error
);
442 xpc_dictionary_set_value(replyMessage
, kSecXPCKeyError
, xpcError
);
444 } else if (replyMessage
) {
445 secdebug("ipc", "%@ %@ responding %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), replyMessage
);
448 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType
, sSecXPCErrorDomain
, NULL
, &error
, 0, CFSTR("Messages expect to be xpc dictionary, got: %@"), event
);
449 secerror("%@: returning error: %@", client
.task
, error
);
450 xpcError
= SecCreateXPCObjectWithCFError(error
);
451 replyMessage
= xpc_create_reply_with_format(event
, "{%string: %value}", kSecXPCKeyError
, xpcError
);
455 xpc_connection_send_message(connection
, replyMessage
);
456 xpc_release(replyMessage
);
459 xpc_release(xpcError
);
460 CFReleaseSafe(error
);
461 CFReleaseSafe(client
.accessGroups
);
462 CFReleaseSafe(client
.musr
);
463 CFReleaseSafe(client
.task
);
464 CFReleaseSafe(domains
);
465 CFReleaseSafe(clientAuditToken
);
468 static void trustd_xpc_init(const char *service_name
)
470 secdebug("serverxpc", "start");
471 xpc_connection_t listener
= xpc_connection_create_mach_service(service_name
, NULL
, XPC_CONNECTION_MACH_SERVICE_LISTENER
);
473 seccritical("security failed to register xpc listener for %s, exiting", service_name
);
477 xpc_connection_set_event_handler(listener
, ^(xpc_object_t connection
) {
478 if (xpc_get_type(connection
) == XPC_TYPE_CONNECTION
) {
479 xpc_connection_set_event_handler(connection
, ^(xpc_object_t event
) {
480 if (xpc_get_type(event
) == XPC_TYPE_DICTIONARY
) {
481 xpc_retain(connection
);
483 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
484 trustd_xpc_dictionary_handler(connection
, event
);
486 xpc_release(connection
);
490 xpc_connection_resume(connection
);
493 xpc_connection_resume(listener
);
496 static void trustd_delete_old_files(void) {
498 #if TARGET_OS_EMBEDDED
499 if (getuid() != 64) // _securityd
504 /* If we get past this line, then we can attempt to delete old revocation files;
505 otherwise we won't have sufficient privilege. */
507 /* We try to clean up after ourselves, but don't care if we succeed. */
508 WithPathInRevocationInfoDirectory(CFSTR("update-current"), ^(const char *utf8String
) {
509 (void)remove(utf8String
);
511 WithPathInRevocationInfoDirectory(CFSTR("update-full"), ^(const char *utf8String
) {
512 (void)remove(utf8String
);
514 WithPathInRevocationInfoDirectory(CFSTR("update-full.gz"), ^(const char *utf8String
) {
515 (void)remove(utf8String
);
520 static void trustd_delete_old_caches(void) {
521 /* We try to clean up after ourselves, but don't care if we succeed. */
522 WithPathInKeychainDirectory(CFSTR("ocspcache.sqlite3"), ^(const char *utf8String
) {
523 (void)remove(utf8String
);
525 WithPathInKeychainDirectory(CFSTR("ocspcache.sqlite3-wal"), ^(const char *utf8String
) {
526 (void)remove(utf8String
);
528 WithPathInKeychainDirectory(CFSTR("ocspcache.sqlite3-shm"), ^(const char *utf8String
) {
529 (void)remove(utf8String
);
531 WithPathInKeychainDirectory(CFSTR("ocspcache.sqlite3-journal"), ^(const char *utf8String
) {
532 (void)remove(utf8String
);
534 WithPathInKeychainDirectory(CFSTR("caissuercache.sqlite3"), ^(const char *utf8String
) {
535 (void)remove(utf8String
);
537 WithPathInKeychainDirectory(CFSTR("caissuercache.sqlite3-wal"), ^(const char *utf8String
) {
538 (void)remove(utf8String
);
540 WithPathInKeychainDirectory(CFSTR("caissuercache.sqlite3-shm"), ^(const char *utf8String
) {
541 (void)remove(utf8String
);
543 WithPathInKeychainDirectory(CFSTR("caissuercache.sqlite3-journal"), ^(const char *utf8String
) {
544 (void)remove(utf8String
);
548 static void trustd_sandbox(void) {
549 char buf
[PATH_MAX
] = "";
551 if (!_set_user_dir_suffix("com.apple.trustd") ||
552 confstr(_CS_DARWIN_USER_TEMP_DIR
, buf
, sizeof(buf
)) == 0 ||
553 (mkdir(buf
, 0700) && errno
!= EEXIST
)) {
554 secerror("failed to initialize temporary directory (%d): %s", errno
, strerror(errno
));
558 char *tempdir
= realpath(buf
, NULL
);
559 if (tempdir
== NULL
) {
560 secerror("failed to resolve temporary directory (%d): %s", errno
, strerror(errno
));
564 if (confstr(_CS_DARWIN_USER_CACHE_DIR
, buf
, sizeof(buf
)) == 0 ||
565 (mkdir(buf
, 0700) && errno
!= EEXIST
)) {
566 secerror("failed to initialize cache directory (%d): %s", errno
, strerror(errno
));
570 char *cachedir
= realpath(buf
, NULL
);
571 if (cachedir
== NULL
) {
572 secerror("failed to resolve cache directory (%d): %s", errno
, strerror(errno
));
576 const char *parameters
[] = {
578 "_DARWIN_CACHE_DIR", cachedir
,
582 char *sberror
= NULL
;
583 if (sandbox_init_with_parameters("com.apple.trustd", SANDBOX_NAMED
, parameters
, &sberror
) != 0) {
584 secerror("Failed to enter trustd sandbox: %{public}s", sberror
);
592 static void trustd_sandbox(void) {
593 char buf
[PATH_MAX
] = "";
594 _set_user_dir_suffix("com.apple.trustd");
595 confstr(_CS_DARWIN_USER_TEMP_DIR
, buf
, sizeof(buf
));
599 static void trustd_cfstream_init() {
600 /* <rdar://problem/33635964> Force legacy CFStream run loop initialization before any NSURLSession usage */
601 CFReadStreamRef rs
= CFReadStreamCreateWithBytesNoCopy(kCFAllocatorDefault
, (const UInt8
*) "", 0, kCFAllocatorNull
);
602 CFReadStreamSetDispatchQueue(rs
, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0));
603 CFReadStreamSetDispatchQueue(rs
, NULL
);
607 int main(int argc
, char *argv
[])
609 char *wait4debugger
= getenv("WAIT4DEBUGGER");
610 if (wait4debugger
&& !strcasecmp("YES", wait4debugger
)) {
611 seccritical("SIGSTOPing self, awaiting debugger");
612 kill(getpid(), SIGSTOP
);
613 seccritical("Again, for good luck (or bad debuggers)");
614 kill(getpid(), SIGSTOP
);
617 /* <rdar://problem/15792007> Users with network home folders are unable to use/save password for Mail/Cal/Contacts/websites
618 Our process doesn't realize DB connections get invalidated when network home directory users logout
619 and their home gets unmounted. Exit our process and start fresh when user logs back in.
622 int sessionstatechanged_tok
;
623 notify_register_dispatch(kSA_SessionStateChangedNotification
, &sessionstatechanged_tok
, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(int token __unused
) {
624 // we could be a process running as root.
625 // However, since root never logs out this isn't an issue.
626 if (SASSessionStateForUser(getuid()) == kSA_state_loggingout_pointofnoreturn
) {
627 dispatch_after(dispatch_time(DISPATCH_TIME_NOW
, 3ull*NSEC_PER_SEC
), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
628 xpc_transaction_exit_clean();
635 /* Before we enter the sandbox, we need to delete the old caches kept in ~/Library/Keychains
636 * After we enter the sandbox, we won't be able to access them. */
637 trustd_delete_old_caches();
639 /* Also clean up old files in /Library/Keychains/crls */
640 trustd_delete_old_files();
644 const char *serviceName
= kTrustdXPCServiceName
;
645 if (argc
> 1 && (!strcmp(argv
[1], "--agent"))) {
646 serviceName
= kTrustdAgentXPCServiceName
;
649 /* set up SQLite before some other component has a chance to create a database connection */
652 /* set up revocation database if it doesn't already exist, or needs to be replaced */
653 SecRevocationDbInitialize();
655 gTrustd
= &trustd_spi
;
656 SecPolicyServerInitialize();
657 SecPinningDbInitialize();
659 SecTrustLegacySourcesListenForKeychainEvents();
661 trustd_cfstream_init();
662 trustd_xpc_init(serviceName
);