#ifndef _SECURITY_KEYCHAINS_H_
#define _SECURITY_KEYCHAINS_H_
#include <security_cdsa_client/cspclient.h>
#include <security_cdsa_client/dlclient.h>
#include <security_utilities/refcount.h>
#include <security_utilities/seccfobject.h>
#include <Security/SecKeychain.h>
#include <Security/SecKeychainItem.h>
#include <memory>
#include "SecCFTypes.h"
#include "defaultcreds.h"
class EventBuffer;
namespace Security
{
namespace KeychainCore
{
class KCCursor;
class Item;
class PrimaryKey;
class StorageManager;
class KeychainSchemaImpl : public RefCount
{
NOCOPY(KeychainSchemaImpl)
public:
friend class KeychainSchema;
protected:
KeychainSchemaImpl(const CssmClient::Db &db);
public:
virtual ~KeychainSchemaImpl();
CSSM_DB_ATTRIBUTE_FORMAT attributeFormatFor(CSSM_DB_RECORDTYPE recordType, uint32 attributeId) const;
const CssmAutoDbRecordAttributeInfo &primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType) const;
bool operator <(const KeychainSchemaImpl &other) const;
bool operator ==(const KeychainSchemaImpl &other) const;
void getAttributeInfoForRecordType(CSSM_DB_RECORDTYPE recordType, SecKeychainAttributeInfo **Info) const;
CssmDbAttributeInfo attributeInfoFor(CSSM_DB_RECORDTYPE recordType, uint32 attributeId) const;
bool hasAttribute(CSSM_DB_RECORDTYPE recordType, uint32 attributeId) const;
bool hasRecordType(CSSM_DB_RECORDTYPE recordType) const;
void didCreateRelation(CSSM_DB_RECORDTYPE inRelationID,
const char *inRelationName,
uint32 inNumberOfAttributes,
const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *pAttributeInfo,
uint32 inNumberOfIndexes,
const CSSM_DB_SCHEMA_INDEX_INFO *pIndexInfo);
private:
typedef map<CSSM_DB_RECORDTYPE, CssmAutoDbRecordAttributeInfo *> PrimaryKeyInfoMap;
PrimaryKeyInfoMap mPrimaryKeyInfoMap;
typedef map<uint32, CSSM_DB_ATTRIBUTE_FORMAT> RelationInfoMap;
typedef map<CSSM_DB_RECORDTYPE, RelationInfoMap> DatabaseInfoMap;
DatabaseInfoMap mDatabaseInfoMap;
Mutex mMutex;
private:
const RelationInfoMap &relationInfoMapFor(CSSM_DB_RECORDTYPE recordType) const;
};
class KeychainSchema : public RefPointer<KeychainSchemaImpl>
{
public:
KeychainSchema() {}
KeychainSchema(KeychainSchemaImpl *impl) : RefPointer<KeychainSchemaImpl>(impl) {}
KeychainSchema(const CssmClient::Db &db) : RefPointer<KeychainSchemaImpl>(new KeychainSchemaImpl(db)) {}
~KeychainSchema();
bool operator <(const KeychainSchema &other) const
{ return ptr && other.ptr ? *ptr < *other.ptr : ptr < other.ptr; }
bool operator ==(const KeychainSchema &other) const
{ return ptr && other.ptr ? *ptr == *other.ptr : ptr == other.ptr; }
private:
typedef KeychainSchemaImpl Impl;
};
class ItemImpl;
class KeychainImpl : public SecCFObject, private CssmClient::Db::DefaultCredentialsMaker
{
NOCOPY(KeychainImpl)
public:
SECCFFUNCTIONS(KeychainImpl, SecKeychainRef, errSecInvalidKeychain, gTypes().KeychainImpl)
friend class Keychain;
friend class ItemImpl;
friend class KeyItem;
friend class KCCursorImpl;
friend class StorageManager;
protected:
KeychainImpl(const CssmClient::Db &db);
protected:
void didUpdate(const Item &inItem, PrimaryKey &oldPK,
PrimaryKey &newPK);
void completeAdd(Item &item, PrimaryKey &key);
public:
virtual ~KeychainImpl();
Mutex* getKeychainMutex();
Mutex* getMutexForObject() const;
ReadWriteLock* getKeychainReadWriteLock();
void aboutToDestruct();
bool operator ==(const KeychainImpl &) const;
void add(Item &item);
void addCopy(Item &item);
void deleteItem(Item &item);
void create(UInt32 passwordLength, const void *inPassword);
void createWithBlob(CssmData &blob);
void create(ConstStringPtr inPassword);
void create();
void create(const ResourceControlContext *rcc);
void open();
void lock();
void unlock();
void unlock(const CssmData &password);
void unlock(ConstStringPtr password); void stash();
void stashCheck();
void getSettings(uint32 &outIdleTimeOut, bool &outLockOnSleep);
void setSettings(uint32 inIdleTimeOut, bool inLockOnSleep);
void changePassphrase(UInt32 oldPasswordLength, const void *oldPassword,
UInt32 newPasswordLength, const void *newPassword);
void changePassphrase(ConstStringPtr oldPassword, ConstStringPtr newPassword);
void authenticate(const CSSM_ACCESS_CREDENTIALS *cred);
const char *name() const { return mDb->name(); }
UInt32 status() const;
bool exists();
bool isActive() const;
KCCursor createCursor(const SecKeychainAttributeList *attrList);
KCCursor createCursor(SecItemClass itemClass, const SecKeychainAttributeList *attrList);
CssmClient::Db database() { StLock<Mutex>_(mDbMutex); return mDb; }
void changeDatabase(CssmClient::Db db);
DLDbIdentifier dlDbIdentifier() const { return mDb->dlDbIdentifier(); }
CssmClient::CSP csp();
PrimaryKey makePrimaryKey(CSSM_DB_RECORDTYPE recordType, CssmClient::DbUniqueRecord &uniqueId);
PrimaryKey makePrimaryKey(CSSM_DB_RECORDTYPE recordType, CssmClient::DbAttributes *currentAttributes);
void gatherPrimaryKeyAttributes(CssmClient::DbAttributes& primaryKeyAttrs);
const CssmAutoDbRecordAttributeInfo &primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType);
Item item(const PrimaryKey& primaryKey);
Item item(CSSM_DB_RECORDTYPE recordType, CssmClient::DbUniqueRecord &uniqueId);
Item itemdeleted(const PrimaryKey& primaryKey);
CssmDbAttributeInfo attributeInfoFor(CSSM_DB_RECORDTYPE recordType, UInt32 tag);
void getAttributeInfoForItemID(CSSM_DB_RECORDTYPE itemID, SecKeychainAttributeInfo **Info);
static void freeAttributeInfo(SecKeychainAttributeInfo *Info);
KeychainSchema keychainSchema();
void resetSchema();
void didDeleteItem(ItemImpl *inItemImpl);
void recode(const CssmData &data, const CssmData &extraData);
void copyBlob(CssmData &dbBlob);
void setBatchMode(Boolean mode, Boolean rollBack);
const AccessCredentials *defaultCredentials();
bool inCache() const throw() { return mInCache; }
void inCache(bool inCache) throw() { mInCache = inCache; }
void postEvent(SecKeychainEvent kcEvent, ItemImpl* item);
void postEvent(SecKeychainEvent kcEvent, ItemImpl* item, PrimaryKey pk);
void addItem(const PrimaryKey &primaryKey, ItemImpl *dbItemImpl);
bool mayDelete();
bool hasIntegrityProtection();
private:
bool performKeychainUpgradeIfNeeded();
void tickle();
dispatch_source_t mCacheTimer;
bool mSuppressTickle;
public:
bool keychainMigration(const string oldPath, const uint32 dbBlobVersion, const string newPath, const uint32 newBlobVersion, const AccessCredentials *cred = NULL);
private:
uint32 attemptKeychainMigration(const string oldPath, const uint32 oldBlobVersion, const string newPath, const uint32 newBlobVersion, const AccessCredentials *cred);
void attemptKeychainRename(const string oldPath, const string newPath, uint32 blobVersion);
bool mAttemptedUpgrade;
void removeItem(const PrimaryKey &primaryKey, ItemImpl *inItemImpl);
void forceRemoveFromCache(ItemImpl* inItemImpl);
ItemImpl *_lookupItem(const PrimaryKey &primaryKey);
ItemImpl *_lookupDeletedItemOnly(const PrimaryKey &primaryKey);
const AccessCredentials *makeCredentials();
typedef map<PrimaryKey, ItemImpl *> DbItemMap;
DbItemMap mDbItemMap;
Mutex mDbItemMapMutex;
DbItemMap mDbDeletedItemMap;
Mutex mDbDeletedItemMapMutex;
bool mInCache;
CssmClient::Db mDb;
KeychainSchema mKeychainSchema;
DefaultCredentials mCustomUnlockCreds;
bool mIsInBatchMode;
EventBuffer *mEventBuffer;
Mutex mMutex;
Mutex mDbMutex;
ReadWriteLock mRWLock;
};
CFIndex GetKeychainRetainCount(Keychain& kc);
class Keychain : public SecPointer<KeychainImpl>
{
public:
Keychain();
Keychain(KeychainImpl *impl) : SecPointer<KeychainImpl>(impl) {}
~Keychain();
static Keychain optional(SecKeychainRef handle);
private:
friend class StorageManager;
friend class KeychainImpl;
friend class TrustKeychains;
Keychain(const CssmClient::Db &db)
: SecPointer<KeychainImpl>(new KeychainImpl(db)) {}
typedef KeychainImpl Impl;
};
}
}
#endif // !_SECURITY_KEYCHAINS_H_