2  * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. 
   4  * The contents of this file constitute Original Code as defined in and are 
   5  * subject to the Apple Public Source License Version 1.2 (the 'License'). 
   6  * You may not use this file except in compliance with the License. Please obtain 
   7  * a copy of the License at http://www.apple.com/publicsource and read it before 
  10  * This Original Code and all software distributed under the License are 
  11  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS 
  12  * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT 
  13  * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
  14  * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the 
  15  * specific language governing rights and limitations under the License. 
  23 #include "MetaRecord.h" 
  24 #include <Security/trackingallocator.h> 
  26 MetaRecord::MetaRecord(CSSM_DB_RECORDTYPE inRecordType
) : 
  27     mRecordType(inRecordType
) 
  31 MetaRecord::MetaRecord(const CSSM_DB_RECORD_ATTRIBUTE_INFO 
&inInfo
) 
  32 :       mRecordType(inInfo
.DataRecordType
) 
  36                 setRecordAttributeInfo(inInfo
); 
  40                 for_each_delete(mAttributeVector
.begin(), mAttributeVector
.end()); 
  44 MetaRecord::MetaRecord(CSSM_DB_RECORDTYPE inRelationID
, 
  45                        uint32 inNumberOfAttributes
, 
  46                                            const CSSM_DB_SCHEMA_ATTRIBUTE_INFO 
*inAttributeInfo
) : 
  47     mRecordType(inRelationID
) 
  50                 for (uint32 anIndex 
= 0; anIndex 
< inNumberOfAttributes
; anIndex
++) 
  53                         if (inAttributeInfo
[anIndex
].AttributeName
) 
  54                                 aName 
= string(inAttributeInfo
[anIndex
].AttributeName
); 
  56                         const CssmData 
*aNameID 
= NULL
; 
  57                         if (inAttributeInfo
[anIndex
].AttributeNameID
.Length 
> 0) 
  58                                 aNameID 
= &CssmData::overlay(inAttributeInfo
[anIndex
].AttributeNameID
); 
  60                         uint32 aNumber 
= inAttributeInfo
[anIndex
].AttributeId
; 
  62                                 inAttributeInfo
[anIndex
].AttributeName 
? &aName 
: NULL
, 
  64                                 inAttributeInfo
[anIndex
].DataType
); 
  69                 for_each_delete(mAttributeVector
.begin(), mAttributeVector
.end()); 
  73 MetaRecord::~MetaRecord() 
  75         for_each_delete(mAttributeVector
.begin(), mAttributeVector
.end()); 
  79 MetaRecord::setRecordAttributeInfo(const CSSM_DB_RECORD_ATTRIBUTE_INFO 
&inInfo
) 
  81     for (uint32 anIndex 
= 0; anIndex 
< inInfo
.NumberOfAttributes
; anIndex
++) 
  83         switch (inInfo
.AttributeInfo
[anIndex
].AttributeNameFormat
) 
  85             case CSSM_DB_ATTRIBUTE_NAME_AS_STRING
: 
  87                 string 
aName(inInfo
.AttributeInfo
[anIndex
].Label
.AttributeName
); 
  88                 createAttribute(&aName
, nil
, anIndex
, 
  89                                                                 inInfo
.AttributeInfo
[anIndex
].AttributeFormat
); 
  92             case CSSM_DB_ATTRIBUTE_NAME_AS_OID
: 
  94                 const CssmData 
&aNameID 
= CssmOid::overlay(inInfo
.AttributeInfo
[anIndex
].Label
.AttributeOID
); 
  95                 createAttribute(nil
, &aNameID
, anIndex
, 
  96                                                                 inInfo
.AttributeInfo
[anIndex
].AttributeFormat
); 
  99             case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER
: 
 101                 uint32 aNumber 
= inInfo
.AttributeInfo
[anIndex
].Label
.AttributeID
; 
 102                 createAttribute(nil
, nil
, aNumber
, 
 103                                                                 inInfo
.AttributeInfo
[anIndex
].AttributeFormat
); 
 107                 CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME
); 
 114 MetaRecord::createAttribute(const string 
*inAttributeName
, 
 115                                                         const CssmOid 
*inAttributeOID
, 
 116                             uint32 inAttributeID
, 
 117                                                         CSSM_DB_ATTRIBUTE_FORMAT inAttributeFormat
) 
 119         // Index of new element is current size of vector 
 120     uint32 anAttributeIndex 
