]> git.saurik.com Git - apple/security.git/blobdiff - libsecurity_mds/lib/MDSAttrUtils.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_mds / lib / MDSAttrUtils.cpp
diff --git a/libsecurity_mds/lib/MDSAttrUtils.cpp b/libsecurity_mds/lib/MDSAttrUtils.cpp
new file mode 100644 (file)
index 0000000..81bb41b
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * 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