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