= mAttributeVector
.size(); 
 121     bool aInsertedAttributeName 
= false; 
 122     bool aInsertedAttributeOID 
= false; 
 123     bool aInsertedAttributeID 
= false; 
 127         if (!mNameStringMap
.insert(NameStringMap::value_type(*inAttributeName
, anAttributeIndex
)).second
) 
 128             CssmError::throwMe(CSSMERR_DL_FIELD_SPECIFIED_MULTIPLE
); 
 129         aInsertedAttributeName 
= true; 
 135             if (!mNameOIDMap
.insert(NameOIDMap::value_type(*inAttributeOID
, anAttributeIndex
)).second
) 
 136                 CssmError::throwMe(CSSMERR_DL_FIELD_SPECIFIED_MULTIPLE
); 
 137             aInsertedAttributeOID 
= true; 
 140                 if (!mNameIntMap
.insert(NameIntMap::value_type(inAttributeID
, anAttributeIndex
)).second
) 
 141                         CssmError::throwMe(CSSMERR_DL_FIELD_SPECIFIED_MULTIPLE
); 
 142                 aInsertedAttributeID 
= true; 
 144                 // Note: this no longer throws INVALID_FIELD_NAME since the attribute will always have 
 145                 // an attribute ID by which it is known 
 147                 mAttributeVector
.push_back(MetaAttribute::create(inAttributeFormat
, 
 148                         anAttributeIndex
, inAttributeID
)); 
 152         if (aInsertedAttributeName
) 
 153             mNameStringMap
.erase(*inAttributeName
); 
 154         if (aInsertedAttributeOID
) 
 155             mNameOIDMap
.erase(*inAttributeOID
); 
 157             mNameIntMap
.erase(inAttributeID
); 
 164 // Create a packed record from the given inputs. 
 166 MetaRecord::packRecord(WriteSection 
&inWriteSection
, 
 167                        const CSSM_DB_RECORD_ATTRIBUTE_DATA 
*inAttributes
, 
 168                        const CssmData 
*inData
) const 
 172         aDataSize 
= inData
->Length
; 
 176     inWriteSection
.put(OffsetDataSize
, aDataSize
); 
 177     uint32 anOffset 
= OffsetAttributeOffsets 
+ AtomSize 
* mAttributeVector
.size(); 
 179         anOffset 
= inWriteSection
.put(anOffset
, aDataSize
, inData
->Data
); 
 181     vector
<uint32
> aNumValues(mAttributeVector
.size(), ~0UL); 
 182     vector
<CSSM_DATA_PTR
> aValues(mAttributeVector
.size()); 
 185     if (inAttributes 
== NULL
) 
 186         inWriteSection
.put(OffsetSemanticInformation
, 0); 
 189         inWriteSection
.put(OffsetSemanticInformation
, inAttributes
->SemanticInformation
); 
 191         // Put the supplied attribute values into the list of attributes 
 193         anIndex 
= inAttributes
->NumberOfAttributes
; 
 194         // Make sure that AttributeData is a valid array. 
 196                         Required(inAttributes
->AttributeData
); 
 198         while (anIndex
-- > 0) 
 200             CSSM_DB_ATTRIBUTE_DATA 
&anAttribute 
= inAttributes
->AttributeData
[anIndex
]; 
 201             uint32 anAttributeIndex 
= attributeIndex(anAttribute
.Info
); 
 202                         // Make sure that the caller specified the attribute values in the correct format. 
 203                         if (anAttribute
.Info
.AttributeFormat 
!= mAttributeVector
[anAttributeIndex
]->attributeFormat()) 
 204                                 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT
); 
 206             // If this attribute was specified before, throw. 
 207             if (aNumValues
[anAttributeIndex
] != ~0UL) 
 208                 CssmError::throwMe(CSSMERR_DL_FIELD_SPECIFIED_MULTIPLE
); 
 210             aNumValues
