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