SecItemBackupServer.c
1 /* 2 * Copyright (c) 2015 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 "keychain/securityd/SecItemBackupServer.h" 25 #include "keychain/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> 30 #include <unistd.h> 31 32 #include "keychain/securityd/SecDbItem.h" 33 #include <utilities/der_plist.h> 34 35 static bool withDataSourceAndEngine(CFErrorRef *error, void (^action)(SOSDataSourceRef ds, SOSEngineRef engine)) { 36 bool ok = false; 37 SOSDataSourceFactoryRef dsf = SecItemDataSourceFactoryGetDefault(); 38 SOSDataSourceRef ds = SOSDataSourceFactoryCreateDataSource(dsf, kSecAttrAccessibleWhenUnlocked, error); 39 if (ds) { 40 SOSEngineRef engine = SOSDataSourceGetSharedEngine(ds, error); 41 if (engine) { 42 action(ds, engine); 43 ok = true; 44 } 45 ok &= SOSDataSourceRelease(ds, error); 46 } 47 return ok; 48 } 49 50 int SecServerItemBackupHandoffFD(CFStringRef backupName, CFErrorRef *error) { 51 __block int fd = -1; 52 if (!withDataSourceAndEngine(error, ^(SOSDataSourceRef ds, SOSEngineRef engine) { 53 SOSEngineForPeerID(engine, backupName, error, ^(SOSTransactionRef txn, SOSPeerRef peer) { 54 fd = SOSPeerHandoffFD(peer, error); 55 }); 56 }) && fd >= 0) { 57 close(fd); 58 fd = -1; 59 } 60 return fd; 61 } 62 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); 67 }); 68 return ok; 69 } 70 71 CFArrayRef SecServerItemBackupCopyNames(CFErrorRef *error) { 72 __block CFArrayRef names = NULL; 73 if (!withDataSourceAndEngine(error, ^(SOSDataSourceRef ds, SOSEngineRef engine) { 74 names = SOSEngineCopyBackupPeerNames(engine, error); 75 })) { 76 CFReleaseNull(names); 77 } 78 return names; 79 } 80 81 CFStringRef SecServerItemBackupEnsureCopyView(CFStringRef viewName, CFErrorRef *error) { 82 __block CFStringRef name = NULL; 83 if(!withDataSourceAndEngine(error, ^(SOSDataSourceRef ds, SOSEngineRef engine) { 84 name = SOSEngineEnsureCopyBackupPeerForView(engine, viewName, error); 85 })) { 86 CFReleaseNull(name); 87 } 88 return name; 89 } 90 91 // TODO Move to datasource and remove dsRestoreObject 92 static bool SOSDataSourceWithBackup(SOSDataSourceRef ds, CFDataRef backup, keybag_handle_t bag_handle, CFErrorRef *error, void(^with)(SOSObjectRef item)) { 93 __block bool ok = true; 94 CFPropertyListRef plist = CFPropertyListCreateWithDERData(kCFAllocatorDefault, backup, kCFPropertyListImmutable, NULL, error); 95 CFDictionaryRef bdict = asDictionary(plist, error); 96 ok = (bdict != NULL); 97 if (ok) CFDictionaryForEach(bdict, ^(const void *key, const void *value) { 98 CFStringRef className = asString(key, error); 99 if (className) { 100 const SecDbClass *cls = kc_class_with_name(className); 101 if (cls) { 102 CFArrayRef items = asArray(value, error); 103 CFDataRef edata; 104 if (items) CFArrayForEachC(items, edata) { 105 SOSObjectRef item = (SOSObjectRef)SecDbItemCreateWithEncryptedData(kCFAllocatorDefault, cls, edata, bag_handle, error); 106 if (item) { 107 with(item); 108 CFRelease(item); 109 } else { 110 ok = false; 111 } 112 } else { 113 ok = false; 114 } 115 } else { 116 ok &= SecError(errSecDecode, error, CFSTR("bad class %@ in backup"), className); 117 } 118 } else { 119 ok = false; 120 } 121 }); 122 CFReleaseSafe(plist); 123 return ok; 124 } 125 126 bool SecServerItemBackupRestore(CFStringRef backupName, CFStringRef peerID, CFDataRef keybag, CFDataRef secret, CFDataRef backup, CFErrorRef *error) { 127 // TODO: Decrypt and merge items in backup to dataSource 128 129 __block bool ok = false; // return false if the bag_handle code fails. 130 CFDataRef aksKeybag = NULL; 131 CFMutableSetRef viewSet = NULL; 132 SOSBackupSliceKeyBagRef backupSliceKeyBag = NULL; 133 keybag_handle_t bag_handle = bad_keybag_handle; 134 135 require(asData(secret, error), xit); 136 require(backupSliceKeyBag = SOSBackupSliceKeyBagCreateFromData(kCFAllocatorDefault, keybag, error), xit); 137 138 if (peerID) { 139 bag_handle = SOSBSKBLoadAndUnlockWithPeerIDAndSecret(backupSliceKeyBag, peerID, secret, error); 140 } else { 141 if (SOSBSKBIsDirect(backupSliceKeyBag)) { 142 bag_handle = SOSBSKBLoadAndUnlockWithDirectSecret(backupSliceKeyBag, secret, error); 143 } else { 144 bag_handle = SOSBSKBLoadAndUnlockWithWrappingSecret(backupSliceKeyBag, secret, error); 145 } 146 } 147 require(bag_handle != bad_keybag_handle, xit); 148 149 // TODO: How do we know which views we are allow to restore 150 //viewSet = SOSAccountCopyRestorableViews(); 151 152 ok = true; // Start from original code start point - otherwise begin in this nest of stuff 153 ok &= withDataSourceAndEngine(error, ^(SOSDataSourceRef ds, SOSEngineRef engine) { 154 ok &= SOSDataSourceWith(ds, error, ^(SOSTransactionRef txn, bool *commit) { 155 ok &= SOSDataSourceWithBackup(ds, backup, bag_handle, error, ^(SOSObjectRef item) { 156 //if (SOSDataSourceIsInViewSet(item, viewSet)) { 157 SOSObjectRef mergedItem = NULL; 158 if (SOSDataSourceMergeObject(ds, txn, item, &mergedItem, error)) { 159 // if mergedItem == item then it was restored otherwise it was rejected by the conflict resolver. 160 CFReleaseSafe(mergedItem); 161 } 162 //} 163 }); 164 }); 165 }); 166 167 xit: 168 if (bag_handle != bad_keybag_handle) 169 ok &= ks_close_keybag(bag_handle, error); 170 171 CFReleaseSafe(backupSliceKeyBag); 172 CFReleaseSafe(aksKeybag); 173 CFReleaseSafe(viewSet); 174 175 return ok; 176 } 177 178 179 180