]> git.saurik.com Git - apple/security.git/blob - libsecurity_mds/lib/MDSAttrParser.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_mds / lib / MDSAttrParser.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 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
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 unsigned 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 const char *cerrStr = NULL;
222 CFStringRef urlStr = CFURLGetString(fileUrl);
223 const char *cUrlStr = CFStringGetCStringPtr(urlStr, kCFStringEncodingUTF8);
224
225 if(errStr) {
226 cerrStr = CFStringGetCStringPtr(errStr, kCFStringEncodingUTF8);
227 Syslog::alert("MDS: %s: bundle %s url %s: error %s",
228 op, mPath, cUrlStr, cerrStr);
229 }
230 else {
231 Syslog::alert("MDS: %s: bundle %s url %s: error %d",
232 op, mPath, cUrlStr, errNo ? *errNo : 0);
233 }
234 }
235
236 /*
237 * Parse a CSSM info file.
238 */
239 void MDSAttrParser::parseCssmInfo(
240 MDSDictionary *mdsDict)
241 {
242 /* first get object info */
243 parseObjectRecord(mdsDict);
244
245 /* now CSSM relation */
246 const RelationInfo *relationInfo =
247 MDSRecordTypeToRelation(MDS_CDSADIR_CSSM_RECORDTYPE);
248 assert(relationInfo != NULL);
249 parseMdsRecord(mdsDict, relationInfo, mCdsaDirHand);
250 }
251
252 /*
253 * Parse a PluginCommon file.
254 */
255 void MDSAttrParser::parsePluginCommon(
256 MDSDictionary *mdsDict)
257 {
258
259 /* first get object info */
260 parseObjectRecord(mdsDict);
261
262 /* now common relation */
263 const RelationInfo *relationInfo =
264 MDSRecordTypeToRelation(MDS_CDSADIR_COMMON_RECORDTYPE);
265 assert(relationInfo != NULL);
266 parseMdsRecord(mdsDict, relationInfo, mCdsaDirHand);
267 }
268
269 /*
270 * Parse a Plugin Specific file.
271 */
272 void MDSAttrParser::parsePluginSpecific(
273 MDSDictionary *mdsDict)
274 {
275 /* determine record type from the file itself */
276 CFStringRef recordTypeStr =
277 (CFStringRef)mdsDict->lookup(MDS_INFO_FILE_RECORD_TYPE,
278 true, CFStringGetTypeID());
279 if(recordTypeStr == NULL) {
280 MPDebug("%s: no %s record found\n", mdsDict->fileDesc(),
281 MDS_INFO_FILE_RECORD_TYPE);
282 return;
283 }
284
285 /* convert to a known schema */
286 const char *recordTypeCStr = MDSCFStringToCString(recordTypeStr);
287 const RelationInfo *relationInfo = MDSRecordTypeNameToRelation(recordTypeCStr);
288 if(relationInfo == NULL) {
289 Syslog::alert("MDS file %s has unsupported record type %s",
290 mdsDict->fileDesc(), recordTypeCStr);
291 MPDebug("MDS file %s has unsupported record type %s",
292 mdsDict->fileDesc(), recordTypeCStr);
293 delete [] recordTypeCStr;
294 return;
295 }
296 MPDebug("Parsing MDS file %s, recordType %s", mdsDict->fileDesc(), recordTypeCStr);
297 delete [] recordTypeCStr;
298
299 /* handle special cases here */
300 switch(relationInfo->DataRecordType) {
301 case MDS_CDSADIR_CSP_CAPABILITY_RECORDTYPE:
302 parseCspCapabilitiesRecord(mdsDict);
303 break;
304 case MDS_CDSADIR_TP_OIDS_RECORDTYPE:
305 parseTpPolicyOidsRecord(mdsDict);
306 break;
307 default:
308 /* all (normal) linear schema */
309 parseMdsRecord(mdsDict, relationInfo, mCdsaDirHand);
310 }
311 }
312
313
314 /*
315 * Given an open MDSDictionary, create an MDS_OBJECT_RECORDTYPE record and
316 * add it to mObjectHand. Used when parsing both CSSM records and MOduleCommon
317 * records.
318 */
319 void MDSAttrParser::parseObjectRecord(
320 MDSDictionary *mdsDict)
321 {
322 assert(mdsDict != NULL);
323 assert(mObjectHand != 0);
324 parseMdsRecord(mdsDict, &kObjectRelation, mObjectHand);
325
326 }
327
328 /*
329 * Given an open dictionary and a RelationInfo defining a schema, fetch all
330 * attributes associated with the specified schema from the dictionary
331 * and write them to specified DB.
332 */
333 void MDSAttrParser::parseMdsRecord(
334 MDSDictionary *mdsDict,
335 const RelationInfo *relInfo,
336 CSSM_DB_HANDLE dbHand)
337 {
338 assert(mdsDict != NULL);
339 assert(relInfo != NULL);
340 assert(dbHand != 0);
341
342 /*
343 * malloc an CSSM_DB_ATTRIBUTE_DATA array associated with specified schema.
344 */
345 unsigned numSchemaAttrs = relInfo->NumberOfAttributes;
346 CSSM_DB_ATTRIBUTE_DATA *dbAttrs = new CSSM_DB_ATTRIBUTE_DATA[numSchemaAttrs];
347
348 /*
349 * Grind thru the attributes in the specified schema. Do not assume the presence
350 * of any given attribute.
351 */
352 uint32 foundAttrs = 0;
353 mdsDict->lookupAttributes(relInfo, dbAttrs, foundAttrs);
354
355 /* write to the DB */
356 MDSInsertRecord(dbAttrs, foundAttrs, relInfo->DataRecordType, mDl, dbHand);
357
358 MDSFreeDbRecordAttrs(dbAttrs, foundAttrs);
359 delete [] dbAttrs;
360 }
361
362 /*
363 * Parse CSP capabilities. This is much more complicated than most records.
364 * The propertly list (*.mdsinfo) is set up like this:
365 *
366 * root(Dictionary) {
367 * ModuleID(String)
368 * SSID(Number)
369 * Capabilities(Array) {
370 * index 0(Dictionary) {
371 * AlgType(String) -- CSSM_ALGID_SHA1
372 * ContextType(String) -- CSSM_ALGCLASS_DIGEST
373 * UseeTag(String) -- CSSM_USEE_NONE
374 * Description(String) -- "SHA1 Digest"
375 * Attributes(Array)
376 * index 0(Dictionary)
377 * AttributeType(String) -- CSSM_ATTRIBUTE_OUTPUT_SIZE
378 * AttributeValue(Array) {
379 * index 0(Number) -- 20
380 * ...
381 * }
382 * index n ...
383 * }
384 * index n...
385 * }
386 * }
387 *
388 * The plist can specify multiple Capabilities, multiple Attributes for each
389 * Capability, and multiple values for each Attribute. (Note that MULTI_UINT32
390 * in the DB is represented in the plist as an Array of Numbers.) Each element
391 * of each Attributes array maps to one record in the DB. The GroupID attribute
392 * of a record is the index into the plist's Capabilities array.
393 */
394 void MDSAttrParser::parseCspCapabilitiesRecord(
395 MDSDictionary *mdsDict)
396 {
397 /*
398 * Malloc an attribute array big enough for the whole schema. We're going
399 * to re-use this array every time we write a new record. Portions of
400 * the array are invariant for some inner loops.
401 */
402 const RelationInfo *topRelInfo =
403 MDSRecordTypeToRelation(MDS_CDSADIR_CSP_CAPABILITY_RECORDTYPE);
404 assert(topRelInfo != NULL);
405 uint32 numInAttrs = topRelInfo->NumberOfAttributes;
406 CSSM_DB_ATTRIBUTE_DATA_PTR outAttrs = new CSSM_DB_ATTRIBUTE_DATA[numInAttrs];
407
408 /* these attrs are only set once, then they remain invariant */
409 uint32 numTopLevelAttrs;
410 mdsDict->lookupAttributes(&CSPCapabilitiesDict1RelInfo, outAttrs,
411 numTopLevelAttrs);
412
413 bool fetchedFromDisk = false;
414
415 /* obtain Capabilities array */
416 CFArrayRef capArray = (CFArrayRef)mdsDict->lookupWithIndirect("Capabilities",
417 mBundle,
418 CFArrayGetTypeID(),
419 fetchedFromDisk);
420 if(capArray == NULL) {
421 /* well we did not get very far.... */
422 MPDebug("parseCspCapabilitiesRecord: no (or bad) Capabilities");
423 delete [] outAttrs;
424 return;
425 }
426
427 /*
428 * Descend into Capabilities array. Each element is a dictionary defined
429 * by CSPCapabilitiesDict2RelInfo.
430 */
431 CFIndex capArraySize = CFArrayGetCount(capArray);
432 CFIndex capDex;
433 for(capDex=0; capDex<capArraySize; capDex++) {
434 MPDebug("...parsing Capability %d", (int)capDex);
435 CFDictionaryRef capDict =
436 (CFDictionaryRef)CFArrayGetValueAtIndex(capArray, capDex);
437 if((capDict == NULL) ||
438 (CFGetTypeID(capDict) != CFDictionaryGetTypeID())) {
439 MPDebug("parseCspCapabilitiesRecord: bad Capabilities element");
440 break;
441 }
442 MDSDictionary capDictMds(capDict);
443
444 /*
445 * Append this dictionary's attributes to outAttrs, after the fixed
446 * attributes from CSPCapabilitiesDict1RelInfo.
447 */
448 uint32 numCapDictAttrs;
449 capDictMds.lookupAttributes(&CSPCapabilitiesDict2RelInfo,
450 &outAttrs[numTopLevelAttrs],
451 numCapDictAttrs);
452
453 /*
454 * Append the GroupId attribute, which we infer from the current index
455 * into Capabilitites. However, thou shalt not use > 4-byte values
456 * for MDS, so convert from CFIndex first.
457 */
458 if (capDex > uint32(~0)) {
459 MPDebug("parseCspCapabilitiesRecord: too large an index for MDS");
460 break;
461 }
462 uint32 index32 = uint32(capDex);
463 MDSRawValueToDbAttr(&index32, sizeof(index32), CSSM_DB_ATTRIBUTE_FORMAT_UINT32,
464 "GroupId", outAttrs[numTopLevelAttrs + numCapDictAttrs]);
465 numCapDictAttrs++;
466
467 /*
468 * Now descend into the array of this capability's attributes.
469 * Each element is a dictionary defined by
470 * by CSPCapabilitiesDict3RelInfo.
471 */
472 CFArrayRef attrArray = (CFArrayRef)capDictMds.lookup("Attributes",
473 true, CFArrayGetTypeID());
474 if(attrArray == NULL) {
475 MPDebug("parseCspCapabilitiesRecord: no (or bad) Attributes");
476 break;
477 }
478 CFIndex attrArraySize = CFArrayGetCount(attrArray);
479 CFIndex attrDex;
480 for(attrDex=0; attrDex<attrArraySize; attrDex++) {
481 MPDebug(" ...parsing Attribute %d", (int)attrDex);
482 CFDictionaryRef attrDict =
483 (CFDictionaryRef)CFArrayGetValueAtIndex(attrArray, attrDex);
484 if((attrDict == NULL) ||
485 (CFGetTypeID(attrDict) != CFDictionaryGetTypeID())) {
486 MPDebug("parseCspCapabilitiesRecord: bad Attributes element");
487 break;
488 }
489 MDSDictionary attrDictMds(attrDict);
490
491 /*
492 * Append this dictionary's attributes to outAttrs, after the fixed
493 * attributes from CSPCapabilitiesDict1RelInfo and this capability's
494 * CSPCapabilitiesDict2RelInfo.
495 */
496 uint32 numAttrDictAttrs;
497 attrDictMds.lookupAttributes(&CSPCapabilitiesDict3RelInfo,
498 &outAttrs[numTopLevelAttrs + numCapDictAttrs],
499 numAttrDictAttrs);
500
501 /* write to DB */
502 MDSInsertRecord(outAttrs,
503 numTopLevelAttrs + numCapDictAttrs + numAttrDictAttrs,
504 MDS_CDSADIR_CSP_CAPABILITY_RECORDTYPE,
505 mDl,
506 mCdsaDirHand);
507
508 /* just free the attrs we allocated in this loop */
509 MDSFreeDbRecordAttrs(&outAttrs[numTopLevelAttrs + numCapDictAttrs],
510 numAttrDictAttrs);
511 } /* for each attribute */
512 /* just free the attrs we allocated in this loop */
513 MDSFreeDbRecordAttrs(&outAttrs[numTopLevelAttrs], numCapDictAttrs);
514 } /* for each capability */
515
516 MDSFreeDbRecordAttrs(outAttrs, numTopLevelAttrs);
517 delete [] outAttrs;
518 if(fetchedFromDisk) {
519 CF_RELEASE(capArray);
520 }
521 }
522
523 /*
524 * Parse TP Policy OIDs.
525 * The propertly list (*.mdsinfo) is set up like this:
526 *
527 * root(Dictionary) {
528 * ModuleID(String)
529 * SSID(Number)
530 * Policies(Array) {
531 * index 0(Dictionary) {
532 * OID(Data) -- <092a8648 86f76364 0102>
533 * Value(Data) -- optional, OID-specific
534 * index n...
535 * }
536 * }
537 *
538 * The plist can specify multiple Policies. Each element of the Policies
539 * array maps to one record in the DB.
540 */
541 void MDSAttrParser::parseTpPolicyOidsRecord(
542 MDSDictionary *mdsDict)
543 {
544 /*
545 * Malloc an attribute array big enough for the whole schema. We're going
546 * to re-use this array every time we write a new record. Portions of
547 * the array are invariant for some inner loops.
548 */
549 const RelationInfo *topRelInfo =
550 MDSRecordTypeToRelation(MDS_CDSADIR_TP_OIDS_RECORDTYPE);
551 assert(topRelInfo != NULL);
552 uint32 numInAttrs = topRelInfo->NumberOfAttributes;
553 CSSM_DB_ATTRIBUTE_DATA_PTR outAttrs = new CSSM_DB_ATTRIBUTE_DATA[numInAttrs];
554
555 /* these attrs are only set once, then they remain invariant */
556 uint32 numTopLevelAttrs;
557 mdsDict->lookupAttributes(&TpPolicyOidsDict1RelInfo, outAttrs,
558 numTopLevelAttrs);
559
560 /* obtain Policies array */
561 CFArrayRef policyArray = (CFArrayRef)mdsDict->lookup("Policies",
562 true, CFArrayGetTypeID());
563 if(policyArray == NULL) {
564 /* well we did not get very far.... */
565 MPDebug("parseTpPolicyOidsRecord: no (or bad) Policies");
566 delete [] outAttrs;
567 return;
568 }
569
570 /*
571 * Descend into Policies array. Each element is a dictionary defined
572 * by TpPolicyOidsDict2RelInfo.
573 */
574 CFIndex policyArraySize = CFArrayGetCount(policyArray);
575 CFIndex policyDex;
576 for(policyDex=0; policyDex<policyArraySize; policyDex++) {
577 MPDebug("...parsing Policy %d", (int)policyDex);
578 CFDictionaryRef policyDict =
579 (CFDictionaryRef)CFArrayGetValueAtIndex(policyArray, policyDex);
580 if((policyDict == NULL) ||
581 (CFGetTypeID(policyDict) != CFDictionaryGetTypeID())) {
582 MPDebug("parseTpPolicyOidsRecord: bad Policies element");
583 break;
584 }
585 MDSDictionary policyDictMds(policyDict);
586
587 /*
588 * Append this dictionary's attributes to outAttrs, after the fixed
589 * attributes from TpPolicyOidsDict1RelInfo.
590 */
591 uint32 numPolicyDictAttrs;
592 policyDictMds.lookupAttributes(&TpPolicyOidsDict2RelInfo,
593 &outAttrs[numTopLevelAttrs],
594 numPolicyDictAttrs);
595
596
597 /* write to DB */
598 MDSInsertRecord(outAttrs,
599 numTopLevelAttrs + numPolicyDictAttrs,
600 MDS_CDSADIR_TP_OIDS_RECORDTYPE,
601 mDl,
602 mCdsaDirHand);
603
604 /* free the attrs allocated in this loop */
605 MDSFreeDbRecordAttrs(outAttrs + numTopLevelAttrs, numPolicyDictAttrs);
606 } /* for each policy */
607 MDSFreeDbRecordAttrs(outAttrs, numTopLevelAttrs);
608 delete [] outAttrs;
609 }
610
611
612 } // end namespace Security