]> git.saurik.com Git - apple/security.git/blob - OSX/trustd/trustd.c
Security-58286.200.222.tar.gz
[apple/security.git] / OSX / trustd / trustd.c
1 /*
2 * Copyright (c) 2017-2018 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <AssertMacros.h>
25 #include <sandbox.h>
26 #include <dirhelper_priv.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <pwd.h>
30 #include <notify.h>
31 #include <xpc/private.h>
32 #include <xpc/xpc.h>
33 #include <CoreFoundation/CFStream.h>
34 #include <os/assumes.h>
35
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>
44
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>
60
61 #if TARGET_OS_OSX
62 #include <Security/SecTaskPriv.h>
63 #include <login/SessionAgentStatusCom.h>
64 #include <trustd/macOS/SecTrustOSXEntryPoints.h>
65 #endif
66
67 #include "OTATrustUtilities.h"
68
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,
83 };
84
85 static bool SecXPCDictionarySetChainOptional(xpc_object_t message, const char *key, CFArrayRef path, CFErrorRef *error) {
86 if (!path)
87 return true;
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);
94 xpc_chain = NULL;
95 }
96 });
97
98 exit:
99 if (!xpc_chain)
100 return false;
101
102 xpc_dictionary_set_value(message, key, xpc_chain);
103 xpc_release(xpc_chain);
104 return true;
105 }
106
107 static SecCertificateRef SecXPCDictionaryCopyCertificate(xpc_object_t message, const char *key, CFErrorRef *error) {
108 size_t length = 0;
109 const void *bytes = xpc_dictionary_get_data(message, key, &length);
110 if (bytes) {
111 SecCertificateRef certificate = SecCertificateCreateWithBytes(kCFAllocatorDefault, bytes, length);
112 if (certificate)
113 return certificate;
114 SecError(errSecDecode, error, CFSTR("object for key %s failed to create certificate from data"), key);
115 } else {
116 SecError(errSecParam, error, CFSTR("object for key %s missing"), key);
117 }
118 return NULL;
119 }
120
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;
127 }
128
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;
133 return true;
134 }
135 *certificates = SecCertificateXPCArrayCopyArray(xpc_certificates, error);
136 return *certificates;
137 }
138
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);
141 if (!xpc_policies) {
142 if (policies)
143 *policies = NULL;
144 return true;
145 }
146 *policies = SecPolicyXPCArrayCopyArray(xpc_policies, error);
147 return *policies != NULL;
148 }
149
150 // Returns error if entitlement isn't present.
151 static bool
152 EntitlementPresentAndTrue(uint64_t op, SecTaskRef clientTask, CFStringRef entitlement, CFErrorRef *error)
153 {
154 if (!SecTaskGetBooleanValueForEntitlement(clientTask, entitlement)) {
155 SecError(errSecMissingEntitlement, error, CFSTR("%@: %@ lacks entitlement %@"), SOSCCGetOperationDescription((enum SecXPCOperation)op), clientTask, entitlement);
156 return false;
157 }
158 return true;
159 }
160
161 static SecTrustStoreRef SecXPCDictionaryGetTrustStore(xpc_object_t message, const char *key, CFErrorRef *error) {
162 SecTrustStoreRef ts = NULL;
163 CFStringRef domain = SecXPCDictionaryCopyString(message, key, error);
164 if (domain) {
165 ts = SecTrustStoreForDomainName(domain, error);
166 CFRelease(domain);
167 }
168 return ts;
169 }
170
171 static bool SecXPCTrustStoreContains(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
172 bool result = false;
173 SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error);
174 if (ts) {
175 CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error);
176 if (digest) {
177 bool contains;
178 if (SecTrustStoreContainsCertificateWithDigest(ts, digest, &contains, error)) {
179 xpc_dictionary_set_bool(reply, kSecXPCKeyResult, contains);
180 result = true;
181 }
182 CFReleaseNull(digest);
183 }
184 }
185 return result;
186 }
187
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);
191 if (ts) {
192 SecCertificateRef certificate = SecXPCDictionaryCopyCertificate(event, kSecXPCKeyCertificate, error);
193 if (certificate) {
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);
198 noError = true;
199 CFReleaseSafe(trustSettingsDictOrArray);
200 }
201 CFReleaseNull(certificate);
202 }
203 }
204 return noError;
205 }
206
207 static bool SecXPCTrustStoreRemoveCertificate(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
208 SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error);
209 if (ts) {
210 CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error);
211 if (digest) {
212 bool result = SecTrustStoreRemoveCertificateWithDigest(ts, digest, error);
213 xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result);
214 CFReleaseNull(digest);
215 return true;
216 }
217 }
218 return false;
219 }
220
221 static bool SecXPCTrustStoreCopyAll(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
222 SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error);
223 if (ts) {
224 CFArrayRef trustStoreContents = NULL;
225 if(_SecTrustStoreCopyAll(ts, &trustStoreContents, error) && trustStoreContents) {
226 SecXPCDictionarySetPList(reply, kSecXPCKeyResult, trustStoreContents, error);
227 CFReleaseNull(trustStoreContents);
228 return true;
229 }
230 }
231 return false;
232 }
233
234 static bool SecXPCTrustStoreCopyUsageConstraints(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
235 bool result = false;
236 SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error);
237 if (ts) {
238 CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error);
239 if (digest) {
240 CFArrayRef usageConstraints = NULL;
241 if(_SecTrustStoreCopyUsageConstraints(ts, digest, &usageConstraints, error) && usageConstraints) {
242 SecXPCDictionarySetPList(reply, kSecXPCKeyResult, usageConstraints, error);
243 CFReleaseNull(usageConstraints);
244 result = true;
245 }
246 CFReleaseNull(digest);
247 }
248 }
249 return result;
250 }
251
252 static bool SecXPC_OCSPCacheFlush(xpc_object_t __unused event, xpc_object_t __unused reply, CFErrorRef *error) {
253 if(SecOCSPCacheFlush(error)) {
254 return true;
255 }
256 return false;
257 }
258
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));
261 return true;
262 }
263
264 static bool SecXPC_OTAPKI_GetEscrowCertificates(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
265 bool result = false;
266 uint32_t escrowRootType = (uint32_t)xpc_dictionary_get_uint64(event, "escrowType");
267 CFArrayRef array = SecOTAPKICopyCurrentEscrowCertificates(escrowRootType, error);
268 if (array) {
269 xpc_object_t xpc_array = _CFXPCCreateXPCObjectFromCFObject(array);
270 xpc_dictionary_set_value(reply, kSecXPCKeyResult, xpc_array);
271 xpc_release(xpc_array);
272 result = true;
273 }
274 CFReleaseNull(array);
275 return result;
276 }
277
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));
280 return true;
281 }
282
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);
286 bool result = false;
287 if (attributes && eventName) {
288 result = SecTLSAnalyticsReport(eventName, attributes, error);
289 }
290 xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result);
291 CFReleaseNull(eventName);
292 return result;
293 }
294
295 typedef bool(*SecXPCOperationHandler)(xpc_object_t event, xpc_object_t reply, CFErrorRef *error);
296
297 typedef struct {
298 CFStringRef entitlement;
299 SecXPCOperationHandler handler;
300 } SecXPCServerOperation;
301
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;
313 };
314
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 },
326 };
327
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 = {
336 .task = NULL,
337 .accessGroups = NULL,
338 .musr = NULL,
339 .uid = xpc_connection_get_euid(connection),
340 .allowSystemKeychain = true,
341 .allowSyncBubbleKeychain = false,
342 .isNetworkExtension = false,
343 .canAccessNetworkExtensionAccessGroups = false,
344 #if TARGET_OS_IPHONE
345 .inMultiUser = false,
346 #endif
347 };
348
349 secdebug("serverxpc", "entering");
350 if (type == XPC_TYPE_DICTIONARY) {
351 replyMessage = xpc_dictionary_create_reply(event);
352
353 uint64_t operation = xpc_dictionary_get_uint64(event, kSecXPCKeyOperation);
354
355 audit_token_t auditToken = {};
356 xpc_connection_get_audit_token(connection, &auditToken);
357
358 client.task = SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken);
359 clientAuditToken = CFDataCreate(kCFAllocatorDefault, (const UInt8*)&auditToken, sizeof(auditToken));
360 client.accessGroups = SecTaskCopyAccessGroups(client.task);
361
362 secinfo("serverxpc", "XPC [%@] operation: %@ (%" PRIu64 ")", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), operation);
363
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);
368 double verifyTime;
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);
381
382 // Clear replyMessage so we don't send a synchronous reply.
383 xpc_object_t asyncReply = replyMessage;
384 replyMessage = NULL;
385
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
391 if (replyError) {
392 CFRetain(replyError);
393 } else {
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);
398 }
399 if (replyError) {
400 secdebug("ipc", "%@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), replyError);
401 xpc_object_t xpcReplyError = SecCreateXPCObjectWithCFError(replyError);
402 if (xpcReplyError) {
403 xpc_dictionary_set_value(asyncReply, kSecXPCKeyError, xpcReplyError);
404 xpc_release(xpcReplyError);
405 }
406 CFReleaseNull(replyError);
407 } else {
408 secdebug("ipc", "%@ %@ responding %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), asyncReply);
409 }
410
411 xpc_connection_send_message(connection, asyncReply);
412 xpc_release(asyncReply);
413 xpc_release(connection);
414 CFReleaseSafe(client.task);
415 CFReleaseSafe(clientAuditToken);
416 });
417 }
418 CFReleaseSafe(policies);
419 CFReleaseSafe(anchors);
420 CFReleaseSafe(certificates);
421 CFReleaseSafe(responses);
422 CFReleaseSafe(scts);
423 CFReleaseSafe(trustedLogs);
424 CFReleaseSafe(exceptions);
425 } else {
426 SecXPCServerOperation *server_op = NULL;
427 switch (operation) {
428 case sec_trust_store_contains_id:
429 server_op = &trustd_ops.trust_store_contains;
430 break;
431 case sec_trust_store_set_trust_settings_id:
432 server_op = &trustd_ops.trust_store_set_trust_settings;
433 break;
434 case sec_trust_store_remove_certificate_id:
435 server_op = &trustd_ops.trust_store_remove_certificate;
436 break;
437 case sec_trust_store_copy_all_id:
438 server_op = &trustd_ops.trust_store_copy_all;
439 break;
440 case sec_trust_store_copy_usage_constraints_id:
441 server_op = &trustd_ops.trust_store_copy_usage_constraints;
442 break;
443 case sec_ocsp_cache_flush_id:
444 server_op = &trustd_ops.ocsp_cache_flush;
445 break;
446 case sec_ota_pki_trust_store_version_id:
447 server_op = &trustd_ops.ota_pki_trust_store_version;
448 break;
449 case kSecXPCOpOTAGetEscrowCertificates:
450 server_op = &trustd_ops.ota_pki_get_escrow_certs;
451 break;
452 case kSecXPCOpOTAPKIGetNewAsset:
453 server_op = &trustd_ops.ota_pki_get_new_asset;
454 break;
455 case kSecXPCOpTLSAnaltyicsReport:
456 server_op = &trustd_ops.tls_analytics_report;
457 default:
458 break;
459 }
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);
464 }
465 if (entitled) {
466 (void)server_op->handler(event, replyMessage, &error);
467 }
468 }
469 }
470
471 if (error)
472 {
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);
477 else
478 secerror("%@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), error);
479
480 xpcError = SecCreateXPCObjectWithCFError(error);
481 if (replyMessage) {
482 xpc_dictionary_set_value(replyMessage, kSecXPCKeyError, xpcError);
483 }
484 } else if (replyMessage) {
485 secdebug("ipc", "%@ %@ responding %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), replyMessage);
486 }
487 } else {
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);
492 }
493
494 if (replyMessage) {
495 xpc_connection_send_message(connection, replyMessage);
496 xpc_release(replyMessage);
497 }
498 if (xpcError)
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);
506 }
507
508 static void trustd_xpc_init(const char *service_name)
509 {
510 secdebug("serverxpc", "start");
511 xpc_connection_t listener = xpc_connection_create_mach_service(service_name, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
512 if (!listener) {
513 seccritical("security failed to register xpc listener for %s, exiting", service_name);
514 abort();
515 }
516
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);
522 }
523 });
524 xpc_connection_resume(connection);
525 }
526 });
527 xpc_connection_resume(listener);
528 }
529
530 static void trustd_delete_old_sqlite_keychain_files(CFStringRef baseFilename) {
531 WithPathInKeychainDirectory(baseFilename, ^(const char *utf8String) {
532 (void)remove(utf8String);
533 });
534 CFStringRef shmFile = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-shm"), baseFilename);
535 WithPathInKeychainDirectory(shmFile, ^(const char *utf8String) {
536 (void)remove(utf8String);
537 });
538 CFReleaseNull(shmFile);
539 CFStringRef walFile = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-wal"), baseFilename);
540 WithPathInKeychainDirectory(walFile, ^(const char *utf8String) {
541 (void)remove(utf8String);
542 });
543 CFReleaseNull(walFile);
544 CFStringRef journalFile = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-journal"), baseFilename);
545 WithPathInKeychainDirectory(journalFile, ^(const char *utf8String) {
546 (void)remove(utf8String);
547 });
548 CFReleaseNull(journalFile);
549 }
550
551 #if TARGET_OS_OSX
552 static void trustd_delete_old_sqlite_user_cache_files(CFStringRef baseFilename) {
553 WithPathInUserCacheDirectory(baseFilename, ^(const char *utf8String) {
554 (void)remove(utf8String);
555 });
556 CFStringRef shmFile = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-shm"), baseFilename);
557 WithPathInUserCacheDirectory(shmFile, ^(const char *utf8String) {
558 (void)remove(utf8String);
559 });
560 CFReleaseNull(shmFile);
561 CFStringRef walFile = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-wal"), baseFilename);
562 WithPathInUserCacheDirectory(walFile, ^(const char *utf8String) {
563 (void)remove(utf8String);
564 });
565 CFReleaseNull(walFile);
566 CFStringRef journalFile = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@-journal"), baseFilename);
567 WithPathInUserCacheDirectory(journalFile, ^(const char *utf8String) {
568 (void)remove(utf8String);
569 });
570 CFReleaseNull(journalFile);
571 }
572 #endif // TARGET_OS_OSX
573
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);
578 });
579 WithPathInRevocationInfoDirectory(CFSTR("update-full"), ^(const char *utf8String) {
580 (void)remove(utf8String);
581 });
582 WithPathInRevocationInfoDirectory(CFSTR("update-full.gz"), ^(const char *utf8String) {
583 (void)remove(utf8String);
584 });
585 #if TARGET_OS_IPHONE
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"));
589 #else
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
594 }
595
596 #if TARGET_OS_OSX
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"));
601 }
602
603 static void trustd_sandbox(void) {
604 char buf[PATH_MAX] = "";
605
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));
610 exit(EXIT_FAILURE);
611 }
612
613 char *tempdir = realpath(buf, NULL);
614 if (tempdir == NULL) {
615 secerror("failed to resolve temporary directory (%d): %s", errno, strerror(errno));
616 exit(EXIT_FAILURE);
617 }
618
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));
622 exit(EXIT_FAILURE);
623 }
624
625 char *cachedir = realpath(buf, NULL);
626 if (cachedir == NULL) {
627 secerror("failed to resolve cache directory (%d): %s", errno, strerror(errno));
628 exit(EXIT_FAILURE);
629 }
630
631 const char *parameters[] = {
632 "_TMPDIR", tempdir,
633 "_DARWIN_CACHE_DIR", cachedir,
634 NULL
635 };
636
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);
640 exit(EXIT_FAILURE);
641 }
642
643 free(tempdir);
644 free(cachedir);
645 }
646 #else
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));
651 }
652 #endif
653
654 int main(int argc, char *argv[])
655 {
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);
662 }
663
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.
667 */
668 #if TARGET_OS_OSX
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();
676 });
677 }
678 });
679 #endif
680
681 #if TARGET_OS_OSX
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();
685 #endif
686
687 trustd_sandbox();
688
689 /* Also clean up old files in our sandbox. After sandboxing, so that user dir suffix is set. */
690 trustd_delete_old_files();
691
692 const char *serviceName = kTrustdXPCServiceName;
693 if (argc > 1 && (!strcmp(argv[1], "--agent"))) {
694 serviceName = kTrustdAgentXPCServiceName;
695 }
696
697 /* set up SQLite before some other component has a chance to create a database connection */
698 _SecDbServerSetup();
699
700 gTrustd = &trustd_spi;
701
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
706 #if TARGET_OS_OSX
707 SecTrustLegacySourcesListenForKeychainEvents(); // set up the legacy keychain event listeners (for cache invalidation)
708 #endif
709
710 /* We're ready now. Go. */
711 trustd_xpc_init(serviceName);
712 dispatch_main();
713 }