X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_mds/lib/MDSAttrUtils.cpp diff --git a/Security/libsecurity_mds/lib/MDSAttrUtils.cpp b/Security/libsecurity_mds/lib/MDSAttrUtils.cpp new file mode 100644 index 00000000..a47ecc4f --- /dev/null +++ b/Security/libsecurity_mds/lib/MDSAttrUtils.cpp @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2000-2001,2011,2014 Apple Inc. All Rights Reserved. + * + * The contents of this file constitute Original Code as defined in and are + * subject to the Apple Public Source License Version 1.2 (the 'License'). + * You may not use this file except in compliance with the License. Please obtain + * a copy of the License at http://www.apple.com/publicsource and read it before + * using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS + * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT + * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the + * specific language governing rights and limitations under the License. + */ + + +/* + File: MDSAttrUtils.cpp + + Contains: Stateless functions used by MDSAttrParser. + + Copyright (c) 2001,2011,2014 Apple Inc. All Rights Reserved. +*/ + +#include "MDSAttrUtils.h" +#include + +namespace Security +{ + +/* + * Fill in one CSSM_DB_ATTRIBUTE_DATA with specified data, type and attribute name. + * CSSM_DB_ATTRIBUTE_DATA.Value and its referent are new[]'d and copied. + * Assumes: + * -- AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING + * -- NumberOfValues = 1 + */ +void MDSRawValueToDbAttr( + const void *value, + size_t len, + CSSM_DB_ATTRIBUTE_FORMAT attrFormat, // CSSM_DB_ATTRIBUTE_FORMAT_STRING, etc. + const char *attrName, + CSSM_DB_ATTRIBUTE_DATA &attr, + uint32 numValues) +{ + CSSM_DB_ATTRIBUTE_INFO_PTR attrInfo = &attr.Info; + attrInfo->AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; + attrInfo->Label.AttributeName = const_cast(attrName); + attrInfo->AttributeFormat = attrFormat; + attr.NumberOfValues = numValues; + attr.Value = new CSSM_DATA[1]; + attr.Value->Data = new uint8[len]; + attr.Value->Length = len; + memcpy(attr.Value->Data, value, len); +} + + +/* + * Free data new[]'d in the above function. + */ +void MDSFreeDbRecordAttrs( + CSSM_DB_ATTRIBUTE_DATA *attrs, + unsigned numAttrs) +{ + uint32 i; + for(i=0; iValue != NULL); + delete [] attrs->Value->Data; + attrs->Value->Data = NULL; + attrs->Value->Length = 0; + delete [] attrs->Value; + attrs->Value = NULL; + attrs++; + } +} + +/* safely get a new[]'d C string from a CFString */ +char *MDSCFStringToCString( + CFStringRef cfStr) +{ + char *rtn = NULL; + CFIndex len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfStr), kCFStringEncodingUTF8) + 1/*nul terminator*/; + rtn = new char[len]; + if(rtn) { + CFStringGetCString(cfStr, rtn, len, kCFStringEncodingUTF8); + } + return rtn; +} + +/* copy a new[]'d C string from a C string */ +char *MDSCopyCstring( + const char *inStr) +{ + char *outStr = new char[::strlen(inStr) + 1]; + strcpy(outStr, inStr); + return outStr; +} + +/* + * Given a CFTypeRef which is either a CFString, a CFNumber, or a CFBoolean, + * do our best to convert it to a uint32. If it's a CFString, we'll use a + * MDSNameValuePair to convert it. CFStrings expressed as decimal numbers + * are also converted properly. (MAYBE we'll convert hex strings too...TBD...) + * Returns true if conversion was successful. + */ +bool MDSCfTypeToUInt32( + CFTypeRef cfValue, + const MDSNameValuePair *nameValues, // optional for converting strings to numbers + const char *key, // for debug logging only + uint32 &iValue, // RETURNED + size_t &iValueLen) // RETURNED +{ + assert(cfValue != NULL); + CFTypeID valueType = CFGetTypeID(cfValue); + if(valueType == CFStringGetTypeID()) { + uint32 tmpValue = 0; + CSSM_RETURN crtn = MDSStringToUint32((CFStringRef)cfValue, + nameValues, tmpValue); + if(crtn) { + MPDebug("cfTypeToInt: key %s uint32 form, string data (%s), " + "bad conv", key, + CFStringGetCStringPtr((CFStringRef)cfValue, + kCFStringEncodingUTF8)); + return false; + } + iValue = tmpValue; + iValueLen = sizeof(tmpValue); + return true; + } /* stored as string */ + else if(valueType == CFNumberGetTypeID()) { + int64_t tmpValue = 0; + /* be paranoid - there is no unsigned type for CFNumber */ + CFNumberRef cfNum = (CFNumberRef)cfValue; + CFNumberType numType = CFNumberGetType(cfNum); + switch(numType) { + case kCFNumberSInt8Type: + iValueLen = 1; break; + case kCFNumberSInt16Type: + iValueLen = 2; break; + case kCFNumberSInt32Type: + iValueLen = 4; break; + case kCFNumberSInt64Type: // apparently the default + // There are no 64-bit types in CDSA, so assume this is how + // CF encoded an unsigned 32-bit int whose high bit was set. + iValueLen = 4; break; + case kCFNumberCharType: + iValueLen = sizeof(char); break; + case kCFNumberShortType: + iValueLen = sizeof(short); break; + case kCFNumberIntType: + iValueLen = sizeof(int); break; + case kCFNumberLongType: + MPDebug("Warning: MDS key %s encoded kCFNumberLongType", key); + iValueLen = sizeof(long); break; + default: + MPDebug("MDS cfTypeToInt: Bad CFNumber type (%ld) key %s", numType, key); + return false; + } + Boolean brtn = CFNumberGetValue(cfNum, numType, &tmpValue); + if(!brtn) { + MPDebug("MDS cfTypeToInt: Bad CFNumber conversion"); + return false; + } + iValue = uint32(tmpValue); + return true; + } /* stored as number */ + else if(valueType == CFBooleanGetTypeID()) { + Boolean b = CFBooleanGetValue((CFBooleanRef)cfValue); + iValue = b ? 1 : 0; + iValueLen = sizeof(iValue); + return true; + } + else { + MPDebug("MDS cfTypeToInt: key %s, uint64 form, bad CF type (%d)", + key, (int)valueType); + return false; + } +} + +/* + * Insert a record, defined by a CSSM_DB_ATTRIBUTE_DATA array, into specified + * DL and DB. Returns true on success. + */ +bool MDSInsertRecord( + const CSSM_DB_ATTRIBUTE_DATA *inAttr, + unsigned numAttrs, + CSSM_DB_RECORDTYPE recordType, + MDSSession &dl, + CSSM_DB_HANDLE dbHand) +{ + CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrData; + CSSM_DB_UNIQUE_RECORD_PTR uid = NULL; + bool ourRtn = true; + + recordAttrData.DataRecordType = recordType; + recordAttrData.SemanticInformation = 0; + recordAttrData.NumberOfAttributes = numAttrs; + recordAttrData.AttributeData = + const_cast(inAttr); + + try { + dl.DataInsert(dbHand, + recordType, + &recordAttrData, + NULL, + uid); + } + catch (const CssmError &cerr) { + MPDebug("MDSInsertRecord: DataInsert: %d", cerr.error); + ourRtn = false; + } + catch(...) { + MPDebug("MDSInsertRecord: DataInsert: unknown exception"); + ourRtn = false; + } + if(uid != NULL) { + dl.FreeUniqueRecord(dbHand, *uid); + } + return ourRtn; +} + +/* + * Convert a number expressed as a CFString to a uint32 using the specified + * name/value conversion table. The string may have multiple fields from that + * table, ORd together in normal C syntax. Like + * + * CSSM_SERVICE_CSP | CSSM_SERVICE_DL + * + * Individual tokens can also be expressed numerically, either in decimal or + * (if prefaced by "0x" hex. Numeric tokens and symbolic string tokens can + * be intermixed in the same incoming string. + * + * Individual tokens can be prefixed with "<<" indicating that the indicated + * value is to be shifted 16 bits. Cf. CL Primary Relation, {Cert,Crl}TypeFormat. + * This applies to both numeric and string tokens. + */ +CSSM_RETURN MDSStringToUint32( + CFStringRef str, + const MDSNameValuePair *table, // optional, string must be decimal + uint32 &value) +{ + char *cstr = MDSCFStringToCString(str); + if(cstr == NULL) { + /* should "never" happen...right? */ + MPDebug("MDSStringToUint32: CFString conversion error"); + return CSSMERR_CSSM_MDS_ERROR; + } + + char tokenStr[200]; + char *src = cstr; + char *dst = tokenStr; + char c; + CSSM_RETURN crtn = CSSM_OK; + + value = 0; + while(*src != '\0') { + /* Get one token from src --> tokenStr[] */ + /* First skip whitespace and '|' */ + for( ; *src != '\0'; src++) { + c = *src; + if(!isspace(c) && (c != '|')) { + /* first char of token */ + *dst++ = c; + src++; + break; + } + } + if((*src == '\0') && (dst == tokenStr)) { + /* done */ + break; + } + + /* dst[-1] is the first good character of token; copy until + * space or '|' */ + for( ; *src != '\0'; src++) { + c = *src; + if(isspace(c) || (c == '|')) { + break; + } + else { + *dst++ = c; + } + } + + /* NULL terminate token string, convert to numeric value */ + *dst = '\0'; + uint32 tokenVal = 0; + CSSM_RETURN crtn = MDSAttrNameToValue(tokenStr, table, tokenVal); + if(crtn) { + /* punt */ + break; + } + value |= tokenVal; + + /* restart */ + dst = tokenStr; + } + delete [] cstr; + return crtn; +} + +} // end namespace Security