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>
34 #include <Security/SecuritydXPC.h>
35 #include <Security/SecTrustStore.h>
36 #include <Security/SecCertificateInternal.h>
37 #include <Security/SecEntitlements.h>
38 #include <Security/SecTrustInternal.h>
39 #include <Security/SecItem.h>
40 #include <Security/SecItemPriv.h>
42 #include <ipc/securityd_client.h>
43 #include <ipc/server_entitlement_helpers.h>
44 #include <utilities/SecCFWrappers.h>
45 #include <utilities/SecDb.h>
46 #include <utilities/SecFileLocations.h>
47 #include <utilities/debugging.h>
48 #include <utilities/SecXPCError.h>
49 #include <securityd/SecTrustStoreServer.h>
50 #include <securityd/SecPinningDb.h>
51 #include <securityd/SecPolicyServer.h>
52 #include <securityd/SecRevocationDb.h>
53 #include <securityd/SecTrustServer.h>
54 #include <securityd/spi.h>
57 #include <Security/SecTaskPriv.h>
58 #include <login/SessionAgentStatusCom.h>
59 #include <trustd/macOS/SecTrustOSXEntryPoints.h>
62 #include "OTATrustUtilities.h"
64 static struct trustd trustd_spi
= {
65 .sec_trust_store_for_domain
= SecTrustStoreForDomainName
,
66 .sec_trust_store_contains
= SecTrustStoreContainsCertificateWithDigest
,
67 .sec_trust_store_set_trust_settings
= _SecTrustStoreSetTrustSettings
,
68 .sec_trust_store_remove_certificate
= SecTrustStoreRemoveCertificateWithDigest
,
69 .sec_truststore_remove_all
= _SecTrustStoreRemoveAll
,
70 .sec_trust_evaluate
= SecTrustServerEvaluate
,
71 .sec_ota_pki_asset_version
= SecOTAPKIGetCurrentAssetVersion
,
72 .ota_CopyEscrowCertificates
= SecOTAPKICopyCurrentEscrowCertificates
,
73 .sec_ota_pki_get_new_asset
= SecOTAPKISignalNewAsset
,
74 .sec_trust_store_copy_all
= _SecTrustStoreCopyAll
,
75 .sec_trust_store_copy_usage_constraints
= _SecTrustStoreCopyUsageConstraints
,
78 static bool SecXPCDictionarySetChainOptional(xpc_object_t message
, const char *key
, SecCertificatePathRef path
, CFErrorRef
*error
) {
81 xpc_object_t xpc_chain
= SecCertificatePathCopyXPCArray(path
, error
);
85 xpc_dictionary_set_value(message
, key
, xpc_chain
);
86 xpc_release(xpc_chain
);
90 static SecCertificateRef
SecXPCDictionaryCopyCertificate(xpc_object_t message
, const char *key
, CFErrorRef
*error
) {
92 const void *bytes
= xpc_dictionary_get_data(message
, key
, &length
);
94 SecCertificateRef certificate
= SecCertificateCreateWithBytes(kCFAllocatorDefault
, bytes
, length
);
97 SecError(errSecDecode
, error
, CFSTR("object for key %s failed to create certificate from data"), key
);
99 SecError(errSecParam
, error
, CFSTR("object for key %s missing"), key
);
104 static bool SecXPCDictionaryCopyCertificates(xpc_object_t message
, const char *key
, CFArrayRef
*certificates
, CFErrorRef
*error
) {
105 xpc_object_t xpc_certificates
= xpc_dictionary_get_value(message
, key
);
106 if (!xpc_certificates
)
107 return SecError(errSecAllocate
, error
, CFSTR("no certs for key %s"), key
);
108 *certificates
= SecCertificateXPCArrayCopyArray(xpc_certificates
, error
);
109 return *certificates
;
112 static bool SecXPCDictionaryCopyCertificatesOptional(xpc_object_t message
, const char *key
, CFArrayRef
*certificates
, CFErrorRef
*error
) {
113 xpc_object_t xpc_certificates
= xpc_dictionary_get_value(message
, key
);
114 if (!xpc_certificates
) {
115 *certificates
= NULL
;
118 *certificates
= SecCertificateXPCArrayCopyArray(xpc_certificates
, error
);
119 return *certificates
;
122 static bool SecXPCDictionaryCopyPoliciesOptional(xpc_object_t message
, const char *key
, CFArrayRef
*policies
, CFErrorRef
*error
) {
123 xpc_object_t xpc_policies
= xpc_dictionary_get_value(message
, key
);
129 *policies
= SecPolicyXPCArrayCopyArray(xpc_policies
, error
);
130 return *policies
!= NULL
;
133 // Returns error if entitlement isn't present.
135 EntitlementPresentAndTrue(uint64_t op
, SecTaskRef clientTask
, CFStringRef entitlement
, CFErrorRef
*error
)
137 if (!SecTaskGetBooleanValueForEntitlement(clientTask
, entitlement
)) {
138 SecError(errSecMissingEntitlement
, error
, CFSTR("%@: %@ lacks entitlement %@"), SOSCCGetOperationDescription((enum SecXPCOperation
)op
), clientTask
, entitlement
);
144 static SecTrustStoreRef
SecXPCDictionaryGetTrustStore(xpc_object_t message
, const char *key
, CFErrorRef
*error
) {
145 SecTrustStoreRef ts
= NULL
;
146 CFStringRef domain
= SecXPCDictionaryCopyString(message
, key
, error
);
148 ts
= SecTrustStoreForDomainName(domain
, error
);
154 static bool SecXPCTrustStoreContains(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
156 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
158 CFDataRef digest
= SecXPCDictionaryCopyData(event
, kSecXPCKeyDigest
, error
);
161 if (SecTrustStoreContainsCertificateWithDigest(ts
, digest
, &contains
, error
)) {
162 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, contains
);
165 CFReleaseNull(digest
);
171 static bool SecXPCTrustStoreSetTrustSettings(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
172 bool noError
= false;
173 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
175 SecCertificateRef certificate
= SecXPCDictionaryCopyCertificate(event
, kSecXPCKeyCertificate
, error
);
177 CFTypeRef trustSettingsDictOrArray
= NULL
;
178 if (SecXPCDictionaryCopyPListOptional(event
, kSecXPCKeySettings
, &trustSettingsDictOrArray
, error
)) {
179 bool result
= _SecTrustStoreSetTrustSettings(ts
, certificate
, trustSettingsDictOrArray
, error
);
180 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, result
);
182 CFReleaseSafe(trustSettingsDictOrArray
);
184 CFReleaseNull(certificate
);
190 static bool SecXPCTrustStoreRemoveCertificate(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
191 bool noError
= false;
192 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
194 CFDataRef digest
= SecXPCDictionaryCopyData(event
, kSecXPCKeyDigest
, error
);
196 bool result
= SecTrustStoreRemoveCertificateWithDigest(ts
, digest
, error
);
197 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, result
);
199 CFReleaseNull(digest
);
205 static bool SecXPCTrustStoreCopyAll(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
207 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
209 CFArrayRef trustStoreContents
= NULL
;
210 if(_SecTrustStoreCopyAll(ts
, &trustStoreContents
, error
) && trustStoreContents
) {
211 SecXPCDictionarySetPList(reply
, kSecXPCKeyResult
, trustStoreContents
, error
);
212 CFReleaseNull(trustStoreContents
);
219 static bool SecXPCTrustStoreCopyUsageConstraints(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
221 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
223 CFDataRef digest
= SecXPCDictionaryCopyData(event
, kSecXPCKeyDigest
, error
);
225 CFArrayRef usageConstraints
= NULL
;
226 if(_SecTrustStoreCopyUsageConstraints(ts
, digest
, &usageConstraints
, error
) && usageConstraints
) {
227 SecXPCDictionarySetPList(reply
, kSecXPCKeyResult
, usageConstraints
, error
);
228 CFReleaseNull(usageConstraints
);
231 CFReleaseNull(digest
);
237 static bool SecXPC_OTAPKI_GetAssetVersion(xpc_object_t __unused event
, xpc_object_t reply
, CFErrorRef
*error
) {
238 xpc_dictionary_set_int64(reply
, kSecXPCKeyResult
, SecOTAPKIGetCurrentAssetVersion(error
));
242 static bool SecXPC_OTAPKI_GetEscrowCertificates(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
244 uint32_t escrowRootType
= (uint32_t)xpc_dictionary_get_uint64(event
, "escrowType");
245 CFArrayRef array
= SecOTAPKICopyCurrentEscrowCertificates(escrowRootType
, error
);
247 xpc_object_t xpc_array
= _CFXPCCreateXPCObjectFromCFObject(array
);
248 xpc_dictionary_set_value(reply
, kSecXPCKeyResult
, xpc_array
);
249 xpc_release(xpc_array
);
252 CFReleaseNull(array
);
256 static bool SecXPC_OTAPKI_GetNewAsset(xpc_object_t __unused event
, xpc_object_t reply
, CFErrorRef
*error
) {
257 xpc_dictionary_set_int64(reply
, kSecXPCKeyResult
, SecOTAPKISignalNewAsset(error
));
261 typedef bool(*SecXPCOperationHandler
)(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
);
264 CFStringRef entitlement
;
265 SecXPCOperationHandler handler
;
266 } SecXPCServerOperation
;
268 struct trustd_operations
{
269 SecXPCServerOperation trust_store_contains
;
270 SecXPCServerOperation trust_store_set_trust_settings
;
271 SecXPCServerOperation trust_store_remove_certificate
;
272 SecXPCServerOperation trust_store_copy_all
;
273 SecXPCServerOperation trust_store_copy_usage_constraints
;
274 SecXPCServerOperation ota_pki_asset_version
;
275 SecXPCServerOperation ota_pki_get_escrow_certs
;
276 SecXPCServerOperation ota_pki_get_new_asset
;
279 static struct trustd_operations trustd_ops
= {
280 .trust_store_contains
= { NULL
, SecXPCTrustStoreContains
},
281 .trust_store_set_trust_settings
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreSetTrustSettings
},
282 .trust_store_remove_certificate
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreRemoveCertificate
},
283 .trust_store_copy_all
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreCopyAll
},
284 .trust_store_copy_usage_constraints
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreCopyUsageConstraints
},
285 .ota_pki_asset_version
= { NULL
, SecXPC_OTAPKI_GetAssetVersion
},
286 .ota_pki_get_escrow_certs
= { NULL
, SecXPC_OTAPKI_GetEscrowCertificates
},
287 .ota_pki_get_new_asset
= { NULL
, SecXPC_OTAPKI_GetNewAsset
},
290 static void trustd_xpc_dictionary_handler(const xpc_connection_t connection
, xpc_object_t event
) {
291 xpc_type_t type
= xpc_get_type(event
);
292 __block CFErrorRef error
= NULL
;
293 xpc_object_t xpcError
= NULL
;
294 xpc_object_t replyMessage
= NULL
;
295 CFDataRef clientAuditToken
= NULL
;
296 CFArrayRef domains
= NULL
;
297 SecurityClient client
= {
299 .accessGroups
= NULL
,
301 .uid
= xpc_connection_get_euid(connection
),
302 .allowSystemKeychain
= true,
303 .allowSyncBubbleKeychain
= false,
304 .isNetworkExtension
= false,
305 .canAccessNetworkExtensionAccessGroups
= false,
307 .inMultiUser
= false,
311 secdebug("serverxpc", "entering");
312 if (type
== XPC_TYPE_DICTIONARY
) {
313 // TODO: Find out what we're dispatching.
314 replyMessage
= xpc_dictionary_create_reply(event
);
317 uint64_t operation
= xpc_dictionary_get_uint64(event
, kSecXPCKeyOperation
);
319 audit_token_t auditToken
= {};
320 xpc_connection_get_audit_token(connection
, &auditToken
);
322 client
.task
= SecTaskCreateWithAuditToken(kCFAllocatorDefault
, auditToken
);
323 clientAuditToken
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)&auditToken
, sizeof(auditToken
));
324 client
.accessGroups
= SecTaskCopyAccessGroups(client
.task
);
326 secinfo("serverxpc", "XPC [%@] operation: %@ (%" PRIu64
")", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), operation
);
328 if (operation
== sec_trust_evaluate_id
) {
329 CFArrayRef certificates
= NULL
, anchors
= NULL
, policies
= NULL
, responses
= NULL
, scts
= NULL
, trustedLogs
= NULL
, exceptions
= NULL
;
330 bool anchorsOnly
= xpc_dictionary_get_bool(event
, kSecTrustAnchorsOnlyKey
);
331 bool keychainsAllowed
= xpc_dictionary_get_bool(event
, kSecTrustKeychainsAllowedKey
);
333 if (SecXPCDictionaryCopyCertificates(event
, kSecTrustCertificatesKey
, &certificates
, &error
) &&
334 SecXPCDictionaryCopyCertificatesOptional(event
, kSecTrustAnchorsKey
, &anchors
, &error
) &&
335 SecXPCDictionaryCopyPoliciesOptional(event
, kSecTrustPoliciesKey
, &policies
, &error
) &&
336 SecXPCDictionaryCopyCFDataArrayOptional(event
, kSecTrustResponsesKey
, &responses
, &error
) &&
337 SecXPCDictionaryCopyCFDataArrayOptional(event
, kSecTrustSCTsKey
, &scts
, &error
) &&
338 SecXPCDictionaryCopyArrayOptional(event
, kSecTrustTrustedLogsKey
, &trustedLogs
, &error
) &&
339 SecXPCDictionaryGetDouble(event
, kSecTrustVerifyDateKey
, &verifyTime
, &error
) &&
340 SecXPCDictionaryCopyArrayOptional(event
, kSecTrustExceptionsKey
, &exceptions
, &error
)) {
341 // If we have no error yet, capture connection and reply in block and properly retain them.
342 xpc_retain(connection
);
343 CFRetainSafe(client
.task
);
344 CFRetainSafe(clientAuditToken
);
346 // Clear replyMessage so we don't send a synchronous reply.
347 xpc_object_t asyncReply
= replyMessage
;
350 SecTrustServerEvaluateBlock(clientAuditToken
, certificates
, anchors
, anchorsOnly
, keychainsAllowed
, policies
,
351 responses
, scts
, trustedLogs
, verifyTime
, client
.accessGroups
, exceptions
,
352 ^(SecTrustResultType tr
, CFArrayRef details
, CFDictionaryRef info
, SecCertificatePathRef chain
,
353 CFErrorRef replyError
) {
354 // Send back reply now
356 CFRetain(replyError
);
358 xpc_dictionary_set_int64(asyncReply
, kSecTrustResultKey
, tr
);
359 SecXPCDictionarySetPListOptional(asyncReply
, kSecTrustDetailsKey
, details
, &replyError
) &&
360 SecXPCDictionarySetPListOptional(asyncReply
, kSecTrustInfoKey
, info
, &replyError
) &&
361 SecXPCDictionarySetChainOptional(asyncReply
, kSecTrustChainKey
, chain
, &replyError
);
364 secdebug("ipc", "%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), replyError
);
365 xpc_object_t xpcReplyError
= SecCreateXPCObjectWithCFError(replyError
);
367 xpc_dictionary_set_value(asyncReply
, kSecXPCKeyError
, xpcReplyError
);
368 xpc_release(xpcReplyError
);
370 CFReleaseNull(replyError
);
372 secdebug("ipc", "%@ %@ responding %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), asyncReply
);
375 xpc_connection_send_message(connection
, asyncReply
);
376 xpc_release(asyncReply
);
377 xpc_release(connection
);
378 CFReleaseSafe(client
.task
);
379 CFReleaseSafe(clientAuditToken
);
382 CFReleaseSafe(policies
);
383 CFReleaseSafe(anchors
);
384 CFReleaseSafe(certificates
);
385 CFReleaseSafe(responses
);
387 CFReleaseSafe(trustedLogs
);
388 CFReleaseSafe(exceptions
);
390 SecXPCServerOperation
*server_op
= NULL
;
392 case sec_trust_store_contains_id
:
393 server_op
= &trustd_ops
.trust_store_contains
;
395 case sec_trust_store_set_trust_settings_id
:
396 server_op
= &trustd_ops
.trust_store_set_trust_settings
;
398 case sec_trust_store_remove_certificate_id
:
399 server_op
= &trustd_ops
.trust_store_remove_certificate
;
401 case sec_trust_store_copy_all_id
:
402 server_op
= &trustd_ops
.trust_store_copy_all
;
404 case sec_trust_store_copy_usage_constraints_id
:
405 server_op
= &trustd_ops
.trust_store_copy_usage_constraints
;
407 case sec_ota_pki_asset_version_id
:
408 server_op
= &trustd_ops
.ota_pki_asset_version
;
410 case kSecXPCOpOTAGetEscrowCertificates
:
411 server_op
= &trustd_ops
.ota_pki_get_escrow_certs
;
413 case kSecXPCOpOTAPKIGetNewAsset
:
414 server_op
= &trustd_ops
.ota_pki_get_new_asset
;
419 if (server_op
&& server_op
->handler
) {
420 bool entitled
= true;
421 if (server_op
->entitlement
) {
422 entitled
= EntitlementPresentAndTrue(operation
, client
.task
, server_op
->entitlement
, &error
);
425 (void)server_op
->handler(event
, replyMessage
, &error
);
432 if(SecErrorGetOSStatus(error
) == errSecItemNotFound
)
433 secdebug("ipc", "%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
434 else if (SecErrorGetOSStatus(error
) == errSecAuthNeeded
)
435 secwarning("Authentication is needed %@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
437 secerror("%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
439 xpcError
= SecCreateXPCObjectWithCFError(error
);
441 xpc_dictionary_set_value(replyMessage
, kSecXPCKeyError
, xpcError
);
443 } else if (replyMessage
) {
444 secdebug("ipc", "%@ %@ responding %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), replyMessage
);
447 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType
, sSecXPCErrorDomain
, NULL
, &error
, 0, CFSTR("Messages expect to be xpc dictionary, got: %@"), event
);
448 secerror("%@: returning error: %@", client
.task
, error
);
449 xpcError
= SecCreateXPCObjectWithCFError(error
);
450 replyMessage
= xpc_create_reply_with_format(event
, "{%string: %value}", kSecXPCKeyError
, xpcError
);
454 xpc_connection_send_message(connection
, replyMessage
);
455 xpc_release(replyMessage
);
458 xpc_release(xpcError
);
459 CFReleaseSafe(error
);
460 CFReleaseSafe(client
.accessGroups
);
461 CFReleaseSafe(client
.musr
);
462 CFReleaseSafe(client
.task
);
463 CFReleaseSafe(domains
);
464 CFReleaseSafe(clientAuditToken
);
467 static void trustd_xpc_init(const char *service_name
)
469 secdebug("serverxpc", "start");
470 xpc_connection_t listener
= xpc_connection_create_mach_service(service_name
, NULL
, XPC_CONNECTION_MACH_SERVICE_LISTENER
);
472 seccritical("security failed to register xpc listener for %s, exiting", service_name
);
476 xpc_connection_set_event_handler(listener
, ^(xpc_object_t connection
) {
477 if (xpc_get_type(connection
) == XPC_TYPE_CONNECTION
) {
478 xpc_connection_set_event_handler(connection
, ^(xpc_object_t event
) {
479 if (xpc_get_type(event
) == XPC_TYPE_DICTIONARY
) {
480 xpc_retain(connection
);
482 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
483 trustd_xpc_dictionary_handler(connection
, event
);
485 xpc_release(connection
);
489 xpc_connection_resume(connection
);
492 xpc_connection_resume(listener
);
495 static void trustd_delete_old_files(void) {
497 #if TARGET_OS_EMBEDDED
498 if (getuid() != 64) // _securityd
503 /* If we get past this line, then we can attempt to delete old revocation files;
504 otherwise we won't have sufficient privilege. */
506 /* We try to clean up after ourselves, but don't care if we succeed. */
507 WithPathInRevocationInfoDirectory(CFSTR("update-current"), ^(const char *utf8String
) {
508 (void)remove(utf8String
);
510 WithPathInRevocationInfoDirectory(CFSTR("update-full"), ^(const char *utf8String
) {
511 (void)remove(utf8String
);
513 WithPathInRevocationInfoDirectory(CFSTR("update-full.gz"), ^(const char *utf8String
) {
514 (void)remove(utf8String
);
519 static void trustd_delete_old_caches(void) {
520 /* We try to clean up after ourselves, but don't care if we succeed. */
521 WithPathInKeychainDirectory(CFSTR("ocspcache.sqlite3"), ^(const char *utf8String
) {
522 (void)remove(utf8String
);
524 WithPathInKeychainDirectory(CFSTR("ocspcache.sqlite3-wal"), ^(const char *utf8String
) {
525 (void)remove(utf8String
);
527 WithPathInKeychainDirectory(CFSTR("ocspcache.sqlite3-shm"), ^(const char *utf8String
) {
528 (void)remove(utf8String
);
530 WithPathInKeychainDirectory(CFSTR("ocspcache.sqlite3-journal"), ^(const char *utf8String
) {
531 (void)remove(utf8String
);
533 WithPathInKeychainDirectory(CFSTR("caissuercache.sqlite3"), ^(const char *utf8String
) {
534 (void)remove(utf8String
);
536 WithPathInKeychainDirectory(CFSTR("caissuercache.sqlite3-wal"), ^(const char *utf8String
) {
537 (void)remove(utf8String
);
539 WithPathInKeychainDirectory(CFSTR("caissuercache.sqlite3-shm"), ^(const char *utf8String
) {
540 (void)remove(utf8String
);
542 WithPathInKeychainDirectory(CFSTR("caissuercache.sqlite3-journal"), ^(const char *utf8String
) {
543 (void)remove(utf8String
);
547 static void trustd_sandbox(void) {
548 char buf
[PATH_MAX
] = "";
550 if (!_set_user_dir_suffix("com.apple.trustd") ||
551 confstr(_CS_DARWIN_USER_TEMP_DIR
, buf
, sizeof(buf
)) == 0 ||
552 (mkdir(buf
, 0700) && errno
!= EEXIST
)) {
553 secerror("failed to initialize temporary directory (%d): %s", errno
, strerror(errno
));
557 char *tempdir
= realpath(buf
, NULL
);
558 if (tempdir
== NULL
) {
559 secerror("failed to resolve temporary directory (%d): %s", errno
, strerror(errno
));
563 if (confstr(_CS_DARWIN_USER_CACHE_DIR
, buf
, sizeof(buf
)) == 0 ||
564 (mkdir(buf
, 0700) && errno
!= EEXIST
)) {
565 secerror("failed to initialize cache directory (%d): %s", errno
, strerror(errno
));
569 char *cachedir
= realpath(buf
, NULL
);
570 if (cachedir
== NULL
) {
571 secerror("failed to resolve cache directory (%d): %s", errno
, strerror(errno
));
575 const char *parameters
[] = {
577 "_DARWIN_CACHE_DIR", cachedir
,
581 char *sberror
= NULL
;
582 if (sandbox_init_with_parameters("com.apple.trustd", SANDBOX_NAMED
, parameters
, &sberror
) != 0) {
583 secerror("Failed to enter trustd sandbox: %{public}s", sberror
);
591 static void trustd_sandbox(void) {
592 char buf
[PATH_MAX
] = "";
593 _set_user_dir_suffix("com.apple.trustd");
594 confstr(_CS_DARWIN_USER_TEMP_DIR
, buf
, sizeof(buf
));
598 int main(int argc
, char *argv
[])
600 char *wait4debugger
= getenv("WAIT4DEBUGGER");
601 if (wait4debugger
&& !strcasecmp("YES", wait4debugger
)) {
602 seccritical("SIGSTOPing self, awaiting debugger");
603 kill(getpid(), SIGSTOP
);
604 seccritical("Again, for good luck (or bad debuggers)");
605 kill(getpid(), SIGSTOP
);
608 /* <rdar://problem/15792007> Users with network home folders are unable to use/save password for Mail/Cal/Contacts/websites
609 Our process doesn't realize DB connections get invalidated when network home directory users logout
610 and their home gets unmounted. Exit our process and start fresh when user logs back in.
613 int sessionstatechanged_tok
;
614 notify_register_dispatch(kSA_SessionStateChangedNotification
, &sessionstatechanged_tok
, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(int token __unused
) {
615 // we could be a process running as root.
616 // However, since root never logs out this isn't an issue.
617 if (SASSessionStateForUser(getuid()) == kSA_state_loggingout_pointofnoreturn
) {
618 dispatch_after(dispatch_time(DISPATCH_TIME_NOW
, 3ull*NSEC_PER_SEC
), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
619 xpc_transaction_exit_clean();
626 /* Before we enter the sandbox, we need to delete the old caches kept in ~/Library/Keychains
627 * After we enter the sandbox, we won't be able to access them. */
628 trustd_delete_old_caches();
630 /* Also clean up old files in /Library/Keychains/crls */
631 trustd_delete_old_files();
635 const char *serviceName
= kTrustdXPCServiceName
;
636 if (argc
> 1 && (!strcmp(argv
[1], "--agent"))) {
637 serviceName
= kTrustdAgentXPCServiceName
;
640 /* set up SQLite before some other component has a chance to create a database connection */
643 /* set up revocation database if it doesn't already exist, or needs to be replaced */
644 SecRevocationDbInitialize();
646 gTrustd
= &trustd_spi
;
647 SecPolicyServerInitialize();
648 SecPinningDbInitialize();
650 SecTrustLegacySourcesListenForKeychainEvents();
652 trustd_xpc_init(serviceName
);