2 * Copyright (c) 2000-2004,2006,2011-2012,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
28 #include <security_cdsa_utilities/cssmdb.h>
29 #include <CommonCrypto/CommonDigest.h>
31 using namespace DataWalkers
;
33 bool DLDbIdentifier::Impl::operator < (const DLDbIdentifier::Impl
&other
) const
35 if (mCssmSubserviceUid
< other
.mCssmSubserviceUid
)
37 if (mCssmSubserviceUid
!= other
.mCssmSubserviceUid
) // i.e. greater than
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.
44 // if (mDbName.canonicalName() == NULL || other.mDbName.canonicalName() == NULL)
49 // this is the correct way
50 const char* a
= mDbName
.canonicalName();
51 const char* b
= other
.mDbName
.canonicalName();
53 if (a
== NULL
&& b
!= NULL
)
55 return true; // NULL is always < something
58 if (a
!= NULL
&& b
== NULL
)
60 return false; // something is always >= NULL
63 if (a
== NULL
&& b
== NULL
)
65 return false; // since == is not <
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;
72 bool DLDbIdentifier::Impl::operator == (const Impl
&other
) const
74 bool subserviceIdEqual
= mCssmSubserviceUid
== other
.mCssmSubserviceUid
;
75 if (!subserviceIdEqual
)
80 const char* a
= mDbName
.canonicalName();
81 const char* b
= other
.mDbName
.canonicalName();
83 if (a
== NULL
&& b
!= NULL
)
88 if (a
!= NULL
&& b
== NULL
)
93 if (a
== NULL
&& b
== NULL
)
98 bool namesEqual
= strcmp(a
, b
) == 0;
105 CssmDLPolyData::operator CSSM_DATE () const
107 assert(mFormat
== CSSM_DB_ATTRIBUTE_FORMAT_BLOB
);
108 if (mData
.Length
!= 8)
109 CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT
);
112 memcpy(date
.Year
, mData
.Data
, 4);
113 memcpy(date
.Month
, mData
.Data
+ 4, 2);
114 memcpy(date
.Day
, mData
.Data
+ 6, 2);
118 CssmDLPolyData::operator Guid () const
120 assert(mFormat
== CSSM_DB_ATTRIBUTE_FORMAT_BLOB
);
121 if (mData
.Length
!= Guid::stringRepLength
+ 1)
122 CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT
);
124 return Guid(reinterpret_cast<const char *>(mData
.Data
));
129 // CssmDbAttributeInfo
131 CssmDbAttributeInfo::CssmDbAttributeInfo(const char *name
, CSSM_DB_ATTRIBUTE_FORMAT vFormat
)
134 AttributeNameFormat
= CSSM_DB_ATTRIBUTE_NAME_AS_STRING
;
135 Label
.AttributeName
= const_cast<char *>(name
); // silly CDSA
136 AttributeFormat
= vFormat
;
139 CssmDbAttributeInfo::CssmDbAttributeInfo(const CSSM_OID
&oid
, CSSM_DB_ATTRIBUTE_FORMAT vFormat
)
142 AttributeNameFormat
= CSSM_DB_ATTRIBUTE_NAME_AS_OID
;
143 Label
.AttributeOID
= oid
;
144 AttributeFormat
= vFormat
;
147 CssmDbAttributeInfo::CssmDbAttributeInfo(uint32 id
, CSSM_DB_ATTRIBUTE_FORMAT vFormat
)
150 AttributeNameFormat
= CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER
;
151 Label
.AttributeID
= id
;
152 AttributeFormat
= vFormat
;
157 CssmDbAttributeInfo::operator <(const CssmDbAttributeInfo
& other
) const
159 if (nameFormat() < other
.nameFormat()) return true;
160 if (other
.nameFormat() < nameFormat()) return false;
161 // nameFormat's are equal.
162 switch (nameFormat())
164 case CSSM_DB_ATTRIBUTE_NAME_AS_STRING
:
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;
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;
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;
180 CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME
);
183 return format() < other
.format();
187 CssmDbAttributeInfo::operator ==(const CssmDbAttributeInfo
& other
) const
189 if (nameFormat() != other
.nameFormat()) return false;
190 if (format() != other
.format()) return false;
191 switch (nameFormat())
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
);
200 CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME
);
205 // CssmDbAttributeData
207 CssmDbAttributeData::operator string() const
210 case CSSM_DB_ATTRIBUTE_FORMAT_STRING
:
211 case CSSM_DB_ATTRIBUTE_FORMAT_BLOB
:
212 return at(0).toString();
214 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT
);
217 CssmDbAttributeData::operator const Guid
&() const
219 if (format() == CSSM_DB_ATTRIBUTE_FORMAT_BLOB
)
220 return *at(0).interpretedAs
<Guid
>();
222 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT
);
225 CssmDbAttributeData::operator bool() const
228 case CSSM_DB_ATTRIBUTE_FORMAT_UINT32
:
229 case CSSM_DB_ATTRIBUTE_FORMAT_SINT32
:
230 return *at(0).interpretedAs
<uint32
>();
232 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT
);
236 CssmDbAttributeData::operator uint32() const
238 if (format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32
)
239 return *at(0).interpretedAs
<uint32
>();
241 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT
);
244 CssmDbAttributeData::operator const uint32
*() const
246 if (format() == CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32
)
247 return reinterpret_cast<const uint32
*>(Value
[0].Data
);
249 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT
);
252 CssmDbAttributeData::operator sint32() const
254 if (format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32
)
255 return *at(0).interpretedAs
<sint32
>();
257 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT
);
260 CssmDbAttributeData::operator double() const
262 if (format() == CSSM_DB_ATTRIBUTE_FORMAT_REAL
)
263 return *at(0).interpretedAs
<double>();
265 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT
);
268 CssmDbAttributeData::operator const CssmData
&() const
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
:
278 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT
);
282 void CssmDbAttributeData::set(const CSSM_DB_ATTRIBUTE_INFO
&inInfo
, const CssmPolyData
&inValue
,
283 Allocator
&inAllocator
)
287 Value
= inAllocator
.alloc
<CSSM_DATA
>();
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
);
295 void CssmDbAttributeData::add(const CssmPolyData
&inValue
, Allocator
&inAllocator
)
297 Value
= reinterpret_cast<CSSM_DATA
*>(inAllocator
.realloc(Value
, sizeof(*Value
) * (NumberOfValues
+ 1)));
298 CssmAutoData
valueCopy(inAllocator
, inValue
);
299 Value
[NumberOfValues
++] = valueCopy
.release();
303 void CssmDbAttributeData::copyValues(const CssmDbAttributeData
&source
, Allocator
&alloc
)
305 assert(size() == 0); // must start out empty
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();
312 // atomic set results
313 info().format(source
.info().format());
314 NumberOfValues
= source
.size();
318 void CssmDbAttributeData::deleteValues(Allocator
&alloc
)
320 // Loop over all values and delete each one.
323 for (uint32 n
= 0; n
< size(); n
++)
325 alloc
.free(at(n
).data());
327 alloc
.free(values());
333 bool CssmDbAttributeData::operator <(const CssmDbAttributeData
&other
) const
335 if (info() < other
.info()) return true;
336 if (other
.info() < info()) return false;
338 uint32 minSize
= min(size(), other
.size());
339 for (uint32 ix
= 0; ix
< minSize
; ++ix
)
341 if (at
<const CssmData
&>(ix
) < other
.at
<const CssmData
&>(ix
))
343 if (other
.at
<const CssmData
&>(ix
) < at
<const CssmData
&>(ix
))
347 return size() < other
.size();
351 CssmDbAttributeData::add(const CssmDbAttributeData
&src
, Allocator
&inAllocator
)
353 // Add all the values from another attribute into this attribute.
355 Value
= reinterpret_cast<CSSM_DATA
*>(inAllocator
.realloc(Value
,
356 sizeof(*Value
) * (NumberOfValues
+ src
.NumberOfValues
)));
358 for (uint32 srcIndex
= 0; srcIndex
< src
.NumberOfValues
; srcIndex
++) {
359 uint32 destIndex
= NumberOfValues
+ srcIndex
;
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
);
367 NumberOfValues
+= src
.NumberOfValues
;
371 CssmDbAttributeData::deleteValue(const CssmData
&src
, Allocator
&inAllocator
)
373 // Delete a single value from this attribute, if it is present.
375 for (uint32 i
= 0; i
< NumberOfValues
; i
++)
376 if (CssmData::overlay(Value
[i
]) == src
)
378 inAllocator
.free(Value
[i
].Data
);
382 Value
[i
].Data
= Value
[NumberOfValues
].Data
;
383 Value
[i
].Length
= Value
[NumberOfValues
].Length
;
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.
396 CssmDbAttributeData::deleteValues(const CssmDbAttributeData
&src
, Allocator
&inAllocator
)
398 for (uint32 i
= 0; i
< src
.NumberOfValues
; i
++)
399 deleteValue(CssmData::overlay(src
.Value
[i
]), inAllocator
);
403 // CssmDbRecordAttributeData
405 CssmDbAttributeData
*
406 CssmDbRecordAttributeData::find(const CSSM_DB_ATTRIBUTE_INFO
&inInfo
)
408 const CssmDbAttributeInfo
&anInfo
= CssmDbAttributeInfo::overlay(inInfo
);
409 for (uint32 ix
= 0; ix
< size(); ++ix
)
411 if (at(ix
).info() == anInfo
)
419 CssmDbRecordAttributeData::operator <(const CssmDbRecordAttributeData
&other
) const
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;
426 uint32 minSize
= min(size(), other
.size());
427 for (uint32 ix
= 0; ix
< minSize
; ++ix
)
429 if (at(ix
) < other
.at(ix
))
431 if (other
.at(ix
) < at(ix
))
435 return size() < other
.size();
440 // CssmAutoDbRecordAttributeData
442 CssmAutoDbRecordAttributeData::~CssmAutoDbRecordAttributeData()
448 CssmAutoDbRecordAttributeData::invalidate()
450 NumberOfAttributes
= 0;
456 CssmAutoDbRecordAttributeData::clear()
459 ArrayBuilder
<CssmDbAttributeData
>::clear();
464 static bool CompareAttributeInfos (const CSSM_DB_ATTRIBUTE_INFO
&a
, const CSSM_DB_ATTRIBUTE_INFO
&b
)
466 // check the format of the names
467 if (a
.AttributeNameFormat
!= b
.AttributeNameFormat
)
472 switch (a
.AttributeNameFormat
)
474 case CSSM_DB_ATTRIBUTE_NAME_AS_STRING
:
476 return strcmp (a
.Label
.AttributeName
, b
.Label
.AttributeName
) == 0;
479 case CSSM_DB_ATTRIBUTE_NAME_AS_OID
:
481 if (a
.Label
.AttributeOID
.Length
!= b
.Label
.AttributeOID
.Length
)
486 return memcmp (a
.Label
.AttributeOID
.Data
, b
.Label
.AttributeOID
.Data
, a
.Label
.AttributeOID
.Length
) == 0;
490 case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER
:
492 return a
.Label
.AttributeID
== b
.Label
.AttributeID
;
496 return true; // just to keep the compiler from complaining
501 CssmDbAttributeData
* CssmAutoDbRecordAttributeData::findAttribute (const CSSM_DB_ATTRIBUTE_INFO
&info
)
503 // walk through the data, looking for an attribute of the same type
505 for (i
= 0; i
< size (); ++i
)
507 CssmDbAttributeData
& d
= at (i
);
508 CSSM_DB_ATTRIBUTE_INFO
&inInfo
= d
.info ();
510 if (CompareAttributeInfos (info
, inInfo
))
522 CssmDbAttributeData
& CssmAutoDbRecordAttributeData::getAttributeReference (const CSSM_DB_ATTRIBUTE_INFO
&info
)
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?
529 anAttr
->deleteValues (mValueAllocator
);
542 CssmDbAttributeData
&
543 CssmAutoDbRecordAttributeData::add(const CSSM_DB_ATTRIBUTE_INFO
&info
)
545 CssmDbAttributeData
& anAttr
= getAttributeReference (info
);
550 CssmDbAttributeData
&
551 CssmAutoDbRecordAttributeData::add(const CSSM_DB_ATTRIBUTE_INFO
&info
, const CssmPolyData
&value
)
553 CssmDbAttributeData
&anAttr
= getAttributeReference (info
);
554 anAttr
.set(info
, value
, mValueAllocator
);
559 CssmAutoDbRecordAttributeData::updateWith(const CssmAutoDbRecordAttributeData
* newValues
) {
563 for(int i
= 0; i
< newValues
->size(); i
++) {
564 CssmDbAttributeData
& c
= newValues
->at(i
);
565 CssmDbAttributeData
& target
= add(c
.info());
567 target
.info(c
.info());
568 target
.copyValues(c
, mValueAllocator
);
569 //.set(c, mValueAllocator);
576 CssmAutoQuery::CssmAutoQuery(const CSSM_QUERY
&query
, Allocator
&allocator
)
577 : ArrayBuilder
<CssmSelectionPredicate
>(CssmSelectionPredicate::overlayVar(SelectionPredicate
),
578 NumSelectionPredicates
,
579 query
.NumSelectionPredicates
, allocator
)
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
);
589 CssmAutoQuery::~CssmAutoQuery()
595 CssmAutoQuery::clear()
598 ArrayBuilder
<CssmSelectionPredicate
>::clear();
601 CssmSelectionPredicate
&
602 CssmAutoQuery::add(CSSM_DB_OPERATOR dbOperator
, const CSSM_DB_ATTRIBUTE_INFO
&info
, const CssmPolyData
&value
)
604 CssmSelectionPredicate
&predicate
= add();
605 predicate
.dbOperator(dbOperator
);
606 predicate
.set(info
, value
, allocator());