]> git.saurik.com Git - apple/security.git/blob - OSX/trustd/trustd.c
Security-58286.41.2.tar.gz
[apple/security.git] / OSX / trustd / trustd.c
1 /*
2 * Copyright (c) 2017 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
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>
42
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>
56
57 #if TARGET_OS_OSX
58 #include <Security/SecTaskPriv.h>
59 #include <login/SessionAgentStatusCom.h>
60 #include <trustd/macOS/SecTrustOSXEntryPoints.h>
61 #endif
62
63 #include "OTATrustUtilities.h"
64
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,
77 };
78
79 static bool SecXPCDictionarySetChainOptional(xpc_object_t message, const char *key, SecCertificatePathRef path, CFErrorRef *error) {
80 if (!path)
81 return true;
82 xpc_object_t xpc_chain = SecCertificatePathCopyXPCArray(path, error);
83 if (!xpc_chain)
84 return false;
85
86 xpc_dictionary_set_value(message, key, xpc_chain);
87 xpc_release(xpc_chain);
88 return true;
89 }
90
91 static SecCertificateRef SecXPCDictionaryCopyCertificate(xpc_object_t message, const char *key, CFErrorRef *error) {
92 size_t length = 0;
93 const void *bytes = xpc_dictionary_get_data(message, key, &length);
94 if (bytes) {
95 SecCertificateRef certificate = SecCertificateCreateWithBytes(kCFAllocatorDefault, bytes, length);
96 if (certificate)
97 return certificate;
98 SecError(errSecDecode, error, CFSTR("object for key %s failed to create certificate from data"), key);
99 } else {
100 SecError(errSecParam, error, CFSTR("object for key %s missing"), key);
101 }
102 return NULL;
103 }
104
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;
111 }
112
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;
117 return true;
118 }
119 *certificates = SecCertificateXPCArrayCopyArray(xpc_certificates, error);
120 return *certificates;
121 }
122
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);
125 if (!xpc_policies) {
126 if (policies)
127 *policies = NULL;
128 return true;
129 }
130 *policies = SecPolicyXPCArrayCopyArray(xpc_policies, error);
131 return *policies != NULL;
132 }
133
134 // Returns error if entitlement isn't present.
135 static bool
136 EntitlementPresentAndTrue(uint64_t op, SecTaskRef clientTask, CFStringRef entitlement, CFErrorRef *error)
137 {
138 if (!SecTaskGetBooleanValueForEntitlement(clientTask, entitlement)) {
139 SecError(errSecMissingEntitlement, error, CFSTR("%@: %@ lacks entitlement %@"), SOSCCGetOperationDescription((enum SecXPCOperation)op), clientTask, entitlement);
140 return false;
141 }
142 return true;
143 }
144
145 static SecTrustStoreRef SecXPCDictionaryGetTrustStore(xpc_object_t message, const char *key, CFErrorRef *error) {
146 SecTrustStoreRef ts = NULL;
147 CFStringRef domain = SecXPCDictionaryCopyString(message, key, error);
148 if (domain) {
149 ts = SecTrustStoreForDomainName(domain, error);
150 CFRelease(domain);
151 }
152 return ts;
153 }
154
155 static bool SecXPCTrustStoreContains(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
156 bool result = false;
157 SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error);
158 if (ts) {
159 CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error);
160 if (digest) {
161 bool contains;
162 if (SecTrustStoreContainsCertificateWithDigest(ts, digest, &contains, error)) {
163 xpc_dictionary_set_bool(reply, kSecXPCKeyResult, contains);
164 result = true;
165 }
166 CFReleaseNull(digest);
167 }
168 }
169 return result;
170 }
171
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);
175 if (ts) {
176 SecCertificateRef certificate = SecXPCDictionaryCopyCertificate(event, kSecXPCKeyCertificate, error);
177 if (certificate) {
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);
182 noError = true;
183 CFReleaseSafe(trustSettingsDictOrArray);
184 }
185 CFReleaseNull(certificate);
186 }
187 }
188 return noError;
189 }
190
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);
194 if (ts) {
195 CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error);
196 if (digest) {
197 bool result = SecTrustStoreRemoveCertificateWithDigest(ts, digest, error);
198 xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result);
199 noError = true;
200 CFReleaseNull(digest);
201 }
202 }
203 return noError;
204 }
205
206 static bool SecXPCTrustStoreCopyAll(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
207 bool result = false;
208 SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error);
209 if (ts) {
210 CFArrayRef trustStoreContents = NULL;
211 if(_SecTrustStoreCopyAll(ts, &trustStoreContents, error) && trustStoreContents) {
212 SecXPCDictionarySetPList(reply, kSecXPCKeyResult, trustStoreContents, error);
213 CFReleaseNull(trustStoreContents);
214 result = true;
215 }
216 }
217 return result;
218 }
219
220 static bool SecXPCTrustStoreCopyUsageConstraints(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
221 bool result = false;
222 SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, error);
223 if (ts) {
224 CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, error);
225 if (digest) {
226 CFArrayRef usageConstraints = NULL;
227 if(_SecTrustStoreCopyUsageConstraints(ts, digest, &usageConstraints, error) && usageConstraints) {
228 SecXPCDictionarySetPList(reply, kSecXPCKeyResult, usageConstraints, error);
229 CFReleaseNull(usageConstraints);
230 result = true;
231 }
232 CFReleaseNull(digest);
233 }
234 }
235 return result;
236 }
237
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));
240 return true;
241 }
242
243 static bool SecXPC_OTAPKI_GetEscrowCertificates(xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
244 bool result = false;
245 uint32_t escrowRootType = (uint32_t)xpc_dictionary_get_uint64(event, "escrowType");
246 CFArrayRef array = SecOTAPKICopyCurrentEscrowCertificates(escrowRootType, error);
247 if (array) {
248 xpc_object_t xpc_array = _CFXPCCreateXPCObjectFromCFObject(array);
249 xpc_dictionary_set_value(reply, kSecXPCKeyResult, xpc_array);
250 xpc_release(xpc_array);
251 result = true;
252 }
253 CFReleaseNull(array);
254 return result;
255 }
256
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));
259 return true;
260 }
261
262 typedef bool(*SecXPCOperationHandler)(xpc_object_t event, xpc_object_t reply, CFErrorRef *error);
263
264 typedef struct {
265 CFStringRef entitlement;
266 SecXPCOperationHandler handler;
267 } SecXPCServerOperation;
268
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;
278 };
279
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 },
289 };
290
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 = {
299 .task = NULL,
300 .accessGroups = NULL,
301 .musr = NULL,
302 .uid = xpc_connection_get_euid(connection),
303 .allowSystemKeychain = true,
304 .allowSyncBubbleKeychain = false,
305 .isNetworkExtension = false,
306 .canAccessNetworkExtensionAccessGroups = false,
307 #if TARGET_OS_IPHONE
308 .inMultiUser = false,
309 #endif
310 };
311
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);
316
317
318 uint64_t operation = xpc_dictionary_get_uint64(event, kSecXPCKeyOperation);
319
320 audit_token_t auditToken = {};
321 xpc_connection_get_audit_token(connection, &auditToken);
322
323 client.task = SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken);
324 clientAuditToken = CFDataCreate(kCFAllocatorDefault, (const UInt8*)&auditToken, sizeof(auditToken));
325 client.accessGroups = SecTaskCopyAccessGroups(client.task);
326
327 secinfo("serverxpc", "XPC [%@] operation: %@ (%" PRIu64 ")", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), operation);
328
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);
333 double verifyTime;
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);
346
347 // Clear replyMessage so we don't send a synchronous reply.
348 xpc_object_t asyncReply = replyMessage;
349 replyMessage = NULL;
350
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
356 if (replyError) {
357 CFRetain(replyError);
358 } else {
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);
363 }
364 if (replyError) {
365 secdebug("ipc", "%@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), replyError);
366 xpc_object_t xpcReplyError = SecCreateXPCObjectWithCFError(replyError);
367 if (xpcReplyError) {
368 xpc_dictionary_set_value(asyncReply, kSecXPCKeyError, xpcReplyError);
369 xpc_release(xpcReplyError);
370 }
371 CFReleaseNull(replyError);
372 } else {
373 secdebug("ipc", "%@ %@ responding %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), asyncReply);
374 }
375
376 xpc_connection_send_message(connection, asyncReply);
377 xpc_release(asyncReply);
378 xpc_release(connection);
379 CFReleaseSafe(client.task);
380 CFReleaseSafe(clientAuditToken);
381 });
382 }
383 CFReleaseSafe(policies);
384 CFReleaseSafe(anchors);
385 CFReleaseSafe(certificates);
386 CFReleaseSafe(responses);
387 CFReleaseSafe(scts);
388 CFReleaseSafe(trustedLogs);
389 CFReleaseSafe(exceptions);
390 } else {
391 SecXPCServerOperation *server_op = NULL;
392 switch (operation) {
393 case sec_trust_store_contains_id:
394 server_op = &trustd_ops.trust_store_contains;
395 break;
396 case sec_trust_store_set_trust_settings_id:
397 server_op = &trustd_ops.trust_store_set_trust_settings;
398 break;
399 case sec_trust_store_remove_certificate_id:
400 server_op = &trustd_ops.trust_store_remove_certificate;
401 break;
402 case sec_trust_store_copy_all_id:
403 server_op = &trustd_ops.trust_store_copy_all;
404 break;
405 case sec_trust_store_copy_usage_constraints_id:
406 server_op = &trustd_ops.trust_store_copy_usage_constraints;
407 break;
408 case sec_ota_pki_asset_version_id:
409 server_op = &trustd_ops.ota_pki_asset_version;
410 break;
411 case kSecXPCOpOTAGetEscrowCertificates:
412 server_op = &trustd_ops.ota_pki_get_escrow_certs;
413 break;
414 case kSecXPCOpOTAPKIGetNewAsset:
415 server_op = &trustd_ops.ota_pki_get_new_asset;
416 break;
417 default:
418 break;
419 }
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);
424 }
425 if (entitled) {
426 (void)server_op->handler(event, replyMessage, &error);
427 }
428 }
429 }
430
431 if (error)
432 {
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);
437 else
438 secerror("%@ %@ %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), error);
439
440 xpcError = SecCreateXPCObjectWithCFError(error);
441 if (replyMessage) {
442 xpc_dictionary_set_value(replyMessage, kSecXPCKeyError, xpcError);
443 }
444 } else if (replyMessage) {
445 secdebug("ipc", "%@ %@ responding %@", client.task, SOSCCGetOperationDescription((enum SecXPCOperation)operation), replyMessage);
446 }
447 } else {
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);
452 }
453
454 if (replyMessage) {
455 xpc_connection_send_message(connection, replyMessage);
456 xpc_release(replyMessage);
457 }
458 if (xpcError)
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);
466 }
467
468 static void trustd_xpc_init(const char *service_name)
469 {
470 secdebug("serverxpc", "start");
471 xpc_connection_t listener = xpc_connection_create_mach_service(service_name, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
472 if (!listener) {
473 seccritical("security failed to register xpc listener for %s, exiting", service_name);
474 abort();
475 }
476
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);
482 xpc_retain(event);
483 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
484 trustd_xpc_dictionary_handler(connection, event);
485 xpc_release(event);
486 xpc_release(connection);
487 });
488 }
489 });
490 xpc_connection_resume(connection);
491 }
492 });
493 xpc_connection_resume(listener);
494 }
495
496 static void trustd_delete_old_files(void) {
497
498 #if TARGET_OS_EMBEDDED
499 if (getuid() != 64) // _securityd
500 #else
501 if (getuid() != 0)
502 #endif
503 { return; }
504 /* If we get past this line, then we can attempt to delete old revocation files;
505 otherwise we won't have sufficient privilege. */
506
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);
510 });
511 WithPathInRevocationInfoDirectory(CFSTR("update-full"), ^(const char *utf8String) {
512 (void)remove(utf8String);
513 });
514 WithPathInRevocationInfoDirectory(CFSTR("update-full.gz"), ^(const char *utf8String) {
515 (void)remove(utf8String);
516 });
517 }
518
519 #if TARGET_OS_OSX
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);
524 });
525 WithPathInKeychainDirectory(CFSTR("ocspcache.sqlite3-wal"), ^(const char *utf8String) {
526 (void)remove(utf8String);
527 });
528 WithPathInKeychainDirectory(CFSTR("ocspcache.sqlite3-shm"), ^(const char *utf8String) {
529 (void)remove(utf8String);
530 });
531 WithPathInKeychainDirectory(CFSTR("ocspcache.sqlite3-journal"), ^(const char *utf8String) {
532 (void)remove(utf8String);
533 });
534 WithPathInKeychainDirectory(CFSTR("caissuercache.sqlite3"), ^(const char *utf8String) {
535 (void)remove(utf8String);
536 });
537 WithPathInKeychainDirectory(CFSTR("caissuercache.sqlite3-wal"), ^(const char *utf8String) {
538 (void)remove(utf8String);
539 });
540 WithPathInKeychainDirectory(CFSTR("caissuercache.sqlite3-shm"), ^(const char *utf8String) {
541 (void)remove(utf8String);
542 });
543 WithPathInKeychainDirectory(CFSTR("caissuercache.sqlite3-journal"), ^(const char *utf8String) {
544 (void)remove(utf8String);
545 });
546 }
547
548 static void trustd_sandbox(void) {
549 char buf[PATH_MAX] = "";
550
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));
555 exit(EXIT_FAILURE);
556 }
557
558 char *tempdir = realpath(buf, NULL);
559 if (tempdir == NULL) {
560 secerror("failed to resolve temporary directory (%d): %s", errno, strerror(errno));
561 exit(EXIT_FAILURE);
562 }
563
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));
567 exit(EXIT_FAILURE);
568 }
569
570 char *cachedir = realpath(buf, NULL);
571 if (cachedir == NULL) {
572 secerror("failed to resolve cache directory (%d): %s", errno, strerror(errno));
573 exit(EXIT_FAILURE);
574 }
575
576 const char *parameters[] = {
577 "_TMPDIR", tempdir,
578 "_DARWIN_CACHE_DIR", cachedir,
579 NULL
580 };
581
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);
585 exit(EXIT_FAILURE);
586 }
587
588 free(tempdir);
589 free(cachedir);
590 }
591 #else
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));
596 }
597 #endif
598
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);
604 CFRelease(rs);
605 }
606
607 int main(int argc, char *argv[])
608 {
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);
615 }
616
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.
620 */
621 #if TARGET_OS_OSX
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();
629 });
630 }
631 });
632 #endif
633
634 #if TARGET_OS_OSX
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();
638 #endif
639 /* Also clean up old files in /Library/Keychains/crls */
640 trustd_delete_old_files();
641
642 trustd_sandbox();
643
644 const char *serviceName = kTrustdXPCServiceName;
645 if (argc > 1 && (!strcmp(argv[1], "--agent"))) {
646 serviceName = kTrustdAgentXPCServiceName;
647 }
648
649 /* set up SQLite before some other component has a chance to create a database connection */
650 _SecDbServerSetup();
651
652 /* set up revocation database if it doesn't already exist, or needs to be replaced */
653 SecRevocationDbInitialize();
654
655 gTrustd = &trustd_spi;
656 SecPolicyServerInitialize();
657 SecPinningDbInitialize();
658 #if TARGET_OS_OSX
659 SecTrustLegacySourcesListenForKeychainEvents();
660 #endif
661 trustd_cfstream_init();
662 trustd_xpc_init(serviceName);
663
664 dispatch_main();
665 }