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