2 * Copyright (c) 2017-2018 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>
34 #include <os/assumes.h>
36 #include <Security/SecuritydXPC.h>
37 #include <Security/SecTrustStore.h>
38 #include <Security/SecCertificateInternal.h>
39 #include <Security/SecEntitlements.h>
40 #include <Security/SecTrustInternal.h>
41 #include <Security/SecPolicyPriv.h>
42 #include <Security/SecItem.h>
43 #include <Security/SecItemPriv.h>
45 #include <ipc/securityd_client.h>
46 #include <ipc/server_entitlement_helpers.h>
47 #include <utilities/SecCFWrappers.h>
48 #include <utilities/SecDb.h>
49 #include <utilities/SecFileLocations.h>
50 #include <utilities/debugging.h>
51 #include <utilities/SecXPCError.h>
52 #include <securityd/SecOCSPCache.h>
53 #include <securityd/SecTrustStoreServer.h>
54 #include <securityd/SecPinningDb.h>
55 #include <securityd/SecPolicyServer.h>
56 #include <securityd/SecRevocationDb.h>
57 #include <securityd/SecTrustServer.h>
58 #include <securityd/spi.h>
59 #include <securityd/SecTrustLoggingServer.h>
62 #include <Security/SecTaskPriv.h>
63 #include <login/SessionAgentStatusCom.h>
64 #include <trustd/macOS/SecTrustOSXEntryPoints.h>
67 #include "OTATrustUtilities.h"
69 static struct trustd trustd_spi
= {
70 .sec_trust_store_for_domain
= SecTrustStoreForDomainName
,
71 .sec_trust_store_contains
= SecTrustStoreContainsCertificateWithDigest
,
72 .sec_trust_store_set_trust_settings
= _SecTrustStoreSetTrustSettings
,
73 .sec_trust_store_remove_certificate
= SecTrustStoreRemoveCertificateWithDigest
,
74 .sec_truststore_remove_all
= _SecTrustStoreRemoveAll
,
75 .sec_trust_evaluate
= SecTrustServerEvaluate
,
76 .sec_ota_pki_trust_store_version
= SecOTAPKIGetCurrentTrustStoreVersion
,
77 .ota_CopyEscrowCertificates
= SecOTAPKICopyCurrentEscrowCertificates
,
78 .sec_ota_pki_get_new_asset
= SecOTAPKISignalNewAsset
,
79 .sec_trust_store_copy_all
= _SecTrustStoreCopyAll
,
80 .sec_trust_store_copy_usage_constraints
= _SecTrustStoreCopyUsageConstraints
,
81 .sec_ocsp_cache_flush
= SecOCSPCacheFlush
,
82 .sec_tls_analytics_report
= SecTLSAnalyticsReport
,
85 static bool SecXPCDictionarySetChainOptional(xpc_object_t message
, const char *key
, CFArrayRef path
, CFErrorRef
*error
) {
88 __block xpc_object_t xpc_chain
= NULL
;
89 require_action_quiet(xpc_chain
= xpc_array_create(NULL
, 0), exit
, SecError(errSecParam
, error
, CFSTR("xpc_array_create failed")));
90 CFArrayForEach(path
, ^(const void *value
) {
91 SecCertificateRef cert
= (SecCertificateRef
)value
;
92 if (xpc_chain
&& !SecCertificateAppendToXPCArray(cert
, xpc_chain
, error
)) {
93 xpc_release(xpc_chain
);
102 xpc_dictionary_set_value(message
, key
, xpc_chain
);
103 xpc_release(xpc_chain
);
107 static SecCertificateRef
SecXPCDictionaryCopyCertificate(xpc_object_t message
, const char *key
, CFErrorRef
*error
) {
109 const void *bytes
= xpc_dictionary_get_data(message
, key
, &length
);
111 SecCertificateRef certificate
= SecCertificateCreateWithBytes(kCFAllocatorDefault
, bytes
, length
);
114 SecError(errSecDecode
, error
, CFSTR("object for key %s failed to create certificate from data"), key
);
116 SecError(errSecParam
, error
, CFSTR("object for key %s missing"), key
);
121 static bool SecXPCDictionaryCopyCertificates(xpc_object_t message
, const char *key
, CFArrayRef
*certificates
, CFErrorRef
*error
) {
122 xpc_object_t xpc_certificates
= xpc_dictionary_get_value(message
, key
);
123 if (!xpc_certificates
)
124 return SecError(errSecAllocate
, error
, CFSTR("no certs for key %s"), key
);
125 *certificates
= SecCertificateXPCArrayCopyArray(xpc_certificates
, error
);
126 return *certificates
;
129 static bool SecXPCDictionaryCopyCertificatesOptional(xpc_object_t message
, const char *key
, CFArrayRef
*certificates
, CFErrorRef
*error
) {
130 xpc_object_t xpc_certificates
= xpc_dictionary_get_value(message
, key
);
131 if (!xpc_certificates
) {
132 *certificates
= NULL
;
135 *certificates
= SecCertificateXPCArrayCopyArray(xpc_certificates
, error
);
136 return *certificates
;
139 static bool SecXPCDictionaryCopyPoliciesOptional(xpc_object_t message
, const char *key
, CFArrayRef
*policies
, CFErrorRef
*error
) {
140 xpc_object_t xpc_policies
= xpc_dictionary_get_value(message
, key
);
146 *policies
= SecPolicyXPCArrayCopyArray(xpc_policies
, error
);
147 return *policies
!= NULL
;
150 // Returns error if entitlement isn't present.
152 EntitlementPresentAndTrue(uint64_t op
, SecTaskRef clientTask
, CFStringRef entitlement
, CFErrorRef
*error
)
154 if (!SecTaskGetBooleanValueForEntitlement(clientTask
, entitlement
)) {
155 SecError(errSecMissingEntitlement
, error
, CFSTR("%@: %@ lacks entitlement %@"), SOSCCGetOperationDescription((enum SecXPCOperation
)op
), clientTask
, entitlement
);
161 static SecTrustStoreRef
SecXPCDictionaryGetTrustStore(xpc_object_t message
, const char *key
, CFErrorRef
*error
) {
162 SecTrustStoreRef ts
= NULL
;
163 CFStringRef domain
= SecXPCDictionaryCopyString(message
, key
, error
);
165 ts
= SecTrustStoreForDomainName(domain
, error
);
171 static bool SecXPCTrustStoreContains(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
173 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
175 CFDataRef digest
= SecXPCDictionaryCopyData(event
, kSecXPCKeyDigest
, error
);
178 if (SecTrustStoreContainsCertificateWithDigest(ts
, digest
, &contains
, error
)) {
179 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, contains
);
182 CFReleaseNull(digest
);
188 static bool SecXPCTrustStoreSetTrustSettings(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
189 bool noError
= false;
190 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
192 SecCertificateRef certificate
= SecXPCDictionaryCopyCertificate(event
, kSecXPCKeyCertificate
, error
);
194 CFTypeRef trustSettingsDictOrArray
= NULL
;
195 if (SecXPCDictionaryCopyPListOptional(event
, kSecXPCKeySettings
, &trustSettingsDictOrArray
, error
)) {
196 bool result
= _SecTrustStoreSetTrustSettings(ts
, certificate
, trustSettingsDictOrArray
, error
);
197 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, result
);
199 CFReleaseSafe(trustSettingsDictOrArray
);
201 CFReleaseNull(certificate
);
207 static bool SecXPCTrustStoreRemoveCertificate(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
208 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
210 CFDataRef digest
= SecXPCDictionaryCopyData(event
, kSecXPCKeyDigest
, error
);
212 bool result
= SecTrustStoreRemoveCertificateWithDigest(ts
, digest
, error
);
213 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, result
);
214 CFReleaseNull(digest
);
221 static bool SecXPCTrustStoreCopyAll(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
222 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
224 CFArrayRef trustStoreContents
= NULL
;
225 if(_SecTrustStoreCopyAll(ts
, &trustStoreContents
, error
) && trustStoreContents
) {
226 SecXPCDictionarySetPList(reply
, kSecXPCKeyResult
, trustStoreContents
, error
);
227 CFReleaseNull(trustStoreContents
);
234 static bool SecXPCTrustStoreCopyUsageConstraints(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
236 SecTrustStoreRef ts
= SecXPCDictionaryGetTrustStore(event
, kSecXPCKeyDomain
, error
);
238 CFDataRef digest
= SecXPCDictionaryCopyData(event
, kSecXPCKeyDigest
, error
);
240 CFArrayRef usageConstraints
= NULL
;
241 if(_SecTrustStoreCopyUsageConstraints(ts
, digest
, &usageConstraints
, error
) && usageConstraints
) {
242 SecXPCDictionarySetPList(reply
, kSecXPCKeyResult
, usageConstraints
, error
);
243 CFReleaseNull(usageConstraints
);
246 CFReleaseNull(digest
);
252 static bool SecXPC_OCSPCacheFlush(xpc_object_t __unused event
, xpc_object_t __unused reply
, CFErrorRef
*error
) {
253 if(SecOCSPCacheFlush(error
)) {
259 static bool SecXPC_OTAPKI_GetAssetVersion(xpc_object_t __unused event
, xpc_object_t reply
, CFErrorRef
*error
) {
260 xpc_dictionary_set_uint64(reply
, kSecXPCKeyResult
, SecOTAPKIGetCurrentTrustStoreVersion(error
));
264 static bool SecXPC_OTAPKI_GetEscrowCertificates(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
266 uint32_t escrowRootType
= (uint32_t)xpc_dictionary_get_uint64(event
, "escrowType");
267 CFArrayRef array
= SecOTAPKICopyCurrentEscrowCertificates(escrowRootType
, error
);
269 xpc_object_t xpc_array
= _CFXPCCreateXPCObjectFromCFObject(array
);
270 xpc_dictionary_set_value(reply
, kSecXPCKeyResult
, xpc_array
);
271 xpc_release(xpc_array
);
274 CFReleaseNull(array
);
278 static bool SecXPC_OTAPKI_GetNewAsset(xpc_object_t __unused event
, xpc_object_t reply
, CFErrorRef
*error
) {
279 xpc_dictionary_set_uint64(reply
, kSecXPCKeyResult
, SecOTAPKISignalNewAsset(error
));
283 static bool SecXPC_TLS_AnalyticsReport(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
) {
284 xpc_object_t attributes
= xpc_dictionary_get_dictionary(event
, kSecTrustEventAttributesKey
);
285 CFStringRef eventName
= SecXPCDictionaryCopyString(event
, kSecTrustEventNameKey
, error
);
287 if (attributes
&& eventName
) {
288 result
= SecTLSAnalyticsReport(eventName
, attributes
, error
);
290 xpc_dictionary_set_bool(reply
, kSecXPCKeyResult
, result
);
291 CFReleaseNull(eventName
);
295 typedef bool(*SecXPCOperationHandler
)(xpc_object_t event
, xpc_object_t reply
, CFErrorRef
*error
);
298 CFStringRef entitlement
;
299 SecXPCOperationHandler handler
;
300 } SecXPCServerOperation
;
302 struct trustd_operations
{
303 SecXPCServerOperation trust_store_contains
;
304 SecXPCServerOperation trust_store_set_trust_settings
;
305 SecXPCServerOperation trust_store_remove_certificate
;
306 SecXPCServerOperation trust_store_copy_all
;
307 SecXPCServerOperation trust_store_copy_usage_constraints
;
308 SecXPCServerOperation ocsp_cache_flush
;
309 SecXPCServerOperation ota_pki_trust_store_version
;
310 SecXPCServerOperation ota_pki_get_escrow_certs
;
311 SecXPCServerOperation ota_pki_get_new_asset
;
312 SecXPCServerOperation tls_analytics_report
;
315 static struct trustd_operations trustd_ops
= {
316 .trust_store_contains
= { NULL
, SecXPCTrustStoreContains
},
317 .trust_store_set_trust_settings
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreSetTrustSettings
},
318 .trust_store_remove_certificate
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreRemoveCertificate
},
319 .trust_store_copy_all
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreCopyAll
},
320 .trust_store_copy_usage_constraints
= { kSecEntitlementModifyAnchorCertificates
, SecXPCTrustStoreCopyUsageConstraints
},
321 .ocsp_cache_flush
= { NULL
, SecXPC_OCSPCacheFlush
},
322 .ota_pki_trust_store_version
= { NULL
, SecXPC_OTAPKI_GetAssetVersion
},
323 .ota_pki_get_escrow_certs
= { NULL
, SecXPC_OTAPKI_GetEscrowCertificates
},
324 .ota_pki_get_new_asset
= { NULL
, SecXPC_OTAPKI_GetNewAsset
},
325 .tls_analytics_report
= { NULL
, SecXPC_TLS_AnalyticsReport
},
328 static void trustd_xpc_dictionary_handler(const xpc_connection_t connection
, xpc_object_t event
) {
329 xpc_type_t type
= xpc_get_type(event
);
330 __block CFErrorRef error
= NULL
;
331 xpc_object_t xpcError
= NULL
;
332 xpc_object_t replyMessage
= NULL
;
333 CFDataRef clientAuditToken
= NULL
;
334 CFArrayRef domains
= NULL
;
335 SecurityClient client
= {
337 .accessGroups
= NULL
,
339 .uid
= xpc_connection_get_euid(connection
),
340 .allowSystemKeychain
= true,
341 .allowSyncBubbleKeychain
= false,
342 .isNetworkExtension
= false,
343 .canAccessNetworkExtensionAccessGroups
= false,
345 .inMultiUser
= false,
349 secdebug("serverxpc", "entering");
350 if (type
== XPC_TYPE_DICTIONARY
) {
351 replyMessage
= xpc_dictionary_create_reply(event
);
353 uint64_t operation
= xpc_dictionary_get_uint64(event
, kSecXPCKeyOperation
);
355 audit_token_t auditToken
= {};
356 xpc_connection_get_audit_token(connection
, &auditToken
);
358 client
.task
= SecTaskCreateWithAuditToken(kCFAllocatorDefault
, auditToken
);
359 clientAuditToken
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)&auditToken
, sizeof(auditToken
));
360 client
.accessGroups
= SecTaskCopyAccessGroups(client
.task
);
362 secinfo("serverxpc", "XPC [%@] operation: %@ (%" PRIu64
")", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), operation
);
364 if (operation
== sec_trust_evaluate_id
) {
365 CFArrayRef certificates
= NULL
, anchors
= NULL
, policies
= NULL
, responses
= NULL
, scts
= NULL
, trustedLogs
= NULL
, exceptions
= NULL
;
366 bool anchorsOnly
= xpc_dictionary_get_bool(event
, kSecTrustAnchorsOnlyKey
);
367 bool keychainsAllowed
= xpc_dictionary_get_bool(event
, kSecTrustKeychainsAllowedKey
);
369 if (SecXPCDictionaryCopyCertificates(event
, kSecTrustCertificatesKey
, &certificates
, &error
) &&
370 SecXPCDictionaryCopyCertificatesOptional(event
, kSecTrustAnchorsKey
, &anchors
, &error
) &&
371 SecXPCDictionaryCopyPoliciesOptional(event
, kSecTrustPoliciesKey
, &policies
, &error
) &&
372 SecXPCDictionaryCopyCFDataArrayOptional(event
, kSecTrustResponsesKey
, &responses
, &error
) &&
373 SecXPCDictionaryCopyCFDataArrayOptional(event
, kSecTrustSCTsKey
, &scts
, &error
) &&
374 SecXPCDictionaryCopyArrayOptional(event
, kSecTrustTrustedLogsKey
, &trustedLogs
, &error
) &&
375 SecXPCDictionaryGetDouble(event
, kSecTrustVerifyDateKey
, &verifyTime
, &error
) &&
376 SecXPCDictionaryCopyArrayOptional(event
, kSecTrustExceptionsKey
, &exceptions
, &error
)) {
377 // If we have no error yet, capture connection and reply in block and properly retain them.
378 xpc_retain(connection
);
379 CFRetainSafe(client
.task
);
380 CFRetainSafe(clientAuditToken
);
382 // Clear replyMessage so we don't send a synchronous reply.
383 xpc_object_t asyncReply
= replyMessage
;
386 SecTrustServerEvaluateBlock(clientAuditToken
, certificates
, anchors
, anchorsOnly
, keychainsAllowed
, policies
,
387 responses
, scts
, trustedLogs
, verifyTime
, client
.accessGroups
, exceptions
,
388 ^(SecTrustResultType tr
, CFArrayRef details
, CFDictionaryRef info
, CFArrayRef chain
,
389 CFErrorRef replyError
) {
390 // Send back reply now
392 CFRetain(replyError
);
394 xpc_dictionary_set_int64(asyncReply
, kSecTrustResultKey
, tr
);
395 SecXPCDictionarySetPListOptional(asyncReply
, kSecTrustDetailsKey
, details
, &replyError
) &&
396 SecXPCDictionarySetPListOptional(asyncReply
, kSecTrustInfoKey
, info
, &replyError
) &&
397 SecXPCDictionarySetChainOptional(asyncReply
, kSecTrustChainKey
, chain
, &replyError
);
400 secdebug("ipc", "%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), replyError
);
401 xpc_object_t xpcReplyError
= SecCreateXPCObjectWithCFError(replyError
);
403 xpc_dictionary_set_value(asyncReply
, kSecXPCKeyError
, xpcReplyError
);
404 xpc_release(xpcReplyError
);
406 CFReleaseNull(replyError
);
408 secdebug("ipc", "%@ %@ responding %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), asyncReply
);
411 xpc_connection_send_message(connection
, asyncReply
);
412 xpc_release(asyncReply
);
413 xpc_release(connection
);
414 CFReleaseSafe(client
.task
);
415 CFReleaseSafe(clientAuditToken
);
418 CFReleaseSafe(policies
);
419 CFReleaseSafe(anchors
);
420 CFReleaseSafe(certificates
);
421 CFReleaseSafe(responses
);
423 CFReleaseSafe(trustedLogs
);
424 CFReleaseSafe(exceptions
);
426 SecXPCServerOperation
*server_op
= NULL
;
428 case sec_trust_store_contains_id
:
429 server_op
= &trustd_ops
.trust_store_contains
;
431 case sec_trust_store_set_trust_settings_id
:
432 server_op
= &trustd_ops
.trust_store_set_trust_settings
;
434 case sec_trust_store_remove_certificate_id
:
435 server_op
= &trustd_ops
.trust_store_remove_certificate
;
437 case sec_trust_store_copy_all_id
:
438 server_op
= &trustd_ops
.trust_store_copy_all
;
440 case sec_trust_store_copy_usage_constraints_id
:
441 server_op
= &trustd_ops
.trust_store_copy_usage_constraints
;
443 case sec_ocsp_cache_flush_id
:
444 server_op
= &trustd_ops
.ocsp_cache_flush
;
446 case sec_ota_pki_trust_store_version_id
:
447 server_op
= &trustd_ops
.ota_pki_trust_store_version
;
449 case kSecXPCOpOTAGetEscrowCertificates
:
450 server_op
= &trustd_ops
.ota_pki_get_escrow_certs
;
452 case kSecXPCOpOTAPKIGetNewAsset
:
453 server_op
= &trustd_ops
.ota_pki_get_new_asset
;
455 case kSecXPCOpTLSAnaltyicsReport
:
456 server_op
= &trustd_ops
.tls_analytics_report
;
460 if (server_op
&& server_op
->handler
) {
461 bool entitled
= true;
462 if (server_op
->entitlement
) {
463 entitled
= EntitlementPresentAndTrue(operation
, client
.task
, server_op
->entitlement
, &error
);
466 (void)server_op
->handler(event
, replyMessage
, &error
);
473 if(SecErrorGetOSStatus(error
) == errSecItemNotFound
)
474 secdebug("ipc", "%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
475 else if (SecErrorGetOSStatus(error
) == errSecAuthNeeded
)
476 secwarning("Authentication is needed %@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
478 secerror("%@ %@ %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), error
);
480 xpcError
= SecCreateXPCObjectWithCFError(error
);
482 xpc_dictionary_set_value(replyMessage
, kSecXPCKeyError
, xpcError
);
484 } else if (replyMessage
) {
485 secdebug("ipc", "%@ %@ responding %@", client
.task
, SOSCCGetOperationDescription((enum SecXPCOperation
)operation
), replyMessage
);
488 SecCFCreateErrorWithFormat(kSecXPCErrorUnexpectedType
, sSecXPCErrorDomain
, NULL
, &error
, 0, CFSTR("Messages expect to be xpc dictionary, got: %@"), event
);
489 secerror("%@: returning error: %@", client
.task
, error
);
490 xpcError
= SecCreateXPCObjectWithCFError(error
);
491 replyMessage
= xpc_create_reply_with_format(event
, "{%string: %value}", kSecXPCKeyError
, xpcError
);
495 xpc_connection_send_message(connection
, replyMessage
);
496 xpc_release(replyMessage
);
499 xpc_release(xpcError
);
500 CFReleaseSafe(error
);
501 CFReleaseSafe(client
.accessGroups
);
502 CFReleaseSafe(client
.musr
);
503 CFReleaseSafe(client
.task
);
504 CFReleaseSafe(domains
);
505 CFReleaseSafe(clientAuditToken
);
508 static void trustd_xpc_init(const char *service_name
)
510 secdebug("serverxpc", "start");
511 xpc_connection_t listener
= xpc_connection_create_mach_service(service_name
, NULL
, XPC_CONNECTION_MACH_SERVICE_LISTENER
);
513 seccritical("security failed to register xpc listener for %s, exiting", service_name
);
517 xpc_connection_set_event_handler(listener
, ^(xpc_object_t connection
) {
518 if (xpc_get_type(connection
) == XPC_TYPE_CONNECTION
) {
519 xpc_connection_set_event_handler(connection
, ^(xpc_object_t event
) {
520 if (xpc_get_type(event
) == XPC_TYPE_DICTIONARY
) {
521 trustd_xpc_dictionary_handler(connection
, event
);
524 xpc_connection_resume(connection
);
527 xpc_connection_resume(listener
);
530 static void trustd_delete_old_sqlite_keychain_files(CFStringRef baseFilename
) {
531 WithPathInKeychainDirectory(baseFilename
, ^(const char *utf8String
) {
532 (void)remove(utf8String
);
534 CFStringRef shmFile
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@-shm"), baseFilename
);
535 WithPathInKeychainDirectory(shmFile
, ^(const char *utf8String
) {
536 (void)remove(utf8String
);
538 CFReleaseNull(shmFile
);
539 CFStringRef walFile
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@-wal"), baseFilename
);
540 WithPathInKeychainDirectory(walFile
, ^(const char *utf8String
) {
541 (void)remove(utf8String
);
543 CFReleaseNull(walFile
);
544 CFStringRef journalFile
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@-journal"), baseFilename
);
545 WithPathInKeychainDirectory(journalFile
, ^(const char *utf8String
) {
546 (void)remove(utf8String
);
548 CFReleaseNull(journalFile
);
552 static void trustd_delete_old_sqlite_user_cache_files(CFStringRef baseFilename
) {
553 WithPathInUserCacheDirectory(baseFilename
, ^(const char *utf8String
) {
554 (void)remove(utf8String
);
556 CFStringRef shmFile
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@-shm"), baseFilename
);
557 WithPathInUserCacheDirectory(shmFile
, ^(const char *utf8String
) {
558 (void)remove(utf8String
);
560 CFReleaseNull(shmFile
);
561 CFStringRef walFile
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@-wal"), baseFilename
);
562 WithPathInUserCacheDirectory(walFile
, ^(const char *utf8String
) {
563 (void)remove(utf8String
);
565 CFReleaseNull(walFile
);
566 CFStringRef journalFile
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@-journal"), baseFilename
);
567 WithPathInUserCacheDirectory(journalFile
, ^(const char *utf8String
) {
568 (void)remove(utf8String
);
570 CFReleaseNull(journalFile
);
572 #endif // TARGET_OS_OSX
574 static void trustd_delete_old_files(void) {
575 /* We try to clean up after ourselves, but don't care if we succeed. */
576 WithPathInRevocationInfoDirectory(CFSTR("update-current"), ^(const char *utf8String
) {
577 (void)remove(utf8String
);
579 WithPathInRevocationInfoDirectory(CFSTR("update-full"), ^(const char *utf8String
) {
580 (void)remove(utf8String
);
582 WithPathInRevocationInfoDirectory(CFSTR("update-full.gz"), ^(const char *utf8String
) {
583 (void)remove(utf8String
);
586 trustd_delete_old_sqlite_keychain_files(CFSTR("trustd_health_analytics.db"));
587 trustd_delete_old_sqlite_keychain_files(CFSTR("trust_analytics.db"));
588 trustd_delete_old_sqlite_keychain_files(CFSTR("TLS_analytics.db"));
590 trustd_delete_old_sqlite_user_cache_files(CFSTR("trustd_health_analytics.db"));
591 trustd_delete_old_sqlite_user_cache_files(CFSTR("trust_analytics.db"));
592 trustd_delete_old_sqlite_user_cache_files(CFSTR("TLS_analytics.db"));
593 #endif //TARGET_OS_IPHONE
597 static void trustd_delete_old_caches(void) {
598 /* We try to clean up after ourselves, but don't care if we succeed. */
599 trustd_delete_old_sqlite_keychain_files(CFSTR("ocspcache.sqlite3"));
600 trustd_delete_old_sqlite_keychain_files(CFSTR("caissuercache.sqlite3"));
603 static void trustd_sandbox(void) {
604 char buf
[PATH_MAX
] = "";
606 if (!_set_user_dir_suffix("com.apple.trustd") ||
607 confstr(_CS_DARWIN_USER_TEMP_DIR
, buf
, sizeof(buf
)) == 0 ||
608 (mkdir(buf
, 0700) && errno
!= EEXIST
)) {
609 secerror("failed to initialize temporary directory (%d): %s", errno
, strerror(errno
));
613 char *tempdir
= realpath(buf
, NULL
);
614 if (tempdir
== NULL
) {
615 secerror("failed to resolve temporary directory (%d): %s", errno
, strerror(errno
));
619 if (confstr(_CS_DARWIN_USER_CACHE_DIR
, buf
, sizeof(buf
)) == 0 ||
620 (mkdir(buf
, 0700) && errno
!= EEXIST
)) {
621 secerror("failed to initialize cache directory (%d): %s", errno
, strerror(errno
));
625 char *cachedir
= realpath(buf
, NULL
);
626 if (cachedir
== NULL
) {
627 secerror("failed to resolve cache directory (%d): %s", errno
, strerror(errno
));
631 const char *parameters
[] = {
633 "_DARWIN_CACHE_DIR", cachedir
,
637 char *sberror
= NULL
;
638 if (sandbox_init_with_parameters("com.apple.trustd", SANDBOX_NAMED
, parameters
, &sberror
) != 0) {
639 secerror("Failed to enter trustd sandbox: %{public}s", sberror
);
647 static void trustd_sandbox(void) {
648 char buf
[PATH_MAX
] = "";
649 _set_user_dir_suffix("com.apple.trustd");
650 confstr(_CS_DARWIN_USER_TEMP_DIR
, buf
, sizeof(buf
));
654 int main(int argc
, char *argv
[])
656 char *wait4debugger
= getenv("WAIT4DEBUGGER");
657 if (wait4debugger
&& !strcasecmp("YES", wait4debugger
)) {
658 seccritical("SIGSTOPing self, awaiting debugger");
659 kill(getpid(), SIGSTOP
);
660 seccritical("Again, for good luck (or bad debuggers)");
661 kill(getpid(), SIGSTOP
);
664 /* <rdar://problem/15792007> Users with network home folders are unable to use/save password for Mail/Cal/Contacts/websites
665 Our process doesn't realize DB connections get invalidated when network home directory users logout
666 and their home gets unmounted. Exit our process and start fresh when user logs back in.
669 int sessionstatechanged_tok
;
670 notify_register_dispatch(kSA_SessionStateChangedNotification
, &sessionstatechanged_tok
, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(int token __unused
) {
671 // we could be a process running as root.
672 // However, since root never logs out this isn't an issue.
673 if (SASSessionStateForUser(getuid()) == kSA_state_loggingout_pointofnoreturn
) {
674 dispatch_after(dispatch_time(DISPATCH_TIME_NOW
, 3ull*NSEC_PER_SEC
), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^{
675 xpc_transaction_exit_clean();
682 /* Before we enter the sandbox, we need to delete the old caches kept in ~/Library/Keychains
683 * After we enter the sandbox, we won't be able to access them. */
684 trustd_delete_old_caches();
689 /* Also clean up old files in our sandbox. After sandboxing, so that user dir suffix is set. */
690 trustd_delete_old_files();
692 const char *serviceName
= kTrustdXPCServiceName
;
693 if (argc
> 1 && (!strcmp(argv
[1], "--agent"))) {
694 serviceName
= kTrustdAgentXPCServiceName
;
697 /* set up SQLite before some other component has a chance to create a database connection */
700 gTrustd
= &trustd_spi
;
702 /* Initialize static content */
703 SecPolicyServerInitialize(); // set up callbacks for policy checks
704 SecRevocationDbInitialize(); // set up revocation database if it doesn't already exist, or needs to be replaced
705 SecPinningDbInitialize(); // set up the pinning database
707 SecTrustLegacySourcesListenForKeychainEvents(); // set up the legacy keychain event listeners (for cache invalidation)
710 /* We're ready now. Go. */
711 trustd_xpc_init(serviceName
);