2 * Copyright (c) 2015 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 #include <securityd/SecItemBackupServer.h>
25 #include <securityd/SecItemServer.h>
26 #include "keychain/SecureObjectSync/SOSEnginePriv.h"
27 #include "keychain/SecureObjectSync/SOSPeer.h"
28 #include <Security/SecureObjectSync/SOSBackupSliceKeyBag.h>
29 #include <Security/SecureObjectSync/SOSViews.h>
32 #include <securityd/SecDbItem.h>
33 #include <utilities/der_plist.h>
35 static bool withDataSourceAndEngine(CFErrorRef
*error
, void (^action
)(SOSDataSourceRef ds
, SOSEngineRef engine
)) {
37 SOSDataSourceFactoryRef dsf
= SecItemDataSourceFactoryGetDefault();
38 SOSDataSourceRef ds
= SOSDataSourceFactoryCreateDataSource(dsf
, kSecAttrAccessibleWhenUnlocked
, error
);
40 SOSEngineRef engine
= SOSDataSourceGetSharedEngine(ds
, error
);
45 ok
&= SOSDataSourceRelease(ds
, error
);
50 int SecServerItemBackupHandoffFD(CFStringRef backupName
, CFErrorRef
*error
) {
52 if (!withDataSourceAndEngine(error
, ^(SOSDataSourceRef ds
, SOSEngineRef engine
) {
53 SOSEngineForPeerID(engine
, backupName
, error
, ^(SOSTransactionRef txn
, SOSPeerRef peer
) {
54 fd
= SOSPeerHandoffFD(peer
, error
);
63 bool SecServerItemBackupSetConfirmedManifest(CFStringRef backupName
, CFDataRef keybagDigest
, CFDataRef manifestData
, CFErrorRef
*error
) {
64 __block
bool ok
= true;
65 ok
&= withDataSourceAndEngine(error
, ^(SOSDataSourceRef ds
, SOSEngineRef engine
) {
66 ok
= SOSEngineSetPeerConfirmedManifest(engine
, backupName
, keybagDigest
, manifestData
, error
);
71 CFArrayRef
SecServerItemBackupCopyNames(CFErrorRef
*error
) {
72 __block CFArrayRef names
= NULL
;
73 if (!withDataSourceAndEngine(error
, ^(SOSDataSourceRef ds
, SOSEngineRef engine
) {
74 names
= SOSEngineCopyBackupPeerNames(engine
, error
);
81 // TODO Move to datasource and remove dsRestoreObject
82 static bool SOSDataSourceWithBackup(SOSDataSourceRef ds
, CFDataRef backup
, keybag_handle_t bag_handle
, CFErrorRef
*error
, void(^with
)(SOSObjectRef item
)) {
83 __block
bool ok
= true;
84 CFPropertyListRef plist
= CFPropertyListCreateWithDERData(kCFAllocatorDefault
, backup
, kCFPropertyListImmutable
, NULL
, error
);
85 CFDictionaryRef bdict
= asDictionary(plist
, error
);
87 if (ok
) CFDictionaryForEach(bdict
, ^(const void *key
, const void *value
) {
88 CFStringRef className
= asString(key
, error
);
90 const SecDbClass
*cls
= kc_class_with_name(className
);
92 CFArrayRef items
= asArray(value
, error
);
94 if (items
) CFArrayForEachC(items
, edata
) {
95 SOSObjectRef item
= (SOSObjectRef
)SecDbItemCreateWithEncryptedData(kCFAllocatorDefault
, cls
, edata
, bag_handle
, error
);
106 ok
&= SecError(errSecDecode
, error
, CFSTR("bad class %@ in backup"), className
);
112 CFReleaseSafe(plist
);
116 bool SecServerItemBackupRestore(CFStringRef backupName
, CFStringRef peerID
, CFDataRef keybag
, CFDataRef secret
, CFDataRef backup
, CFErrorRef
*error
) {
117 // TODO: Decrypt and merge items in backup to dataSource
119 __block
bool ok
= false; // return false if the bag_handle code fails.
120 CFDataRef aksKeybag
= NULL
;
121 CFMutableSetRef viewSet
= NULL
;
122 SOSBackupSliceKeyBagRef backupSliceKeyBag
= NULL
;
123 keybag_handle_t bag_handle
= bad_keybag_handle
;
125 require(asData(secret
, error
), xit
);
126 require(backupSliceKeyBag
= SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault
, keybag
, error
), xit
);
129 bag_handle
= SOSBSKBLoadAndUnlockWithPeerIDAndSecret(backupSliceKeyBag
, peerID
, secret
, error
);
131 if (SOSBSKBIsDirect(backupSliceKeyBag
)) {
132 bag_handle
= SOSBSKBLoadAndUnlockWithDirectSecret(backupSliceKeyBag
, secret
, error
);
134 bag_handle
= SOSBSKBLoadAndUnlockWithWrappingSecret(backupSliceKeyBag
, secret
, error
);
137 require(bag_handle
!= bad_keybag_handle
, xit
);
139 // TODO: How do we know which views we are allow to restore
140 //viewSet = SOSAccountCopyRestorableViews();
142 ok
= true; // Start from original code start point - otherwise begin in this nest of stuff
143 ok
&= withDataSourceAndEngine(error
, ^(SOSDataSourceRef ds
, SOSEngineRef engine
) {
144 ok
&= SOSDataSourceWith(ds
, error
, ^(SOSTransactionRef txn
, bool *commit
) {
145 ok
&= SOSDataSourceWithBackup(ds
, backup
, bag_handle
, error
, ^(SOSObjectRef item
) {
146 //if (SOSDataSourceIsInViewSet(item, viewSet)) {
147 SOSObjectRef mergedItem
= NULL
;
148 if (SOSDataSourceMergeObject(ds
, txn
, item
, &mergedItem
, error
)) {
149 // if mergedItem == item then it was restored otherwise it was rejected by the conflict resolver.
150 CFReleaseSafe(mergedItem
);
158 if (bag_handle
!= bad_keybag_handle
)
159 ok
&= ks_close_keybag(bag_handle
, error
);
161 CFReleaseSafe(backupSliceKeyBag
);
162 CFReleaseSafe(aksKeybag
);
163 CFReleaseSafe(viewSet
);