]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/MetaRecord.cpp
Security-164.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 try {
50 for (uint32 anIndex = 0; anIndex < inNumberOfAttributes; anIndex++)
51 {
52 string aName;
53 if (inAttributeInfo[anIndex].AttributeName)
54 aName = string(inAttributeInfo[anIndex].AttributeName);
55
56 const CssmData *aNameID = NULL;
57 if (inAttributeInfo[anIndex].AttributeNameID.Length > 0)
58 aNameID = &CssmData::overlay(inAttributeInfo[anIndex].AttributeNameID);
59
60 uint32 aNumber = inAttributeInfo[anIndex].AttributeId;
61 createAttribute(
62 inAttributeInfo[anIndex].AttributeName ? &aName : NULL,
63 aNameID, aNumber,
64 inAttributeInfo[anIndex].DataType);
65 }
66 }
67 catch (...)
68 {
69 for_each_delete(mAttributeVector.begin(), mAttributeVector.end());
70 }
71 }
72
73 MetaRecord::~MetaRecord()
74 {
75 for_each_delete(mAttributeVector.begin(), mAttributeVector.end());
76 }
77
78 void
79 MetaRecord::setRecordAttributeInfo(const CSSM_DB_RECORD_ATTRIBUTE_INFO &inInfo)
80 {
81 for (uint32 anIndex = 0; anIndex < inInfo.NumberOfAttributes; anIndex++)
82 {
83 switch (inInfo.AttributeInfo[anIndex].AttributeNameFormat)
84 {
85 case CSSM_DB_ATTRIBUTE_NAME_AS_STRING:
86 {
87 string aName(inInfo.AttributeInfo[anIndex].Label.AttributeName);
88 createAttribute(&aName, nil, anIndex,
89 inInfo.AttributeInfo[anIndex].AttributeFormat);
90 break;
91 }
92 case CSSM_DB_ATTRIBUTE_NAME_AS_OID:
93 {
94 const CssmData &aNameID = CssmOid::overlay(inInfo.AttributeInfo[anIndex].Label.AttributeOID);
95 createAttribute(nil, &aNameID, anIndex,
96 inInfo.AttributeInfo[anIndex].AttributeFormat);
97 break;
98 }
99 case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER:
100 {
101 uint32 aNumber = inInfo.AttributeInfo[anIndex].Label.AttributeID;
102 createAttribute(nil, nil, aNumber,
103 inInfo.AttributeInfo[anIndex].AttributeFormat);
104 break;
105 }
106 default:
107 CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME);
108 break;
109 }
110 }
111 }
112
113 void
114 MetaRecord::createAttribute(const string *inAttributeName,
115 const CssmOid *inAttributeOID,
116 uint32 inAttributeID,
117 CSSM_DB_ATTRIBUTE_FORMAT inAttributeFormat)
118 {
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;
124
125 if (inAttributeName)
126 {
127 if (!mNameStringMap.insert(NameStringMap::value_type(*inAttributeName, anAttributeIndex)).second)
128 CssmError::throwMe(CSSMERR_DL_FIELD_SPECIFIED_MULTIPLE);
129 aInsertedAttributeName = true;
130 }
131 try
132 {
133 if (inAttributeOID)
134 {
135 if (!mNameOIDMap.insert(NameOIDMap::value_type(*inAttributeOID, anAttributeIndex)).second)
136 CssmError::throwMe(CSSMERR_DL_FIELD_SPECIFIED_MULTIPLE);
137 aInsertedAttributeOID = true;
138 }
139
140 if (!mNameIntMap.insert(NameIntMap::value_type(inAttributeID, anAttributeIndex)).second)
141 CssmError::throwMe(CSSMERR_DL_FIELD_SPECIFIED_MULTIPLE);
142 aInsertedAttributeID = true;
143
144 // Note: this no longer throws INVALID_FIELD_NAME since the attribute will always have
145 // an attribute ID by which it is known
146
147 mAttributeVector.push_back(MetaAttribute::create(inAttributeFormat,
148 anAttributeIndex, inAttributeID));
149 }
150 catch(...)
151 {
152 if (aInsertedAttributeName)
153 mNameStringMap.erase(*inAttributeName);
154 if (aInsertedAttributeOID)
155 mNameOIDMap.erase(*inAttributeOID);
156 if (inAttributeID)
157 mNameIntMap.erase(inAttributeID);
158
159 throw;
160 }
161 }
162
163
164 // Create a packed record from the given inputs.
165 void
166 MetaRecord::packRecord(WriteSection &inWriteSection,
167 const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes,
168 const CssmData *inData) const
169 {
170 uint32 aDataSize;
171 if (inData)
172 aDataSize = inData->Length;
173 else
174 aDataSize = 0;
175
176 inWriteSection.put(OffsetDataSize, aDataSize);
177 uint32 anOffset = OffsetAttributeOffsets + AtomSize * mAttributeVector.size();
178 if (aDataSize)
179 anOffset = inWriteSection.put(anOffset, aDataSize, inData->Data);
180
181 vector<uint32> aNumValues(mAttributeVector.size(), ~0UL);
182 vector<CSSM_DATA_PTR> aValues(mAttributeVector.size());
183 uint32 anIndex;
184
185 if (inAttributes == NULL)
186 inWriteSection.put(OffsetSemanticInformation, 0);
187 else
188 {
189 inWriteSection.put(OffsetSemanticInformation, inAttributes->SemanticInformation);
190
191 // Put the supplied attribute values into the list of attributes
192 // and values.
193 anIndex = inAttributes->NumberOfAttributes;
194 // Make sure that AttributeData is a valid array.
195 if (anIndex > 0)
196 Required(inAttributes->AttributeData);
197
198 while (anIndex-- > 0)
199 {
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);
205
206 // If this attribute was specified before, throw.
207 if (aNumValues[anAttributeIndex] != ~0UL)
208 CssmError::throwMe(CSSMERR_DL_FIELD_SPECIFIED_MULTIPLE);
209
210 aNumValues[anAttributeIndex] = anAttribute.NumberOfValues;
211 aValues[anAttributeIndex] = anAttribute.Value;
212 }
213 }
214
215 for (anIndex = 0; anIndex < mAttributeVector.size(); ++anIndex)
216 {
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]);
223
224 // XXX When do we throw CSSMERR_DL_MISSING_VALUE? Maybe if an
225 // attribute is part of a unique index.
226
227 // Now we have a valuelist for this attribute. Let's encode it.
228 aMetaAttribute.packAttribute(inWriteSection, anOffset, aNumberOfValues, aValues[anIndex]);
229 }
230
231 inWriteSection.put(OffsetRecordSize, anOffset);
232 inWriteSection.size(anOffset);
233 }
234
235 inline void
236 MetaRecord::unpackAttribute(const ReadSection &inReadSection,
237 CssmAllocator &inAllocator,
238 CSSM_DB_ATTRIBUTE_DATA &inoutAttribute) const
239 {
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);
246 }
247
248 void
249 MetaRecord::unpackRecord(const ReadSection &inReadSection,
250 CssmAllocator &inAllocator,
251 CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes,
252 CssmData *inoutData,
253 CSSM_QUERY_FLAGS inQueryFlags) const
254 {
255 // XXX Use POD wrapper for inoutAttributes here.
256 TrackingAllocator anAllocator(inAllocator);
257 if (inoutData)
258 {
259 // XXX Treat KEY records specially.
260
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);
266 }
267
268 if (inoutAttributes)
269 {
270 inoutAttributes->DataRecordType = dataRecordType();
271 inoutAttributes->SemanticInformation = semanticInformation(inReadSection);
272 uint32 anIndex = inoutAttributes->NumberOfAttributes;
273
274 // Make sure that AttributeData is a valid array.
275 if (anIndex > 0 && inoutAttributes->AttributeData == NULL)
276 CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER);
277
278 while (anIndex-- > 0)
279 {
280 unpackAttribute(inReadSection, anAllocator,
281 inoutAttributes->AttributeData[anIndex]);
282 }
283 }
284
285 // Don't free anything the trackingAllocator allocated when it is destructed.
286 anAllocator.commit();
287 }
288
289 // Return the index (0 though NumAttributes - 1) of the attribute
290 // represented by inAttributeInfo
291
292 #ifndef NDEBUG
293 #define LOG_NAME_AS_STRING_FAIL
294 #endif
295 uint32
296 MetaRecord::attributeIndex(const CSSM_DB_ATTRIBUTE_INFO &inAttributeInfo) const
297 {
298 uint32 anIndex;
299 switch (inAttributeInfo.AttributeNameFormat)
300 {
301 case CSSM_DB_ATTRIBUTE_NAME_AS_STRING:
302 {
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();
312 it++) {
313 printf("name %s val %lu\n", it->first.c_str(), it->second);
314 }
315 #endif
316 CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME);
317 }
318 anIndex = it->second;
319 break;
320 }
321 case CSSM_DB_ATTRIBUTE_NAME_AS_OID:
322 {
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;
328 break;
329 }
330 case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER:
331 {
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;
337 break;
338 }
339 default:
340 CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME);
341 break;
342 }
343
344 return anIndex;
345 }
346
347 const MetaAttribute &
348 MetaRecord::metaAttribute(const CSSM_DB_ATTRIBUTE_INFO &inAttributeInfo) const
349 {
350 return *mAttributeVector[attributeIndex(inAttributeInfo)];
351 }
352
353 // Create a packed record from the given inputs and the old packed record inReadSection.
354 void
355 MetaRecord::updateRecord(const ReadSection &inReadSection,
356 WriteSection &inWriteSection,
357 const CssmDbRecordAttributeData *inAttributes,
358 const CssmData *inData,
359 CSSM_DB_MODIFY_MODE inModifyMode) const
360 {
361 TrackingAllocator anAllocator(CssmAllocator::standard());
362
363 // modify the opaque data associated with the record
364
365 uint32 aDataSize;
366 const uint8 *aDataData = NULL;
367
368 if (inData)
369 {
370 // prepare to write new data
371 aDataSize = inData->Length;
372 aDataData = inData->Data;
373 }
374 else
375 {
376 // prepare to copy old data
377 Range aDataRange = dataRange(inReadSection);
378 aDataSize = aDataRange.mSize;
379 if (aDataSize)
380 aDataData = inReadSection.range(aDataRange);
381 }
382
383 // compute the data offset; this will keep a running total of the record size
384 uint32 anOffset = OffsetAttributeOffsets + AtomSize * mAttributeVector.size();
385
386 // write the appropriate data to the new record
387 inWriteSection.put(OffsetDataSize, aDataSize);
388 if (aDataSize)
389 anOffset = inWriteSection.put(anOffset, aDataSize, aDataData);
390
391 // unpack the old attributes since some of them may need to be preserved
392
393 auto_array<CssmDbAttributeData> attributeData(mAttributeVector.size());
394
395 for (uint32 anAttributeIndex = mAttributeVector.size(); anAttributeIndex-- > 0; )
396 {
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);
402 }
403
404 // retrieve the currrent semantic information
405
406 uint32 oldSemanticInformation = semanticInformation(inReadSection);
407
408 // process each input attribute as necessary, based on the modification mode
409
410 if (inAttributes == NULL)
411 {
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);
416 }
417
418 else {
419
420 // modify the semantic information
421
422 uint32 inSemanticInformation = inAttributes ? inAttributes->SemanticInformation : 0;
423
424 if (inModifyMode == CSSM_DB_MODIFY_ATTRIBUTE_ADD)
425 oldSemanticInformation |= inSemanticInformation;
426
427 else if (inModifyMode == CSSM_DB_MODIFY_ATTRIBUTE_DELETE)
428 oldSemanticInformation &= ~inSemanticInformation;
429
430 else if (inModifyMode == CSSM_DB_MODIFY_ATTRIBUTE_REPLACE)
431 oldSemanticInformation = inSemanticInformation;
432
433 uint32 anIndex = inAttributes->NumberOfAttributes;
434 if (anIndex > 0)
435 Required(inAttributes->AttributeData);
436
437 // modify the attributes
438
439 while (anIndex-- > 0) {
440
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);
445
446 CssmDbAttributeData &oldAttribute = attributeData[anAttributeIndex];
447
448 // if the modify mode is ADD, merge new values with pre-existing values
449
450 if (inModifyMode == CSSM_DB_MODIFY_ATTRIBUTE_ADD)
451 oldAttribute.add(anAttribute, anAllocator);
452
453 // if the modify mode is DELETE, remove the indicated values, or remove
454 // all values if none are specified
455
456 else if (inModifyMode == CSSM_DB_MODIFY_ATTRIBUTE_DELETE)
457 {
458 if (anAttribute.size() == 0)
459 oldAttribute.deleteValues(anAllocator);
460 else
461 oldAttribute.deleteValues(anAttribute, anAllocator);
462 }
463
464 // if the modify mode is REPLACE, then replace the specified values, or
465 // delete all values if no values are specified
466
467 else if (inModifyMode == CSSM_DB_MODIFY_ATTRIBUTE_REPLACE)
468 {
469 oldAttribute.deleteValues(anAllocator);
470 if (anAttribute.size() > 0)
471 oldAttribute.add(anAttribute, anAllocator);
472 else
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.
477 ;
478 }
479 }
480 }
481
482 // write the resulting attributes into the new record
483
484 inWriteSection.put(OffsetSemanticInformation, oldSemanticInformation);
485
486 for (uint32 anIndex = 0; anIndex < mAttributeVector.size(); ++anIndex)
487 {
488 const MetaAttribute &metaAttribute = *mAttributeVector[anIndex];
489 metaAttribute.packAttribute(inWriteSection, anOffset,
490 attributeData[anIndex].NumberOfValues,
491 attributeData[anIndex].Value);
492 }
493
494 inWriteSection.put(OffsetRecordSize, anOffset);
495 inWriteSection.size(anOffset);
496 }
497