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