2  * Copyright (c) 2000-2004,2011-2014 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@ 
  25 // Keychains.h - The Keychain class 
  27 #ifndef _SECURITY_KEYCHAINS_H_ 
  28 #define _SECURITY_KEYCHAINS_H_ 
  30 #include <security_cdsa_client/cspclient.h> 
  31 #include <security_cdsa_client/dlclient.h> 
  32 #include <security_utilities/refcount.h> 
  33 #include <security_utilities/seccfobject.h> 
  34 #include <Security/SecKeychain.h> 
  35 #include <Security/SecKeychainItem.h> 
  37 #include "SecCFTypes.h" 
  38 #include "defaultcreds.h" 
  45 namespace KeychainCore
 
  53 class KeychainSchemaImpl 
: public RefCount
 
  55         NOCOPY(KeychainSchemaImpl
) 
  57         friend class KeychainSchema
; 
  59     KeychainSchemaImpl(const CssmClient::Db 
&db
); 
  61     virtual ~KeychainSchemaImpl(); 
  63         CSSM_DB_ATTRIBUTE_FORMAT 
attributeFormatFor(CSSM_DB_RECORDTYPE recordType
, uint32 attributeId
) const; 
  64         const CssmAutoDbRecordAttributeInfo 
&primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType
) const; 
  66         bool operator <(const KeychainSchemaImpl 
&other
) const; 
  67         bool operator ==(const KeychainSchemaImpl 
&other
) const; 
  69         void getAttributeInfoForRecordType(CSSM_DB_RECORDTYPE recordType
, SecKeychainAttributeInfo 
**Info
) const; 
  70         CssmDbAttributeInfo 
attributeInfoFor(CSSM_DB_RECORDTYPE recordType
, uint32 attributeId
) const; 
  71         bool hasAttribute(CSSM_DB_RECORDTYPE recordType
, uint32 attributeId
) const; 
  72         bool hasRecordType(CSSM_DB_RECORDTYPE recordType
) const; 
  74         void didCreateRelation(CSSM_DB_RECORDTYPE inRelationID
, 
  75                 const char *inRelationName
, 
  76                 uint32 inNumberOfAttributes
, 
  77                 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO 
*pAttributeInfo
, 
  78                 uint32 inNumberOfIndexes
, 
  79                 const CSSM_DB_SCHEMA_INDEX_INFO 
*pIndexInfo
); 
  82         typedef map
<CSSM_DB_RECORDTYPE
, CssmAutoDbRecordAttributeInfo 
*> PrimaryKeyInfoMap
; 
  83         PrimaryKeyInfoMap mPrimaryKeyInfoMap
; 
  85         typedef map
<uint32
, CSSM_DB_ATTRIBUTE_FORMAT
> RelationInfoMap
; 
  86         typedef map
<CSSM_DB_RECORDTYPE
, RelationInfoMap
> DatabaseInfoMap
; 
  87         DatabaseInfoMap mDatabaseInfoMap
; 
  91         const RelationInfoMap 
&relationInfoMapFor(CSSM_DB_RECORDTYPE recordType
) const; 
  95 class KeychainSchema 
: public RefPointer
<KeychainSchemaImpl
> 
  99     KeychainSchema(KeychainSchemaImpl 
*impl
) : RefPointer
<KeychainSchemaImpl
>(impl
) {} 
 100     KeychainSchema(const CssmClient::Db 
&db
) : RefPointer
<KeychainSchemaImpl
>(new KeychainSchemaImpl(db
)) {} 
 103         bool operator <(const KeychainSchema 
&other
) const 
 104         { return ptr 
&& other
.ptr 
? *ptr 
< *other
.ptr 
: ptr 
< other
.ptr
; } 
 105         bool operator ==(const KeychainSchema 
&other
) const 
 106         { return ptr 
&& other
.ptr 
? *ptr 
== *other
.ptr 
: ptr 
== other
.ptr
; } 
 109         typedef KeychainSchemaImpl Impl
; 
 115 class KeychainImpl 
: public SecCFObject
, private CssmClient::Db::DefaultCredentialsMaker
 
 119         SECCFFUNCTIONS(KeychainImpl
, SecKeychainRef
, errSecInvalidKeychain
, gTypes().KeychainImpl
) 
 121         friend class Keychain
; 
 122         friend class ItemImpl
; 
 123         friend class KeyItem
; 
 124     friend class KCCursorImpl
; 
 125     friend class StorageManager
