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