[anAttributeIndex
] = anAttribute
.NumberOfValues
; 
 211             aValues
[anAttributeIndex
] = anAttribute
.Value
; 
 215     for (anIndex 
= 0; anIndex 
< mAttributeVector
.size(); ++anIndex
) 
 217         const MetaAttribute 
&aMetaAttribute 
= *mAttributeVector
[anIndex
]; 
 218         uint32 aNumberOfValues 
= aNumValues
[anIndex
]; 
 219         // Now call the parsingmodule for each attribute that 
 220         // wasn't explicitly specified and that has a parsingmodule. 
 221         if (aNumberOfValues 
== ~0UL) 
 222             aNumberOfValues 
= aDataSize 
== 0 ? 0 : aMetaAttribute
.parse(*inData
, aValues
[anIndex
]); 
 224         // XXX When do we throw CSSMERR_DL_MISSING_VALUE?  Maybe if an 
 225                 // attribute is part of a unique index. 
 227         // Now we have a valuelist for this attribute.  Let's encode it. 
 228         aMetaAttribute
.packAttribute(inWriteSection
, anOffset
, aNumberOfValues
, aValues
[anIndex
]); 
 231         inWriteSection
.put(OffsetRecordSize
, anOffset
); 
 232     inWriteSection
.size(anOffset
); 
 236 MetaRecord::unpackAttribute(const ReadSection 
&inReadSection
, 
 237                                                         CssmAllocator 
&inAllocator
, 
 238                             CSSM_DB_ATTRIBUTE_DATA 
&inoutAttribute
) const 
 240     const MetaAttribute 
&aMetaAttribute 
= metaAttribute(inoutAttribute
.Info
); 
 241     // XXX: See ISSUES on whether AttributeFormat should be an outputvalue or not. 
 242         inoutAttribute
.Info
.AttributeFormat 
= aMetaAttribute
.attributeFormat(); 
 243     aMetaAttribute
.unpackAttribute(inReadSection
, inAllocator
, 
 244                                    inoutAttribute
.NumberOfValues
, 
 245                                                                    inoutAttribute
.Value
); 
 249 MetaRecord::unpackRecord(const ReadSection 
&inReadSection
, 
 250                                                  CssmAllocator 
&inAllocator
, 
 251                          CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes
, 
 253                                                  CSSM_QUERY_FLAGS inQueryFlags
) const 
 255         // XXX Use POD wrapper for inoutAttributes here. 
 256         TrackingAllocator 
anAllocator(inAllocator
); 
 259         // XXX Treat KEY records specially. 
 261         // If inQueryFlags & CSSM_QUERY_RETURN_DATA is true return the raw 
 262         // key bits in the CSSM_KEY structure 
 263         Range aDataRange 
= dataRange(inReadSection
); 
 264         inoutData
->Length 
= aDataRange
.mSize
; 
 265         inoutData
->Data 
= inReadSection
.allocCopyRange(aDataRange
, anAllocator
); 
 270         inoutAttributes
->DataRecordType 
= dataRecordType(); 
 271         inoutAttributes
->SemanticInformation 
= semanticInformation(inReadSection
); 
 272         uint32 anIndex 
= inoutAttributes
->NumberOfAttributes
; 
 274         // Make sure that AttributeData is a valid array. 
 275         if (anIndex 
> 0 && inoutAttributes
->AttributeData 
== NULL
) 
 276             CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER
); 
 278         while (anIndex
-- > 0) 
 280             unpackAttribute(inReadSection
, anAllocator
, 
 281                                         inoutAttributes
->AttributeData
[anIndex
]); 
 285         // Don't free anything the trackingAllocator allocated when it is destructed. 
 286         anAllocator
.commit(); 
 289 // Return the index (0 though NumAttributes - 1) of the attribute 
 290 // represented by inAttributeInfo 
 293 #define LOG_NAME_AS_STRING_FAIL          
 296 MetaRecord::attributeIndex(const CSSM_DB_ATTRIBUTE_INFO 
&inAttributeInfo
) const 
 299         switch (inAttributeInfo
.AttributeNameFormat
) 
 301             case CSSM_DB_ATTRIBUTE_NAME_AS_STRING
