#include "MDSAttrParser.h"
#include "MDSAttrUtils.h"
#include "MDSDictionary.h"
#include <security_utilities/logging.h>
#include <security_utilities/cfutilities.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),
mGuid(NULL),
mDefaults(NULL)
{
size_t 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;
delete [] mGuid;
}
void MDSAttrParser::parseAttrs(CFStringRef subdir)
{
CFRef<CFArrayRef> bundleInfoFiles = CFBundleCopyResourceURLsOfType(mBundle,
CFSTR(MDS_INFO_TYPE),
subdir);
if(!bundleInfoFiles) {
Syslog::alert("MDSAttrParser: no mdsattr files for %s", mPath);
return;
}
assert(CFGetTypeID(bundleInfoFiles) == CFArrayGetTypeID());
CFIndex numFiles = CFArrayGetCount(bundleInfoFiles);
for(CFIndex i=0; i<numFiles; i++) {
CFURLRef infoUrl = 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;
}
CFRef<CFStringRef> lastComponent = CFURLCopyLastPathComponent(infoUrl);
if (lastComponent) {
CFStringRef resFilePfx = CFSTR("._");
CFIndex resFilePfxLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(resFilePfx), kCFStringEncodingUTF8);
CFRange range = CFRangeMake(0, resFilePfxLen);
Boolean skip = CFStringFindWithOptions(lastComponent,
resFilePfx,
range,
0,
NULL);
if (skip == true) {
Syslog::warning("MDSAttrParser: ignoring resource file");
continue;
}
}
parseFile(infoUrl, subdir);
}
}
void MDSAttrParser::parseFile(CFURLRef infoUrl, CFStringRef subdir)
{
CFStringRef infoType = NULL;
MDSDictionary mdsDict(infoUrl, subdir, mPath);
mdsDict.setDefaults(mDefaults);
if (mGuid == NULL) {
CFStringRef guid = (CFStringRef)mdsDict.lookup("ModuleID", true, CFStringGetTypeID());
if (guid) {
CFIndex copylen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(guid), kCFStringEncodingUTF8) + 1;
mGuid = new char[copylen];
if (false == CFStringGetCString(guid, mGuid, copylen, kCFStringEncodingUTF8)) {
logFileError("Error copying GUID", infoUrl, NULL, NULL);
delete [] mGuid;
mGuid = NULL;
CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR);
}
}
else {
logFileError("No GUID associated with plugin?", infoUrl, NULL, NULL);
CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR);
}
}
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);
CssmError::throwMe(CSSM_ERRCODE_MDS_ERROR);
}
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(...) {
}
}
void MDSAttrParser::logFileError(
const char *op,
CFURLRef fileUrl,
CFStringRef errStr, SInt32 *errNo) {
CFStringRef urlStr = CFURLGetString(fileUrl);
const char *cUrlStr = CFStringGetCStringPtr(urlStr, kCFStringEncodingUTF8);
char* stringBuffer = NULL;
if (cUrlStr == NULL)
{
CFIndex maxLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(urlStr), kCFStringEncodingUTF8) + 1;
stringBuffer = (char*) malloc(maxLen);
CFStringGetCString(urlStr, stringBuffer, maxLen, kCFStringEncodingUTF8);
cUrlStr = stringBuffer;
}
if(errStr) {
const char *cerrStr = CFStringGetCStringPtr(errStr, kCFStringEncodingUTF8);
char* sbuf2 = NULL;
if (cerrStr == NULL)
{
CFIndex maxLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(errStr), kCFStringEncodingUTF8) + 1;
sbuf2 = (char*) malloc(maxLen);
CFStringGetCString(urlStr, sbuf2, maxLen, kCFStringEncodingUTF8);
cUrlStr = sbuf2;
}
Syslog::alert("MDS: %s: bundle %s url %s: error %s",
op, mPath, cUrlStr, cerrStr);
if (sbuf2 != NULL)
{
free(sbuf2);
}
}
else {
Syslog::alert("MDS: %s: bundle %s url %s: error %d",
op, mPath, cUrlStr, (int)(errNo ? *errNo : 0));
}
if (stringBuffer != NULL)
{
free(stringBuffer);
}
}
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);
CFRef<CFArrayRef> capArray = (CFArrayRef)mdsDict->lookupWithIndirect("Capabilities",
mBundle,
CFArrayGetTypeID());
if(!capArray) {
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);
if (capDex > uint32(~0)) {
MPDebug("parseCspCapabilitiesRecord: too large an index for MDS");
break;
}
uint32 index32 = uint32(capDex);
MDSRawValueToDbAttr(&index32, sizeof(index32), 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;
}
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;
}
}