]> git.saurik.com Git - apple/security.git/blob - sec/ipc/server.c
46541ba7f9dea2ce9f0c80f9fb5c8c9f56a626f5
[apple/security.git] / sec / ipc / server.c
1 /*
2 * Copyright (c) 2007-2013 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 <mach/mach.h>
25 #include <mach/message.h>
26
27 #include <stdlib.h>
28 #include <sys/queue.h>
29
30 #include <Security/SecInternal.h>
31 #include <Security/SecBasePriv.h>
32 #include <Security/SecItemPriv.h> /* For SecItemDeleteAll */
33 #include <Security/SecCertificatePriv.h>
34 #include <Security/SecPolicyInternal.h>
35 #include <CoreFoundation/CoreFoundation.h>
36
37 #include <asl.h>
38 #include <syslog.h>
39 #include <bsm/libbsm.h>
40 #include <utilities/SecIOFormat.h>
41 #include <utilities/debugging.h>
42
43 #include "securityd_client.h"
44
45 #include <securityd/SecItemServer.h>
46 #include <securityd/SecTrustServer.h>
47 #include <securityd/SecTrustStoreServer.h>
48 #include <securityd/spi.h>
49 #include <Security/SecTask.h>
50
51 #include <utilities/SecCFWrappers.h>
52 #include <utilities/SecCFError.h>
53 #include <utilities/SecXPCError.h>
54
55 // TODO: Make this include work on both platforms.
56 #if TARGET_OS_EMBEDDED
57 #include <Security/SecEntitlements.h>
58 #else
59 #define kSecEntitlementKeychainSyncUpdates CFSTR("keychain-sync-updates")
60 #define kSecEntitlementKeychainCloudCircle CFSTR("keychain-cloud-circle")
61 /* defines from <Security/SecTask.h> */
62 /* defines from <Security/SecEntitlements.h> */
63 #define kSecEntitlementGetTaskAllow CFSTR("get-task-allow")
64 #define kSecEntitlementApplicationIdentifier CFSTR("application-identifier")
65 #define kSecEntitlementKeychainAccessGroups CFSTR("keychain-access-groups")
66 #define kSecEntitlementModifyAnchorCertificates CFSTR("modify-anchor-certificates")
67 #define kSecEntitlementDebugApplications CFSTR("com.apple.springboard.debugapplications")
68 #define kSecEntitlementOpenSensitiveURL CFSTR("com.apple.springboard.opensensitiveurl")
69 #define kSecEntitlementWipeDevice CFSTR("com.apple.springboard.wipedevice")
70 #define kSecEntitlementRemoteNotificationConfigure CFSTR("com.apple.remotenotification.configure")
71 #define kSecEntitlementMigrateKeychain CFSTR("migrate-keychain")
72 #define kSecEntitlementRestoreKeychain CFSTR("restore-keychain")
73 #define kSecEntitlementSyncKeychain CFSTR("sync-keychain")
74 #endif
75
76 #include <Security/SecuritydXPC.h>
77
78 #include <libkern/OSAtomic.h>
79
80 #include <CoreFoundation/CFXPCBridge.h>
81
82 #include <xpc/xpc.h>
83 #include <xpc/private.h>
84 #include <xpc/connection_private.h>
85 #include <AssertMacros.h>
86 #include <SecureObjectSync/SOSCloudCircle.h>
87
88 #include <securityd/SOSCloudCircleServer.h>
89 #include <SecureObjectSync/SOSCloudCircleInternal.h>
90 #include <sys/sysctl.h>
91
92 // For SecError
93 #include <utilities/SecDb.h>
94
95 #include <securityd/OTATrustUtilities.h>
96
97
98 #if TARGET_IPHONE_SIMULATOR
99 #define CHECK_ENTITLEMENTS 0
100 #else
101 #define CHECK_ENTITLEMENTS 1
102 #endif
103
104 #if CHECK_ENTITLEMENTS
105 static CFStringRef SecTaskCopyStringForEntitlement(SecTaskRef task,
106 CFStringRef entitlement)
107 {
108 CFStringRef value = (CFStringRef)SecTaskCopyValueForEntitlement(task,
109 entitlement, NULL);
110 if (value && CFGetTypeID(value) != CFStringGetTypeID()) {
111 CFRelease(value);
112 value = NULL;
113 }
114
115 return value;
116 }
117
118 static CFArrayRef SecTaskCopyArrayOfStringsForEntitlement(SecTaskRef task,
119 CFStringRef entitlement)
120 {
121 CFArrayRef value = (CFArrayRef)SecTaskCopyValueForEntitlement(task,
122 entitlement, NULL);
123 if (value) {
124 if (CFGetTypeID(value) == CFArrayGetTypeID()) {
125 CFIndex ix, count = CFArrayGetCount(value);
126 for (ix = 0; ix < count; ++ix) {
127 CFStringRef string = (CFStringRef)CFArrayGetValueAtIndex(value, ix);
128 if (CFGetTypeID(string) != CFStringGetTypeID()) {
129 CFRelease(value);
130 value = NULL;
131 break;
132 }
133 }
134 } else {
135 CFRelease(value);
136 value = NULL;
137 }
138 }
139
140 return value;
141 }
142
143 #endif /* CHECK_ENTITLEMENTS */
144
145 static CFArrayRef SecTaskCopyAccessGroups(SecTaskRef task) {
146 #if CHECK_ENTITLEMENTS
147 CFStringRef appID = SecTaskCopyStringForEntitlement(task,
148 kSecEntitlementApplicationIdentifier);
149 CFArrayRef groups = SecTaskCopyArrayOfStringsForEntitlement(task,
150 kSecEntitlementKeychainAccessGroups);
151 if (appID) {
152 if (groups) {
153 CFMutableArrayRef nGroups = CFArrayCreateMutableCopy(
154 CFGetAllocator(groups), CFArrayGetCount(groups) + 1, groups);
155 CFArrayAppendValue(nGroups, appID);
156 CFRelease(groups);
157 groups = nGroups;
158 } else {
159 groups = CFArrayCreate(CFGetAllocator(task),
160 (const void **)&appID, 1, &kCFTypeArrayCallBacks);
161 }
162 CFRelease(appID);
163 }
164 #else
165 CFArrayRef groups = SecAccessGroupsGetCurrent();
166 if (groups)
167 CFRetain(groups);
168 #endif
169 return groups;
170 }
171
172 static bool SecTaskGetBooleanValueForEntitlement(SecTaskRef task,
173 CFStringRef entitlement) {
174 #if CHECK_ENTITLEMENTS
175 CFStringRef canModify = (CFStringRef)SecTaskCopyValueForEntitlement(task,
176 entitlement, NULL);
177 if (!canModify)
178 return false;
179 CFTypeID canModifyType = CFGetTypeID(canModify);
180 bool ok = (CFBooleanGetTypeID() == canModifyType) && CFBooleanGetValue((CFBooleanRef)canModify);
181 CFRelease(canModify);
182 return ok;
183 #else
184 return true;
185 #endif /* !CHECK_ENTITLEMENTS */
186 }
187
188 static void with_label_and_password(xpc_object_t message, void (^action)(CFStringRef label, CFDataRef password)) {
189 const char *label_utf8 = xpc_dictionary_get_string(message, kSecXPCKeyUserLabel);
190
191 size_t password_length = 0;
192 const void *password_data = xpc_dictionary_get_data(message, kSecXPCKeyUserPassword, &password_length);
193
194 CFDataRef user_password = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, password_data, password_length, kCFAllocatorNull);
195 CFStringRef user_label = CFStringCreateWithCString(kCFAllocatorDefault, label_utf8, kCFStringEncodingUTF8);
196
197 action(user_label, user_password);
198
199 CFReleaseNull(user_password);
200 CFReleaseNull(user_label);
201 }
202
203 static bool SecXPCDictionarySetChainOptional(xpc_object_t message, const char *key, SecCertificatePathRef path, CFErrorRef *error) {
204 if (!path)
205 return true;
206 xpc_object_t xpc_chain = SecCertificatePathCopyXPCArray(path, error);
207 if (!xpc_chain)
208 return false;
209
210 xpc_dictionary_set_value(message, key, xpc_chain);
211 xpc_release(xpc_chain);
212 return true;
213 }
214
215 static SecCertificateRef SecXPCDictionaryCopyCertificate(xpc_object_t message, const char *key, CFErrorRef *error) {
216 size_t length = 0;
217 const void *bytes = xpc_dictionary_get_data(message, key, &length);
218 if (bytes) {
219 SecCertificateRef certificate = SecCertificateCreateWithBytes(kCFAllocatorDefault, bytes, length);
220 if (certificate)
221 return certificate;
222 SecError(errSecDecode, error, CFSTR("object for key %s failed to create certificate from data"), key);
223 } else {
224 SecError(errSecParam, error, CFSTR("object for key %s missing"), key);
225 }
226 return NULL;
227 }
228
229 static bool SecXPCDictionaryCopyCertificates(xpc_object_t message, const char *key, CFArrayRef *certificates, CFErrorRef *error) {
230 xpc_object_t xpc_certificates = xpc_dictionary_get_value(message, key);
231 if (!xpc_certificates)
232 return SecError(errSecAllocate, error, CFSTR("no certs for key %s"), key);
233 *certificates = SecCertificateXPCArrayCopyArray(xpc_certificates, error);
234 return *certificates;
235 }
236
237 static bool SecXPCDictionaryCopyCertificatesOptional(xpc_object_t message, const char *key, CFArrayRef *certificates, CFErrorRef *error) {
238 xpc_object_t xpc_certificates = xpc_dictionary_get_value(message, key);
239 if (!xpc_certificates) {
240 *certificates = NULL;
241 return true;
242 }
243 *certificates = SecCertificateXPCArrayCopyArray(xpc_certificates, error);
244 return *certificates;
245 }
246
247 static bool SecXPCDictionaryCopyPoliciesOptional(xpc_object_t message, const char *key, CFArrayRef *policies, CFErrorRef *error) {
248 xpc_object_t xpc_policies = xpc_dictionary_get_value(message, key);
249 if (!xpc_policies) {
250 if (policies)
251 *policies = NULL;
252 return true;
253 }
254 *policies = SecPolicyXPCArrayCopyArray(xpc_policies, error);
255 return *policies != NULL;
256 }
257
258 static SecTrustStoreRef SecXPCDictionaryGetTrustStore(xpc_object_t message, const char *key, CFErrorRef *error) {
259 SecTrustStoreRef ts = NULL;
260 CFStringRef domain = SecXPCDictionaryCopyString(message, key, error);
261 if (domain) {
262 ts = SecTrustStoreForDomainName(domain, error);
263 CFRelease(domain);
264 }
265 return ts;
266 }
267
268 static bool SecXPCDictionaryGetDouble(xpc_object_t message, const char *key, double *pvalue, CFErrorRef *error) {
269 *pvalue = xpc_dictionary_get_double(message, key);
270 if (*pvalue == NAN) {
271 return SecError(errSecParam, error, CFSTR("object for key %s bad double"), key);
272 }
273 return true;
274 }
275
276 static void securityd_xpc_dictionary_handler(const xpc_connection_t connection, xpc_object_t event) {
277 xpc_type_t type = xpc_get_type(event);
278 __block CFErrorRef error = NULL;
279 xpc_object_t xpcError = NULL;
280 xpc_object_t replyMessage = NULL;
281 SecTaskRef clientTask = NULL;
282 CFArrayRef accessGroups = NULL;
283
284 secdebug("serverxpc", "entering");
285 if (type == XPC_TYPE_DICTIONARY) {
286 // TODO: Find out what we're dispatching.
287 replyMessage = xpc_dictionary_create_reply(event);
288
289 uint64_t operation = xpc_dictionary_get_uint64(event, kSecXPCKeyOperation);
290 secdebug("serverxpc", "operation: %@ (%" PRIu64 ")", SOSCCGetOperationDescription((enum SecXPCOperation)operation), operation);
291
292 bool hasEntitlement;
293 #if 1 // CHECK_ENTITLEMENTS
294 audit_token_t auditToken = {};
295 xpc_connection_get_audit_token(connection, &auditToken);
296 clientTask = SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken);
297 accessGroups = SecTaskCopyAccessGroups(clientTask);
298
299 // operations before kSecXPCOpTryUserCredentials don't need this entitlement.
300 hasEntitlement = (operation < kSecXPCOpTryUserCredentials) ||
301 (clientTask && SecTaskGetBooleanValueForEntitlement(clientTask, kSecEntitlementKeychainCloudCircle));
302 #else
303 clientTask = NULL;
304 hasEntitlement = true;
305 #endif
306
307 // Per <rdar://problem/13315020> Disable the entitlement check for "keychain-cloud-circle"
308 // we disable entitlement enforcement. However, we still log so we know who needs the entitlement
309
310 if (!hasEntitlement) {
311 CFErrorRef entitlementError = NULL;
312 SecError(errSecMissingEntitlement, &entitlementError, CFSTR("%@: %@ lacks entitlement %@"), SOSCCGetOperationDescription((enum SecXPCOperation)operation), clientTask, kSecEntitlementKeychainCloudCircle);
313 secnotice("serverxpc", "MissingEntitlement: %@", entitlementError);
314 CFReleaseSafe(entitlementError);
315 }
316
317 if (true) {
318 switch (operation)
319 {
320 case sec_item_add_id:
321 {
322 CFDictionaryRef query = SecXPCDictionaryCopyDictionary(event, kSecXPCKeyQuery, &error);
323 if (query) {
324 CFTypeRef result = NULL;
325 if (_SecItemAdd(query, accessGroups, &result, &error) && result) {
326 SecXPCDictionarySetPList(replyMessage, kSecXPCKeyResult, result, &error);
327 CFRelease(result);
328 }
329 CFRelease(query);
330 }
331 break;
332 }
333 case sec_item_copy_matching_id:
334 {
335 CFDictionaryRef query = SecXPCDictionaryCopyDictionary(event, kSecXPCKeyQuery, &error);
336 if (query) {
337 CFTypeRef result = NULL;
338 if (_SecItemCopyMatching(query, accessGroups, &result, &error) && result) {
339 SecXPCDictionarySetPList(replyMessage, kSecXPCKeyResult, result, &error);
340 CFRelease(result);
341 }
342 CFRelease(query);
343 }
344 break;
345 }
346 case sec_item_update_id:
347 {
348 CFDictionaryRef query = SecXPCDictionaryCopyDictionary(event, kSecXPCKeyQuery, &error);
349 if (query) {
350 CFDictionaryRef attributesToUpdate = SecXPCDictionaryCopyDictionary(event, kSecXPCKeyAttributesToUpdate, &error);
351 if (attributesToUpdate) {
352 bool result = _SecItemUpdate(query, attributesToUpdate, accessGroups, &error);
353 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, result);
354 CFRelease(attributesToUpdate);
355 }
356 CFRelease(query);
357 }
358 break;
359 }
360 case sec_item_delete_id:
361 {
362 CFDictionaryRef query = SecXPCDictionaryCopyDictionary(event, kSecXPCKeyQuery, &error);
363 if (query) {
364 bool result = _SecItemDelete(query, accessGroups, &error);
365 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, result);
366 CFRelease(query);
367 }
368 break;
369 }
370 case sec_trust_store_contains_id:
371 {
372 SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, &error);
373 if (ts) {
374 CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, &error);
375 if (digest) {
376 bool contains;
377 if (SecTrustStoreContainsCertificateWithDigest(ts, digest, &contains, &error))
378 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, contains);
379 CFRelease(digest);
380 }
381 }
382 break;
383 }
384 case sec_trust_store_set_trust_settings_id:
385 {
386 SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, &error);
387 if (ts) {
388 SecCertificateRef certificate = SecXPCDictionaryCopyCertificate(event, kSecXPCKeyCertificate, &error);
389 if (certificate) {
390 CFTypeRef trustSettingsDictOrArray = NULL;
391 if (SecXPCDictionaryCopyPListOptional(event, kSecXPCKeySettings, &trustSettingsDictOrArray, &error)) {
392 bool result = _SecTrustStoreSetTrustSettings(ts, certificate, trustSettingsDictOrArray, &error);
393 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, result);
394 CFReleaseSafe(trustSettingsDictOrArray);
395 }
396 CFRelease(certificate);
397 }
398 }
399 break;
400 }
401 case sec_trust_store_remove_certificate_id:
402 {
403 SecTrustStoreRef ts = SecXPCDictionaryGetTrustStore(event, kSecXPCKeyDomain, &error);
404 if (ts) {
405 CFDataRef digest = SecXPCDictionaryCopyData(event, kSecXPCKeyDigest, &error);
406 if (digest) {
407 bool result = SecTrustStoreRemoveCertificateWithDigest(ts, digest, &error);
408 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, result);
409 CFRelease(digest);
410 }
411 }
412 break;
413 }
414 case sec_delete_all_id:
415 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, _SecItemDeleteAll(&error));
416 break;
417 case sec_trust_evaluate_id:
418 {
419 CFArrayRef certificates = NULL, anchors = NULL, policies = NULL;
420 bool anchorsOnly = xpc_dictionary_get_bool(event, kSecTrustAnchorsOnlyKey);
421 double verifyTime;
422 if (SecXPCDictionaryCopyCertificates(event, kSecTrustCertificatesKey, &certificates, &error) &&
423 SecXPCDictionaryCopyCertificatesOptional(event, kSecTrustAnchorsKey, &anchors, &error) &&
424 SecXPCDictionaryCopyPoliciesOptional(event, kSecTrustPoliciesKey, &policies, &error) &&
425 SecXPCDictionaryGetDouble(event, kSecTrustVerifyDateKey, &verifyTime, &error)) {
426 // If we have no error yet, capture connection and reply in block and properly retain them.
427 xpc_retain(connection);
428 CFRetainSafe(clientTask);
429
430 // Clear replyMessage so we don't send a synchronous reply.
431 xpc_object_t asyncReply = replyMessage;
432 replyMessage = NULL;
433
434 SecTrustServerEvaluateBlock(certificates, anchors, anchorsOnly, policies, verifyTime, accessGroups, ^(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, SecCertificatePathRef chain, CFErrorRef replyError) {
435 // Send back reply now
436 if (replyError) {
437 CFRetain(replyError);
438 } else {
439 xpc_dictionary_set_int64(asyncReply, kSecTrustResultKey, tr);
440 SecXPCDictionarySetPListOptional(asyncReply, kSecTrustDetailsKey, details, &replyError) &&
441 SecXPCDictionarySetPListOptional(asyncReply, kSecTrustInfoKey, info, &replyError) &&
442 SecXPCDictionarySetChainOptional(asyncReply, kSecTrustChainKey, chain, &replyError);
443 }
444 if (replyError) {
445 secdebug("ipc", "%@ %@ %@", clientTask, SOSCCGetOperationDescription((enum SecXPCOperation)operation), replyError);
446 xpc_object_t xpcReplyError = SecCreateXPCObjectWithCFError(replyError);
447 if (xpcReplyError) {
448 xpc_dictionary_set_value(asyncReply, kSecXPCKeyError, xpcReplyError);
449 xpc_release(xpcReplyError);
450 }
451 CFRelease(replyError);
452 } else {
453 secdebug("ipc", "%@ %@ reponding %@", clientTask, SOSCCGetOperationDescription((enum SecXPCOperation)operation), asyncReply);
454 }
455
456 xpc_connection_send_message(connection, asyncReply);
457 xpc_release(asyncReply);
458 xpc_release(connection);
459 CFReleaseSafe(clientTask);
460 });
461 }
462 CFReleaseSafe(policies);
463 CFReleaseSafe(anchors);
464 CFReleaseSafe(certificates);
465 break;
466 }
467 case sec_keychain_backup_id:
468 {
469 CFDataRef keybag = NULL, passcode = NULL;
470 if (SecXPCDictionaryCopyDataOptional(event, kSecXPCKeyKeybag, &keybag, &error)) {
471 if (SecXPCDictionaryCopyDataOptional(event, kSecXPCKeyUserPassword, &passcode, &error)) {
472 CFDataRef backup = _SecServerKeychainBackup(keybag, passcode, &error);
473 if (backup) {
474 SecXPCDictionarySetData(replyMessage, kSecXPCKeyResult, backup, &error);
475 CFRelease(backup);
476 }
477 CFReleaseSafe(passcode);
478 }
479 CFReleaseSafe(keybag);
480 }
481 break;
482 }
483 case sec_keychain_restore_id:
484 {
485 CFDataRef backup = SecXPCDictionaryCopyData(event, kSecXPCKeyBackup, &error);
486 if (backup) {
487 CFDataRef keybag = SecXPCDictionaryCopyData(event, kSecXPCKeyKeybag, &error);
488 if (keybag) {
489 CFDataRef passcode = NULL;
490 if (SecXPCDictionaryCopyDataOptional(event, kSecXPCKeyUserPassword, &passcode, &error)) {
491 bool result = _SecServerKeychainRestore(backup, keybag, passcode, &error);
492 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, result);
493 CFReleaseSafe(passcode);
494 }
495 CFRelease(keybag);
496 }
497 CFRelease(backup);
498 }
499 break;
500 }
501 case sec_keychain_sync_update_id:
502 {
503 CFDictionaryRef updates = SecXPCDictionaryCopyDictionary(event, kSecXPCKeyQuery, &error);
504 if (updates) {
505 bool result = _SecServerKeychainSyncUpdate(updates, &error);
506 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, result);
507 CFRelease(updates);
508 }
509 break;
510 }
511 case sec_keychain_backup_syncable_id:
512 {
513 CFDictionaryRef oldbackup = NULL;
514 if (SecXPCDictionaryCopyDictionaryOptional(event, kSecXPCKeyBackup, &oldbackup, &error)) {
515 CFDataRef keybag = SecXPCDictionaryCopyData(event, kSecXPCKeyKeybag, &error);
516 if (keybag) {
517 CFDataRef passcode = NULL;
518 if (SecXPCDictionaryCopyDataOptional(event, kSecXPCKeyUserPassword, &passcode, &error)) {
519 CFDictionaryRef newbackup = _SecServerBackupSyncable(oldbackup, keybag, passcode, &error);
520 if (newbackup) {
521 SecXPCDictionarySetPList(replyMessage, kSecXPCKeyResult, newbackup, &error);
522 CFRelease(newbackup);
523 }
524 CFReleaseSafe(passcode);
525 }
526 CFRelease(keybag);
527 }
528 CFReleaseSafe(oldbackup);
529 }
530 break;
531 }
532 case sec_keychain_restore_syncable_id:
533 {
534 CFDictionaryRef backup = SecXPCDictionaryCopyDictionary(event, kSecXPCKeyBackup, &error);
535 if (backup) {
536 CFDataRef keybag = SecXPCDictionaryCopyData(event, kSecXPCKeyKeybag, &error);
537 if (keybag) {
538 CFDataRef passcode = NULL;
539 if (SecXPCDictionaryCopyDataOptional(event, kSecXPCKeyUserPassword, &passcode, &error)) {
540 bool result = _SecServerRestoreSyncable(backup, keybag, passcode, &error);
541 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, result);
542 CFReleaseSafe(passcode);
543 }
544 CFRelease(keybag);
545 }
546 CFRelease(backup);
547 }
548 break;
549 }
550 case sec_ota_pki_asset_version_id:
551 xpc_dictionary_set_int64(replyMessage, kSecXPCKeyResult,
552 SecOTAPKIGetCurrentAssetVersion(&error));
553 break;
554 case kSecXPCOpTryUserCredentials:
555 with_label_and_password(event, ^(CFStringRef label, CFDataRef password) {
556 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult,
557 SOSCCTryUserCredentials_Server(label, password, &error));
558 });
559 break;
560 case kSecXPCOpSetUserCredentials:
561 with_label_and_password(event, ^(CFStringRef label, CFDataRef password) {
562 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult,
563 SOSCCSetUserCredentials_Server(label, password, &error));
564 });
565 break;
566 case kSecXPCOpCanAuthenticate:
567 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult,
568 SOSCCCanAuthenticate_Server(&error));
569 break;
570 case kSecXPCOpPurgeUserCredentials:
571 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult,
572 SOSCCPurgeUserCredentials_Server(&error));
573 break;
574 case kSecXPCOpDeviceInCircle:
575 xpc_dictionary_set_int64(replyMessage, kSecXPCKeyResult,
576 SOSCCThisDeviceIsInCircle_Server(&error));
577 break;
578 case kSecXPCOpRequestToJoin:
579 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult,
580 SOSCCRequestToJoinCircle_Server(&error));
581 break;
582 case kSecXPCOpRequestToJoinAfterRestore:
583 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult,
584 SOSCCRequestToJoinCircleAfterRestore_Server(&error));
585 break;
586 case kSecXPCOpResetToOffering:
587 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult,
588 SOSCCResetToOffering_Server(&error));
589 break;
590 case kSecXPCOpResetToEmpty:
591 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult,
592 SOSCCResetToEmpty_Server(&error));
593 break;
594 case kSecXPCOpRemoveThisDeviceFromCircle:
595 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult,
596 SOSCCRemoveThisDeviceFromCircle_Server(&error));
597 break;
598 case kSecXPCOpBailFromCircle:
599 {
600 uint64_t limit_in_seconds = xpc_dictionary_get_uint64(event, kSecXPCLimitInMinutes);
601 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult,
602 SOSCCBailFromCircle_Server(limit_in_seconds, &error));
603 }
604 break;
605 case kSecXPCOpAcceptApplicants:
606 {
607 xpc_object_t xapplicants = xpc_dictionary_get_value(event, kSecXPCKeyPeerInfos);
608 CFArrayRef applicants = CreateArrayOfPeerInfoWithXPCObject(xapplicants, &error); //(CFArrayRef)(_CFXPCCreateCFObjectFromXPCObject(xapplicants));
609 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult,
610 (applicants && SOSCCAcceptApplicants_Server(applicants, &error)));
611 CFReleaseSafe(applicants);
612 }
613 break;
614 case kSecXPCOpRejectApplicants:
615 {
616 xpc_object_t xapplicants = xpc_dictionary_get_value(event, kSecXPCKeyPeerInfos);
617 CFArrayRef applicants = CreateArrayOfPeerInfoWithXPCObject(xapplicants, &error); //(CFArrayRef)(_CFXPCCreateCFObjectFromXPCObject(xapplicants));
618 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult,
619 (applicants && SOSCCRejectApplicants_Server(applicants, &error)));
620 CFReleaseSafe(applicants);
621 }
622 break;
623 case kSecXPCOpCopyApplicantPeerInfo:
624 {
625 CFArrayRef array = SOSCCCopyApplicantPeerInfo_Server(&error);
626 if (array) {
627 xpc_object_t xpc_array = CreateXPCObjectWithArrayOfPeerInfo(array, &error);
628 xpc_dictionary_set_value(replyMessage, kSecXPCKeyResult, xpc_array);
629 xpc_release(xpc_array);
630 }
631 CFReleaseNull(array);
632 }
633 break;
634 case kSecXPCOpCopyPeerPeerInfo:
635 {
636 CFArrayRef array = SOSCCCopyPeerPeerInfo_Server(&error);
637 if (array) {
638 xpc_object_t xpc_array = CreateXPCObjectWithArrayOfPeerInfo(array, &error);
639 xpc_dictionary_set_value(replyMessage, kSecXPCKeyResult, xpc_array);
640 xpc_release(xpc_array);
641 }
642 CFReleaseNull(array);
643 }
644 break;
645 case kSecXPCOpCopyConcurringPeerPeerInfo:
646 {
647 CFArrayRef array = SOSCCCopyConcurringPeerPeerInfo_Server(&error);
648 if (array) {
649 xpc_object_t xpc_array = CreateXPCObjectWithArrayOfPeerInfo(array, &error);
650 xpc_dictionary_set_value(replyMessage, kSecXPCKeyResult, xpc_array);
651 xpc_release(xpc_array);
652 }
653 CFReleaseNull(array);
654 }
655 break;
656 case kSecXPCOpGetLastDepartureReason:
657 xpc_dictionary_set_int64(replyMessage, kSecXPCKeyResult,
658 SOSCCGetLastDepartureReason_Server(&error));
659 break;
660 case kSecXPCOpProcessSyncWithAllPeers:
661 xpc_dictionary_set_int64(replyMessage, kSecXPCKeyResult,
662 SOSCCProcessSyncWithAllPeers_Server(&error));
663 break;
664 case kSecXPCOpCopyIncompatibilityInfo:
665 xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult,
666 SOSCCCopyIncompatibilityInfo_Server(&error));
667 break;
668 case kSecXPCOpOTAGetEscrowCertificates:
669 {
670 CFArrayRef array = SecOTAPKICopyCurrentEscrowCertificates(&error);
671 if (array) {
672 xpc_object_t xpc_array = _CFXPCCreateXPCObjectFromCFObject(array);
673 xpc_dictionary_set_value(replyMessage, kSecXPCKeyResult, xpc_array);
674 xpc_release(xpc_array);
675 }
676 CFReleaseNull(array);
677 }
678 break;
679 case kSecXPCOpOTAPKIGetNewAsset:
680 xpc_dictionary_set_int64(replyMessage, kSecXPCKeyResult,
681 SecOTAPKISignalNewAsset(&error));
682 break;
683 default:
684 break;
685 }
686 }
687
688 if (error)
689 {
690 if(SecErrorGetOSStatus(error) == errSecItemNotFound)
691 secdebug("ipc", "%@ %@ %@", clientTask, SOSCCGetOperationDescription((enum SecXPCOperation)operation), error);
692 else
693 secerror("%@ %@ %@", clientTask, SOSCCGetOperationDescription((enum SecXPCOperation)operation), error);
694
695 xpcError = SecCreateXPCObjectWithCFError(error);
696 xpc_dictionary_set_value(replyMessage, kSecXPCKeyError, xpcError);
697 } else if (replyMessage) {
698 secdebug("ipc", "%@ %@ reponding %@", clientTask, SOSCCGetOperationDescription((enum SecXPCOperation)operation), replyMessage);
699 }
700 } else {
701 SecCFCreateErrorWithFormatAndArguments(kSecXPCErrorUnexpectedType, sSecXPCErrorDomain, NULL, &error, 0, CFSTR("Messages expect to be xpc dictionary, got: %@"), event);
702 secerror("%@: returning error: %@", clientTask, error);
703 xpcError = SecCreateXPCObjectWithCFError(error);
704 replyMessage = xpc_create_reply_with_format(event, "{%string: %value}", kSecXPCKeyError, xpcError);
705 }
706
707 if (replyMessage) {
708 xpc_connection_send_message(connection, replyMessage);
709 xpc_release(replyMessage);
710 }
711 if (xpcError)
712 xpc_release(xpcError);
713 CFReleaseSafe(error);
714 CFReleaseSafe(accessGroups);
715 CFReleaseSafe(clientTask);
716 }
717
718 static void securityd_xpc_init()
719 {
720 secdebug("serverxpc", "start");
721
722 xpc_track_activity();
723 xpc_connection_t listener = xpc_connection_create_mach_service(kSecuritydXPCServiceName, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
724 if (!listener) {
725 seccritical("security failed to register xpc listener, exiting");
726 abort();
727 }
728
729 xpc_connection_set_event_handler(listener, ^(xpc_object_t connection) {
730 if (xpc_get_type(connection) == XPC_TYPE_CONNECTION) {
731 xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
732 if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) {
733 xpc_retain(connection);
734 xpc_retain(event);
735 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
736 securityd_xpc_dictionary_handler(connection, event);
737 xpc_release(event);
738 xpc_release(connection);
739 });
740 }
741 });
742 xpc_connection_resume(connection);
743 }
744 });
745 xpc_connection_resume(listener);
746 }
747
748 int main(int argc, char *argv[])
749 {
750 char *wait4debugger = getenv("WAIT4DEBUGGER");
751 if (wait4debugger && !strcasecmp("YES", wait4debugger)) {
752 seccritical("SIGSTOPing self, awaiting debugger");
753 kill(getpid(), SIGSTOP);
754 asl_log(NULL, NULL, ASL_LEVEL_CRIT,
755 "Again, for good luck (or bad debuggers)");
756 kill(getpid(), SIGSTOP);
757 }
758
759 securityd_init_server();
760 securityd_xpc_init();
761 dispatch_main();
762 return 0;
763 }
764
765 /* vi:set ts=4 sw=4 et: */