: 
 303                         string 
aName(inAttributeInfo
.Label
.AttributeName
); 
 304                         assert(aName
.size() < 500);             // MDS leak debug 
 305                         NameStringMap::const_iterator it 
= mNameStringMap
.find(aName
); 
 306                         if (it 
== mNameStringMap
.end()) { 
 307                                 #ifdef  LOG_NAME_AS_STRING_FAIL 
 308                                 printf("NAME_AS_STRING failure; attrName %s\n",  
 309                                         inAttributeInfo
.Label
.AttributeName
); 
 310                                 for(it 
= mNameStringMap
.begin(); 
 311                                     it 
!= mNameStringMap
.end(); 
 313                                                 printf("name %s val %lu\n", it
->first
.c_str(), it
->second
); 
 316                                 CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME
); 
 318                         anIndex 
= it
->second
; 
 321             case CSSM_DB_ATTRIBUTE_NAME_AS_OID
: 
 323                         const CssmOid 
&aName 
= CssmOid::overlay(inAttributeInfo
.Label
.AttributeOID
); 
 324                         NameOIDMap::const_iterator it 
= mNameOIDMap
.find(aName
); 
 325                         if (it 
== mNameOIDMap
.end()) 
 326                                 CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME
); 
 327                         anIndex 
= it
->second
; 
 330                 case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER
: 
 332                         uint32 aName 
= inAttributeInfo
.Label
.AttributeID
; 
 333                         NameIntMap::const_iterator it 
= mNameIntMap
.find(aName
); 
 334                         if (it 
== mNameIntMap
.end()) 
 335                                 CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME
); 
 336                         anIndex 
= it
->second
; 
 340                         CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME
); 
 347 const MetaAttribute 
& 
 348 MetaRecord::metaAttribute(const CSSM_DB_ATTRIBUTE_INFO 
&inAttributeInfo
) const 
 350         return *mAttributeVector
[attributeIndex(inAttributeInfo
)]; 
 353 // Create a packed record from the given inputs and the old packed record inReadSection. 
 355 MetaRecord::updateRecord(const ReadSection 
&inReadSection
, 
 356                                                  WriteSection 
&inWriteSection
, 
 357                                                  const CssmDbRecordAttributeData 
*inAttributes
, 
 358                                                  const CssmData 
*inData
, 
 359                                                  CSSM_DB_MODIFY_MODE inModifyMode
) const 
 361         TrackingAllocator 
anAllocator(CssmAllocator::standard()); 
 363         // modify the opaque data associated with the record 
 366         const uint8 
*aDataData 
= NULL
; 
 370                 // prepare to write new data 
 371         aDataSize 
= inData
->Length
; 
 372                 aDataData 
= inData
->Data
; 
 376                 // prepare to copy old data 
 377         Range aDataRange 
= dataRange(inReadSection
); 
 378         aDataSize 
= aDataRange
.mSize
; 
 380                         aDataData 
= inReadSection
.range(aDataRange
); 
 383         // compute the data offset; this will keep a running total of the record size 
 384     uint32 anOffset 
= OffsetAttributeOffsets 
+ AtomSize 
* mAttributeVector
.size(); 
 386         // write the appropriate data to the new record 
 387         inWriteSection
.put(OffsetDataSize
, aDataSize
); 
 389                 anOffset 
= inWriteSection
.put(anOffset
, aDataSize
, aDataData
); 
 391         // unpack the old attributes since some of them may need to be preserved 
 393         auto_array
<CssmDbAttributeData
> attributeData(mAttributeVector
.size()); 
 395         for (uint32 anAttributeIndex 
= mAttributeVector
.size(); anAttributeIndex
-- > 0; ) 
 397                 // unpack the old attribute data for this attribute index 
 398                 const MetaAttribute 
&attribute 
= *mAttributeVector
[anAttributeIndex
]; 
 399                 attribute
