]> git.saurik.com Git - apple/security.git/blob - Security/libsecurity_mds/lib/MDSAttrParser.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / Security / libsecurity_mds / lib / MDSAttrParser.cpp
1 /*
2 * Copyright (c) 2000-2001,2011-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 File: MDSAttrParser.cpp
21
22 Contains: Classes to parse XML plists and fill in MDS DBs with the
23 attributes found there.
24
25 Copyright (c) 2001,2011-2014 Apple Inc. All Rights Reserved.
26 */
27
28 #include "MDSAttrParser.h"
29 #include "MDSAttrUtils.h"
30 #include "MDSDictionary.h"
31 #include <security_utilities/logging.h>
32 #include <Security/mds_schema.h>
33
34 namespace Security
35 {
36
37 MDSAttrParser::MDSAttrParser(
38 const char *bundlePath,
39 MDSSession &dl,
40 CSSM_DB_HANDLE objectHand,
41 CSSM_DB_HANDLE cdsaDirHand) :
42 mBundle(NULL),
43 mPath(NULL),
44 mDl(dl),
45 mObjectHand(objectHand),
46 mCdsaDirHand(cdsaDirHand),
47 mGuid(NULL),
48 mDefaults(NULL)
49 {
50 /* Only task here is to cook up a CFBundle for the specified path */
51 size_t pathLen = strlen(bundlePath);
52 CFURLRef url = CFURLCreateFromFileSystemRepresentation(NULL,
53 (unsigned char *)bundlePath,
54 pathLen,
55 false);
56 if(url == NULL) {
57 Syslog::alert("CFURLCreateFromFileSystemRepresentation(%s) failure", mPath);
58 CssmError::throwMe(CSSMERR_DL_INVALID_DB_NAME);
59 }
60
61 /* FIXME - this leaks 28 bytes each time thru, even though we CFRelease the
62 * mBundle in out destructor. I think this is a CF leak. */
63 mBundle = CFBundleCreate(NULL, url);
64 CFRelease(url);
65 if(mBundle == NULL) {
66 Syslog::alert("CFBundleCreate(%s) failure", mPath);
67 CssmError::throwMe(CSSMERR_DL_INVALID_DB_NAME);
68 }
69 mPath = new char[pathLen + 1];
70 strcpy(mPath, bundlePath);
71 }
72
73 MDSAttrParser::~MDSAttrParser()
74 {
75 CF_RELEASE(mBundle);
76 delete [] mPath;
77 delete [] mGuid;
78 }
79
80 /*********************
81 Main public function.
82
83 Parsing bundle {
84 get all *.mdsinfo files;
85 for each mdsinfo {
86 get contents of that file as dictionary;
87 switch (ModuleType) {
88 case CSSM:
89 parse this mdsinfo --> MDS_OBJECT_RECORDTYPE, MDS_CDSADIR_CSSM_RECORDTYPE;
90 break;
91 case Plugin:
92 parse this info --> MDS_OBJECT_RECORDTYPE, MDS_CDSADIR_COMMON_RECORDTYPE;
93 case PluginInfo:
94 recordType = lookup("MdsRecordType");
95 dispatch to recordtype-specific parsing;
96 }
97 }
98 }
99 ************/
100
101 void MDSAttrParser::parseAttrs(CFStringRef subdir)
102 {
103 /* get all *.mdsinfo files */
104 CFArrayRef bundleInfoFiles = CFBundleCopyResourceURLsOfType(mBundle,
105 CFSTR(MDS_INFO_TYPE),
106 subdir);
107 if(bundleInfoFiles == NULL) {
108 Syslog::alert("MDSAttrParser: no mdsattr files for %s", mPath);
109 return;
110 }
111 assert(CFGetTypeID(bundleInfoFiles) == CFArrayGetTypeID());
112
113 /* process each .mdsinfo file */
114 CFIndex numFiles = CFArrayGetCount(bundleInfoFiles);
115 for(CFIndex i=0; i<numFiles; i++) {
116 /* get filename as CFURL */
117 CFURLRef infoUrl = NULL;
118
119 infoUrl = reinterpret_cast<CFURLRef>(
120 CFArrayGetValueAtIndex(bundleInfoFiles, i));
121 if(infoUrl == NULL) {
122 MPDebug("MDSAttrParser: CFBundleCopyResourceURLsOfType screwup 1");
123 continue;
124 }
125 if(CFGetTypeID(infoUrl) != CFURLGetTypeID()) {
126 MPDebug("MDSAttrParser: CFBundleCopyResourceURLsOfType screwup 2");
127 continue;
128 }
129
130 // @@@ Workaround for 4234967: skip any filename beginning with "._"
131 CFStringRef lastComponent = CFURLCopyLastPathComponent(infoUrl);
132 if (lastComponent) {
133 CFStringRef resFilePfx = CFSTR("._");
134 // setting the search length and location like this permits,
135 // e.g., ".foo.mdsinfo" to be valid
136 CFIndex resFilePfxLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(resFilePfx), kCFStringEncodingUTF8);
137 CFRange range = CFRangeMake(0, resFilePfxLen);
138 Boolean skip = CFStringFindWithOptions(lastComponent,
139 resFilePfx,
140 range,
141 0/*options*/,
142 NULL/*returned substr*/);
143 CFRelease(lastComponent);
144 if (skip == true) {
145 Syslog::warning("MDSAttrParser: ignoring resource file");
146 continue;
147 }
148 }
149
150 parseFile(infoUrl, subdir);
151 } /* for each mdsinfo */
152 CF_RELEASE(bundleInfoFiles);
153 }
154
155 void MDSAttrParser::parseFile(CFURLRef infoUrl, CFStringRef subdir)
156 {
157 CFStringRef infoType = NULL;
158
159 /* Get contents of mdsinfo file as dictionary */
160 MDSDictionary mdsDict(infoUrl, subdir, mPath);
161 /* Make sure we set all possible MDS values before checking for GUID */
162 mdsDict.setDefaults(mDefaults);
163 if (mGuid == NULL) {
164 CFStringRef guid = (CFStringRef)mdsDict.lookup("ModuleID", true, CFStringGetTypeID());
165 if (guid) {
166 CFIndex copylen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(guid), kCFStringEncodingUTF8) + 1/*nul terminator*/;
167 mGuid = new char[copylen];
168 if (false == CFStringGetCString(guid, mGuid, copylen, kCFStringEncodingUTF8)) {
169 logFileError("Error copying GUID", infoUrl, NULL, NULL);
170 delete [] mGuid;
171 mGuid = NULL;
172 CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR);
173 }
174 }
175 else {
176 logFileError("No GUID associated with plugin?", infoUrl, NULL, NULL);
177 CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR);
178 }
179 }
180
181 MPDebug("Parsing mdsinfo file %s", mdsDict.fileDesc());
182
183 /* Determine what kind of info file this is and dispatch accordingly */
184 infoType = (CFStringRef)mdsDict.lookup(CFSTR(MDS_INFO_FILE_TYPE),
185 true, CFStringGetTypeID());
186 if(infoType == NULL) {
187 logFileError("Malformed MDS Info file", infoUrl, NULL, NULL);
188 CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR);
189 }
190
191 /* be robust here, errors in these low-level routines do not affect
192 * the rest of our task */
193 try {
194 if(CFStringCompare(infoType, CFSTR(MDS_INFO_FILE_TYPE_CSSM), 0)
195 == kCFCompareEqualTo) {
196 parseCssmInfo(&mdsDict);
197 }
198 else if(CFStringCompare(infoType, CFSTR(MDS_INFO_FILE_TYPE_PLUGIN), 0)
199 == kCFCompareEqualTo) {
200 parsePluginCommon(&mdsDict);
201 }
202 else if(CFStringCompare(infoType, CFSTR(MDS_INFO_FILE_TYPE_RECORD), 0)
203 == kCFCompareEqualTo) {
204 parsePluginSpecific(&mdsDict);
205 }
206 else {
207 logFileError("Malformed MDS Info file", infoUrl, NULL, NULL);
208 }
209 }
210 catch(...) {
211
212 }
213 }
214
215 void MDSAttrParser::logFileError(
216 const char *op,
217 CFURLRef fileUrl,
218 CFStringRef errStr, // optional if you have it
219 SInt32 *errNo) // optional if you have it
220 {
221 CFStringRef urlStr = CFURLGetString(fileUrl);
222 const char *cUrlStr = CFStringGetCStringPtr(urlStr, kCFStringEncodingUTF8);
223 char* stringBuffer = NULL;
224
225 if (cUrlStr == NULL)
226 {
227 CFIndex maxLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(urlStr), kCFStringEncodingUTF8) + 1;
228 stringBuffer = (char*) malloc(maxLen);
229 CFStringGetCString(urlStr, stringBuffer, maxLen, kCFStringEncodingUTF8);
230 cUrlStr = stringBuffer;
231 }
232
233 if(errStr) {
234 const char *cerrStr = CFStringGetCStringPtr(errStr, kCFStringEncodingUTF8);
235 char* sbuf2 = NULL;
236
237 if (cerrStr == NULL)
238 {
239 CFIndex maxLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(errStr), kCFStringEncodingUTF8) + 1;
240 sbuf2 = (char*) malloc(maxLen);
241 CFStringGetCString(urlStr, sbuf2, maxLen, kCFStringEncodingUTF8);
242 cUrlStr = sbuf2;
243 }
244
245 Syslog::alert("MDS: %s: bundle %s url %s: error %s",
246 op, mPath, cUrlStr, cerrStr);
247
248 if (sbuf2 != NULL)
249 {
250 free(sbuf2);
251 }
252 }
253 else {
254 Syslog::alert("MDS: %s: bundle %s url %s: error %d",
255 op, mPath, cUrlStr, (int)(errNo ? *errNo : 0));
256 }
257
258 if (stringBuffer != NULL)
259 {
260 free(stringBuffer);
261 }
262 }
263
264 /*
265 * Parse a CSSM info file.
266 */
267 void MDSAttrParser::parseCssmInfo(
268 MDSDictionary *mdsDict)
269 {
270 /* first get object info */
271 parseObjectRecord(mdsDict);
272
273 /* now CSSM relation */
274 const RelationInfo *relationInfo =
275 MDSRecordTypeToRelation(MDS_CDSADIR_CSSM_RECORDTYPE);
276 assert(relationInfo != NULL);
277 parseMdsRecord(mdsDict, relationInfo, mCdsaDirHand);
278 }
279
280 /*
281 * Parse a PluginCommon file.
282 */
283 void MDSAttrParser::parsePluginCommon(
284 MDSDictionary *mdsDict)
285 {
286
287 /* first get object info */
288 parseObjectRecord(mdsDict);
289
290 /* now common relation */
291 const RelationInfo *relationInfo =
292 MDSRecordTypeToRelation(MDS_CDSADIR_COMMON_RECORDTYPE);
293 assert(relationInfo != NULL);
294 parseMdsRecord(mdsDict, relationInfo, mCdsaDirHand);
295 }
296
297 /*
298 * Parse a Plugin Specific file.
299 */
300 void MDSAttrParser::parsePluginSpecific(
301 MDSDictionary *mdsDict)
302 {
303 /* determine record type from the file itself */
304 CFStringRef recordTypeStr =
305 (CFStringRef)mdsDict->lookup(MDS_INFO_FILE_RECORD_TYPE,
306 true, CFStringGetTypeID());
307 if(recordTypeStr == NULL) {
308 MPDebug("%s: no %s record found\n", mdsDict->fileDesc(),
309 MDS_INFO_FILE_RECORD_TYPE);
310 return;
311 }
312
313 /* convert to a known schema */
314 const char *recordTypeCStr = MDSCFStringToCString(recordTypeStr);
315 const RelationInfo *relationInfo = MDSRecordTypeNameToRelation(recordTypeCStr);
316 if(relationInfo == NULL) {
317 Syslog::alert("MDS file %s has unsupported record type %s",
318 mdsDict->fileDesc(), recordTypeCStr);
319 MPDebug("MDS file %s has unsupported record type %s",
320 mdsDict->fileDesc(), recordTypeCStr);
321 delete [] recordTypeCStr;
322 return;
323 }
324 MPDebug("Parsing MDS file %s, recordType %s", mdsDict->fileDesc(), recordTypeCStr);
325 delete [] recordTypeCStr;
326
327 /* handle special cases here */
328 switch(relationInfo->DataRecordType) {
329 case MDS_CDSADIR_CSP_CAPABILITY_RECORDTYPE:
330 parseCspCapabilitiesRecord(mdsDict);
331 break;
332 case MDS_CDSADIR_TP_OIDS_RECORDTYPE:
333 parseTpPolicyOidsRecord(mdsDict);
334 break;
335 default:
336 /* all (normal) linear schema */
337 parseMdsRecord(mdsDict, relationInfo, mCdsaDirHand);
338 }
339 }
340
341
342 /*
343 * Given an open MDSDictionary, create an MDS_OBJECT_RECORDTYPE record and
344 * add it to mObjectHand. Used when parsing both CSSM records and MOduleCommon
345 * records.
346 */
347 void MDSAttrParser::parseObjectRecord(
348 MDSDictionary *mdsDict)
349 {
350 assert(mdsDict != NULL);
351 assert(mObjectHand != 0);
352 parseMdsRecord(mdsDict, &kObjectRelation, mObjectHand);
353
354 }
355
356 /*
357 * Given an open dictionary and a RelationInfo defining a schema, fetch all
358 * attributes associated with the specified schema from the dictionary
359 * and write them to specified DB.
360 */
361 void MDSAttrParser::parseMdsRecord(
362 MDSDictionary *mdsDict,
363 const RelationInfo *relInfo,
364 CSSM_DB_HANDLE dbHand)
365 {
366 assert(mdsDict != NULL);
367 assert(relInfo != NULL);
368 assert(dbHand != 0);
369
370 /*
371 * malloc an CSSM_DB_ATTRIBUTE_DATA array associated with specified schema.
372 */
373 unsigned numSchemaAttrs = relInfo->NumberOfAttributes;
374 CSSM_DB_ATTRIBUTE_DATA *dbAttrs = new CSSM_DB_ATTRIBUTE_DATA[numSchemaAttrs];
375
376 /*
377 * Grind thru the attributes in the specified schema. Do not assume the presence
378 * of any given attribute.
379 */
380 uint32 foundAttrs = 0;
381 mdsDict->lookupAttributes(relInfo, dbAttrs, foundAttrs);
382
383 /* write to the DB */
384 MDSInsertRecord(dbAttrs, foundAttrs, relInfo->DataRecordType, mDl, dbHand);
385
386 MDSFreeDbRecordAttrs(dbAttrs, foundAttrs);
387 delete [] dbAttrs;
388 }
389
390 /*
391 * Parse CSP capabilities. This is much more complicated than most records.
392 * The propertly list (*.mdsinfo) is set up like this:
393 *
394 * root(Dictionary) {
395 * ModuleID(String)
396 * SSID(Number)
397 * Capabilities(Array) {
398 * index 0(Dictionary) {
399 * AlgType(String) -- CSSM_ALGID_SHA1
400 * ContextType(String) -- CSSM_ALGCLASS_DIGEST
401 * UseeTag(String) -- CSSM_USEE_NONE
402 * Description(String) -- "SHA1 Digest"
403 * Attributes(Array)
404 * index 0(Dictionary)
405 * AttributeType(String) -- CSSM_ATTRIBUTE_OUTPUT_SIZE
406 * AttributeValue(Array) {
407 * index 0(Number) -- 20
408 * ...
409 * }
410 * index n ...
411 * }
412 * index n...
413 * }
414 * }
415 *
416 * The plist can specify multiple Capabilities, multiple Attributes for each
417 * Capability, and multiple values for each Attribute. (Note that MULTI_UINT32
418 * in the DB is represented in the plist as an Array of Numbers.) Each element
419 * of each Attributes array maps to one record in the DB. The GroupID attribute
420 * of a record is the index into the plist's Capabilities array.
421 */
422 void MDSAttrParser::parseCspCapabilitiesRecord(
423 MDSDictionary *mdsDict)
424 {
425 /*
426 * Malloc an attribute array big enough for the whole schema. We're going
427 * to re-use this array every time we write a new record. Portions of
428 * the array are invariant for some inner loops.
429 */
430 const RelationInfo *topRelInfo =
431 MDSRecordTypeToRelation(MDS_CDSADIR_CSP_CAPABILITY_RECORDTYPE);
432 assert(topRelInfo != NULL);
433 uint32 numInAttrs = topRelInfo->NumberOfAttributes;
434 CSSM_DB_ATTRIBUTE_DATA_PTR outAttrs = new CSSM_DB_ATTRIBUTE_DATA[numInAttrs];
435
436 /* these attrs are only set once, then they remain invariant */
437 uint32 numTopLevelAttrs;
438 mdsDict->lookupAttributes(&CSPCapabilitiesDict1RelInfo, outAttrs,
439 numTopLevelAttrs);
440
441 bool fetchedFromDisk = false;
442
443 /* obtain Capabilities array */
444 CFArrayRef capArray = (CFArrayRef)mdsDict->lookupWithIndirect("Capabilities",
445 mBundle,
446 CFArrayGetTypeID(),
447 fetchedFromDisk);
448 if(capArray == NULL) {
449 /* well we did not get very far.... */
450 MPDebug("parseCspCapabilitiesRecord: no (or bad) Capabilities");
451 delete [] outAttrs;
452 return;
453 }
454
455 /*
456 * Descend into Capabilities array. Each element is a dictionary defined
457 * by CSPCapabilitiesDict2RelInfo.
458 */
459 CFIndex capArraySize = CFArrayGetCount(capArray);
460 CFIndex capDex;
461 for(capDex=0; capDex<capArraySize; capDex++) {
462 MPDebug("...parsing Capability %d", (int)capDex);
463 CFDictionaryRef capDict =
464 (CFDictionaryRef)CFArrayGetValueAtIndex(capArray, capDex);
465 if((capDict == NULL) ||
466 (CFGetTypeID(capDict) != CFDictionaryGetTypeID())) {
467 MPDebug("parseCspCapabilitiesRecord: bad Capabilities element");
468 break;
469 }
470 MDSDictionary capDictMds(capDict);
471
472 /*
473 * Append this dictionary's attributes to outAttrs, after the fixed
474 * attributes from CSPCapabilitiesDict1RelInfo.
475 */
476 uint32 numCapDictAttrs;
477 capDictMds.lookupAttributes(&CSPCapabilitiesDict2RelInfo,
478 &outAttrs[numTopLevelAttrs],
479 numCapDictAttrs);
480
481 /*
482 * Append the GroupId attribute, which we infer from the current index
483 * into Capabilitites. However, thou shalt not use > 4-byte values
484 * for MDS, so convert from CFIndex first.
485 */
486 if (capDex > uint32(~0)) {
487 MPDebug("parseCspCapabilitiesRecord: too large an index for MDS");
488 break;
489 }
490 uint32 index32 = uint32(capDex);
491 MDSRawValueToDbAttr(&index32, sizeof(index32), CSSM_DB_ATTRIBUTE_FORMAT_UINT32,
492 "GroupId", outAttrs[numTopLevelAttrs + numCapDictAttrs]);
493 numCapDictAttrs++;
494
495 /*
496 * Now descend into the array of this capability's attributes.
497 * Each element is a dictionary defined by
498 * by CSPCapabilitiesDict3RelInfo.
499 */
500 CFArrayRef attrArray = (CFArrayRef)capDictMds.lookup("Attributes",
501 true, CFArrayGetTypeID());
502 if(attrArray == NULL) {
503 MPDebug("parseCspCapabilitiesRecord: no (or bad) Attributes");
504 break;
505 }
506 CFIndex attrArraySize = CFArrayGetCount(attrArray);
507 CFIndex attrDex;
508 for(attrDex=0; attrDex<attrArraySize; attrDex++) {
509 MPDebug(" ...parsing Attribute %d", (int)attrDex);
510 CFDictionaryRef attrDict =
511 (CFDictionaryRef)CFArrayGetValueAtIndex(attrArray, attrDex);
512 if((attrDict == NULL) ||
513 (CFGetTypeID(attrDict) != CFDictionaryGetTypeID())) {
514 MPDebug("parseCspCapabilitiesRecord: bad Attributes element");
515 break;
516 }
517 MDSDictionary attrDictMds(attrDict);
518
519 /*
520 * Append this dictionary's attributes to outAttrs, after the fixed
521 * attributes from CSPCapabilitiesDict1RelInfo and this capability's
522 * CSPCapabilitiesDict2RelInfo.
523 */
524 uint32 numAttrDictAttrs;
525 attrDictMds.lookupAttributes(&CSPCapabilitiesDict3RelInfo,
526 &outAttrs[numTopLevelAttrs + numCapDictAttrs],
527 numAttrDictAttrs);
528
529 /* write to DB */
530 MDSInsertRecord(outAttrs,
531 numTopLevelAttrs + numCapDictAttrs + numAttrDictAttrs,
532 MDS_CDSADIR_CSP_CAPABILITY_RECORDTYPE,
533 mDl,
534 mCdsaDirHand);
535
536 /* just free the attrs we allocated in this loop */
537 MDSFreeDbRecordAttrs(&outAttrs[numTopLevelAttrs + numCapDictAttrs],
538 numAttrDictAttrs);
539 } /* for each attribute */
540 /* just free the attrs we allocated in this loop */
541 MDSFreeDbRecordAttrs(&outAttrs[numTopLevelAttrs], numCapDictAttrs);
542 } /* for each capability */
543
544 MDSFreeDbRecordAttrs(outAttrs, numTopLevelAttrs);
545 delete [] outAttrs;
546 if(fetchedFromDisk) {
547 CF_RELEASE(capArray);
548 }
549 }
550
551 /*
552 * Parse TP Policy OIDs.
553 * The propertly list (*.mdsinfo) is set up like this:
554 *
555 * root(Dictionary) {
556 * ModuleID(String)
557 * SSID(Number)
558 * Policies(Array) {
559 * index 0(Dictionary) {
560 * OID(Data) -- <092a8648 86f76364 0102>
561 * Value(Data) -- optional, OID-specific
562 * index n...
563 * }
564 * }
565 *
566 * The plist can specify multiple Policies. Each element of the Policies
567 * array maps to one record in the DB.
568 */
569 void MDSAttrParser::parseTpPolicyOidsRecord(
570 MDSDictionary *mdsDict)
571 {
572 /*
573 * Malloc an attribute array big enough for the whole schema. We're going
574 * to re-use this array every time we write a new record. Portions of
575 * the array are invariant for some inner loops.
576 */
577 const RelationInfo *topRelInfo =
578 MDSRecordTypeToRelation(MDS_CDSADIR_TP_OIDS_RECORDTYPE);
579 assert(topRelInfo != NULL);
580 uint32 numInAttrs = topRelInfo->NumberOfAttributes;
581 CSSM_DB_ATTRIBUTE_DATA_PTR outAttrs = new CSSM_DB_ATTRIBUTE_DATA[numInAttrs];
582
583 /* these attrs are only set once, then they remain invariant */
584 uint32 numTopLevelAttrs;
585 mdsDict->lookupAttributes(&TpPolicyOidsDict1RelInfo, outAttrs,
586 numTopLevelAttrs);
587
588 /* obtain Policies array */
589 CFArrayRef policyArray = (CFArrayRef)mdsDict->lookup("Policies",
590 true, CFArrayGetTypeID());
591 if(policyArray == NULL) {
592 /* well we did not get very far.... */
593 MPDebug("parseTpPolicyOidsRecord: no (or bad) Policies");
594 delete [] outAttrs;
595 return;
596 }
597
598 /*
599 * Descend into Policies array. Each element is a dictionary defined
600 * by TpPolicyOidsDict2RelInfo.
601 */
602 CFIndex policyArraySize = CFArrayGetCount(policyArray);
603 CFIndex policyDex;
604 for(policyDex=0; policyDex<policyArraySize; policyDex++) {
605 MPDebug("...parsing Policy %d", (int)policyDex);
606 CFDictionaryRef policyDict =
607 (CFDictionaryRef)CFArrayGetValueAtIndex(policyArray, policyDex);
608 if((policyDict == NULL) ||
609 (CFGetTypeID(policyDict) != CFDictionaryGetTypeID())) {
610 MPDebug("parseTpPolicyOidsRecord: bad Policies element");
611 break;
612 }
613 MDSDictionary policyDictMds(policyDict);
614
615 /*
616 * Append this dictionary's attributes to outAttrs, after the fixed
617 * attributes from TpPolicyOidsDict1RelInfo.
618 */
619 uint32 numPolicyDictAttrs;
620 policyDictMds.lookupAttributes(&TpPolicyOidsDict2RelInfo,
621 &outAttrs[numTopLevelAttrs],
622 numPolicyDictAttrs);
623
624
625 /* write to DB */
626 MDSInsertRecord(outAttrs,
627 numTopLevelAttrs + numPolicyDictAttrs,
628 MDS_CDSADIR_TP_OIDS_RECORDTYPE,
629 mDl,
630 mCdsaDirHand);
631
632 /* free the attrs allocated in this loop */
633 MDSFreeDbRecordAttrs(outAttrs + numTopLevelAttrs, numPolicyDictAttrs);
634 } /* for each policy */
635 MDSFreeDbRecordAttrs(outAttrs, numTopLevelAttrs);
636 delete [] outAttrs;
637 }
638
639
640 } // end namespace Security