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 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 Apple Computer, 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 34namespace Security 35{ 36 37MDSAttrParser::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 73MDSAttrParser::~MDSAttrParser() 74{ 75 CF_RELEASE(mBundle); 76 delete [] mPath; 77 delete [] mGuid; 78} 79 80/********************* 81 Main public function. 82 83Parsing 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 101void 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 155void 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 215void 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 */ 267void 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 */ 283void 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 */ 300void 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 */ 347void 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 */ 361void 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 */ 422void 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 */ 569void 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 641