]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 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_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 */ | |
427c49bc | 51 | size_t pathLen = strlen(bundlePath); |
b1ab9ed8 A |
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 | { | |
b1ab9ed8 A |
221 | CFStringRef urlStr = CFURLGetString(fileUrl); |
222 | const char *cUrlStr = CFStringGetCStringPtr(urlStr, kCFStringEncodingUTF8); | |
427c49bc A |
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 | ||
b1ab9ed8 | 233 | if(errStr) { |
427c49bc A |
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 | ||
b1ab9ed8 A |
245 | Syslog::alert("MDS: %s: bundle %s url %s: error %s", |
246 | op, mPath, cUrlStr, cerrStr); | |
427c49bc A |
247 | |
248 | if (sbuf2 != NULL) | |
249 | { | |
250 | free(sbuf2); | |
251 | } | |
b1ab9ed8 A |
252 | } |
253 | else { | |
254 | Syslog::alert("MDS: %s: bundle %s url %s: error %d", | |
427c49bc | 255 | op, mPath, cUrlStr, (int)(errNo ? *errNo : 0)); |
b1ab9ed8 | 256 | } |
427c49bc A |
257 | |
258 | if (stringBuffer != NULL) | |
259 | { | |
260 | free(stringBuffer); | |
261 | } | |
b1ab9ed8 A |
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 |