/ OSX / libsecurity_utilities / lib / CSPDLTransaction.cpp
CSPDLTransaction.cpp
  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 "CSPDLTransaction.h"
 25  #include <Security/SecBasePriv.h>
 26  #include <syslog.h>
 27  
 28  #if TARGET_OS_OSX
 29  
 30  DLTransaction::DLTransaction(CSSM_DL_DB_HANDLE dldbh)
 31      : mDldbh(dldbh), mSuccess(false), mFinalized(false), mAutoCommit(CSSM_TRUE) {
 32      initialize();
 33  }
 34  
 35  DLTransaction::DLTransaction()
 36      : mSuccess(false), mFinalized(false), mAutoCommit(CSSM_TRUE) {
 37  }
 38  
 39  void DLTransaction::initialize() {
 40      // Turn off autocommit on the underlying DL and remember the old state.
 41      Security::CssmClient::ObjectImpl::check(CSSM_DL_PassThrough(mDldbh,
 42                  CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT,
 43                  NULL, reinterpret_cast<void **>(&mAutoCommit)));
 44  }
 45  
 46  DLTransaction::~DLTransaction() {
 47      finalize();
 48  }
 49  
 50  void DLTransaction::commit() {
 51      // Commit the transaction, and throw if it fails
 52  
 53      // If autocommit wasn't on on the database when we started, don't
 54      // actually commit. There might be something else going on...
 55      if(mAutoCommit) {
 56          Security::CssmClient::ObjectImpl::check(CSSM_DL_PassThrough(mDldbh, CSSM_APPLEFILEDL_COMMIT, NULL, NULL));
 57          CSSM_DL_PassThrough(mDldbh, CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT, reinterpret_cast<const void *>(mAutoCommit), NULL);
 58      }
 59  
 60      // Throwing above means this wasn't a success and we're not finalized. On exit, we'll roll back the transaction.
 61      mSuccess = true;
 62      mFinalized = true;
 63  }
 64  
 65  void DLTransaction::rollback() {
 66      // If autocommit wasn't on on the database when we started, don't
 67      // actually roll back. There might be something else going on...
 68      if(mAutoCommit) {
 69          CSSM_DL_PassThrough(mDldbh, CSSM_APPLEFILEDL_ROLLBACK, NULL, NULL);
 70          CSSM_DL_PassThrough(mDldbh, CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT,
 71                              reinterpret_cast<const void *>(mAutoCommit), NULL);
 72      }
 73  }
 74  
 75  void DLTransaction::finalize() {
 76      if(mFinalized) {
 77          return;
 78      }
 79  
 80      // if this transaction was not a success, roll back.
 81      if(!mSuccess) {
 82          // Note that we're likely (but not necessarily) unwinding the stack for an exception right now.
 83          // (If this transaction succeeded, we wouldn't be here. So, it failed, and this code likes to fail with exceptions.)
 84          // If this throws an exception, we might crash the whole process.
 85          // Swallow exceptions whole, but log them aggressively.
 86          try {
 87              rollback();
 88          } catch(CssmError cssme) {
 89              const char* errStr = cssmErrorString(cssme.error);
 90              secnotice("integrity", "caught CssmError during transaction rollback: %d %s", (int) cssme.error, errStr);
 91              syslog(LOG_ERR, "ERROR: failed to rollback keychain transaction: %d %s", (int) cssme.error, errStr);
 92          }
 93      }
 94      mFinalized = true;
 95  }
 96  
 97  
 98  CSPDLTransaction::CSPDLTransaction(Security::CssmClient::Db& db)
 99      : DLTransaction(), mDb(db) {
100      // Get the handle of the DL underlying this CSPDL.
101      mDb->passThrough(CSSM_APPLECSPDL_DB_GET_HANDLE, NULL,
102              reinterpret_cast<void **>(&mDldbh));
103  
104      initialize();
105  }
106  
107  CSPDLTransaction::~CSPDLTransaction() {
108  }
109  
110  #endif //TARGET_OS_OSX