; 
 127     KeychainImpl(const CssmClient::Db 
&db
); 
 130         // Methods called by ItemImpl; 
 131         void didUpdate(const Item 
&inItem
, PrimaryKey 
&oldPK
, 
 133         void completeAdd(Item 
&item
, PrimaryKey 
&key
); 
 136     virtual ~KeychainImpl(); 
 138         Mutex
* getKeychainMutex(); 
 139         Mutex
* getMutexForObject() const; 
 141     ReadWriteLock
* getKeychainReadWriteLock(); 
 142         void aboutToDestruct(); 
 144         bool operator ==(const KeychainImpl 
&) const; 
 147         void add(Item 
&item
); 
 148         void addCopy(Item 
&item
); 
 149     void deleteItem(Item 
&item
); // item must be persistent. 
 152         void create(UInt32 passwordLength
, const void *inPassword
); 
 153         void createWithBlob(CssmData 
&blob
); 
 154     void create(ConstStringPtr inPassword
); 
 156     void create(const ResourceControlContext 
*rcc
); 
 159         // Locking and unlocking a keychain. 
 162         void unlock(const CssmData 
&password
); 
 163     void unlock(ConstStringPtr password
); // @@@ This has a length limit, we should remove it. 
 167         void getSettings(uint32 
&outIdleTimeOut
, bool &outLockOnSleep
); 
 168         void setSettings(uint32 inIdleTimeOut
, bool inLockOnSleep
); 
 170         // Passing in NULL for either oldPassword or newPassword will cause them to be prompted for. 
 171         // To specify a zero length password in either case the oldPasswordLength or newPasswordLength 
 172         // value must be 0 and the oldPassword or newPassword must not be NULL. 
 173         void changePassphrase(UInt32 oldPasswordLength
, const void *oldPassword
, 
 174                 UInt32 newPasswordLength
, const void *newPassword
); 
 175         void changePassphrase(ConstStringPtr oldPassword
, ConstStringPtr newPassword
); 
 177     void authenticate(const CSSM_ACCESS_CREDENTIALS 
*cred
);     // Does not do an unlock. 
 179         const char *name() const { return mDb
->name(); } 
 180         UInt32 
status() const; 
 182         bool isActive() const; 
 184         KCCursor 
createCursor(const SecKeychainAttributeList 
*attrList
); 
 185         KCCursor 
createCursor(SecItemClass itemClass
, const SecKeychainAttributeList 
*attrList
); 
 186         CssmClient::Db 
database() { StLock
<Mutex
>_(mDbMutex
); return mDb
; } 
 187     void changeDatabase(CssmClient::Db db
); 
 188         DLDbIdentifier 
dlDbIdentifier() const { return mDb
->dlDbIdentifier(); } 
 190         CssmClient::CSP 
csp(); 
 192         PrimaryKey 
makePrimaryKey(CSSM_DB_RECORDTYPE recordType
, CssmClient::DbUniqueRecord 
&uniqueId
); 
 194     // This will make a primary key for this record type, and populate it completely from the given attributes 
 195         PrimaryKey 
makePrimaryKey(CSSM_DB_RECORDTYPE recordType
, CssmClient::DbAttributes 
*currentAttributes
); 
 196         void gatherPrimaryKeyAttributes(CssmClient::DbAttributes
& primaryKeyAttrs
); 
 198         const CssmAutoDbRecordAttributeInfo 
&primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType
); 
 200     Item 
item(const PrimaryKey
& primaryKey
); 
 201     Item 
item(CSSM_DB_RECORDTYPE recordType
, CssmClient::DbUniqueRecord 
&uniqueId
); 
 203     // Check for an item that may have been deleted. 
 204     Item 
itemdeleted(const PrimaryKey
& primaryKey
); 
 206         CssmDbAttributeInfo 
attributeInfoFor(CSSM_DB_RECORDTYPE recordType
, UInt32 tag
); 
 207         void getAttributeInfoForItemID(CSSM_DB_RECORDTYPE itemID
, SecKeychainAttributeInfo 
**Info
); 
 208         static void freeAttributeInfo(SecKeychainAttributeInfo 
*Info
); 
 209         KeychainSchema 
keychainSchema(); 
 211         void didDeleteItem(ItemImpl 
*inItemImpl
); 
 213         void recode(const CssmData 
&data
, const CssmData 
&extraData
); 
 214         void copyBlob(CssmData 
&dbBlob
); 
 216         void setBatchMode(Boolean mode
, Boolean rollBack
); 
 218         // yield default open() credentials for this keychain (as of now) 
 219         const AccessCredentials 
*defaultCredentials(); 
 221         // Only call these functions while holding globals().apiLock. 
 222         bool inCache() const throw() { return mInCache
; } 
 223         void inCache(bool inCache
) throw() { mInCache 
= inCache
; } 
 225         void postEvent(SecKeychainEvent kcEvent
, ItemImpl
* item
); 
 226     void postEvent(SecKeychainEvent kcEvent
, ItemImpl
* item
, PrimaryKey pk
); 
 228         void addItem(const PrimaryKey 
&primaryKey
, ItemImpl 
*dbItemImpl
); 
 232     // Returns true if this keychain supports the attribute integrity and 
 233     // partition ID protections 
 234     bool hasIntegrityProtection(); 
 237     // Checks for and triggers a keychain database upgrade 
 238     // DO NOT hold any of the keychain locks when you call this 
 239     bool performKeychainUpgradeIfNeeded(); 
 241     // Notify the keychain that you're accessing it. Used in conjunction with 
 242     // the StorageManager for time-based caching. 
 245     // Used by StorageManager to remember the timer->keychain pairing 
 246     dispatch_source_t mCacheTimer
