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 }