1/* 2 * Copyright (c) 2000-2004,2006 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// cssmdb.cpp 26// 27// 28#include <security_cdsa_utilities/cssmdb.h> 29 30bool 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 // Murf correctly points out that 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 69bool 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// 102CssmDLPolyData::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 115CssmDLPolyData::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// 128CssmDbAttributeInfo::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 136CssmDbAttributeInfo::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 144CssmDbAttributeInfo::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 153bool 154CssmDbAttributeInfo::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 183bool 184CssmDbAttributeInfo::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// 204CssmDbAttributeData::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} 214CssmDbAttributeData::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 222CssmDbAttributeData::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 233CssmDbAttributeData::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 241CssmDbAttributeData::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 249CssmDbAttributeData::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 257CssmDbAttributeData::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 265CssmDbAttributeData::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 279void 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 292void 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 300void 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 315void 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 330bool 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 347void 348CssmDbAttributeData::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 367bool 368CssmDbAttributeData::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 392void 393CssmDbAttributeData::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// 402CssmDbAttributeData * 403CssmDbRecordAttributeData::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 415bool 416CssmDbRecordAttributeData::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// 439CssmAutoDbRecordAttributeData::~CssmAutoDbRecordAttributeData() 440{ 441 clear(); 442} 443 444void 445CssmAutoDbRecordAttributeData::invalidate() 446{ 447 NumberOfAttributes = 0; 448} 449 450 451 452void 453CssmAutoDbRecordAttributeData::clear() 454{ 455 deleteValues(); 456 ArrayBuilder<CssmDbAttributeData>::clear(); 457} 458 459 460 461static 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 498CssmDbAttributeData* 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 519CssmDbAttributeData& 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 539CssmDbAttributeData & 540CssmAutoDbRecordAttributeData::add(const CSSM_DB_ATTRIBUTE_INFO &info) 541{ 542 CssmDbAttributeData& anAttr = getAttributeReference (info); 543 anAttr.info(info); 544 return anAttr; 545} 546 547CssmDbAttributeData & 548CssmAutoDbRecordAttributeData::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// 558CssmAutoQuery::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 571CssmAutoQuery::~CssmAutoQuery() 572{ 573 clear(); 574} 575 576void 577CssmAutoQuery::clear() 578{ 579 deleteValues(); 580 ArrayBuilder<CssmSelectionPredicate>::clear(); 581} 582 583CssmSelectionPredicate & 584CssmAutoQuery::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} 591