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