/ keychain / securityd / SecItemBackupServer.c
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