]>
Commit | Line | Data |
---|---|---|
29654253 A |
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/cssmerrno.h> | |
32 | #include <Security/utilities.h> | |
33 | #include <Security/logging.h> | |
34 | #include <Security/mds_schema.h> | |
35 | ||
36 | namespace Security | |
37 | { | |
38 | ||
39 | MDSAttrParser::MDSAttrParser( | |
40 | const char *bundlePath, | |
41 | MDSSession &dl, | |
42 | CSSM_DB_HANDLE objectHand, | |
43 | CSSM_DB_HANDLE cdsaDirHand) : | |
44 | mBundle(NULL), | |
45 | mPath(NULL), | |
46 | mDl(dl), | |
47 | mObjectHand(objectHand), | |
48 | mCdsaDirHand(cdsaDirHand) | |
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 | } | |
78 | ||
79 | /********************* | |
80 | Main public function. | |
81 | ||
82 | Parsing bundle { | |
83 | get all *.mdsinfo files; | |
84 | for each mdsinfo { | |
85 | get contents of that file as dictionary; | |
86 | switch (ModuleType) { | |
87 | case CSSM: | |
88 | parse this mdsinfo --> MDS_OBJECT_RECORDTYPE, MDS_CDSADIR_CSSM_RECORDTYPE; | |
89 | break; | |
90 | case Plugin: | |
91 | parse this info --> MDS_OBJECT_RECORDTYPE, MDS_CDSADIR_COMMON_RECORDTYPE; | |
92 | case PluginInfo: | |
93 | recordType = lookup("MdsRecordType"); | |
94 | dispatch to recordtype-specific parsing; | |
95 | } | |
96 | } | |
97 | } | |
98 | ************/ | |
99 | ||
100 | #define RELEASE_EACH_URL 0 | |
101 | ||
102 | void MDSAttrParser::parseAttrs() | |
103 | { | |
104 | /* get all *.mdsinfo files */ | |
105 | /* | |
106 | * FIXME - this leaks like crazy even though we CFRelease the array. | |
107 | * With RELEASE_EACH_URL true, we attempt to release each element of | |
108 | * the array, but that results in a ton of mallocDebug errors. I believe | |
109 | * this is a CF leak. | |
110 | */ | |
111 | CFArrayRef bundleInfoFiles = CFBundleCopyResourceURLsOfType(mBundle, | |
112 | CFSTR(MDS_INFO_TYPE), | |
113 | NULL); // any subdir | |
114 | if(bundleInfoFiles == NULL) { | |
115 | Syslog::alert("MDSAttrParser: no mdsattr files for %s", mPath); | |
116 | return; | |
117 | } | |
118 | assert(CFGetTypeID(bundleInfoFiles) == CFArrayGetTypeID()); | |
119 | ||
120 | /* process each .mdsinfo file */ | |
121 | for(CFIndex i=0; i<CFArrayGetCount(bundleInfoFiles); i++) { | |
122 | /* get filename as CFURL */ | |
123 | CFURLRef infoUrl = NULL; | |
124 | MDSDictionary *mdsDict = NULL; | |
125 | CFStringRef infoType = NULL; | |
126 | ||
127 | infoUrl = reinterpret_cast<CFURLRef>( | |
128 | CFArrayGetValueAtIndex(bundleInfoFiles, i)); | |
129 | if(infoUrl == NULL) { | |
130 | MPDebug("MDSAttrParser: CFBundleCopyResourceURLsOfType screwup 1"); | |
131 | continue; | |
132 | } | |
133 | if(CFGetTypeID(infoUrl) != CFURLGetTypeID()) { | |
134 | MPDebug("MDSAttrParser: CFBundleCopyResourceURLsOfType screwup 2"); | |
135 | continue; | |
136 | } | |
137 | ||
138 | /* Get contents of mdsinfo file as dictionary */ | |
139 | mdsDict = new MDSDictionary(infoUrl, mPath); | |
140 | if(mdsDict == NULL) { | |
141 | goto abortInfoFile; | |
142 | } | |
143 | MPDebug("Parsing mdsinfo file %s", mdsDict->fileDesc()); | |
144 | ||
145 | /* Determine what kind of info file this is and dispatch accordingly */ | |
146 | infoType = (CFStringRef)mdsDict->lookup(CFSTR(MDS_INFO_FILE_TYPE), | |
147 | true, CFStringGetTypeID()); | |
148 | if(infoType == NULL) { | |
149 | logFileError("Malformed MDS Info file", infoUrl, NULL, NULL); | |
150 | goto abortInfoFile; | |
151 | } | |
152 | ||
153 | /* be robust here, errors in these low-level routines do not affect | |
154 | * the rest of our task */ | |
155 | try { | |
156 | if(CFStringCompare(infoType, CFSTR(MDS_INFO_FILE_TYPE_CSSM), 0) | |
157 | == kCFCompareEqualTo) { | |
158 | parseCssmInfo(mdsDict); | |
159 | } | |
160 | else if(CFStringCompare(infoType, CFSTR(MDS_INFO_FILE_TYPE_PLUGIN), 0) | |
161 | == kCFCompareEqualTo) { | |
162 | parsePluginCommon(mdsDict); | |
163 | } | |
164 | else if(CFStringCompare(infoType, CFSTR(MDS_INFO_FILE_TYPE_RECORD), 0) | |
165 | == kCFCompareEqualTo) { | |
166 | parsePluginSpecific(mdsDict); | |
167 | } | |
168 | else { | |
169 | logFileError("Malformed MDS Info file", infoUrl, NULL, NULL); | |
170 | } | |
171 | } | |
172 | catch(...) { | |
173 | ||
174 | } | |
175 | abortInfoFile: | |
176 | delete mdsDict; | |
177 | } /* for each mdsinfo */ | |
178 | /* FIXME - do we have to release each element of the array? */ | |
179 | #if RELEASE_EACH_URL | |
180 | for(CFIndex i=0; i<CFArrayGetCount(bundleInfoFiles); i++) { | |
181 | CFTypeRef elmt = (CFTypeRef)CFArrayGetValueAtIndex(bundleInfoFiles, i); | |
182 | CF_RELEASE(elmt); | |
183 | } | |
184 | #endif | |
185 | CF_RELEASE(bundleInfoFiles); | |
186 | } | |
187 | ||
188 | void MDSAttrParser::logFileError( | |
189 | const char *op, | |
190 | CFURLRef fileUrl, | |
191 | CFStringRef errStr, // optional if you have it | |
192 | SInt32 *errNo) // optional if you have it | |
193 | { | |
194 | const char *cerrStr = NULL; | |
195 | CFStringRef urlStr = CFURLGetString(fileUrl); | |
196 | const char *cUrlStr = CFStringGetCStringPtr(urlStr, CFStringGetSystemEncoding()); | |
197 | ||
198 | if(errStr) { | |
199 | cerrStr = CFStringGetCStringPtr(errStr, CFStringGetSystemEncoding()); | |
200 | Syslog::alert("MDS: %s: bundle %s url %s: error %s", | |
201 | op, mPath, cUrlStr, cerrStr); | |
202 | } | |
203 | else { | |
204 | Syslog::alert("MDS: %s: bundle %s url %s: error %d", | |
205 | op, mPath, cUrlStr, errNo ? *errNo : 0); | |
206 | } | |
207 | } | |
208 | ||
209 | /* | |
210 | * Parse a CSSM info file. | |
211 | */ | |
212 | void MDSAttrParser::parseCssmInfo( | |
213 | MDSDictionary *mdsDict) | |
214 | { | |
215 | /* first get object info */ | |
216 | parseObjectRecord(mdsDict); | |
217 | ||
218 | /* now CSSM relation */ | |
219 | const RelationInfo *relationInfo = | |
220 | MDSRecordTypeToRelation(MDS_CDSADIR_CSSM_RECORDTYPE); | |
221 | assert(relationInfo != NULL); | |
222 | parseMdsRecord(mdsDict, relationInfo, mCdsaDirHand); | |
223 | } | |
224 | ||
225 | /* | |
226 | * Parse a PluginCommon file. | |
227 | */ | |
228 | void MDSAttrParser::parsePluginCommon( | |
229 | MDSDictionary *mdsDict) | |
230 | { | |
231 | ||
232 | /* first get object info */ | |
233 | parseObjectRecord(mdsDict); | |
234 | ||
235 | /* now common relation */ | |
236 | const RelationInfo *relationInfo = | |
237 | MDSRecordTypeToRelation(MDS_CDSADIR_COMMON_RECORDTYPE); | |
238 | assert(relationInfo != NULL); | |
239 | parseMdsRecord(mdsDict, relationInfo, mCdsaDirHand); | |
240 | } | |
241 | ||
242 | /* | |
243 | * Parse a Plugin Specific file. | |
244 | */ | |
245 | void MDSAttrParser::parsePluginSpecific( | |
246 | MDSDictionary *mdsDict) | |
247 | { | |
248 | /* determine record type from the file itself */ | |
249 | CFStringRef recordTypeStr = | |
250 | (CFStringRef)mdsDict->lookup(MDS_INFO_FILE_RECORD_TYPE, | |
251 | true, CFStringGetTypeID()); | |
252 | if(recordTypeStr == NULL) { | |
253 | MPDebug("%s: no %s record found\n", mdsDict->fileDesc(), | |
254 | MDS_INFO_FILE_RECORD_TYPE); | |
255 | return; | |
256 | } | |
257 | ||
258 | /* convert to a known schema */ | |
259 | const char *recordTypeCStr = MDSCFStringToCString(recordTypeStr); | |
260 | const RelationInfo *relationInfo = MDSRecordTypeNameToRelation(recordTypeCStr); | |
261 | if(relationInfo == NULL) { | |
262 | Syslog::alert("MDS file %s has unsupported record type %s", | |
263 | mdsDict->fileDesc(), recordTypeCStr); | |
264 | MPDebug("MDS file %s has unsupported record type %s", | |
265 | mdsDict->fileDesc(), recordTypeCStr); | |
266 | delete [] recordTypeCStr; | |
267 | return; | |
268 | } | |
269 | MPDebug("Parsing MDS file %s, recordType %s", mdsDict->fileDesc(), recordTypeCStr); | |
270 | delete [] recordTypeCStr; | |
271 | ||
272 | /* handle special cases here */ | |
273 | switch(relationInfo->DataRecordType) { | |
274 | case MDS_CDSADIR_CSP_CAPABILITY_RECORDTYPE: | |
275 | parseCspCapabilitiesRecord(mdsDict); | |
276 | break; | |
277 | case MDS_CDSADIR_TP_OIDS_RECORDTYPE: | |
278 | parseTpPolicyOidsRecord(mdsDict); | |
279 | break; | |
280 | default: | |
281 | /* all (normal) linear schema */ | |
282 | parseMdsRecord(mdsDict, relationInfo, mCdsaDirHand); | |
283 | } | |
284 | } | |
285 | ||
286 | ||
287 | /* | |
288 | * Given an open MDSDictionary, create an MDS_OBJECT_RECORDTYPE record and | |
289 | * add it to mObjectHand. Used when parsing both CSSM records and MOduleCommon | |
290 | * records. | |
291 | */ | |
292 | void MDSAttrParser::parseObjectRecord( | |
293 | MDSDictionary *mdsDict) | |
294 | { | |
295 | assert(mdsDict != NULL); | |
296 | assert(mObjectHand != 0); | |
297 | parseMdsRecord(mdsDict, &kObjectRelation, mObjectHand); | |
298 | ||
299 | } | |
300 | ||
301 | /* | |
302 | * Given an open dictionary and a RelationInfo defining a schema, fetch all | |
303 | * attributes associated with the specified schema from the dictionary | |
304 | * and write them to specified DB. | |
305 | */ | |
306 | void MDSAttrParser::parseMdsRecord( | |
307 | MDSDictionary *mdsDict, | |
308 | const RelationInfo *relInfo, | |
309 | CSSM_DB_HANDLE dbHand) | |
310 | { | |
311 | assert(mdsDict != NULL); | |
312 | assert(relInfo != NULL); | |
313 | assert(dbHand != 0); | |
314 | ||
315 | /* | |
316 | * malloc an CSSM_DB_ATTRIBUTE_DATA array associated with specified schema. | |
317 | */ | |
318 | unsigned numSchemaAttrs = relInfo->NumberOfAttributes; | |
319 | CSSM_DB_ATTRIBUTE_DATA *dbAttrs = new CSSM_DB_ATTRIBUTE_DATA[numSchemaAttrs]; | |
320 | ||
321 | /* | |
322 | * Grind thru the attributes in the specified schema. Do not assume the presence | |
323 | * of any given attribute. | |
324 | */ | |
325 | uint32 foundAttrs = 0; | |
326 | mdsDict->lookupAttributes(relInfo, dbAttrs, foundAttrs); | |
327 | ||
328 | /* write to the DB */ | |
329 | MDSInsertRecord(dbAttrs, foundAttrs, relInfo->DataRecordType, mDl, dbHand); | |
330 | ||
331 | MDSFreeDbRecordAttrs(dbAttrs, foundAttrs); | |
332 | delete [] dbAttrs; | |
333 | } | |
334 | ||
335 | /* | |
336 | * Parse CSP capabilities. This is much more complicated than most records. | |
337 | * The propertly list (*.mdsinfo) is set up like this: | |
338 | * | |
339 | * root(Dictionary) { | |
340 | * ModuleID(String) | |
341 | * SSID(Number) | |
342 | * Capabilities(Array) { | |
343 | * index 0(Dictionary) { | |
344 | * AlgType(String) -- CSSM_ALGID_SHA1 | |
345 | * ContextType(String) -- CSSM_ALGCLASS_DIGEST | |
346 | * UseeTag(String) -- CSSM_USEE_NONE | |
347 | * Description(String) -- "SHA1 Digest" | |
348 | * Attributes(Array) | |
349 | * index 0(Dictionary) | |
350 | * AttributeType(String) -- CSSM_ATTRIBUTE_OUTPUT_SIZE | |
351 | * AttributeValue(Array) { | |
352 | * index 0(Number) -- 20 | |
353 | * ... | |
354 | * } | |
355 | * index n ... | |
356 | * } | |
357 | * index n... | |
358 | * } | |
359 | * } | |
360 | * | |
361 | * The plist can specify multiple Capabilities, multiple Attributes for each | |
362 | * Capability, and multiple values for each Attribute. (Note that MULTI_UINT32 | |
363 | * in the DB is represented in the plist as an Array of Numbers.) Each element | |
364 | * of each Attributes array maps to one record in the DB. The GroupID attribute | |
365 | * of a record is the index into the plist's Capabilities array. | |
366 | */ | |
367 | void MDSAttrParser::parseCspCapabilitiesRecord( | |
368 | MDSDictionary *mdsDict) | |
369 | { | |
370 | /* | |
371 | * Malloc an attribute array big enough for the whole schema. We're going | |
372 | * to re-use this array every time we write a new record. Portions of | |
373 | * the array are invariant for some inner loops. | |
374 | */ | |
375 | const RelationInfo *topRelInfo = | |
376 | MDSRecordTypeToRelation(MDS_CDSADIR_CSP_CAPABILITY_RECORDTYPE); | |
377 | assert(topRelInfo != NULL); | |
378 | uint32 numInAttrs = topRelInfo->NumberOfAttributes; | |
379 | CSSM_DB_ATTRIBUTE_DATA_PTR outAttrs = new CSSM_DB_ATTRIBUTE_DATA[numInAttrs]; | |
380 | ||
381 | /* these attrs are only set once, then they remain invariant */ | |
382 | uint32 numTopLevelAttrs; | |
383 | mdsDict->lookupAttributes(&CSPCapabilitiesDict1RelInfo, outAttrs, | |
384 | numTopLevelAttrs); | |
385 | ||
386 | bool fetchedFromDisk = false; | |
387 | ||
388 | /* obtain Capabilities array */ | |
389 | CFArrayRef capArray = (CFArrayRef)mdsDict->lookupWithIndirect("Capabilities", | |
390 | mBundle, | |
391 | CFArrayGetTypeID(), | |
392 | fetchedFromDisk); | |
393 | if(capArray == NULL) { | |
394 | /* well we did not get very far.... */ | |
395 | MPDebug("parseCspCapabilitiesRecord: no (or bad) Capabilities"); | |
396 | delete [] outAttrs; | |
397 | return; | |
398 | } | |
399 | ||
400 | /* | |
401 | * Descend into Capabilities array. Each element is a dictionary defined | |
402 | * by CSPCapabilitiesDict2RelInfo. | |
403 | */ | |
404 | CFIndex capArraySize = CFArrayGetCount(capArray); | |
405 | CFIndex capDex; | |
406 | for(capDex=0; capDex<capArraySize; capDex++) { | |
407 | MPDebug("...parsing Capability %d", (int)capDex); | |
408 | CFDictionaryRef capDict = | |
409 | (CFDictionaryRef)CFArrayGetValueAtIndex(capArray, capDex); | |
410 | if((capDict == NULL) || | |
411 | (CFGetTypeID(capDict) != CFDictionaryGetTypeID())) { | |
412 | MPDebug("parseCspCapabilitiesRecord: bad Capabilities element"); | |
413 | break; | |
414 | } | |
415 | MDSDictionary capDictMds(capDict); | |
416 | ||
417 | /* | |
418 | * Append this dictionary's attributes to outAttrs, after the fixed | |
419 | * attributes from CSPCapabilitiesDict1RelInfo. | |
420 | */ | |
421 | uint32 numCapDictAttrs; | |
422 | capDictMds.lookupAttributes(&CSPCapabilitiesDict2RelInfo, | |
423 | &outAttrs[numTopLevelAttrs], | |
424 | numCapDictAttrs); | |
425 | ||
426 | /* | |
427 | * Append the GroupId attribute, which we infer from the current index | |
428 | * into Capabilitites. | |
429 | */ | |
430 | MDSRawValueToDbAttr(&capDex, sizeof(CFIndex), CSSM_DB_ATTRIBUTE_FORMAT_UINT32, | |
431 | "GroupId", outAttrs[numTopLevelAttrs + numCapDictAttrs]); | |
432 | numCapDictAttrs++; | |
433 | ||
434 | /* | |
435 | * Now descend into the array of this capability's attributes. | |
436 | * Each element is a dictionary defined by | |
437 | * by CSPCapabilitiesDict3RelInfo. | |
438 | */ | |
439 | CFArrayRef attrArray = (CFArrayRef)capDictMds.lookup("Attributes", | |
440 | true, CFArrayGetTypeID()); | |
441 | if(attrArray == NULL) { | |
442 | MPDebug("parseCspCapabilitiesRecord: no (or bad) Attributes"); | |
443 | break; | |
444 | } | |
445 | CFIndex attrArraySize = CFArrayGetCount(attrArray); | |
446 | CFIndex attrDex; | |
447 | for(attrDex=0; attrDex<attrArraySize; attrDex++) { | |
448 | MPDebug(" ...parsing Attribute %d", (int)attrDex); | |
449 | CFDictionaryRef attrDict = | |
450 | (CFDictionaryRef)CFArrayGetValueAtIndex(attrArray, attrDex); | |
451 | if((attrDict == NULL) || | |
452 | (CFGetTypeID(attrDict) != CFDictionaryGetTypeID())) { | |
453 | MPDebug("parseCspCapabilitiesRecord: bad Attributes element"); | |
454 | break; | |
455 | } | |
456 | MDSDictionary attrDictMds(attrDict); | |
457 | ||
458 | /* | |
459 | * Append this dictionary's attributes to outAttrs, after the fixed | |
460 | * attributes from CSPCapabilitiesDict1RelInfo and this capability's | |
461 | * CSPCapabilitiesDict2RelInfo. | |
462 | */ | |
463 | uint32 numAttrDictAttrs; | |
464 | attrDictMds.lookupAttributes(&CSPCapabilitiesDict3RelInfo, | |
465 | &outAttrs[numTopLevelAttrs + numCapDictAttrs], | |
466 | numAttrDictAttrs); | |
467 | ||
468 | /* write to DB */ | |
469 | MDSInsertRecord(outAttrs, | |
470 | numTopLevelAttrs + numCapDictAttrs + numAttrDictAttrs, | |
471 | MDS_CDSADIR_CSP_CAPABILITY_RECORDTYPE, | |
472 | mDl, | |
473 | mCdsaDirHand); | |
474 | ||
475 | /* just free the attrs we allocated in this loop */ | |
476 | MDSFreeDbRecordAttrs(&outAttrs[numTopLevelAttrs + numCapDictAttrs], | |
477 | numAttrDictAttrs); | |
478 | } /* for each attribute */ | |
479 | /* just free the attrs we allocated in this loop */ | |
480 | MDSFreeDbRecordAttrs(&outAttrs[numTopLevelAttrs], numCapDictAttrs); | |
481 | } /* for each capability */ | |
482 | ||
483 | MDSFreeDbRecordAttrs(outAttrs, numTopLevelAttrs); | |
484 | delete [] outAttrs; | |
485 | if(fetchedFromDisk) { | |
486 | CF_RELEASE(capArray); | |
487 | } | |
488 | } | |
489 | ||
490 | /* | |
491 | * Parse TP Policy OIDs. | |
492 | * The propertly list (*.mdsinfo) is set up like this: | |
493 | * | |
494 | * root(Dictionary) { | |
495 | * ModuleID(String) | |
496 | * SSID(Number) | |
497 | * Policies(Array) { | |
498 | * index 0(Dictionary) { | |
499 | * OID(Data) -- <092a8648 86f76364 0102> | |
500 | * Value(Data) -- optional, OID-specific | |
501 | * index n... | |
502 | * } | |
503 | * } | |
504 | * | |
505 | * The plist can specify multiple Policies. Each element of the Policies | |
506 | * array maps to one record in the DB. | |
507 | */ | |
508 | void MDSAttrParser::parseTpPolicyOidsRecord( | |
509 | MDSDictionary *mdsDict) | |
510 | { | |
511 | /* | |
512 | * Malloc an attribute array big enough for the whole schema. We're going | |
513 | * to re-use this array every time we write a new record. Portions of | |
514 | * the array are invariant for some inner loops. | |
515 | */ | |
516 | const RelationInfo *topRelInfo = | |
517 | MDSRecordTypeToRelation(MDS_CDSADIR_TP_OIDS_RECORDTYPE); | |
518 | assert(topRelInfo != NULL); | |
519 | uint32 numInAttrs = topRelInfo->NumberOfAttributes; | |
520 | CSSM_DB_ATTRIBUTE_DATA_PTR outAttrs = new CSSM_DB_ATTRIBUTE_DATA[numInAttrs]; | |
521 | ||
522 | /* these attrs are only set once, then they remain invariant */ | |
523 | uint32 numTopLevelAttrs; | |
524 | mdsDict->lookupAttributes(&TpPolicyOidsDict1RelInfo, outAttrs, | |
525 | numTopLevelAttrs); | |
526 | ||
527 | /* obtain Policies array */ | |
528 | CFArrayRef policyArray = (CFArrayRef)mdsDict->lookup("Policies", | |
529 | true, CFArrayGetTypeID()); | |
530 | if(policyArray == NULL) { | |
531 | /* well we did not get very far.... */ | |
532 | MPDebug("parseTpPolicyOidsRecord: no (or bad) Policies"); | |
533 | delete [] outAttrs; | |
534 | return; | |
535 | } | |
536 | ||
537 | /* | |
538 | * Descend into Policies array. Each element is a dictionary defined | |
539 | * by TpPolicyOidsDict2RelInfo. | |
540 | */ | |
541 | CFIndex policyArraySize = CFArrayGetCount(policyArray); | |
542 | CFIndex policyDex; | |
543 | for(policyDex=0; policyDex<policyArraySize; policyDex++) { | |
544 | MPDebug("...parsing Policy %d", (int)policyDex); | |
545 | CFDictionaryRef policyDict = | |
546 | (CFDictionaryRef)CFArrayGetValueAtIndex(policyArray, policyDex); | |
547 | if((policyDict == NULL) || | |
548 | (CFGetTypeID(policyDict) != CFDictionaryGetTypeID())) { | |
549 | MPDebug("parseTpPolicyOidsRecord: bad Policies element"); | |
550 | break; | |
551 | } | |
552 | MDSDictionary policyDictMds(policyDict); | |
553 | ||
554 | /* | |
555 | * Append this dictionary's attributes to outAttrs, after the fixed | |
556 | * attributes from TpPolicyOidsDict1RelInfo. | |
557 | */ | |
558 | uint32 numPolicyDictAttrs; | |
559 | policyDictMds.lookupAttributes(&TpPolicyOidsDict2RelInfo, | |
560 | &outAttrs[numTopLevelAttrs], | |
561 | numPolicyDictAttrs); | |
562 | ||
563 | ||
564 | /* write to DB */ | |
565 | MDSInsertRecord(outAttrs, | |
566 | numTopLevelAttrs + numPolicyDictAttrs, | |
567 | MDS_CDSADIR_TP_OIDS_RECORDTYPE, | |
568 | mDl, | |
569 | mCdsaDirHand); | |
570 | ||
571 | /* free the attrs allocated in this loop */ | |
572 | MDSFreeDbRecordAttrs(outAttrs + numTopLevelAttrs, numPolicyDictAttrs); | |
573 | } /* for each policy */ | |
574 | MDSFreeDbRecordAttrs(outAttrs, numTopLevelAttrs); | |
575 | delete [] outAttrs; | |
576 | } | |
577 | ||
578 | ||
579 | } // end namespace Security |