]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
1 | /* |
2 | * Copyright (c) 2000-2004 Apple Computer, 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 | // | |
26 | // KCCursor.cpp | |
27 | // | |
28 | ||
29 | #include "KCCursor.h" | |
30 | ||
31 | #include "Item.h" | |
32 | #include <security_cdsa_utilities/Schema.h> | |
33 | #include <security_cdsa_utilities/KeySchema.h> | |
34 | #include "cssmdatetime.h" | |
35 | #include "Globals.h" | |
36 | #include "StorageManager.h" | |
b1ab9ed8 | 37 | #include <Security/SecKeychainItemPriv.h> |
427c49bc | 38 | #include <SecBase.h> |
b1ab9ed8 A |
39 | |
40 | using namespace KeychainCore; | |
41 | using namespace CssmClient; | |
42 | using namespace CSSMDateTimeUtils; | |
43 | ||
44 | using namespace KeySchema; | |
45 | ||
46 | // define a table of our attributes for easy lookup | |
47 | static const CSSM_DB_ATTRIBUTE_INFO* gKeyAttributeLookupTable[] = | |
48 | { | |
49 | &KeyClass, &PrintName, &Alias, &Permanent, &Private, &Modifiable, &Label, &ApplicationTag, &KeyCreator, | |
50 | &KeyType, &KeySizeInBits, &EffectiveKeySize, &StartDate, &EndDate, &Sensitive, &AlwaysSensitive, &Extractable, | |
51 | &NeverExtractable, &Encrypt, &Decrypt, &Derive, &Sign, &Verify, &SignRecover, &VerifyRecover, &Wrap, &Unwrap | |
52 | }; | |
53 | ||
54 | // | |
55 | // KCCursorImpl | |
56 | // | |
57 | KCCursorImpl::KCCursorImpl(const StorageManager::KeychainList &searchList, SecItemClass itemClass, const SecKeychainAttributeList *attrList, CSSM_DB_CONJUNCTIVE dbConjunctive, CSSM_DB_OPERATOR dbOperator) : | |
58 | mSearchList(searchList), | |
59 | mCurrent(mSearchList.begin()), | |
60 | mAllFailed(true), | |
61 | mMutex(Mutex::recursive) | |
62 | { | |
63 | recordType(Schema::recordTypeFor(itemClass)); | |
64 | ||
65 | if (!attrList) // No additional selectionPredicates: we are done | |
66 | return; | |
67 | ||
68 | conjunctive(dbConjunctive); | |
69 | const SecKeychainAttribute *end=&attrList->attr[attrList->count]; | |
70 | // Add all the attrs in attrs list to the cursor. | |
71 | for (const SecKeychainAttribute *attr=attrList->attr; attr != end; ++attr) | |
72 | { | |
73 | const CSSM_DB_ATTRIBUTE_INFO *temp; | |
74 | ||
75 | if (attr->tag <' ') // ok, is this a key schema? Handle differently, just because we can... | |
76 | { | |
77 | temp = gKeyAttributeLookupTable[attr->tag]; | |
78 | } | |
79 | else | |
80 | { | |
81 | temp = &Schema::attributeInfo(attr->tag); | |
82 | } | |
83 | const CssmDbAttributeInfo &info = *temp; | |
84 | void *buf = attr->data; | |
85 | UInt32 length = attr->length; | |
86 | uint8 timeString[16]; | |
87 | ||
88 | // XXX This code is duplicated in NewItemImpl::setAttribute() | |
89 | // Convert a 4 or 8 byte TIME_DATE to a CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE | |
90 | // style attribute value. | |
91 | if (info.format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE) | |
92 | { | |
93 | if (length == sizeof(UInt32)) | |
94 | { | |
95 | MacSecondsToTimeString(*reinterpret_cast<const UInt32 *>(buf), | |
96 | 16, &timeString); | |
97 | buf = &timeString; | |
98 | length = 16; | |
99 | } | |
100 | else if (length == sizeof(SInt64)) | |
101 | { | |
102 | MacLongDateTimeToTimeString(*reinterpret_cast<const SInt64 *>(buf), | |
103 | 16, &timeString); | |
104 | buf = &timeString; | |
105 | length = 16; | |
106 | } | |
107 | } | |
108 | add(dbOperator ,info, CssmData(buf,length)); | |
109 | } | |
110 | } | |
111 | ||
112 | KCCursorImpl::KCCursorImpl(const StorageManager::KeychainList &searchList, const SecKeychainAttributeList *attrList) : | |
113 | mSearchList(searchList), | |
114 | mCurrent(mSearchList.begin()), | |
115 | mAllFailed(true), | |
116 | mMutex(Mutex::recursive) | |
117 | { | |
118 | if (!attrList) // No additional selectionPredicates: we are done | |
119 | return; | |
120 | ||
121 | conjunctive(CSSM_DB_AND); | |
122 | bool foundClassAttribute=false; | |
123 | const SecKeychainAttribute *end=&attrList->attr[attrList->count]; | |
124 | // Add all the attrs in attrs list to the cursor. | |
125 | for (const SecKeychainAttribute *attr=attrList->attr; attr != end; ++attr) | |
126 | { | |
127 | if (attr->tag!=kSecClassItemAttr) // a regular attribute | |
128 | { | |
129 | const CssmDbAttributeInfo &info = Schema::attributeInfo(attr->tag); | |
130 | void *buf = attr->data; | |
131 | UInt32 length = attr->length; | |
132 | uint8 timeString[16]; | |
133 | ||
134 | // XXX This code is duplicated in NewItemImpl::setAttribute() | |
135 | // Convert a 4 or 8 byte TIME_DATE to a CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE | |
136 | // style attribute value. | |
137 | if (info.format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE) | |
138 | { | |
139 | if (length == sizeof(UInt32)) | |
140 | { | |
141 | MacSecondsToTimeString(*reinterpret_cast<const UInt32 *>(buf), | |
142 | 16, &timeString); | |
143 | buf = &timeString; | |
144 | length = 16; | |
145 | } | |
146 | else if (length == sizeof(SInt64)) | |
147 | { | |
148 | MacLongDateTimeToTimeString(*reinterpret_cast<const SInt64 *>(buf), | |
149 | 16, &timeString); | |
150 | buf = &timeString; | |
151 | length = 16; | |
152 | } | |
153 | } | |
154 | add(CSSM_DB_EQUAL,info, CssmData(buf,length)); | |
155 | ||
156 | continue; | |
157 | } | |
158 | ||
159 | // the class attribute | |
160 | if (foundClassAttribute || attr->length != sizeof(SecItemClass)) | |
427c49bc | 161 | MacOSError::throwMe(errSecParam); // We have 2 different 'clas' attributes |
b1ab9ed8 A |
162 | |
163 | recordType(Schema::recordTypeFor(*reinterpret_cast<SecItemClass *>(attr->data))); | |
164 | foundClassAttribute=true; | |
165 | } | |
166 | } | |
167 | ||
168 | KCCursorImpl::~KCCursorImpl() throw() | |
169 | { | |
170 | } | |
171 | ||
427c49bc | 172 | //static ModuleNexus<Mutex> gActivationMutex; |
b1ab9ed8 A |
173 | |
174 | bool | |
175 | KCCursorImpl::next(Item &item) | |
176 | { | |
177 | StLock<Mutex>_(mMutex); | |
178 | DbAttributes dbAttributes; | |
179 | DbUniqueRecord uniqueId; | |
180 | OSStatus status = 0; | |
181 | ||
182 | for (;;) | |
183 | { | |
184 | while (!mDbCursor) | |
185 | { | |
186 | if (mCurrent == mSearchList.end()) | |
187 | { | |
188 | // If we got always failed when calling mDbCursor->next return the error from | |
189 | // the last call to mDbCursor->next now | |
190 | if (mAllFailed && status) | |
191 | CssmError::throwMe(status); | |
192 | ||
193 | // No more keychains to search so we are done. | |
194 | return false; | |
195 | } | |
196 | ||
197 | try | |
198 | { | |
427c49bc A |
199 | // StLock<Mutex> _(gActivationMutex()); // force serialization of cursor creation |
200 | Keychain &kc = *mCurrent; | |
201 | Mutex* mutex = kc->getKeychainMutex(); | |
202 | StLock<Mutex> _(*mutex); | |
b1ab9ed8 A |
203 | (*mCurrent)->database()->activate(); |
204 | mDbCursor = DbCursor((*mCurrent)->database(), *this); | |
205 | } | |
206 | catch(const CommonError &err) | |
207 | { | |
208 | ++mCurrent; | |
209 | } | |
210 | } | |
211 | ||
427c49bc A |
212 | Keychain &kc = *mCurrent; |
213 | Mutex* mutex = kc->getKeychainMutex(); | |
214 | StLock<Mutex> _(*mutex); | |
215 | ||
b1ab9ed8 A |
216 | bool gotRecord; |
217 | try | |
218 | { | |
219 | // Clear out existing attributes first! | |
220 | // (the previous iteration may have left attributes from a different schema) | |
221 | dbAttributes.clear(); | |
222 | ||
223 | gotRecord = mDbCursor->next(&dbAttributes, NULL, uniqueId); | |
224 | mAllFailed = false; | |
225 | } | |
226 | catch(const CommonError &err) | |
227 | { | |
228 | // Catch the last error we get and move on to the next keychain | |
229 | // This error will be returned when we reach the end of our keychain list | |
230 | // iff all calls to KCCursorImpl::next failed | |
231 | status = err.osStatus(); | |
232 | gotRecord = false; | |
233 | dbAttributes.invalidate(); | |
234 | } | |
235 | catch(...) | |
236 | { | |
237 | // Catch all other errors | |
238 | status = errSecItemNotFound; | |
239 | gotRecord = false; | |
240 | } | |
241 | ||
242 | // If we did not get a record from the current keychain or the current | |
243 | // keychain did not exist skip to the next keychain in the list. | |
244 | if (!gotRecord) | |
245 | { | |
246 | ++mCurrent; | |
247 | mDbCursor = DbCursor(); | |
248 | continue; | |
249 | } | |
250 | ||
251 | // If doing a search for all records, skip the db blob added by the CSPDL | |
252 | if (dbAttributes.recordType() == CSSM_DL_DB_RECORD_METADATA && | |
253 | mDbCursor->recordType() == CSSM_DL_DB_RECORD_ANY) | |
254 | continue; | |
255 | ||
256 | // Filter out group keys at this layer | |
257 | if (dbAttributes.recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY) | |
258 | { | |
259 | bool groupKey = false; | |
260 | try | |
261 | { | |
262 | // fetch the key label attribute, if it exists | |
263 | dbAttributes.add(KeySchema::Label); | |
264 | Db db((*mCurrent)->database()); | |
265 | CSSM_RETURN getattr_result = CSSM_DL_DataGetFromUniqueRecordId(db->handle(), uniqueId, &dbAttributes, NULL); | |
266 | if (getattr_result == CSSM_OK) | |
267 | { | |
268 | CssmDbAttributeData *label = dbAttributes.find(KeySchema::Label); | |
269 | CssmData attrData; | |
270 | if (label) | |
271 | attrData = *label; | |
272 | if (attrData.length() > 4 && !memcmp(attrData.data(), "ssgp", 4)) | |
273 | groupKey = true; | |
274 | } | |
275 | else | |
276 | { | |
277 | dbAttributes.invalidate(); | |
278 | } | |
279 | } | |
280 | catch (...) {} | |
281 | ||
282 | if (groupKey) | |
283 | continue; | |
284 | } | |
285 | ||
286 | break; | |
287 | } | |
288 | ||
289 | // Go though Keychain since item might already exist. | |
427c49bc A |
290 | Keychain &kc = *mCurrent; |
291 | StLock<Mutex> _mutexLocker(*kc->getKeychainMutex()); | |
b1ab9ed8 A |
292 | item = (*mCurrent)->item(dbAttributes.recordType(), uniqueId); |
293 | return true; | |
294 | } | |
427c49bc A |
295 | |
296 | ||
297 | ||
298 | bool KCCursorImpl::mayDelete() | |
299 | { | |
300 | if (mDbCursor.get() != NULL) | |
301 | { | |
302 | return mDbCursor->isIdle(); | |
303 | } | |
304 | else | |
305 | { | |
306 | return true; | |
307 | } | |
308 | } |