]> git.saurik.com Git - apple/security.git/blob - cdsa/mds/MDSAttrParser.cpp
Security-54.1.3.tar.gz
[apple/security.git] / cdsa / mds / 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/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