]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2000-2004,2011-2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
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 | ||
40 | class EventBuffer; | |
41 | ||
42 | namespace Security | |
43 | { | |
44 | ||
45 | namespace KeychainCore | |
46 | { | |
47 | ||
48 | class KCCursor; | |
49 | class Item; | |
50 | class PrimaryKey; | |
51 | class StorageManager; | |
52 | ||
53 | class KeychainSchemaImpl : public RefCount | |
54 | { | |
55 | NOCOPY(KeychainSchemaImpl) | |
56 | public: | |
57 | friend class KeychainSchema; | |
58 | protected: | |
59 | KeychainSchemaImpl(const CssmClient::Db &db); | |
60 | public: | |
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 | ||
81 | private: | |
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 | ||
90 | private: | |
91 | const RelationInfoMap &relationInfoMapFor(CSSM_DB_RECORDTYPE recordType) const; | |
92 | }; | |
93 | ||
94 | ||
95 | class KeychainSchema : public RefPointer<KeychainSchemaImpl> | |
96 | { | |
97 | public: | |
98 | KeychainSchema() {} | |
99 | KeychainSchema(KeychainSchemaImpl *impl) : RefPointer<KeychainSchemaImpl>(impl) {} | |
100 | KeychainSchema(const CssmClient::Db &db) : RefPointer<KeychainSchemaImpl>(new KeychainSchemaImpl(db)) {} | |
427c49bc A |
101 | ~KeychainSchema(); |
102 | ||
b1ab9ed8 A |
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 | ||
108 | private: | |
109 | typedef KeychainSchemaImpl Impl; | |
110 | }; | |
111 | ||
112 | ||
113 | class ItemImpl; | |
114 | ||
115 | class KeychainImpl : public SecCFObject, private CssmClient::Db::DefaultCredentialsMaker | |
116 | { | |
117 | NOCOPY(KeychainImpl) | |
118 | public: | |
119 | SECCFFUNCTIONS(KeychainImpl, SecKeychainRef, errSecInvalidKeychain, gTypes().KeychainImpl) | |
120 | ||
121 | friend class Keychain; | |
122 | friend class ItemImpl; | |
e3d460c9 A |
123 | friend class KeyItem; |
124 | friend class KCCursorImpl; | |
125 | friend class StorageManager; | |
b1ab9ed8 A |
126 | protected: |
127 | KeychainImpl(const CssmClient::Db &db); | |
128 | ||
129 | protected: | |
130 | // Methods called by ItemImpl; | |
131 | void didUpdate(const Item &inItem, PrimaryKey &oldPK, | |
132 | PrimaryKey &newPK); | |
133 | void completeAdd(Item &item, PrimaryKey &key); | |
b1ab9ed8 A |
134 | |
135 | public: | |
136 | virtual ~KeychainImpl(); | |
137 | ||
138 | Mutex* getKeychainMutex(); | |
fa7225c8 | 139 | Mutex* getMutexForObject() const; |
e3d460c9 | 140 | |
b1ab9ed8 A |
141 | void aboutToDestruct(); |
142 | ||
143 | bool operator ==(const KeychainImpl &) const; | |
144 | ||
145 | // Item calls | |
146 | void add(Item &item); | |
147 | void addCopy(Item &item); | |
5c19dc3a | 148 | void deleteItem(Item &item); // item must be persistent. |
b1ab9ed8 A |
149 | |
150 | // Keychain calls | |
151 | void create(UInt32 passwordLength, const void *inPassword); | |
152 | void createWithBlob(CssmData &blob); | |
153 | void create(ConstStringPtr inPassword); | |
154 | void create(); | |
155 | void create(const ResourceControlContext *rcc); | |
156 | void open(); | |
157 | ||
158 | // Locking and unlocking a keychain. | |
159 | void lock(); | |
160 | void unlock(); | |
161 | void unlock(const CssmData &password); | |
162 | void unlock(ConstStringPtr password); // @@@ This has a length limit, we should remove it. | |
427c49bc A |
163 | void stash(); |
164 | void stashCheck(); | |
b1ab9ed8 A |
165 | |
166 | void getSettings(uint32 &outIdleTimeOut, bool &outLockOnSleep); | |
167 | void setSettings(uint32 inIdleTimeOut, bool inLockOnSleep); | |
168 | ||
169 | // Passing in NULL for either oldPassword or newPassword will cause them to be prompted for. | |
170 | // To specify a zero length password in either case the oldPasswordLength or newPasswordLength | |
171 | // value must be 0 and the oldPassword or newPassword must not be NULL. | |
172 | void changePassphrase(UInt32 oldPasswordLength, const void *oldPassword, | |
173 | UInt32 newPasswordLength, const void *newPassword); | |
174 | void changePassphrase(ConstStringPtr oldPassword, ConstStringPtr newPassword); | |
175 | ||
176 | void authenticate(const CSSM_ACCESS_CREDENTIALS *cred); // Does not do an unlock. | |
177 | ||
178 | const char *name() const { return mDb->name(); } | |
179 | UInt32 status() const; | |
180 | bool exists(); | |
181 | bool isActive() const; | |
182 | ||
183 | KCCursor createCursor(const SecKeychainAttributeList *attrList); | |
184 | KCCursor createCursor(SecItemClass itemClass, const SecKeychainAttributeList *attrList); | |
e3d460c9 | 185 | CssmClient::Db database() { StLock<Mutex>_(mDbMutex); return mDb; } |
fa7225c8 | 186 | void changeDatabase(CssmClient::Db db); |
b1ab9ed8 A |
187 | DLDbIdentifier dlDbIdentifier() const { return mDb->dlDbIdentifier(); } |
188 | ||
189 | CssmClient::CSP csp(); | |
190 | ||
191 | PrimaryKey makePrimaryKey(CSSM_DB_RECORDTYPE recordType, CssmClient::DbUniqueRecord &uniqueId); | |
e3d460c9 A |
192 | |
193 | // This will make a primary key for this record type, and populate it completely from the given attributes | |
194 | PrimaryKey makePrimaryKey(CSSM_DB_RECORDTYPE recordType, CssmClient::DbAttributes *currentAttributes); | |
b1ab9ed8 A |
195 | void gatherPrimaryKeyAttributes(CssmClient::DbAttributes& primaryKeyAttrs); |
196 | ||
197 | const CssmAutoDbRecordAttributeInfo &primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType); | |
198 | ||
199 | Item item(const PrimaryKey& primaryKey); | |
200 | Item item(CSSM_DB_RECORDTYPE recordType, CssmClient::DbUniqueRecord &uniqueId); | |
201 | ||
e3d460c9 A |
202 | // Check for an item that may have been deleted. |
203 | Item itemdeleted(const PrimaryKey& primaryKey); | |
204 | ||
b1ab9ed8 A |
205 | CssmDbAttributeInfo attributeInfoFor(CSSM_DB_RECORDTYPE recordType, UInt32 tag); |
206 | void getAttributeInfoForItemID(CSSM_DB_RECORDTYPE itemID, SecKeychainAttributeInfo **Info); | |
207 | static void freeAttributeInfo(SecKeychainAttributeInfo *Info); | |
208 | KeychainSchema keychainSchema(); | |
209 | void resetSchema(); | |
210 | void didDeleteItem(ItemImpl *inItemImpl); | |
211 | ||
212 | void recode(const CssmData &data, const CssmData &extraData); | |
213 | void copyBlob(CssmData &dbBlob); | |
214 | ||
215 | void setBatchMode(Boolean mode, Boolean rollBack); | |
216 | ||
217 | // yield default open() credentials for this keychain (as of now) | |
218 | const AccessCredentials *defaultCredentials(); | |
219 | ||
220 | // Only call these functions while holding globals().apiLock. | |
221 | bool inCache() const throw() { return mInCache; } | |
222 | void inCache(bool inCache) throw() { mInCache = inCache; } | |
223 | ||
224 | void postEvent(SecKeychainEvent kcEvent, ItemImpl* item); | |
fa7225c8 | 225 | void postEvent(SecKeychainEvent kcEvent, ItemImpl* item, PrimaryKey pk); |
b1ab9ed8 A |
226 | |
227 | void addItem(const PrimaryKey &primaryKey, ItemImpl *dbItemImpl); | |
228 | ||
427c49bc A |
229 | bool mayDelete(); |
230 | ||
e3d460c9 A |
231 | // Returns true if this keychain supports the attribute integrity and |
232 | // partition ID protections | |
233 | bool hasIntegrityProtection(); | |
234 | ||
b1ab9ed8 | 235 | private: |
e3d460c9 A |
236 | // Checks for and triggers a keychain database upgrade |
237 | // DO NOT hold any of the keychain locks when you call this | |
238 | bool performKeychainUpgradeIfNeeded(); | |
239 | ||
fa7225c8 A |
240 | // Notify the keychain that you're accessing it. Used in conjunction with |
241 | // the StorageManager for time-based caching. | |
242 | void tickle(); | |
243 | ||
244 | // Used by StorageManager to remember the timer->keychain pairing | |
245 | dispatch_source_t mCacheTimer; | |
246 | ||
247 | // Set this to true to make tickling do nothing. | |
248 | bool mSuppressTickle; | |
249 | ||
250 | public: | |
251 | // Grab the locks and then call attemptKeychainMigration | |
252 | // The access credentials are only used when downgrading version, and will be passed along with ACL edits | |
253 | bool keychainMigration(const string oldPath, const uint32 dbBlobVersion, const string newPath, const uint32 newBlobVersion, const AccessCredentials *cred = NULL); | |
254 | ||
255 | private: | |
e3d460c9 | 256 | // Attempt to upgrade this keychain's database |
fa7225c8 A |
257 | uint32 attemptKeychainMigration(const string oldPath, const uint32 oldBlobVersion, const string newPath, const uint32 newBlobVersion, const AccessCredentials *cred); |
258 | ||
259 | // Attempt to rename this keychain, if someone hasn't beaten us to it | |
260 | void attemptKeychainRename(const string oldPath, const string newPath, uint32 blobVersion); | |
e3d460c9 A |
261 | |
262 | // Remember if we've attempted to upgrade this keychain's database | |
263 | bool mAttemptedUpgrade; | |
264 | ||
b1ab9ed8 | 265 | void removeItem(const PrimaryKey &primaryKey, ItemImpl *inItemImpl); |
e3d460c9 A |
266 | |
267 | // Use this when you want to be extra sure this item is removed from the | |
268 | // cache. Iterates over the whole cache to find all instances. This function | |
269 | // will take both cache map mutexes, so you must not hold only the | |
270 | // mDbDeletedItemMapMutex when you call this function. | |
271 | void forceRemoveFromCache(ItemImpl* inItemImpl); | |
272 | ||
fa7225c8 A |
273 | // Looks up an item in the item cache. |
274 | // | |
275 | // To use this in a thread-safe manner, you must hold this keychain's mutex | |
276 | // from before you begin this operation until you have safely completed a | |
277 | // CFRetain on the resulting ItemImpl. | |
b1ab9ed8 A |
278 | ItemImpl *_lookupItem(const PrimaryKey &primaryKey); |
279 | ||
e3d460c9 | 280 | // Looks up a deleted item in the deleted item map. Does not check the normal map. |
fa7225c8 A |
281 | // |
282 | // To use this in a thread-safe manner, you must hold this keychain's mutex | |
283 | // from before you begin this operation until you have safely completed a | |
284 | // CFRetain on the resulting ItemImpl. | |
e3d460c9 A |
285 | ItemImpl *_lookupDeletedItemOnly(const PrimaryKey &primaryKey); |
286 | ||
b1ab9ed8 A |
287 | const AccessCredentials *makeCredentials(); |
288 | ||
e3d460c9 A |
289 | typedef map<PrimaryKey, ItemImpl *> DbItemMap; |
290 | // Reference map of all items we know about that have a primaryKey | |
b1ab9ed8 | 291 | DbItemMap mDbItemMap; |
e3d460c9 A |
292 | Mutex mDbItemMapMutex; |
293 | ||
294 | // Reference map of all items we know about that have been deleted | |
295 | // but we haven't yet received a deleted notification about. | |
296 | // We need this for when we delete an item (and so don't want it anymore) | |
297 | // but stil need the item around to pass along to the client process with the | |
298 | // deletion notification (if they've registered for such things). | |
299 | DbItemMap mDbDeletedItemMap; | |
300 | Mutex mDbDeletedItemMapMutex; | |
301 | ||
302 | // Note on ItemMapMutexes: STL maps are not thread-safe, so you must hold the | |
303 | // mutex for the entire duration of your access/modification to the map. | |
304 | // Otherwise, other processes might interrupt your iterator by adding/removing | |
305 | // items. If you must hold both mutexes, you must take mDbItemMapMutex before | |
306 | // mDbDeletedItemMapMutex. | |
307 | ||
b1ab9ed8 A |
308 | // True iff we are in the cache of keychains in StorageManager |
309 | bool mInCache; | |
310 | ||
311 | CssmClient::Db mDb; | |
312 | ||
313 | KeychainSchema mKeychainSchema; | |
314 | ||
315 | // Data for auto-unlock credentials | |
316 | DefaultCredentials mCustomUnlockCreds; | |
317 | bool mIsInBatchMode; | |
318 | EventBuffer *mEventBuffer; | |
b04fe171 | 319 | mutable Mutex mMutex; |
e3d460c9 A |
320 | |
321 | // Now that we sometimes change the database object, Db object | |
322 | // creation/returning needs a mutex. You should only hold this if you're | |
323 | // copying or changing the mDb object. | |
324 | Mutex mDbMutex; | |
b1ab9ed8 A |
325 | }; |
326 | ||
327 | ||
328 | CFIndex GetKeychainRetainCount(Keychain& kc); | |
329 | ||
330 | class Keychain : public SecPointer<KeychainImpl> | |
331 | { | |
332 | public: | |
333 | Keychain(); | |
334 | Keychain(KeychainImpl *impl) : SecPointer<KeychainImpl>(impl) {} | |
427c49bc | 335 | ~Keychain(); |
b1ab9ed8 A |
336 | |
337 | static Keychain optional(SecKeychainRef handle); | |
338 | ||
339 | private: | |
340 | friend class StorageManager; | |
e3d460c9 A |
341 | friend class KeychainImpl; |
342 | friend class TrustKeychains; | |
b1ab9ed8 A |
343 | Keychain(const CssmClient::Db &db) |
344 | : SecPointer<KeychainImpl>(new KeychainImpl(db)) {} | |
345 | ||
346 | typedef KeychainImpl Impl; | |
347 | }; | |
348 | ||
349 | ||
350 | } // end namespace KeychainCore | |
351 | ||
352 | } // end namespace Security | |
353 | ||
354 | #endif // !_SECURITY_KEYCHAINS_H_ |