#include "MDSAttrParser.h"
#include "MDSAttrUtils.h"
#include "MDSDictionary.h"
#include <Security/cssmerrno.h>
#include <Security/utilities.h>
#include <Security/logging.h>
#include <Security/mds_schema.h>
namespace Security
{
MDSAttrParser::MDSAttrParser(
const char *bundlePath,
MDSSession &dl,
CSSM_DB_HANDLE objectHand,
CSSM_DB_HANDLE cdsaDirHand) :
mBundle(NULL),
mPath(NULL),
mDl(dl),
mObjectHand(objectHand),
mCdsaDirHand(cdsaDirHand)
{
unsigned pathLen = strlen(bundlePath);
CFURLRef url = CFURLCreateFromFileSystemRepresentation(NULL,
(unsigned char *)bundlePath,
pathLen,
false);
if(url == NULL) {
Syslog::alert("CFURLCreateFromFileSystemRepresentation(%s) failure", mPath);
CssmError::throwMe(CSSMERR_DL_INVALID_DB_NAME);
}
mBundle = CFBundleCreate(NULL, url);
CFRelease(url);
if(mBundle == NULL) {
Syslog::alert("CFBundleCreate(%s) failure", mPath);
CssmError::throwMe(CSSMERR_DL_INVALID_DB_NAME);
}
mPath = new char[pathLen + 1];
strcpy(mPath, bundlePath);
}
MDSAttrParser::~MDSAttrParser()
{
CF_RELEASE(mBundle);
delete [] mPath;
}
#define RELEASE_EACH_URL 0
void MDSAttrParser::parseAttrs()
{
CFArrayRef bundleInfoFiles = CFBundleCopyResourceURLsOfType(mBundle,
CFSTR(MDS_INFO_TYPE),
NULL); if(bundleInfoFiles == NULL) {
Syslog::alert("MDSAttrParser: no mdsattr files for %s", mPath);
return;
}
assert(CFGetTypeID(bundleInfoFiles) == CFArrayGetTypeID());
for(CFIndex i=0; i<CFArrayGetCount(bundleInfoFiles); i++) {
CFURLRef infoUrl = NULL;
MDSDictionary *mdsDict = NULL;
CFStringRef infoType = NULL;
infoUrl = reinterpret_cast<CFURLRef>(
CFArrayGetValueAtIndex(bundleInfoFiles, i));
if(infoUrl == NULL) {
MPDebug("MDSAttrParser: CFBundleCopyResourceURLsOfType screwup 1");
continue;
}
if(CFGetTypeID(infoUrl) != CFURLGetTypeID()) {
MPDebug("MDSAttrParser: CFBundleCopyResourceURLsOfType screwup 2");
continue;
}
mdsDict = new MDSDictionary(infoUrl, mPath);
if(mdsDict == NULL) {
goto abortInfoFile;
}
MPDebug("Parsing mdsinfo file %s", mdsDict->fileDesc());
infoType = (CFStringRef)mdsDict->lookup(CFSTR(MDS_INFO_FILE_TYPE),
true, CFStringGetTypeID());
if(infoType == NULL) {
logFileError("Malformed MDS Info file", infoUrl, NULL, NULL);
goto abortInfoFile;
}
try {
if(CFStringCompare(infoType, CFSTR(MDS_INFO_FILE_TYPE_CSSM), 0)
== kCFCompareEqualTo) {
parseCssmInfo(mdsDict);
}
else if(CFStringCompare(infoType, CFSTR(MDS_INFO_FILE_TYPE_PLUGIN), 0)
== kCFCompareEqualTo) {
parsePluginCommon(mdsDict);
}
else if(CFStringCompare(infoType, CFSTR(MDS_INFO_FILE_TYPE_RECORD), 0)
== kCFCompareEqualTo) {
parsePluginSpecific(mdsDict);
}
else {
logFileError("Malformed MDS Info file", infoUrl, NULL, NULL);
}
}
catch(...) {
}
abortInfoFile:
delete mdsDict;
}
#if RELEASE_EACH_URL
for(CFIndex i=0; i<CFArrayGetCount(bundleInfoFiles); i++) {
CFTypeRef elmt = (CFTypeRef)CFArrayGetValueAtIndex(bundleInfoFiles, i);
CF_RELEASE(elmt);
}
#endif
CF_RELEASE(bundleInfoFiles);
}
void MDSAttrParser::logFileError(
const char *op,
CFURLRef fileUrl,
CFStringRef errStr, SInt32 *errNo) {
const char *cerrStr = NULL;
CFStringRef urlStr = CFURLGetString(fileUrl);
const char *cUrlStr = CFStringGetCStringPtr(urlStr, CFStringGetSystemEncoding());
if(errStr) {
cerrStr = CFStringGetCStringPtr(errStr, CFStringGetSystemEncoding());
Syslog::alert("MDS: %s: bundle %s url %s: error %s",
op, mPath, cUrlStr, cerrStr);
}
else {
Syslog::alert("MDS: %s: bundle %s url %s: error %d",
op, mPath, cUrlStr, errNo ? *errNo : 0);
}
}
void MDSAttrParser::parseCssmInfo(
MDSDictionary *mdsDict)
{
parseObjectRecord(mdsDict);
const RelationInfo *relationInfo =
MDSRecordTypeToRelation(MDS_CDSADIR_CSSM_RECORDTYPE);
assert(relationInfo != NULL);
parseMdsRecord(mdsDict, relationInfo, mCdsaDirHand);
}
void MDSAttrParser::parsePluginCommon(
MDSDictionary *mdsDict)
{
parseObjectRecord(mdsDict);
const RelationInfo *relationInfo =
MDSRecordTypeToRelation(MDS_CDSADIR_COMMON_RECORDTYPE);
assert(relationInfo != NULL);
parseMdsRecord(mdsDict, relationInfo, mCdsaDirHand);
}
void MDSAttrParser::parsePluginSpecific(
MDSDictionary *mdsDict)
{
CFStringRef recordTypeStr =
(CFStringRef)mdsDict->lookup(MDS_INFO_FILE_RECORD_TYPE,
true, CFStringGetTypeID());
if(recordTypeStr == NULL) {
MPDebug("%s: no %s record found\n", mdsDict->fileDesc(),
MDS_INFO_FILE_RECORD_TYPE);
return;
}
const char *recordTypeCStr = MDSCFStringToCString(recordTypeStr);
const RelationInfo *relationInfo = MDSRecordTypeNameToRelation(recordTypeCStr);
if(relationInfo == NULL) {
Syslog::alert("MDS file %s has unsupported record type %s",
mdsDict->fileDesc(), recordTypeCStr);
MPDebug("MDS file %s has unsupported record type %s",
mdsDict->fileDesc(), recordTypeCStr);
delete [] recordTypeCStr;
return;
}
MPDebug("Parsing MDS file %s, recordType %s", mdsDict->fileDesc(), recordTypeCStr);
delete [] recordTypeCStr;
switch(relationInfo->DataRecordType) {
case MDS_CDSADIR_CSP_CAPABILITY_RECORDTYPE:
parseCspCapabilitiesRecord(mdsDict);
break;
case MDS_CDSADIR_TP_OIDS_RECORDTYPE:
parseTpPolicyOidsRecord(mdsDict);
break;
default:
parseMdsRecord(mdsDict, relationInfo, mCdsaDirHand);
}
}
void MDSAttrParser::parseObjectRecord(
MDSDictionary *mdsDict)
{
assert(mdsDict != NULL);
assert(mObjectHand != 0);
parseMdsRecord(mdsDict, &kObjectRelation, mObjectHand);
}
void MDSAttrParser::parseMdsRecord(
MDSDictionary *mdsDict,
const RelationInfo *relInfo,
CSSM_DB_HANDLE dbHand)
{
assert(mdsDict != NULL);
assert(relInfo != NULL);
assert(dbHand != 0);
unsigned numSchemaAttrs = relInfo->NumberOfAttributes;
CSSM_DB_ATTRIBUTE_DATA *dbAttrs = new CSSM_DB_ATTRIBUTE_DATA[numSchemaAttrs];
uint32 foundAttrs = 0;
mdsDict->lookupAttributes(relInfo, dbAttrs, foundAttrs);
MDSInsertRecord(dbAttrs, foundAttrs, relInfo->DataRecordType, mDl, dbHand);
MDSFreeDbRecordAttrs(dbAttrs, foundAttrs);
delete [] dbAttrs;
}
void MDSAttrParser::parseCspCapabilitiesRecord(
MDSDictionary *mdsDict)
{
const RelationInfo *topRelInfo =
MDSRecordTypeToRelation(MDS_CDSADIR_CSP_CAPABILITY_RECORDTYPE);
assert(topRelInfo != NULL);
uint32 numInAttrs = topRelInfo->NumberOfAttributes;
CSSM_DB_ATTRIBUTE_DATA_PTR outAttrs = new CSSM_DB_ATTRIBUTE_DATA[numInAttrs];
uint32 numTopLevelAttrs;
mdsDict->lookupAttributes(&CSPCapabilitiesDict1RelInfo, outAttrs,
numTopLevelAttrs);
bool fetchedFromDisk = false;
CFArrayRef capArray = (CFArrayRef)mdsDict->lookupWithIndirect("Capabilities",
mBundle,
CFArrayGetTypeID(),
fetchedFromDisk);
if(capArray == NULL) {
MPDebug("parseCspCapabilitiesRecord: no (or bad) Capabilities");
delete [] outAttrs;
return;
}
CFIndex capArraySize = CFArrayGetCount(capArray);
CFIndex capDex;
for(capDex=0; capDex<capArraySize; capDex++) {
MPDebug("...parsing Capability %d", (int)capDex);
CFDictionaryRef capDict =
(CFDictionaryRef)CFArrayGetValueAtIndex(capArray, capDex);
if((capDict == NULL) ||
(CFGetTypeID(capDict) != CFDictionaryGetTypeID())) {
MPDebug("parseCspCapabilitiesRecord: bad Capabilities element");
break;
}
MDSDictionary capDictMds(capDict);
uint32 numCapDictAttrs;
capDictMds.lookupAttributes(&CSPCapabilitiesDict2RelInfo,
&outAttrs[numTopLevelAttrs],
numCapDictAttrs);
MDSRawValueToDbAttr(&capDex, sizeof(CFIndex), CSSM_DB_ATTRIBUTE_FORMAT_UINT32,
"GroupId", outAttrs[numTopLevelAttrs + numCapDictAttrs]);
numCapDictAttrs++;
CFArrayRef attrArray = (CFArrayRef)capDictMds.lookup("Attributes",
true, CFArrayGetTypeID());
if(attrArray == NULL) {
MPDebug("parseCspCapabilitiesRecord: no (or bad) Attributes");
break;
}
CFIndex attrArraySize = CFArrayGetCount(attrArray);
CFIndex attrDex;
for(attrDex=0; attrDex<attrArraySize; attrDex++) {
MPDebug(" ...parsing Attribute %d", (int)attrDex);
CFDictionaryRef attrDict =
(CFDictionaryRef)CFArrayGetValueAtIndex(attrArray, attrDex);
if((attrDict == NULL) ||
(CFGetTypeID(attrDict) != CFDictionaryGetTypeID())) {
MPDebug("parseCspCapabilitiesRecord: bad Attributes element");
break;
}
MDSDictionary attrDictMds(attrDict);
uint32 numAttrDictAttrs;
attrDictMds.lookupAttributes(&CSPCapabilitiesDict3RelInfo,
&outAttrs[numTopLevelAttrs + numCapDictAttrs],
numAttrDictAttrs);
MDSInsertRecord(outAttrs,
numTopLevelAttrs + numCapDictAttrs + numAttrDictAttrs,
MDS_CDSADIR_CSP_CAPABILITY_RECORDTYPE,
mDl,
mCdsaDirHand);
MDSFreeDbRecordAttrs(&outAttrs[numTopLevelAttrs + numCapDictAttrs],
numAttrDictAttrs);
}
MDSFreeDbRecordAttrs(&outAttrs[numTopLevelAttrs], numCapDictAttrs);
}
MDSFreeDbRecordAttrs(outAttrs, numTopLevelAttrs);
delete [] outAttrs;
if(fetchedFromDisk) {
CF_RELEASE(capArray);
}
}
void MDSAttrParser::parseTpPolicyOidsRecord(
MDSDictionary *mdsDict)
{
const RelationInfo *topRelInfo =
MDSRecordTypeToRelation(MDS_CDSADIR_TP_OIDS_RECORDTYPE);
assert(topRelInfo != NULL);
uint32 numInAttrs = topRelInfo->NumberOfAttributes;
CSSM_DB_ATTRIBUTE_DATA_PTR outAttrs = new CSSM_DB_ATTRIBUTE_DATA[numInAttrs];
uint32 numTopLevelAttrs;
mdsDict->lookupAttributes(&TpPolicyOidsDict1RelInfo, outAttrs,
numTopLevelAttrs);
CFArrayRef policyArray = (CFArrayRef)mdsDict->lookup("Policies",
true, CFArrayGetTypeID());
if(policyArray == NULL) {
MPDebug("parseTpPolicyOidsRecord: no (or bad) Policies");
delete [] outAttrs;
return;
}
CFIndex policyArraySize = CFArrayGetCount(policyArray);
CFIndex policyDex;
for(policyDex=0; policyDex<policyArraySize; policyDex++) {
MPDebug("...parsing Policy %d", (int)policyDex);
CFDictionaryRef policyDict =
(CFDictionaryRef)CFArrayGetValueAtIndex(policyArray, policyDex);
if((policyDict == NULL) ||
(CFGetTypeID(policyDict) != CFDictionaryGetTypeID())) {
MPDebug("parseTpPolicyOidsRecord: bad Policies element");
break;
}
MDSDictionary policyDictMds(policyDict);
uint32 numPolicyDictAttrs;
policyDictMds.lookupAttributes(&TpPolicyOidsDict2RelInfo,
&outAttrs[numTopLevelAttrs],
numPolicyDictAttrs);
MDSInsertRecord(outAttrs,
numTopLevelAttrs + numPolicyDictAttrs,
MDS_CDSADIR_TP_OIDS_RECORDTYPE,
mDl,
mCdsaDirHand);
MDSFreeDbRecordAttrs(outAttrs + numTopLevelAttrs, numPolicyDictAttrs);
}
MDSFreeDbRecordAttrs(outAttrs, numTopLevelAttrs);
delete [] outAttrs;
}
}