.unpackAttribute(inReadSection
, anAllocator
, 
 400                                                                   attributeData
[anAttributeIndex
].NumberOfValues
, 
 401                                                                   attributeData
[anAttributeIndex
].Value
); 
 404         // retrieve the currrent semantic information 
 406         uint32 oldSemanticInformation 
= semanticInformation(inReadSection
); 
 408         // process each input attribute as necessary, based on the modification mode 
 410         if (inAttributes 
== NULL
) 
 412                 // make sure the modification mode is NONE, otherwise it's an 
 413                 // error accordining to the spec 
 414                 if (inModifyMode 
!= CSSM_DB_MODIFY_ATTRIBUTE_NONE
) 
 415                         CssmError::throwMe(CSSMERR_DL_INVALID_MODIFY_MODE
); 
 420                 // modify the semantic information 
 422                 uint32 inSemanticInformation 
= inAttributes 
? inAttributes
->SemanticInformation 
: 0; 
 424                 if (inModifyMode 
== CSSM_DB_MODIFY_ATTRIBUTE_ADD
) 
 425                         oldSemanticInformation 
|= inSemanticInformation
; 
 427                 else if (inModifyMode 
== CSSM_DB_MODIFY_ATTRIBUTE_DELETE
) 
 428                         oldSemanticInformation 
&= ~inSemanticInformation
; 
 430                 else if (inModifyMode 
== CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
) 
 431                         oldSemanticInformation 
= inSemanticInformation
; 
 433                 uint32 anIndex 
= inAttributes
->NumberOfAttributes
; 
 435                         Required(inAttributes
->AttributeData
); 
 437                 // modify the attributes 
 439                 while (anIndex
-- > 0) { 
 441                         const CssmDbAttributeData 
&anAttribute 
= inAttributes
->at(anIndex
); 
 442                         uint32 anAttributeIndex 
= attributeIndex(anAttribute
.info()); 
 443                         if (anAttribute
.format() != mAttributeVector
[anAttributeIndex
]->attributeFormat()) 
 444                                 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT
); 
 446                         CssmDbAttributeData 
&oldAttribute 
= attributeData
[anAttributeIndex
]; 
 448                         // if the modify mode is ADD, merge new values with pre-existing values 
 450                         if (inModifyMode 
== CSSM_DB_MODIFY_ATTRIBUTE_ADD
) 
 451                                 oldAttribute
.add(anAttribute
, anAllocator
); 
 453                         // if the modify mode is DELETE, remove the indicated values, or remove 
 454                         // all values if none are specified 
 456                         else if (inModifyMode 
== CSSM_DB_MODIFY_ATTRIBUTE_DELETE
) 
 458                                 if (anAttribute
.size() == 0) 
 459                                         oldAttribute
.deleteValues(anAllocator
); 
 461                                         oldAttribute
.deleteValues(anAttribute
, anAllocator
); 
 464                         // if the modify mode is REPLACE, then replace the specified values, or 
 465                         // delete all values if no values are specified 
 467                         else if (inModifyMode 
== CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
) 
 469                                 oldAttribute
.deleteValues(anAllocator
); 
 470                                 if (anAttribute
.size() > 0) 
 471                                         oldAttribute
.add(anAttribute
, anAllocator
); 
 473                                         // The spec says "all values are deleted or the the value is replaced 
 474                                         // with the default" but doesn't say which. We could call the parsing 
 475                                         // module for the attribute here...if they were implemented! But instead 
 476                                         // we choose "all values are deleted" and leave it at that. 
 482         // write the resulting attributes into the new record 
 484         inWriteSection
.put(OffsetSemanticInformation
, oldSemanticInformation
); 
 486         for (uint32 anIndex 
= 0; anIndex 
< mAttributeVector
.size(); ++anIndex
) 
 488                 const MetaAttribute 
&metaAttribute 
= *mAttributeVector
[anIndex
]; 
 489                 metaAttribute
.packAttribute(inWriteSection
, anOffset
, 
 490                                                                     attributeData
[anIndex
].NumberOfValues
, 
 491                                                                         attributeData
[anIndex
].Value
); 
 494         inWriteSection
.put(OffsetRecordSize
, anOffset
); 
 495         inWriteSection
.size(anOffset
);