]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_keychain/lib/Item.cpp
Security-59306.120.7.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / Item.cpp
index 2c571084dbad7976fef7d5c68cd42f3b446638e8..4d4dc772e14dbc548e949c50289fe3d6b205013b 100644 (file)
@@ -46,9 +46,7 @@
 #include <utilities/der_plist.h>
 
 #include <security_utilities/CSPDLTransaction.h>
-#include <SecBasePriv.h>
-
-#define SENDACCESSNOTIFICATIONS 1
+#include <Security/SecBasePriv.h>
 
 //%%% schema indexes should be defined in Schema.h
 #define _kSecAppleSharePasswordItemClass               'ashp'
@@ -77,8 +75,8 @@ ItemImpl *ItemImpl::required(SecKeychainItemRef ptr)
 
 ItemImpl *ItemImpl::optional(SecKeychainItemRef ptr)
 {
-    if (SecCFObject *p = KeyItem::fromSecKeyRef(ptr)) {
-        return dynamic_cast<ItemImpl *>(p);
+    if (ptr != NULL && CFGetTypeID(ptr) == SecKeyGetTypeID()) {
+        return dynamic_cast<ItemImpl *>(KeyItem::fromSecKeyRef(ptr));
     } else if (SecCFObject *p = SecCFObject::optional(ptr)) {
         if (ItemImpl *pp = dynamic_cast<ItemImpl *>(p)) {
             return pp;
@@ -196,14 +194,22 @@ ItemImpl::ItemImpl(ItemImpl &item) :
 }
 
 ItemImpl::~ItemImpl()
-{
+try {
        if (secd_PersistentRef) {
                CFRelease(secd_PersistentRef);
        }
+} catch (...) {
+#ifndef NDEBUG
+    /* if we get an exception in destructor, presumably the mutex, lets throw if we
+     * are in a debug build (ie reach end of block) */
+#else
+    return;
+#endif
 }
 
 
 
+
 Mutex*
 ItemImpl::getMutexForObject() const
 {
@@ -275,7 +281,7 @@ void ItemImpl::fillDbAttributesFromSchema(DbAttributes& dbAttributes, CSSM_DB_RE
     SecKeychainAttributeInfo* infos;
     keychain->getAttributeInfoForItemID(recordType, &infos);
 
-    secnotice("integrity", "filling %u attributes for type %u", (unsigned int)infos->count, recordType);
+    secinfo("integrity", "filling %u attributes for type %u", (unsigned int)infos->count, recordType);
 
     for (uint32 i = 0; i < infos->count; i++) {
         CSSM_DB_ATTRIBUTE_INFO info;
@@ -293,7 +299,7 @@ void ItemImpl::fillDbAttributesFromSchema(DbAttributes& dbAttributes, CSSM_DB_RE
 
 DbAttributes* ItemImpl::getCurrentAttributes() {
     DbAttributes* dbAttributes;
-    secnotice("integrity", "getting current attributes...");
+    secinfo("integrity", "getting current attributes...");
 
     if(mUniqueId.get()) {
         // If we have a unique id, there's an item in the database backing us. Ask for its attributes.
@@ -303,7 +309,7 @@ DbAttributes* ItemImpl::getCurrentAttributes() {
 
         // and fold in any updates.
         if(mDbAttributes.get()) {
-            secnotice("integrity", "adding %d attributes from mDbAttributes", mDbAttributes->size());
+            secinfo("integrity", "adding %d attributes from mDbAttributes", mDbAttributes->size());
             dbAttributes->updateWithDbAttributes(&(*mDbAttributes.get()));
         }
     } else if (mDbAttributes.get()) {
@@ -335,7 +341,7 @@ void ItemImpl::encodeAttributesFromDictionary(CssmOwnedData &attributeBlob, DbAt
     CFRef<CFMutableDictionaryRef> attributes;
     attributes.take(CFDictionaryCreateMutable(NULL, dbAttributes->size(), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
 
-    secnotice("integrity", "looking at %d attributes", dbAttributes->size());
+    secinfo("integrity", "looking at %d attributes", dbAttributes->size());
     // TODO: include record type and semantic information?
 
     for(int i = 0; i < dbAttributes->size(); i++) {
@@ -461,7 +467,7 @@ void ItemImpl::computeDigestFromDictionary(CssmOwnedData &sha2, DbAttributes* db
 
         sha2.length(CC_SHA256_DIGEST_LENGTH);
         CC_SHA256(attributeBlob.get().data(), static_cast<CC_LONG>(attributeBlob.get().length()), sha2);
-        secnotice("integrity", "finished: %s", sha2.get().toHex().c_str());
+        secinfo("integrity", "finished: %s", sha2.get().toHex().c_str());
     } catch (MacOSError mose) {
         secnotice("integrity", "MacOSError: %d", (int)mose.osStatus());
     } catch (...) {
@@ -471,7 +477,7 @@ void ItemImpl::computeDigestFromDictionary(CssmOwnedData &sha2, DbAttributes* db
 
 void ItemImpl::addIntegrity(Access &access, bool force) {
     if(!force && (!mKeychain || !mKeychain->hasIntegrityProtection())) {
-        secnotice("integrity", "skipping integrity add due to keychain version\n");
+        secinfo("integrity", "skipping integrity add due to keychain version\n");
         return;
     }
 
@@ -486,7 +492,7 @@ void ItemImpl::addIntegrity(Access &access, bool force) {
     if(acls.size() >= 1) {
         // Use the existing ACL
         acl = acls[0];
-        secnotice("integrity", "previous integrity acl exists; setting integrity");
+        secinfo("integrity", "previous integrity acl exists; setting integrity");
         acl->setIntegrity(digest.get());
 
         // Delete all extra ACLs
@@ -566,7 +572,7 @@ bool ItemImpl::checkIntegrity() {
     }
 
     if(!mKeychain || !mKeychain->hasIntegrityProtection()) {
-        secnotice("integrity", "skipping integrity check due to keychain version");
+        secinfo("integrity", "skipping integrity check due to keychain version");
         return true;
     }
 
@@ -583,7 +589,7 @@ bool ItemImpl::checkIntegrity() {
 
 bool ItemImpl::checkIntegrity(AclBearer& aclBearer) {
     if(!mKeychain || !mKeychain->hasIntegrityProtection()) {
-        secnotice("integrity", "skipping integrity check due to keychain version");
+        secinfo("integrity", "skipping integrity check due to keychain version");
         return true;
     }
 
@@ -632,7 +638,7 @@ bool ItemImpl::checkIntegrityFromDictionary(AclBearer& aclBearer, DbAttributes*
             return false; // No MAC, no integrity.
         }
 
-        throw cssme;
+        throw;
     }
 
     secnotice("integrity", "***** INVALID ITEM");
@@ -731,6 +737,7 @@ PrimaryKey ItemImpl::addWithCopyInfo (Keychain &keychain, bool isCopy)
 
     try {
         mKeychain = keychain;
+        StLock<Mutex>_(*(mKeychain->getKeychainMutex())); // must hold this mutex before calling db->insert
 
         Db db(keychain->database());
         if (mDoNotEncrypt)
@@ -818,6 +825,9 @@ ItemImpl::update()
        if (!isModified())
                return;
 
+    // Hold this before modifying the db below
+    StLock<Mutex>__(*(mKeychain->getKeychainMutex()));
+
        CSSM_DB_RECORDTYPE aRecordType = recordType();
        KeychainSchema schema = mKeychain->keychainSchema();
 
@@ -896,7 +906,7 @@ ItemImpl::updateSSGroup(Db& db, CSSM_DB_RECORDTYPE recordType, CssmDataContainer
     // If there aren't any attributes, make up some blank ones.
     if (!mDbAttributes.get())
     {
-        secnotice("integrity", "making new dbattributes");
+        secinfo("integrity", "making new dbattributes");
         mDbAttributes.reset(new DbAttributes());
         mDbAttributes->recordType(mPrimaryKey->recordType());
     }
@@ -914,7 +924,7 @@ ItemImpl::updateSSGroup(Db& db, CSSM_DB_RECORDTYPE recordType, CssmDataContainer
 
     if ((!access) && (haveOldUniqueId)) {
         // Copy the ACL from the old group.
-        secnotice("integrity", "copying old ACL");
+        secinfo("integrity", "copying old ACL");
         access = new Access(*(ssGroup));
 
         // We can't copy these over to the new item; they're going to be reset.
@@ -922,27 +932,13 @@ ItemImpl::updateSSGroup(Db& db, CSSM_DB_RECORDTYPE recordType, CssmDataContainer
         access->removeAclsForRight(CSSM_ACL_AUTHORIZATION_PARTITION_ID);
         access->removeAclsForRight(CSSM_ACL_AUTHORIZATION_INTEGRITY);
     } else if (!access) {
-        secnotice("integrity", "setting up new ACL");
+        secinfo("integrity", "setting up new ACL");
         // create default access controls for the new item
         CssmDbAttributeData *data = mDbAttributes->find(Schema::attributeInfo(kSecLabelItemAttr));
         string printName = data ? CssmData::overlay(data->Value[0]).toString() : "keychain item";
         access = new Access(printName);
-
-        // special case for "iTools" password - allow anyone to decrypt the item
-        if (recordType == CSSM_DL_DB_RECORD_GENERIC_PASSWORD)
-        {
-            CssmDbAttributeData *data = mDbAttributes->find(Schema::attributeInfo(kSecServiceItemAttr));
-            if (data && data->Value[0].Length == 6 && !memcmp("iTools", data->Value[0].Data, 6))
-            {
-                typedef vector<SecPointer<ACL> > AclSet;
-                AclSet acls;
-                access->findAclsForRight(CSSM_ACL_AUTHORIZATION_DECRYPT, acls);
-                for (AclSet::const_iterator it = acls.begin(); it != acls.end(); it++)
-                    (*it)->form(ACL::allowAllForm);
-            }
-        }
     } else {
-        secnotice("integrity", "passed an Access, use it");
+        secinfo("integrity", "passed an Access, use it");
         // Access is non-null. Do nothing.
     }
 
@@ -962,17 +958,17 @@ ItemImpl::updateSSGroup(Db& db, CSSM_DB_RECORDTYPE recordType, CssmDataContainer
     maker.initialOwner(prototype, nullCred);
 
     if(saveToNewSSGroup) {
-        secnotice("integrity", "saving to a new SSGroup");
+        secinfo("integrity", "saving to a new SSGroup");
 
         // If we're updating an item, it has an old group and possibly an
         // old mUniqueId. Delete these from the database, so we can insert
         // new ones.
         if(haveOldUniqueId) {
-            secnotice("integrity", "deleting old mUniqueId");
+            secinfo("integrity", "deleting old mUniqueId");
             mUniqueId->deleteRecord();
             mUniqueId.release();
         } else {
-            secnotice("integrity", "no old mUniqueId");
+            secinfo("integrity", "no old mUniqueId");
         }
 
         // Create a new SSGroup with temporary access controls
@@ -1016,7 +1012,7 @@ ItemImpl::updateSSGroup(Db& db, CSSM_DB_RECORDTYPE recordType, CssmDataContainer
         }
     } else {
         // Modify the old SSGroup
-        secnotice("integrity", "modifying the existing SSGroup");
+        secinfo("integrity", "modifying the existing SSGroup");
 
         try {
             doChange(keychain, recordType, ^{
@@ -1088,7 +1084,7 @@ ItemImpl::doChange(Keychain keychain, CSSM_DB_RECORDTYPE recordType, void (^tryC
 
             // Only check for corrupt items if the keychain supports them
             if((!kc) || !kc->hasIntegrityProtection()) {
-                secnotice("integrity", "skipping integrity check for corrupt items due to keychain support");
+                secinfo("integrity", "skipping integrity check for corrupt items due to keychain support");
                 throw;
             } else {
                 primaryKeyAttrs.reset(getCurrentAttributes());
@@ -1109,7 +1105,7 @@ ItemImpl::doChange(Keychain keychain, CSSM_DB_RECORDTYPE recordType, void (^tryC
                     // Our keychain doesn't know about any item with this primary key, so maybe
                     // we have a corrupt item in the database. Let's check.
 
-                    secnotice("integrity", "making a cursor from primary key");
+                    secinfo("integrity", "making a cursor from primary key");
                     CssmClient::DbCursor cursor = pk->createCursor(kc);
                     DbUniqueRecord uniqueId;
 
@@ -1123,7 +1119,7 @@ ItemImpl::doChange(Keychain keychain, CSSM_DB_RECORDTYPE recordType, void (^tryC
                     // Occasionally this cursor won't return the item attributes (for an unknown reason).
                     // However, we know the attributes any item with this primary key should have, so use those instead.
                     while (cursor->next(dbDupAttributes.get(), NULL, uniqueId)) {
-                        secnotice("integrity", "got an item...");
+                        secinfo("integrity", "got an item...");
 
                         SSGroup group = safer_cast<SSDbUniqueRecordImpl &>(*uniqueId).group();
                         if(!ItemImpl::checkIntegrityFromDictionary(*group, dbDupAttributes.get())) {
@@ -1227,7 +1223,7 @@ ItemImpl::dbUniqueRecord()
     // Check that our Db still matches our keychain's db. If not, find this item again in the new Db.
     // Why silly !(x == y) construction? Compiler calls operator bool() on each pointer otherwise.
     if(!(mUniqueId->database() == keychain()->database())) {
-        secnotice("integrity", "updating db of mUniqueRecord");
+        secinfo("integrity", "updating db of mUniqueRecord");
 
         DbCursor cursor(mPrimaryKey->createCursor(mKeychain));
         if (!cursor->next(NULL, NULL, mUniqueId))
@@ -1314,7 +1310,7 @@ void
 ItemImpl::modifyContent(const SecKeychainAttributeList *attrList, UInt32 dataLength, const void *inData)
 {
        StLock<Mutex>_(mMutex);
-    unique_ptr<StReadWriteLock> __(mKeychain == NULL ? NULL : new StReadWriteLock(*(mKeychain->getKeychainReadWriteLock()), StReadWriteLock::Write));
+    StMaybeLock<Mutex>__ (mKeychain == NULL ? NULL : mKeychain->getKeychainMutex());
 
        if (!mDbAttributes.get())
        {
@@ -1417,23 +1413,12 @@ ItemImpl::getContent(SecItemClass *itemClass, SecKeychainAttributeList *attrList
     {
                getLocalContent(attrList, length, outData);
        }
-
-       // Inform anyone interested that we are doing this
-#if SENDACCESSNOTIFICATIONS
-    if (outData)
-    {
-               secinfo("kcnotify", "ItemImpl::getContent(%p, %p, %p, %p) retrieved content",
-                       itemClass, attrList, length, outData);
-
-        KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent, mKeychain, this);
-    }
-#endif
 }
 
 void
 ItemImpl::freeContent(SecKeychainAttributeList *attrList, void *data)
 {
-    Allocator &allocator = Allocator::standard(); // @@@ This might not match the one used originally
+    Allocator &allocator = Allocator::standard(Allocator::sensitive); // @@@ This might not match the one used originally
     if (data)
                allocator.free(data);
 
@@ -1536,29 +1521,35 @@ ItemImpl::getAttributesAndData(SecKeychainAttributeInfo *info, SecItemClass *ite
        if (info && attrList)
        {
                SecKeychainAttributeList *theList=reinterpret_cast<SecKeychainAttributeList *>(malloc(sizeof(SecKeychainAttributeList)));
-               SecKeychainAttribute *attr=reinterpret_cast<SecKeychainAttribute *>(malloc(sizeof(SecKeychainAttribute)*attrCount));
-               theList->count=attrCount;
-               theList->attr=attr;
 
-               for (UInt32 ix = 0; ix < attrCount; ++ix)
-               {
-                       attr[ix].tag=info->tag[ix];
+        if(attrCount == 0) {
+            theList->count = 0;
+            theList->attr = NULL;
+        } else {
+            SecKeychainAttribute *attr=reinterpret_cast<SecKeychainAttribute *>(calloc(attrCount, sizeof(SecKeychainAttribute)));
+            theList->count=attrCount;
+            theList->attr=attr;
 
-                       if (dbAttributes.at(ix).NumberOfValues > 0)
-                       {
-                               attr[ix].data = dbAttributes.at(ix).Value[0].Data;
-                               attr[ix].length = (UInt32)dbAttributes.at(ix).Value[0].Length;
+            for (UInt32 ix = 0; ix < attrCount; ++ix)
+            {
+                attr[ix].tag=info->tag[ix];
 
-                               // We don't want the data released, it is up the client
-                               dbAttributes.at(ix).Value[0].Data = NULL;
-                               dbAttributes.at(ix).Value[0].Length = 0;
-                       }
-                       else
-                       {
-                               attr[ix].data = NULL;
-                               attr[ix].length = 0;
-                       }
-               }
+                if (dbAttributes.at(ix).NumberOfValues > 0)
+                {
+                    attr[ix].data = dbAttributes.at(ix).Value[0].Data;
+                    attr[ix].length = (UInt32)dbAttributes.at(ix).Value[0].Length;
+
+                    // We don't want the data released, it is up the client
+                    dbAttributes.at(ix).Value[0].Data = NULL;
+                    dbAttributes.at(ix).Value[0].Length = 0;
+                }
+                else
+                {
+                    attr[ix].data = NULL;
+                    attr[ix].length = 0;
+                }
+            }
+        }
                *attrList=theList;
        }
 
@@ -1569,13 +1560,6 @@ ItemImpl::getAttributesAndData(SecKeychainAttributeInfo *info, SecItemClass *ite
 
                if (length) *length=(UInt32)itemData.length();
                itemData.Length=0;
-
-#if SENDACCESSNOTIFICATIONS
-               secinfo("kcnotify", "ItemImpl::getAttributesAndData(%p, %p, %p, %p, %p) retrieved data",
-                       info, itemClass, attrList, length, outData);
-
-               KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent, mKeychain, this);
-#endif
        }
 
 }
@@ -1583,7 +1567,7 @@ ItemImpl::getAttributesAndData(SecKeychainAttributeInfo *info, SecItemClass *ite
 void
 ItemImpl::freeAttributesAndData(SecKeychainAttributeList *attrList, void *data)
 {
-       Allocator &allocator = Allocator::standard(); // @@@ This might not match the one used originally
+       Allocator &allocator = Allocator::standard(Allocator::sensitive); // @@@ This might not match the one used originally
 
        if (data)
                allocator.free(data);
@@ -1736,13 +1720,6 @@ ItemImpl::getData(CssmDataContainer& outData)
        }
 
     getContent(NULL, &outData);
-
-#if SENDACCESSNOTIFICATIONS
-    secinfo("kcnotify", "ItemImpl::getData retrieved data");
-
-       //%%%<might> be done elsewhere, but here is good for now
-       KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent, mKeychain, this);
-#endif
 }
 
 SSGroup
@@ -1829,7 +1806,7 @@ ItemImpl::getContent(DbAttributes *dbAttributes, CssmDataContainer *itemData)
                 }
             } catch(CssmError cssme) {
                 secnotice("integrity", "error while checking integrity, denying access: %s", cssme.what());
-                throw cssme;
+                throw;
             }
 
                        SSDbUniqueRecordImpl* impl = dynamic_cast<SSDbUniqueRecordImpl *>(&(*dbUniqueRecord()));