]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/MetaRecord.cpp
Security-54.1.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / MetaRecord.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
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
8 * using this file.
9 *
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.
16 */
17
18
19 //
20 // MetaRecord.cpp
21 //
22
23 #include "MetaRecord.h"
24 #include <Security/trackingallocator.h>
25
26 MetaRecord::MetaRecord(CSSM_DB_RECORDTYPE inRecordType) :
27 mRecordType(inRecordType)
28 {
29 }
30
31 MetaRecord::MetaRecord(const CSSM_DB_RECORD_ATTRIBUTE_INFO &inInfo)
32 : mRecordType(inInfo.DataRecordType)
33 {
34 try
35 {
36 setRecordAttributeInfo(inInfo);
37 }
38 catch (...)
39 {
40 for_each_delete(mAttributeVector.begin(), mAttributeVector.end());
41 }
42 }
43
44 MetaRecord::MetaRecord(CSSM_DB_RECORDTYPE inRelationID,
45 uint32 inNumberOfAttributes,
46 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *inAttributeInfo) :
47 mRecordType(inRelationID)
48 {
49 // XXX Is there any particular reason not to allow this?
50 #if 0
51 if (inNumberOfAttributes == 0 || inAttributeInfo == NULL)
52 CssmError::throwMe(CSSMERR_DL_UNSUPPORTED_NUM_ATTRIBUTES);
53 #endif
54
55 try {
56 for (uint32 anIndex = 0; anIndex < inNumberOfAttributes; anIndex++)
57 {
58 string aName;
59 if (inAttributeInfo[anIndex].AttributeName)
60 aName = string(inAttributeInfo[anIndex].AttributeName);
61
62 const CssmData *aNameID = NULL;
63 if (inAttributeInfo[anIndex].AttributeNameID.Length > 0)
64 aNameID = &CssmData::overlay(inAttributeInfo[anIndex].AttributeNameID);
65
66 uint32 aNumber = inAttributeInfo[anIndex].AttributeId;
67 createAttribute(
68 inAttributeInfo[anIndex].AttributeName ? &aName : NULL,
69 aNameID, aNumber,
70 inAttributeInfo[anIndex].DataType);
71 }
72 }
73 catch (...)
74 {
75 for_each_delete(mAttributeVector.begin(), mAttributeVector.end());
76 }
77 }
78
79 MetaRecord::~MetaRecord()
80 {
81 for_each_delete(mAttributeVector.begin(), mAttributeVector.end());
82 }
83
84 void
85 MetaRecord::setRecordAttributeInfo(const CSSM_DB_RECORD_ATTRIBUTE_INFO &inInfo)
86 {
87 // XXX Is there any particular reason not to allow this?
88 #if 0
89 if (inInfo.NumberOfAttributes == 0 || inInfo.AttributeInfo == NULL)
90 CssmError::throwMe(CSSMERR_DL_UNSUPPORTED_NUM_ATTRIBUTES);
91 #endif
92
93 for (uint32 anIndex = 0; anIndex < inInfo.NumberOfAttributes; anIndex++)
94 {
95 switch (inInfo.AttributeInfo[anIndex].AttributeNameFormat)
96 {
97 case CSSM_DB_ATTRIBUTE_NAME_AS_STRING:
98 {
99 string aName(inInfo.AttributeInfo[anIndex].Label.AttributeName);
100 createAttribute(&aName, nil, anIndex,
101 inInfo.AttributeInfo[anIndex].AttributeFormat);
102 break;
103 }
104 case CSSM_DB_ATTRIBUTE_NAME_AS_OID:
105 {
106 const CssmData &aNameID = CssmOid::overlay(inInfo.AttributeInfo[anIndex].Label.AttributeOID);
107 createAttribute(nil, &aNameID, anIndex,
108 inInfo.AttributeInfo[anIndex].AttributeFormat);
109 break;
110 }
111 case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER:
112 {
113 uint32 aNumber = inInfo.AttributeInfo[anIndex].Label.AttributeID;
114 createAttribute(nil, nil, aNumber,
115 inInfo.AttributeInfo[anIndex].AttributeFormat);
116 break;
117 }
118 default:
119 CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME);
120 break;
121 }
122 }
123 }
124
125 void
126 MetaRecord::createAttribute(const string *inAttributeName,
127 const CssmOid *inAttributeOID,
128 uint32 inAttributeID,
129 CSSM_DB_ATTRIBUTE_FORMAT inAttributeFormat)
130 {
131 // Index of new element is current size of vector
132 uint32 anAttributeIndex = mAttributeVector.size();
133 bool aInsertedAttributeName = false;
134 bool aInsertedAttributeOID = false;
135 bool aInsertedAttributeID = false;
136
137 if (inAttributeName)
138 {
139 if (!mNameStringMap.insert(NameStringMap::value_type(*inAttributeName, anAttributeIndex)).second)
140 CssmError::throwMe(CSSMERR_DL_FIELD_SPECIFIED_MULTIPLE);
141 aInsertedAttributeName = true;
142 }
143 try
144 {
145 if (inAttributeOID)
146 {
147 if (!mNameOIDMap.insert(NameOIDMap::value_type(*inAttributeOID, anAttributeIndex)).second)
148 CssmError::throwMe(CSSMERR_DL_FIELD_SPECIFIED_MULTIPLE);
149 aInsertedAttributeOID = true;
150 }
151
152 if (!mNameIntMap.insert(NameIntMap::value_type(inAttributeID, anAttributeIndex)).second)
153 CssmError::throwMe(CSSMERR_DL_FIELD_SPECIFIED_MULTIPLE);
154 aInsertedAttributeID = true;
155
156 // Note: this no longer throws INVALID_FIELD_NAME since the attribute will always have
157 // an attribute ID by which it is known
158
159 mAttributeVector.push_back(MetaAttribute::create(inAttributeFormat,
160 anAttributeIndex, inAttributeID));
161 }
162 catch(...)
163 {
164 if (aInsertedAttributeName)
165 mNameStringMap.erase(*inAttributeName);
166 if (aInsertedAttributeOID)
167 mNameOIDMap.erase(*inAttributeOID);
168 if (inAttributeID)
169 mNameIntMap.erase(inAttributeID);
170
171 throw;
172 }
173 }
174
175
176 // Create a packed record from the given inputs.
177 void
178 MetaRecord::packRecord(WriteSection &inWriteSection,
179 const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
180 const CssmData *inData) const
181 {
182 uint32 aDataSize;
183 if (inData)
184 aDataSize = inData->Length;
185 else
186 aDataSize = 0;
187
188 inWriteSection.put(OffsetDataSize, aDataSize);
189 uint32 anOffset = OffsetAttributeOffsets + AtomSize * mAttributeVector.size();
190 if (aDataSize)
191 anOffset = inWriteSection.put(anOffset, aDataSize, inData->Data);
192
193 vector<uint32> aNumValues(mAttributeVector.size(), ~0UL);
194 vector<CSSM_DATA_PTR> aValues(mAttributeVector.size());
195 uint32 anIndex;
196
197 if (inAttributes == NULL)
198 inWriteSection.put(OffsetSemanticInformation, 0);
199 else
200 {
201 inWriteSection.put(OffsetSemanticInformation, inAttributes->SemanticInformation);
202
203 // Put the supplied attribute values into the list of attributes
204 // and values.
205 anIndex = inAttributes->NumberOfAttributes;
206 // Make sure that AttributeData is a valid array.
207 if (anIndex > 0)
208 Required(inAttributes->AttributeData);
209
210 while (anIndex-- > 0)
211 {
212 CSSM_DB_ATTRIBUTE_DATA &anAttribute = inAttributes->AttributeData[anIndex];
213 uint32 anAttributeIndex = attributeIndex(anAttribute.Info);
214 // Make sure that the caller specified the attribute values in the correct format.
215 if (anAttribute.Info.AttributeFormat != mAttributeVector[anAttributeIndex]->attributeFormat())
216 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
217
218 // If this attribute was specified before, throw.
219 if (aNumValues[anAttributeIndex] != ~0UL)
220 CssmError::throwMe(CSSMERR_DL_FIELD_SPECIFIED_MULTIPLE);
221
222 aNumValues[anAttributeIndex] = anAttribute.NumberOfValues;
223 aValues[anAttributeIndex] = anAttribute.Value;
224 }
225 }
226
227 for (anIndex = 0; anIndex < mAttributeVector.size(); ++anIndex)
228 {
229 const MetaAttribute &aMetaAttribute = *mAttributeVector[anIndex];
230 uint32 aNumberOfValues = aNumValues[anIndex];
231 // Now call the parsingmodule for each attribute that
232 // wasn't explicitly specified and that has a parsingmodule.
233 if (aNumberOfValues == ~0UL)
234 aNumberOfValues = aDataSize == 0 ? 0 : aMetaAttribute.parse(*inData, aValues[anIndex]);
235
236 // XXX When do we throw CSSMERR_DL_MISSING_VALUE? Maybe if an
237 // attribute is part of a unique index.
238
239 // Now we have a valuelist for this attribute. Let's encode it.
240 aMetaAttribute.packAttribute(inWriteSection, anOffset, aNumberOfValues, aValues[anIndex]);
241 }
242
243 inWriteSection.put(OffsetRecordSize, anOffset);
244 inWriteSection.size(anOffset);
245 }
246
247 inline void
248 MetaRecord::unpackAttribute(const ReadSection &inReadSection,
249 CssmAllocator &inAllocator,
250 CSSM_DB_ATTRIBUTE_DATA &inoutAttribute) const
251 {
252 const MetaAttribute &aMetaAttribute = metaAttribute(inoutAttribute.Info);
253 // XXX: See ISSUES on whether AttributeFormat should be an outputvalue or not.
254 inoutAttribute.Info.AttributeFormat = aMetaAttribute.attributeFormat();
255 aMetaAttribute.unpackAttribute(inReadSection, inAllocator,
256 inoutAttribute.NumberOfValues,
257 inoutAttribute.Value);
258 }
259
260 void
261 MetaRecord::unpackRecord(const ReadSection &inReadSection,
262 CssmAllocator &inAllocator,
263 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
264 CssmData *inoutData,
265 CSSM_QUERY_FLAGS inQueryFlags) const
266 {
267 // XXX Use POD wrapper for inoutAttributes here.
268 TrackingAllocator anAllocator(inAllocator);
269 if (inoutData)
270 {
271 // XXX Treat KEY records specially.
272
273 // If inQueryFlags & CSSM_QUERY_RETURN_DATA is true return the raw
274 // key bits in the CSSM_KEY structure
275 Range aDataRange = dataRange(inReadSection);
276 inoutData->Length = aDataRange.mSize;
277 inoutData->Data = inReadSection.allocCopyRange(aDataRange, anAllocator);
278 }
279
280 if (inoutAttributes)
281 {
282 inoutAttributes->DataRecordType = dataRecordType();
283 inoutAttributes->SemanticInformation = semanticInformation(inReadSection);
284 uint32 anIndex = inoutAttributes->NumberOfAttributes;
285
286 // Make sure that AttributeData is a valid array.
287 if (anIndex > 0 && inoutAttributes->AttributeData == NULL)
288 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER);
289
290 while (anIndex-- > 0)
291 {
292 unpackAttribute(inReadSection, anAllocator,
293 inoutAttributes->AttributeData[anIndex]);
294 }
295 }
296
297 // Don't free anything the trackingAllocator allocated when it is destructed.
298 anAllocator.commit();
299 }
300
301 // Return the index (0 though NumAttributes - 1) of the attribute
302 // represented by inAttributeInfo
303
304 #ifndef NDEBUG
305 #define LOG_NAME_AS_STRING_FAIL
306 #endif
307 uint32
308 MetaRecord::attributeIndex(const CSSM_DB_ATTRIBUTE_INFO &inAttributeInfo) const
309 {
310 uint32 anIndex;
311 switch (inAttributeInfo.AttributeNameFormat)
312 {
313 case CSSM_DB_ATTRIBUTE_NAME_AS_STRING:
314 {
315 string aName(inAttributeInfo.Label.AttributeName);
316 assert(aName.size() < 500); // MDS leak debug
317 NameStringMap::const_iterator it = mNameStringMap.find(aName);
318 if (it == mNameStringMap.end()) {
319 #ifdef LOG_NAME_AS_STRING_FAIL
320 printf("NAME_AS_STRING failure; attrName %s\n",
321 inAttributeInfo.Label.AttributeName);
322 for(it = mNameStringMap.begin();
323 it != mNameStringMap.end();
324 it++) {
325 printf("name %s val %ul\n", it->first.c_str(), it->second);
326 }
327 #endif
328 CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME);
329 }
330 anIndex = it->second;
331 break;
332 }
333 case CSSM_DB_ATTRIBUTE_NAME_AS_OID:
334 {
335 const CssmOid &aName = CssmOid::overlay(inAttributeInfo.Label.AttributeOID);
336 NameOIDMap::const_iterator it = mNameOIDMap.find(aName);
337 if (it == mNameOIDMap.end())
338 CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME);
339 anIndex = it->second;
340 break;
341 }
342 case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER:
343 {
344 uint32 aName = inAttributeInfo.Label.AttributeID;
345 NameIntMap::const_iterator it = mNameIntMap.find(aName);
346 if (it == mNameIntMap.end())
347 CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME);
348 anIndex = it->second;
349 break;
350 }
351 default:
352 CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME);
353 break;
354 }
355
356 return anIndex;
357 }
358
359 const MetaAttribute &
360 MetaRecord::metaAttribute(const CSSM_DB_ATTRIBUTE_INFO &inAttributeInfo) const
361 {
362 return *mAttributeVector[attributeIndex(inAttributeInfo)];
363 }
364
365 // Create a packed record from the given inputs and the old packed record inReadSection.
366 void
367 MetaRecord::updateRecord(const ReadSection &inReadSection,
368 WriteSection &inWriteSection,
369 const CssmDbRecordAttributeData *inAttributes,
370 const CssmData *inData,
371 CSSM_DB_MODIFY_MODE inModifyMode) const
372 {
373 TrackingAllocator anAllocator(CssmAllocator::standard());
374
375 // modify the opaque data associated with the record
376
377 uint32 aDataSize;
378 const uint8 *aDataData = NULL;
379
380 if (inData)
381 {
382 // prepare to write new data
383 aDataSize = inData->Length;
384 aDataData = inData->Data;
385 }
386 else
387 {
388 // prepare to copy old data
389 Range aDataRange = dataRange(inReadSection);
390 aDataSize = aDataRange.mSize;
391 if (aDataSize)
392 aDataData = inReadSection.range(aDataRange);
393 }
394
395 // compute the data offset; this will keep a running total of the record size
396 uint32 anOffset = OffsetAttributeOffsets + AtomSize * mAttributeVector.size();
397
398 // write the appropriate data to the new record
399 inWriteSection.put(OffsetDataSize, aDataSize);
400 if (aDataSize)
401 anOffset = inWriteSection.put(anOffset, aDataSize, aDataData);
402
403 // unpack the old attributes since some of them may need to be preserved
404
405 auto_array<CssmDbAttributeData> attributeData(mAttributeVector.size());
406
407 for (uint32 anAttributeIndex = mAttributeVector.size(); anAttributeIndex-- > 0; )
408 {
409 // unpack the old attribute data for this attribute index
410 const MetaAttribute &attribute = *mAttributeVector[anAttributeIndex];
411 attribute.unpackAttribute(inReadSection, anAllocator,
412 attributeData[anAttributeIndex].NumberOfValues,
413 attributeData[anAttributeIndex].Value);
414 }
415
416 // retrieve the currrent semantic information
417
418 uint32 oldSemanticInformation = semanticInformation(inReadSection);
419
420 // process each input attribute as necessary, based on the modification mode
421
422 if (inAttributes == NULL)
423 {
424 // make sure the modification mode is NONE, otherwise it's an
425 // error accordining to the spec
426 if (inModifyMode != CSSM_DB_MODIFY_ATTRIBUTE_NONE)
427 CssmError::throwMe(CSSMERR_DL_INVALID_MODIFY_MODE);
428 }
429
430 else {
431
432 // modify the semantic information
433
434 uint32 inSemanticInformation = inAttributes ? inAttributes->SemanticInformation : 0;
435
436 if (inModifyMode == CSSM_DB_MODIFY_ATTRIBUTE_ADD)
437 oldSemanticInformation |= inSemanticInformation;
438
439 else if (inModifyMode == CSSM_DB_MODIFY_ATTRIBUTE_DELETE)
440 oldSemanticInformation &= ~inSemanticInformation;
441
442 else if (inModifyMode == CSSM_DB_MODIFY_ATTRIBUTE_REPLACE)
443 oldSemanticInformation = inSemanticInformation;
444
445 uint32 anIndex = inAttributes->NumberOfAttributes;
446 if (anIndex > 0)
447 Required(inAttributes->AttributeData);
448
449 // modify the attributes
450
451 while (anIndex-- > 0) {
452
453 const CssmDbAttributeData &anAttribute = inAttributes->at(anIndex);
454 uint32 anAttributeIndex = attributeIndex(anAttribute.info());
455 if (anAttribute.format() != mAttributeVector[anAttributeIndex]->attributeFormat())
456 CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT);
457
458 CssmDbAttributeData &oldAttribute = attributeData[anAttributeIndex];
459
460 // if the modify mode is ADD, merge new values with pre-existing values
461
462 if (inModifyMode == CSSM_DB_MODIFY_ATTRIBUTE_ADD)
463 oldAttribute.add(anAttribute, anAllocator);
464
465 // if the modify mode is DELETE, remove the indicated values, or remove
466 // all values if none are specified
467
468 else if (inModifyMode == CSSM_DB_MODIFY_ATTRIBUTE_DELETE)
469 {
470 if (anAttribute.size() == 0)
471 oldAttribute.deleteValues(anAllocator);
472 else
473 oldAttribute.deleteValues(anAttribute, anAllocator);
474 }
475
476 // if the modify mode is REPLACE, then replace the specified values, or
477 // delete all values if no values are specified
478
479 else if (inModifyMode == CSSM_DB_MODIFY_ATTRIBUTE_REPLACE)
480 {
481 oldAttribute.deleteValues(anAllocator);
482 if (anAttribute.size() > 0)
483 oldAttribute.add(anAttribute, anAllocator);
484 else
485 // The spec says "all values are deleted or the the value is replaced
486 // with the default" but doesn't say which. We could call the parsing
487 // module for the attribute here...if they were implemented! But instead
488 // we choose "all values are deleted" and leave it at that.
489 ;
490 }
491 }
492 }
493
494 // write the resulting attributes into the new record
495
496 inWriteSection.put(OffsetSemanticInformation, oldSemanticInformation);
497
498 for (uint32 anIndex = 0; anIndex < mAttributeVector.size(); ++anIndex)
499 {
500 const MetaAttribute &metaAttribute = *mAttributeVector[anIndex];
501 metaAttribute.packAttribute(inWriteSection, anOffset,
502 attributeData[anIndex].NumberOfValues,
503 attributeData[anIndex].Value);
504 }
505
506 inWriteSection.put(OffsetRecordSize, anOffset);
507 inWriteSection.size(anOffset);
508 }
509