--- /dev/null
+/*
+ * Copyright (c) 2000-2001 Apple Computer, 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 Apple Computer, Inc., all rights reserved.
+*/
+
+#include "MDSAttrUtils.h"
+#include <strings.h>
+
+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<char *>(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; i<numAttrs; i++) {
+ assert(attrs->Value != 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<CSSM_DB_ATTRIBUTE_DATA_PTR>(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