1/*
2 * Copyright (c) 2000-2004,2011-2014 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//
25// Keychains.h - The Keychain class
26//
27#ifndef _SECURITY_KEYCHAINS_H_
28#define _SECURITY_KEYCHAINS_H_
29
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>
36#include <memory>
37#include "SecCFTypes.h"
38#include "defaultcreds.h"
39
40class EventBuffer;
41
42namespace Security
43{
44
45namespace KeychainCore
46{
47
48class KCCursor;
49class Item;
50class PrimaryKey;
51class StorageManager;
52
53class KeychainSchemaImpl : public RefCount
54{
55	NOCOPY(KeychainSchemaImpl)
56public:
57	friend class KeychainSchema;
58protected:
59    KeychainSchemaImpl(const CssmClient::Db &db);
60public:
61    virtual ~KeychainSchemaImpl();
62
63	CSSM_DB_ATTRIBUTE_FORMAT attributeFormatFor(CSSM_DB_RECORDTYPE recordType, uint32 attributeId) const;
64	const CssmAutoDbRecordAttributeInfo &primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType) const;
65
66	bool operator <(const KeychainSchemaImpl &other) const;
67	bool operator ==(const KeychainSchemaImpl &other) const;
68
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;
73
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);
80
81private:
82	typedef map<CSSM_DB_RECORDTYPE, CssmAutoDbRecordAttributeInfo *> PrimaryKeyInfoMap;
83	PrimaryKeyInfoMap mPrimaryKeyInfoMap;
84
85	typedef map<uint32, CSSM_DB_ATTRIBUTE_FORMAT> RelationInfoMap;
86	typedef map<CSSM_DB_RECORDTYPE, RelationInfoMap> DatabaseInfoMap;
87	DatabaseInfoMap mDatabaseInfoMap;
88	Mutex mMutex;
89
90private:
91	const RelationInfoMap &relationInfoMapFor(CSSM_DB_RECORDTYPE recordType) const;
92};
93
94
95class KeychainSchema : public RefPointer<KeychainSchemaImpl>
96{
97public:
98    KeychainSchema() {}
99    KeychainSchema(KeychainSchemaImpl *impl) : RefPointer<KeychainSchemaImpl>(impl) {}
100    KeychainSchema(const CssmClient::Db &db) : RefPointer<KeychainSchemaImpl>(new KeychainSchemaImpl(db)) {}
101    ~KeychainSchema();
102
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; }
107
108private:
109	typedef KeychainSchemaImpl Impl;
110};
111
112
113class ItemImpl;
114
115class KeychainImpl : public SecCFObject, private CssmClient::Db::DefaultCredentialsMaker
116{
117    NOCOPY(KeychainImpl)
118public:
119	SECCFFUNCTIONS(KeychainImpl, SecKeychainRef, errSecInvalidKeychain, gTypes().KeychainImpl)
120
121	friend class Keychain;
122	friend class ItemImpl;
123protected:
124    KeychainImpl(const CssmClient::Db &db);
125
126protected:
127	// Methods called by ItemImpl;
128	void didUpdate(const Item &inItem, PrimaryKey &oldPK,
129		PrimaryKey &newPK);
130	void completeAdd(Item &item, PrimaryKey &key);
131
132public:
133    virtual ~KeychainImpl();
134
135	Mutex* getKeychainMutex();
136	Mutex* getMutexForObject();
137	void aboutToDestruct();
138
139	bool operator ==(const KeychainImpl &) const;
140
141    // Item calls
142	void add(Item &item);
143	void addCopy(Item &item);
144    void deleteItem(Item &item); // item must be persistant.
145
146    // Keychain calls
147	void create(UInt32 passwordLength, const void *inPassword);
148	void createWithBlob(CssmData &blob);
149    void create(ConstStringPtr inPassword);
150    void create();
151    void create(const ResourceControlContext *rcc);
152    void open();
153
154	// Locking and unlocking a keychain.
155    void lock();
156    void unlock();
157	void unlock(const CssmData &password);
158    void unlock(ConstStringPtr password); // @@@ This has a length limit, we should remove it.
159    void stash();
160    void stashCheck();
161
162	void getSettings(uint32 &outIdleTimeOut, bool &outLockOnSleep);
163	void setSettings(uint32 inIdleTimeOut, bool inLockOnSleep);
164
165	// Passing in NULL for either oldPassword or newPassword will cause them to be prompted for.
166	// To specify a zero length password in either case the oldPasswordLength or newPasswordLength
167	// value must be 0 and the oldPassword or newPassword must not be NULL.
168	void changePassphrase(UInt32 oldPasswordLength, const void *oldPassword,
169		UInt32 newPasswordLength, const void *newPassword);
170	void changePassphrase(ConstStringPtr oldPassword, ConstStringPtr newPassword);
171
172    void authenticate(const CSSM_ACCESS_CREDENTIALS *cred);     // Does not do an unlock.
173
174	const char *name() const { return mDb->name(); }
175	UInt32 status() const;
176	bool exists();
177	bool isActive() const;
178
179	KCCursor createCursor(const SecKeychainAttributeList *attrList);
180	KCCursor createCursor(SecItemClass itemClass, const SecKeychainAttributeList *attrList);
181	CssmClient::Db database() { return mDb; }
182	DLDbIdentifier dlDbIdentifier() const { return mDb->dlDbIdentifier(); }
183
184	CssmClient::CSP csp();
185
186	PrimaryKey makePrimaryKey(CSSM_DB_RECORDTYPE recordType, CssmClient::DbUniqueRecord &uniqueId);
187	void gatherPrimaryKeyAttributes(CssmClient::DbAttributes& primaryKeyAttrs);
188
189	const CssmAutoDbRecordAttributeInfo &primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType);
190
191    Item item(const PrimaryKey& primaryKey);
192    Item item(CSSM_DB_RECORDTYPE recordType, CssmClient::DbUniqueRecord &uniqueId);
193
194	CssmDbAttributeInfo attributeInfoFor(CSSM_DB_RECORDTYPE recordType, UInt32 tag);
195	void getAttributeInfoForItemID(CSSM_DB_RECORDTYPE itemID, SecKeychainAttributeInfo **Info);
196	static void freeAttributeInfo(SecKeychainAttributeInfo *Info);
197	KeychainSchema keychainSchema();
198	void resetSchema();
199	void didDeleteItem(ItemImpl *inItemImpl);
200
201	void recode(const CssmData &data, const CssmData &extraData);
202	void copyBlob(CssmData &dbBlob);
203
204	void setBatchMode(Boolean mode, Boolean rollBack);
205
206	// yield default open() credentials for this keychain (as of now)
207	const AccessCredentials *defaultCredentials();
208
209	// Only call these functions while holding globals().apiLock.
210	bool inCache() const throw() { return mInCache; }
211	void inCache(bool inCache) throw() { mInCache = inCache; }
212
213	void postEvent(SecKeychainEvent kcEvent, ItemImpl* item);
214
215	void addItem(const PrimaryKey &primaryKey, ItemImpl *dbItemImpl);
216
217    bool mayDelete();
218
219private:
220	void removeItem(const PrimaryKey &primaryKey, ItemImpl *inItemImpl);
221	ItemImpl *_lookupItem(const PrimaryKey &primaryKey);
222
223	const AccessCredentials *makeCredentials();
224
225    typedef map<PrimaryKey, __weak ItemImpl *> DbItemMap;
226	// Weak reference map of all items we know about that have a primaryKey
227    DbItemMap mDbItemMap;
228	// True iff we are in the cache of keychains in StorageManager
229	bool mInCache;
230
231    CssmClient::Db mDb;
232
233	KeychainSchema mKeychainSchema;
234
235	// Data for auto-unlock credentials
236	DefaultCredentials mCustomUnlockCreds;
237	bool mIsInBatchMode;
238	EventBuffer *mEventBuffer;
239	Mutex mMutex;
240};
241
242
243CFIndex GetKeychainRetainCount(Keychain& kc);
244
245class Keychain : public SecPointer<KeychainImpl>
246{
247public:
248    Keychain();
249    Keychain(KeychainImpl *impl) : SecPointer<KeychainImpl>(impl) {}
250    ~Keychain();
251
252	static Keychain optional(SecKeychainRef handle);
253
254private:
255	friend class StorageManager;
256    Keychain(const CssmClient::Db &db)
257	: SecPointer<KeychainImpl>(new KeychainImpl(db)) {}
258
259	typedef KeychainImpl Impl;
260};
261
262
263} // end namespace KeychainCore
264
265} // end namespace Security
266
267#endif // !_SECURITY_KEYCHAINS_H_
268