; 
 248     // Set this to true to make tickling do nothing. 
 249     bool mSuppressTickle
; 
 252     // Grab the locks and then call attemptKeychainMigration 
 253     // The access credentials are only used when downgrading version, and will be passed along with ACL edits 
 254     bool keychainMigration(const string oldPath
, const uint32 dbBlobVersion
, const string newPath
, const uint32 newBlobVersion
, const AccessCredentials 
*cred 
= NULL
); 
 257     // Attempt to upgrade this keychain's database 
 258     uint32 
attemptKeychainMigration(const string oldPath
, const uint32 oldBlobVersion
, const string newPath
, const uint32 newBlobVersion
, const AccessCredentials 
*cred
); 
 260     // Attempt to rename this keychain, if someone hasn't beaten us to it 
 261     void attemptKeychainRename(const string oldPath
, const string newPath
, uint32 blobVersion
); 
 263     // Remember if we've attempted to upgrade this keychain's database 
 264     bool mAttemptedUpgrade
; 
 266         void removeItem(const PrimaryKey 
&primaryKey
, ItemImpl 
*inItemImpl
); 
 268     // Use this when you want to be extra sure this item is removed from the 
 269     // cache. Iterates over the whole cache to find all instances. This function 
 270     // will take both cache map mutexes, so you must not hold only the 
 271     // mDbDeletedItemMapMutex when you call this function. 
 272     void forceRemoveFromCache(ItemImpl
* inItemImpl
); 
 274     // Looks up an item in the item cache. 
 276     // To use this in a thread-safe manner, you must hold this keychain's mutex 
 277     // from before you begin this operation until you have safely completed a 
 278     // CFRetain on the resulting ItemImpl. 
 279         ItemImpl 
*_lookupItem(const PrimaryKey 
&primaryKey
); 
 281     // Looks up a deleted item in the deleted item map. Does not check the normal map. 
 283     // To use this in a thread-safe manner, you must hold this keychain's mutex 
 284     // from before you begin this operation until you have safely completed a 
 285     // CFRetain on the resulting ItemImpl. 
 286     ItemImpl 
*_lookupDeletedItemOnly(const PrimaryKey 
&primaryKey
); 
 288         const AccessCredentials 
*makeCredentials(); 
 290     typedef map
<PrimaryKey
, ItemImpl 
*> DbItemMap
; 
 291         // Reference map of all items we know about that have a primaryKey 
 292     DbItemMap mDbItemMap
; 
 293     Mutex mDbItemMapMutex
; 
 295     // Reference map of all items we know about that have been deleted 
 296     // but we haven't yet received a deleted notification about. 
 297     // We need this for when we delete an item (and so don't want it anymore) 
 298     // but stil need the item around to pass along to the client process with the 
 299     // deletion notification (if they've registered for such things). 
 300     DbItemMap mDbDeletedItemMap
; 
 301     Mutex mDbDeletedItemMapMutex
; 
 303     // Note on ItemMapMutexes: STL maps are not thread-safe, so you must hold the 
 304     // mutex for the entire duration of your access/modification to the map. 
 305     // Otherwise, other processes might interrupt your iterator by adding/removing 
 306     // items. If you must hold both mutexes, you must take mDbItemMapMutex before 
 307     // mDbDeletedItemMapMutex. 
 309         // True iff we are in the cache of keychains in StorageManager 
 314         KeychainSchema mKeychainSchema
; 
 316         // Data for auto-unlock credentials 
 317         DefaultCredentials mCustomUnlockCreds
; 
 319         EventBuffer 
*mEventBuffer
; 
 320     mutable Mutex mMutex
; 
 322     // Now that we sometimes change the database object, Db object 
 323     // creation/returning needs a mutex. You should only hold this if you're 
 324     // copying or changing the mDb object. 
 327     // Used to protect mDb across calls. 
 328     // Grab a read lock if you expect to read from this keychain in the future. 
 329     // The write lock is taken if we're replacing the database wholesale with something new. 
 330     ReadWriteLock mRWLock
; 
 334 CFIndex 
GetKeychainRetainCount(Keychain
& kc
); 
 336 class Keychain 
: public SecPointer
<KeychainImpl
> 
 340     Keychain(KeychainImpl 
*impl
) : SecPointer
<KeychainImpl
>(impl
) {} 
 343         static Keychain 
optional(SecKeychainRef handle
);  
 346         friend class StorageManager
; 
 347     friend class KeychainImpl
; 
 348     friend class TrustKeychains
; 
 349     Keychain(const CssmClient::Db 
&db
) 
 350         : SecPointer
<KeychainImpl
>(new KeychainImpl(db
)) {} 
 352         typedef KeychainImpl Impl
; 
 356 } // end namespace KeychainCore 
 358 } // end namespace Security 
 360 #endif // !_SECURITY_KEYCHAINS_H_