X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_cdsa_utilities/lib/cssmdb.cpp?ds=inline diff --git a/Security/libsecurity_cdsa_utilities/lib/cssmdb.cpp b/Security/libsecurity_cdsa_utilities/lib/cssmdb.cpp new file mode 100644 index 00000000..e3546459 --- /dev/null +++ b/Security/libsecurity_cdsa_utilities/lib/cssmdb.cpp @@ -0,0 +1,590 @@ +/* + * Copyright (c) 2000-2004,2006,2011-2012,2014 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// cssmdb.cpp +// +// +#include + +bool DLDbIdentifier::Impl::operator < (const DLDbIdentifier::Impl &other) const +{ + if (mCssmSubserviceUid < other.mCssmSubserviceUid) + return true; + if (mCssmSubserviceUid != other.mCssmSubserviceUid) // i.e. greater than + return false; + + // This test will produce unreproducible results, + // depending on what items are being compared. To do this properly, we need to + // assign a lexical value to NULL. + // + // if (mDbName.canonicalName() == NULL || other.mDbName.canonicalName() == NULL) + // { + // return false; + // } + + // this is the correct way + const char* a = mDbName.canonicalName(); + const char* b = other.mDbName.canonicalName(); + + if (a == NULL && b != NULL) + { + return true; // NULL is always < something + } + + if (a != NULL && b == NULL) + { + return false; // something is always >= NULL + } + + if (a == NULL && b == NULL) + { + return false; // since == is not < + } + + // if we get to this point, both are not null. No crash and the lexical value is correct. + return strcmp(a, b) < 0; +} + +bool DLDbIdentifier::Impl::operator == (const Impl &other) const +{ + bool subserviceIdEqual = mCssmSubserviceUid == other.mCssmSubserviceUid; + if (!subserviceIdEqual) + { + return false; + } + + const char* a = mDbName.canonicalName(); + const char* b = other.mDbName.canonicalName(); + + if (a == NULL && b != NULL) + { + return false; + } + + if (a != NULL && b == NULL) + { + return false; + } + + if (a == NULL && b == NULL) + { + return true; + } + + bool namesEqual = strcmp(a, b) == 0; + return namesEqual; +} + +// +// CssmDLPolyData +// +CssmDLPolyData::operator CSSM_DATE () const +{ + assert(mFormat == CSSM_DB_ATTRIBUTE_FORMAT_BLOB); + if (mData.Length != 8) + CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT); + + CSSM_DATE date; + memcpy(date.Year, mData.Data, 4); + memcpy(date.Month, mData.Data + 4, 2); + memcpy(date.Day, mData.Data + 6, 2); + return date; +} + +CssmDLPolyData::operator Guid () const +{ + assert(mFormat == CSSM_DB_ATTRIBUTE_FORMAT_BLOB); + if (mData.Length != Guid::stringRepLength + 1) + CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT); + + return Guid(reinterpret_cast(mData.Data)); +} + + +// +// CssmDbAttributeInfo +// +CssmDbAttributeInfo::CssmDbAttributeInfo(const char *name, CSSM_DB_ATTRIBUTE_FORMAT vFormat) +{ + clearPod(); + AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; + Label.AttributeName = const_cast(name); // silly CDSA + AttributeFormat = vFormat; +} + +CssmDbAttributeInfo::CssmDbAttributeInfo(const CSSM_OID &oid, CSSM_DB_ATTRIBUTE_FORMAT vFormat) +{ + clearPod(); + AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_OID; + Label.AttributeOID = oid; + AttributeFormat = vFormat; +} + +CssmDbAttributeInfo::CssmDbAttributeInfo(uint32 id, CSSM_DB_ATTRIBUTE_FORMAT vFormat) +{ + clearPod(); + AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER; + Label.AttributeID = id; + AttributeFormat = vFormat; +} + + +bool +CssmDbAttributeInfo::operator <(const CssmDbAttributeInfo& other) const +{ + if (nameFormat() < other.nameFormat()) return true; + if (other.nameFormat() < nameFormat()) return false; + // nameFormat's are equal. + switch (nameFormat()) + { + case CSSM_DB_ATTRIBUTE_NAME_AS_STRING: + { + int res = strcmp(static_cast(*this), static_cast(other)); + if (res < 0) return true; + if (res > 0) return false; + break; + } + case CSSM_DB_ATTRIBUTE_NAME_AS_OID: + if (static_cast(*this) < static_cast(other)) return true; + if (static_cast(other) < static_cast(*this)) return false; + break; + case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER: + if (static_cast(*this) < static_cast(other)) return true; + if (static_cast(other) < static_cast(*this)) return false; + break; + default: + CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME); + } + + return format() < other.format(); +} + +bool +CssmDbAttributeInfo::operator ==(const CssmDbAttributeInfo& other) const +{ + if (nameFormat() != other.nameFormat()) return false; + if (format() != other.format()) return false; + switch (nameFormat()) + { + case CSSM_DB_ATTRIBUTE_NAME_AS_STRING: + return !strcmp(static_cast(*this), static_cast(other)); + case CSSM_DB_ATTRIBUTE_NAME_AS_OID: + return static_cast(*this) == static_cast(other); + case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER: + return static_cast(*this) == static_cast(other); + default: + CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME); + } +} + +// +// CssmDbAttributeData +// +CssmDbAttributeData::operator string() const +{ + switch (format()) { + case CSSM_DB_ATTRIBUTE_FORMAT_STRING: + case CSSM_DB_ATTRIBUTE_FORMAT_BLOB: + return at(0).toString(); + default: + CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT); + } +} +CssmDbAttributeData::operator const Guid &() const +{ + if (format() == CSSM_DB_ATTRIBUTE_FORMAT_BLOB) + return *at(0).interpretedAs(); + else + CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT); +} + +CssmDbAttributeData::operator bool() const +{ + switch (format()) { + case CSSM_DB_ATTRIBUTE_FORMAT_UINT32: + case CSSM_DB_ATTRIBUTE_FORMAT_SINT32: + return *at(0).interpretedAs(); + default: + CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT); + } +} + +CssmDbAttributeData::operator uint32() const +{ + if (format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32) + return *at(0).interpretedAs(); + else + CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT); +} + +CssmDbAttributeData::operator const uint32 *() const +{ + if (format() == CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32) + return reinterpret_cast(Value[0].Data); + else + CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT); +} + +CssmDbAttributeData::operator sint32() const +{ + if (format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32) + return *at(0).interpretedAs(); + else + CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT); +} + +CssmDbAttributeData::operator double() const +{ + if (format() == CSSM_DB_ATTRIBUTE_FORMAT_REAL) + return *at(0).interpretedAs(); + else + CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT); +} + +CssmDbAttributeData::operator const CssmData &() const +{ + switch (format()) { + case CSSM_DB_ATTRIBUTE_FORMAT_STRING: + case CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM: + case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE: + case CSSM_DB_ATTRIBUTE_FORMAT_BLOB: + case CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32: + return at(0); + default: + CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT); + } +} + +void CssmDbAttributeData::set(const CSSM_DB_ATTRIBUTE_INFO &inInfo, const CssmPolyData &inValue, + Allocator &inAllocator) +{ + info(inInfo); + NumberOfValues = 0; + Value = inAllocator.alloc(); + Value[0].Length = 0; + Value[0].Data = inAllocator.alloc((UInt32)inValue.Length); + Value[0].Length = inValue.Length; + memcpy(Value[0].Data, inValue.Data, inValue.Length); + NumberOfValues = 1; +} + +void CssmDbAttributeData::add(const CssmPolyData &inValue, Allocator &inAllocator) +{ + Value = reinterpret_cast(inAllocator.realloc(Value, sizeof(*Value) * (NumberOfValues + 1))); + CssmAutoData valueCopy(inAllocator, inValue); + Value[NumberOfValues++] = valueCopy.release(); +} + + +void CssmDbAttributeData::copyValues(const CssmDbAttributeData &source, Allocator &alloc) +{ + assert(size() == 0); // must start out empty + + // we're too lazy to arrange for exception safety here + CssmData *vector = alloc.alloc(source.size()); + for (uint32 n = 0; n < source.size(); n++) + vector[n] = CssmAutoData(alloc, source[n]).release(); + + // atomic set results + info().format(source.info().format()); + NumberOfValues = source.size(); + values() = vector; +} + +void CssmDbAttributeData::deleteValues(Allocator &alloc) +{ + // Loop over all values and delete each one. + if (values()) + { + for (uint32 n = 0; n < size(); n++) + { + alloc.free(at(n).data()); + } + alloc.free(values()); + } + NumberOfValues = 0; + values() = NULL; +} + +bool CssmDbAttributeData::operator <(const CssmDbAttributeData &other) const +{ + if (info() < other.info()) return true; + if (other.info() < info()) return false; + + uint32 minSize = min(size(), other.size()); + for (uint32 ix = 0; ix < minSize; ++ix) + { + if (at(ix) < other.at(ix)) + return true; + if (other.at(ix) < at(ix)) + return false; + } + + return size() < other.size(); +} + +void +CssmDbAttributeData::add(const CssmDbAttributeData &src, Allocator &inAllocator) +{ + // Add all the values from another attribute into this attribute. + + Value = reinterpret_cast(inAllocator.realloc(Value, + sizeof(*Value) * (NumberOfValues + src.NumberOfValues))); + + for (uint32 srcIndex = 0; srcIndex < src.NumberOfValues; srcIndex++) { + uint32 destIndex = NumberOfValues + srcIndex; + + Value[destIndex].Length = 0; + Value[destIndex].Data = inAllocator.alloc((UInt32)src.Value[srcIndex].Length); + Value[destIndex].Length = src.Value[srcIndex].Length; + memcpy(Value[destIndex].Data, src.Value[srcIndex].Data, src.Value[srcIndex].Length); + } + + NumberOfValues += src.NumberOfValues; +} + +bool +CssmDbAttributeData::deleteValue(const CssmData &src, Allocator &inAllocator) +{ + // Delete a single value from this attribute, if it is present. + + for (uint32 i = 0; i < NumberOfValues; i++) + if (CssmData::overlay(Value[i]) == src) + { + inAllocator.free(Value[i].Data); + Value[i].Length = 0; + + NumberOfValues--; + Value[i].Data = Value[NumberOfValues].Data; + Value[i].Length = Value[NumberOfValues].Length; + + return true; + } + + return false; +} + +// Delete those values found in src from this object, if they are present. +// Warning: This is O(N^2) worst case; if this becomes a performance bottleneck +// then it will need to be changed. + +void +CssmDbAttributeData::deleteValues(const CssmDbAttributeData &src, Allocator &inAllocator) +{ + for (uint32 i = 0; i < src.NumberOfValues; i++) + deleteValue(CssmData::overlay(src.Value[i]), inAllocator); +} + +// +// CssmDbRecordAttributeData +// +CssmDbAttributeData * +CssmDbRecordAttributeData::find(const CSSM_DB_ATTRIBUTE_INFO &inInfo) +{ + const CssmDbAttributeInfo &anInfo = CssmDbAttributeInfo::overlay(inInfo); + for (uint32 ix = 0; ix < size(); ++ix) + { + if (at(ix).info() == anInfo) + return &at(ix); + } + + return NULL; +} + +bool +CssmDbRecordAttributeData::operator <(const CssmDbRecordAttributeData &other) const +{ + if (recordType() < other.recordType()) return true; + if (other.recordType() < recordType()) return false; + if (semanticInformation() < other.semanticInformation()) return true; + if (other.semanticInformation() < semanticInformation()) return false; + + uint32 minSize = min(size(), other.size()); + for (uint32 ix = 0; ix < minSize; ++ix) + { + if (at(ix) < other.at(ix)) + return true; + if (other.at(ix) < at(ix)) + return false; + } + + return size() < other.size(); +} + + +// +// CssmAutoDbRecordAttributeData +// +CssmAutoDbRecordAttributeData::~CssmAutoDbRecordAttributeData() +{ + clear(); +} + +void +CssmAutoDbRecordAttributeData::invalidate() +{ + NumberOfAttributes = 0; +} + + + +void +CssmAutoDbRecordAttributeData::clear() +{ + deleteValues(); + ArrayBuilder::clear(); +} + + + +static bool CompareAttributeInfos (const CSSM_DB_ATTRIBUTE_INFO &a, const CSSM_DB_ATTRIBUTE_INFO &b) +{ + // check the format of the names + if (a.AttributeNameFormat != b.AttributeNameFormat) + { + return false; + } + + switch (a.AttributeNameFormat) + { + case CSSM_DB_ATTRIBUTE_NAME_AS_STRING: + { + return strcmp (a.Label.AttributeName, b.Label.AttributeName) == 0; + } + + case CSSM_DB_ATTRIBUTE_NAME_AS_OID: + { + if (a.Label.AttributeOID.Length != b.Label.AttributeOID.Length) + { + return false; + } + + return memcmp (a.Label.AttributeOID.Data, b.Label.AttributeOID.Data, a.Label.AttributeOID.Length) == 0; + } + + + case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER: + { + return a.Label.AttributeID == b.Label.AttributeID; + } + } + + return true; // just to keep the compiler from complaining +} + + + +CssmDbAttributeData* CssmAutoDbRecordAttributeData::findAttribute (const CSSM_DB_ATTRIBUTE_INFO &info) +{ + // walk through the data, looking for an attribute of the same type + unsigned i; + for (i = 0; i < size (); ++i) + { + CssmDbAttributeData& d = at (i); + CSSM_DB_ATTRIBUTE_INFO &inInfo = d.info (); + + if (CompareAttributeInfos (info, inInfo)) + { + return &d; + } + } + + // found nothing? + return NULL; +} + + + +CssmDbAttributeData& CssmAutoDbRecordAttributeData::getAttributeReference (const CSSM_DB_ATTRIBUTE_INFO &info) +{ + // Either find an existing reference to an attribute in the list, or make a new one. + CssmDbAttributeData *anAttr = findAttribute (info); + if (anAttr) // was this already in the list? + { + // clean it up + anAttr->deleteValues (mValueAllocator); + } + else + { + // make a new one + anAttr = &add(); + } + + return *anAttr; +} + + + +CssmDbAttributeData & +CssmAutoDbRecordAttributeData::add(const CSSM_DB_ATTRIBUTE_INFO &info) +{ + CssmDbAttributeData& anAttr = getAttributeReference (info); + anAttr.info(info); + return anAttr; +} + +CssmDbAttributeData & +CssmAutoDbRecordAttributeData::add(const CSSM_DB_ATTRIBUTE_INFO &info, const CssmPolyData &value) +{ + CssmDbAttributeData &anAttr = getAttributeReference (info); + anAttr.set(info, value, mValueAllocator); + return anAttr; +} + +// +// CssmAutoQuery +// +CssmAutoQuery::CssmAutoQuery(const CSSM_QUERY &query, Allocator &allocator) +: ArrayBuilder(CssmSelectionPredicate::overlayVar(SelectionPredicate), + NumSelectionPredicates, + query.NumSelectionPredicates, allocator) +{ + RecordType = query.RecordType; + Conjunctive = query.Conjunctive; + QueryLimits = query.QueryLimits; + QueryFlags = query.QueryFlags; + for (uint32 ix = 0; ix < query.NumSelectionPredicates; ++ix) + add().set(query.SelectionPredicate[ix], allocator); +} + +CssmAutoQuery::~CssmAutoQuery() +{ + clear(); +} + +void +CssmAutoQuery::clear() +{ + deleteValues(); + ArrayBuilder::clear(); +} + +CssmSelectionPredicate & +CssmAutoQuery::add(CSSM_DB_OPERATOR dbOperator, const CSSM_DB_ATTRIBUTE_INFO &info, const CssmPolyData &value) +{ + CssmSelectionPredicate &predicate = add(); + predicate.dbOperator(dbOperator); + predicate.set(info, value, allocator()); + return predicate; +}