]> git.saurik.com Git - apple/security.git/blob - OSX/include/security_cdsa_utilities/cssmdb.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / include / security_cdsa_utilities / cssmdb.cpp
1 /*
2 * Copyright (c) 2000-2004,2006,2011-2012,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 // cssmdb.cpp
26 //
27 //
28 #include <security_cdsa_utilities/cssmdb.h>
29
30 bool DLDbIdentifier::Impl::operator < (const DLDbIdentifier::Impl &other) const
31 {
32 if (mCssmSubserviceUid < other.mCssmSubserviceUid)
33 return true;
34 if (mCssmSubserviceUid != other.mCssmSubserviceUid) // i.e. greater than
35 return false;
36
37 // This test will produce unreproducible results,
38 // depending on what items are being compared. To do this properly, we need to
39 // assign a lexical value to NULL.
40 //
41 // if (mDbName.canonicalName() == NULL || other.mDbName.canonicalName() == NULL)
42 // {
43 // return false;
44 // }
45
46 // this is the correct way
47 const char* a = mDbName.canonicalName();
48 const char* b = other.mDbName.canonicalName();
49
50 if (a == NULL && b != NULL)
51 {
52 return true; // NULL is always < something
53 }
54
55 if (a != NULL && b == NULL)
56 {
57 return false; // something is always >= NULL
58 }
59
60 if (a == NULL && b == NULL)
61 {
62 return false; // since == is not <
63 }
64
65 // if we get to this point, both are not null. No crash and the lexical value is correct.
66 return strcmp(a, b) < 0;
67 }
68
69 bool DLDbIdentifier::Impl::operator == (const Impl &other) const
70 {
71 bool subserviceIdEqual = mCssmSubserviceUid == other.mCssmSubserviceUid;
72 if (!subserviceIdEqual)
73 {
74 return false;
75 }
76
77 const char* a = mDbName.canonicalName();
78 const char* b = other.mDbName.canonicalName();
79
80 if (a == NULL && b != NULL)
81 {
82 return false;
83 }
84
85 if (a != NULL && b == NULL)
86 {
87 return false;
88 }
89
90 if (a == NULL && b == NULL)
91 {
92 return true;
93 }
94
95 bool namesEqual = strcmp(a, b) == 0;
96 return namesEqual;
97 }
98
99 //
100 // CssmDLPolyData
101 //
102 CssmDLPolyData::operator CSSM_DATE () const
103 {
104 assert(mFormat == CSSM_DB_ATTRIBUTE_FORMAT_BLOB);
105 if (mData.Length != 8)
106 CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
107
108 CSSM_DATE date;
109 memcpy(date.Year, mData.Data, 4);
110 memcpy(date.Month, mData.Data + 4, 2);
111 memcpy(date.Day, mData.Data + 6, 2);
112 return date;
113 }
114
115 CssmDLPolyData::operator Guid () const
116 {
117 assert(mFormat == CSSM_DB_ATTRIBUTE_FORMAT_BLOB);
118 if (mData.Length != Guid::stringRepLength + 1)
119 CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
120
121 return Guid(reinterpret_cast<const char *>(mData.Data));
122 }
123
124
125 //
126 // CssmDbAttributeInfo
127 //
128 CssmDbAttributeInfo::CssmDbAttributeInfo(const char *name, CSSM_DB_ATTRIBUTE_FORMAT vFormat)
129 {
130 clearPod();
131 AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
132 Label.AttributeName = const_cast<char *>(name); // silly CDSA
133 AttributeFormat = vFormat;
134 }
135
136 CssmDbAttributeInfo::CssmDbAttributeInfo(const CSSM_OID &oid, CSSM_DB_ATTRIBUTE_FORMAT vFormat)
137 {
138 clearPod();
139 AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_OID;
140 Label.AttributeOID = oid;
141 AttributeFormat = vFormat;
142 }
143
144 CssmDbAttributeInfo::CssmDbAttributeInfo(uint32 id, CSSM_DB_ATTRIBUTE_FORMAT vFormat)
145 {
146 clearPod();
147 AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER;
148 Label.AttributeID = id;
149 AttributeFormat = vFormat;
150 }
151
152
153 bool
154 CssmDbAttributeInfo::operator <(const CssmDbAttributeInfo& other) const
155 {
156 if (nameFormat() < other.nameFormat()) return true;
157 if (other.nameFormat() < nameFormat()) return false;
158 // nameFormat's are equal.
159 switch (nameFormat())
160 {
161 case CSSM_DB_ATTRIBUTE_NAME_AS_STRING:
162 {
163 int res = strcmp(static_cast<const char *>(*this), static_cast<const char *>(other));
164 if (res < 0) return true;
165 if (res > 0) return false;
166 break;
167 }
168 case CSSM_DB_ATTRIBUTE_NAME_AS_OID:
169 if (static_cast<const CssmOid &>(*this) < static_cast<const CssmOid &>(other)) return true;
170 if (static_cast<const CssmOid &>(other) < static_cast<const CssmOid &>(*this)) return false;
171 break;
172 case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER:
173 if (static_cast<uint32>(*this) < static_cast<uint32>(other)) return true;
174 if (static_cast<uint32>(other) < static_cast<uint32>(*this)) return false;
175 break;
176 default:
177 CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME);
178 }
179
180 return format() < other.format();
181 }
182
183 bool
184 CssmDbAttributeInfo::operator ==(const CssmDbAttributeInfo& other) const
185 {
186 if (nameFormat() != other.nameFormat()) return false;
187 if (format() != other.format()) return false;
188 switch (nameFormat())
189 {
190 case CSSM_DB_ATTRIBUTE_NAME_AS_STRING:
191 return !strcmp(static_cast<const char *>(*this), static_cast<const char *>(other));
192 case CSSM_DB_ATTRIBUTE_NAME_AS_OID:
193 return static_cast<const CssmOid &>(*this) == static_cast<const CssmOid &>(other);
194 case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER:
195 return static_cast<uint32>(*this) == static_cast<uint32>(other);
196 default:
197 CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME);
198 }
199 }
200
201 //
202 // CssmDbAttributeData
203 //
204 CssmDbAttributeData::operator string() const
205 {
206 switch (format()) {
207 case CSSM_DB_ATTRIBUTE_FORMAT_STRING:
208 case CSSM_DB_ATTRIBUTE_FORMAT_BLOB:
209 return at(0).toString();
210 default:
211 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
212 }
213 }
214 CssmDbAttributeData::operator const Guid &() const
215 {
216 if (format() == CSSM_DB_ATTRIBUTE_FORMAT_BLOB)
217 return *at(0).interpretedAs<Guid>();
218 else
219 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
220 }
221
222 CssmDbAttributeData::operator bool() const
223 {
224 switch (format()) {
225 case CSSM_DB_ATTRIBUTE_FORMAT_UINT32:
226 case CSSM_DB_ATTRIBUTE_FORMAT_SINT32:
227 return *at(0).interpretedAs<uint32>();
228 default:
229 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
230 }
231 }
232
233 CssmDbAttributeData::operator uint32() const
234 {
235 if (format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32)
236 return *at(0).interpretedAs<uint32>();
237 else
238 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
239 }
240
241 CssmDbAttributeData::operator const uint32 *() const
242 {
243 if (format() == CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32)
244 return reinterpret_cast<const uint32 *>(Value[0].Data);
245 else
246 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
247 }
248
249 CssmDbAttributeData::operator sint32() const
250 {
251 if (format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32)
252 return *at(0).interpretedAs<sint32>();
253 else
254 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
255 }
256
257 CssmDbAttributeData::operator double() const
258 {
259 if (format() == CSSM_DB_ATTRIBUTE_FORMAT_REAL)
260 return *at(0).interpretedAs<double>();
261 else
262 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
263 }
264
265 CssmDbAttributeData::operator const CssmData &() const
266 {
267 switch (format()) {
268 case CSSM_DB_ATTRIBUTE_FORMAT_STRING:
269 case CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM:
270 case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE:
271 case CSSM_DB_ATTRIBUTE_FORMAT_BLOB:
272 case CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32:
273 return at(0);
274 default:
275 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
276 }
277 }
278
279 void CssmDbAttributeData::set(const CSSM_DB_ATTRIBUTE_INFO &inInfo, const CssmPolyData &inValue,
280 Allocator &inAllocator)
281 {
282 info(inInfo);
283 NumberOfValues = 0;
284 Value = inAllocator.alloc<CSSM_DATA>();
285 Value[0].Length = 0;
286 Value[0].Data = inAllocator.alloc<uint8>((UInt32)inValue.Length);
287 Value[0].Length = inValue.Length;
288 memcpy(Value[0].Data, inValue.Data, inValue.Length);
289 NumberOfValues = 1;
290 }
291
292 void CssmDbAttributeData::add(const CssmPolyData &inValue, Allocator &inAllocator)
293 {
294 Value = reinterpret_cast<CSSM_DATA *>(inAllocator.realloc(Value, sizeof(*Value) * (NumberOfValues + 1)));
295 CssmAutoData valueCopy(inAllocator, inValue);
296 Value[NumberOfValues++] = valueCopy.release();
297 }
298
299
300 void CssmDbAttributeData::copyValues(const CssmDbAttributeData &source, Allocator &alloc)
301 {
302 assert(size() == 0); // must start out empty
303
304 // we're too lazy to arrange for exception safety here
305 CssmData *vector = alloc.alloc<CssmData>(source.size());
306 for (uint32 n = 0; n < source.size(); n++)
307 vector[n] = CssmAutoData(alloc, source[n]).release();
308
309 // atomic set results
310 info().format(source.info().format());
311 NumberOfValues = source.size();
312 values() = vector;
313 }
314
315 void CssmDbAttributeData::deleteValues(Allocator &alloc)
316 {
317 // Loop over all values and delete each one.
318 if (values())
319 {
320 for (uint32 n = 0; n < size(); n++)
321 {
322 alloc.free(at(n).data());
323 }
324 alloc.free(values());
325 }
326 NumberOfValues = 0;
327 values() = NULL;
328 }
329
330 bool CssmDbAttributeData::operator <(const CssmDbAttributeData &other) const
331 {
332 if (info() < other.info()) return true;
333 if (other.info() < info()) return false;
334
335 uint32 minSize = min(size(), other.size());
336 for (uint32 ix = 0; ix < minSize; ++ix)
337 {
338 if (at<const CssmData &>(ix) < other.at<const CssmData &>(ix))
339 return true;
340 if (other.at<const CssmData &>(ix) < at<const CssmData &>(ix))
341 return false;
342 }
343
344 return size() < other.size();
345 }
346
347 void
348 CssmDbAttributeData::add(const CssmDbAttributeData &src, Allocator &inAllocator)
349 {
350 // Add all the values from another attribute into this attribute.
351
352 Value = reinterpret_cast<CSSM_DATA *>(inAllocator.realloc(Value,
353 sizeof(*Value) * (NumberOfValues + src.NumberOfValues)));
354
355 for (uint32 srcIndex = 0; srcIndex < src.NumberOfValues; srcIndex++) {
356 uint32 destIndex = NumberOfValues + srcIndex;
357
358 Value[destIndex].Length = 0;
359 Value[destIndex].Data = inAllocator.alloc<uint8>((UInt32)src.Value[srcIndex].Length);
360 Value[destIndex].Length = src.Value[srcIndex].Length;
361 memcpy(Value[destIndex].Data, src.Value[srcIndex].Data, src.Value[srcIndex].Length);
362 }
363
364 NumberOfValues += src.NumberOfValues;
365 }
366
367 bool
368 CssmDbAttributeData::deleteValue(const CssmData &src, Allocator &inAllocator)
369 {
370 // Delete a single value from this attribute, if it is present.
371
372 for (uint32 i = 0; i < NumberOfValues; i++)
373 if (CssmData::overlay(Value[i]) == src)
374 {
375 inAllocator.free(Value[i].Data);
376 Value[i].Length = 0;
377
378 NumberOfValues--;
379 Value[i].Data = Value[NumberOfValues].Data;
380 Value[i].Length = Value[NumberOfValues].Length;
381
382 return true;
383 }
384
385 return false;
386 }
387
388 // Delete those values found in src from this object, if they are present.
389 // Warning: This is O(N^2) worst case; if this becomes a performance bottleneck
390 // then it will need to be changed.
391
392 void
393 CssmDbAttributeData::deleteValues(const CssmDbAttributeData &src, Allocator &inAllocator)
394 {
395 for (uint32 i = 0; i < src.NumberOfValues; i++)
396 deleteValue(CssmData::overlay(src.Value[i]), inAllocator);
397 }
398
399 //
400 // CssmDbRecordAttributeData
401 //
402 CssmDbAttributeData *
403 CssmDbRecordAttributeData::find(const CSSM_DB_ATTRIBUTE_INFO &inInfo)
404 {
405 const CssmDbAttributeInfo &anInfo = CssmDbAttributeInfo::overlay(inInfo);
406 for (uint32 ix = 0; ix < size(); ++ix)
407 {
408 if (at(ix).info() == anInfo)
409 return &at(ix);
410 }
411
412 return NULL;
413 }
414
415 bool
416 CssmDbRecordAttributeData::operator <(const CssmDbRecordAttributeData &other) const
417 {
418 if (recordType() < other.recordType()) return true;
419 if (other.recordType() < recordType()) return false;
420 if (semanticInformation() < other.semanticInformation()) return true;
421 if (other.semanticInformation() < semanticInformation()) return false;
422
423 uint32 minSize = min(size(), other.size());
424 for (uint32 ix = 0; ix < minSize; ++ix)
425 {
426 if (at(ix) < other.at(ix))
427 return true;
428 if (other.at(ix) < at(ix))
429 return false;
430 }
431
432 return size() < other.size();
433 }
434
435
436 //
437 // CssmAutoDbRecordAttributeData
438 //
439 CssmAutoDbRecordAttributeData::~CssmAutoDbRecordAttributeData()
440 {
441 clear();
442 }
443
444 void
445 CssmAutoDbRecordAttributeData::invalidate()
446 {
447 NumberOfAttributes = 0;
448 }
449
450
451
452 void
453 CssmAutoDbRecordAttributeData::clear()
454 {
455 deleteValues();
456 ArrayBuilder<CssmDbAttributeData>::clear();
457 }
458
459
460
461 static bool CompareAttributeInfos (const CSSM_DB_ATTRIBUTE_INFO &a, const CSSM_DB_ATTRIBUTE_INFO &b)
462 {
463 // check the format of the names
464 if (a.AttributeNameFormat != b.AttributeNameFormat)
465 {
466 return false;
467 }
468
469 switch (a.AttributeNameFormat)
470 {
471 case CSSM_DB_ATTRIBUTE_NAME_AS_STRING:
472 {
473 return strcmp (a.Label.AttributeName, b.Label.AttributeName) == 0;
474 }
475
476 case CSSM_DB_ATTRIBUTE_NAME_AS_OID:
477 {
478 if (a.Label.AttributeOID.Length != b.Label.AttributeOID.Length)
479 {
480 return false;
481 }
482
483 return memcmp (a.Label.AttributeOID.Data, b.Label.AttributeOID.Data, a.Label.AttributeOID.Length) == 0;
484 }
485
486
487 case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER:
488 {
489 return a.Label.AttributeID == b.Label.AttributeID;
490 }
491 }
492
493 return true; // just to keep the compiler from complaining
494 }
495
496
497
498 CssmDbAttributeData* CssmAutoDbRecordAttributeData::findAttribute (const CSSM_DB_ATTRIBUTE_INFO &info)
499 {
500 // walk through the data, looking for an attribute of the same type
501 unsigned i;
502 for (i = 0; i < size (); ++i)
503 {
504 CssmDbAttributeData& d = at (i);
505 CSSM_DB_ATTRIBUTE_INFO &inInfo = d.info ();
506
507 if (CompareAttributeInfos (info, inInfo))
508 {
509 return &d;
510 }
511 }
512
513 // found nothing?
514 return NULL;
515 }
516
517
518
519 CssmDbAttributeData& CssmAutoDbRecordAttributeData::getAttributeReference (const CSSM_DB_ATTRIBUTE_INFO &info)
520 {
521 // Either find an existing reference to an attribute in the list, or make a new one.
522 CssmDbAttributeData *anAttr = findAttribute (info);
523 if (anAttr) // was this already in the list?
524 {
525 // clean it up
526 anAttr->deleteValues (mValueAllocator);
527 }
528 else
529 {
530 // make a new one
531 anAttr = &add();
532 }
533
534 return *anAttr;
535 }
536
537
538
539 CssmDbAttributeData &
540 CssmAutoDbRecordAttributeData::add(const CSSM_DB_ATTRIBUTE_INFO &info)
541 {
542 CssmDbAttributeData& anAttr = getAttributeReference (info);
543 anAttr.info(info);
544 return anAttr;
545 }
546
547 CssmDbAttributeData &
548 CssmAutoDbRecordAttributeData::add(const CSSM_DB_ATTRIBUTE_INFO &info, const CssmPolyData &value)
549 {
550 CssmDbAttributeData &anAttr = getAttributeReference (info);
551 anAttr.set(info, value, mValueAllocator);
552 return anAttr;
553 }
554
555 //
556 // CssmAutoQuery
557 //
558 CssmAutoQuery::CssmAutoQuery(const CSSM_QUERY &query, Allocator &allocator)
559 : ArrayBuilder<CssmSelectionPredicate>(CssmSelectionPredicate::overlayVar(SelectionPredicate),
560 NumSelectionPredicates,
561 query.NumSelectionPredicates, allocator)
562 {
563 RecordType = query.RecordType;
564 Conjunctive = query.Conjunctive;
565 QueryLimits = query.QueryLimits;
566 QueryFlags = query.QueryFlags;
567 for (uint32 ix = 0; ix < query.NumSelectionPredicates; ++ix)
568 add().set(query.SelectionPredicate[ix], allocator);
569 }
570
571 CssmAutoQuery::~CssmAutoQuery()
572 {
573 clear();
574 }
575
576 void
577 CssmAutoQuery::clear()
578 {
579 deleteValues();
580 ArrayBuilder<CssmSelectionPredicate>::clear();
581 }
582
583 CssmSelectionPredicate &
584 CssmAutoQuery::add(CSSM_DB_OPERATOR dbOperator, const CSSM_DB_ATTRIBUTE_INFO &info, const CssmPolyData &value)
585 {
586 CssmSelectionPredicate &predicate = add();
587 predicate.dbOperator(dbOperator);
588 predicate.set(info, value, allocator());
589 return predicate;
590 }