1/* 2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. 3 * 4 * The contents of this file constitute Original Code as defined in and are 5 * subject to the Apple Public Source License Version 1.2 (the 'License'). 6 * You may not use this file except in compliance with the License. Please obtain 7 * a copy of the License at http://www.apple.com/publicsource and read it before 8 * using this file. 9 * 10 * This Original Code and all software distributed under the License are 11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS 12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT 13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the 15 * specific language governing rights and limitations under the License. 16 */ 17 18 19/* 20 File: MDSAttrUtils.cpp 21 22 Contains: Stateless functions used by MDSAttrParser. 23 24 Copyright: (c) 2001 Apple Computer, Inc., all rights reserved. 25*/ 26 27#include "MDSAttrUtils.h" 28#include <strings.h> 29 30namespace Security 31{ 32 33/* 34 * Fill in one CSSM_DB_ATTRIBUTE_DATA with specified data, type and attribute name. 35 * CSSM_DB_ATTRIBUTE_DATA.Value and its referent are new[]'d and copied. 36 * Assumes: 37 * -- AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING 38 * -- NumberOfValues = 1 39 */ 40void MDSRawValueToDbAttr( 41 const void *value, 42 size_t len, 43 CSSM_DB_ATTRIBUTE_FORMAT attrFormat, // CSSM_DB_ATTRIBUTE_FORMAT_STRING, etc. 44 const char *attrName, 45 CSSM_DB_ATTRIBUTE_DATA &attr, 46 uint32 numValues) 47{ 48 CSSM_DB_ATTRIBUTE_INFO_PTR attrInfo = &attr.Info; 49 attrInfo->AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; 50 attrInfo->Label.AttributeName = const_cast<char *>(attrName); 51 attrInfo->AttributeFormat = attrFormat; 52 attr.NumberOfValues = numValues; 53 attr.Value = new CSSM_DATA[1]; 54 attr.Value->Data = new uint8[len]; 55 attr.Value->Length = len; 56 memcpy(attr.Value->Data, value, len); 57} 58 59 60/* 61 * Free data new[]'d in the above function. 62 */ 63void MDSFreeDbRecordAttrs( 64 CSSM_DB_ATTRIBUTE_DATA *attrs, 65 unsigned numAttrs) 66{ 67 uint32 i; 68 for(i=0; i<numAttrs; i++) { 69 assert(attrs->Value != NULL); 70 delete [] attrs->Value->Data; 71 attrs->Value->Data = NULL; 72 attrs->Value->Length = 0; 73 delete [] attrs->Value; 74 attrs->Value = NULL; 75 attrs++; 76 } 77} 78 79/* safely get a new[]'d C string from a CFString */ 80char *MDSCFStringToCString( 81 CFStringRef cfStr) 82{ 83 char *rtn = NULL; 84 CFIndex len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfStr), kCFStringEncodingUTF8) + 1/*nul terminator*/; 85 rtn = new char[len]; 86 if(rtn) { 87 CFStringGetCString(cfStr, rtn, len, kCFStringEncodingUTF8); 88 } 89 return rtn; 90} 91 92/* copy a new[]'d C string from a C string */ 93char *MDSCopyCstring( 94 const char *inStr) 95{ 96 char *outStr = new char[::strlen(inStr) + 1]; 97 strcpy(outStr, inStr); 98 return outStr; 99} 100 101/* 102 * Given a CFTypeRef which is either a CFString, a CFNumber, or a CFBoolean, 103 * do our best to convert it to a uint32. If it's a CFString, we'll use a 104 * MDSNameValuePair to convert it. CFStrings expressed as decimal numbers 105 * are also converted properly. (MAYBE we'll convert hex strings too...TBD...) 106 * Returns true if conversion was successful. 107 */ 108bool MDSCfTypeToUInt32( 109 CFTypeRef cfValue, 110 const MDSNameValuePair *nameValues, // optional for converting strings to numbers 111 const char *key, // for debug logging only 112 uint32 &iValue, // RETURNED 113 size_t &iValueLen) // RETURNED 114{ 115 assert(cfValue != NULL); 116 CFTypeID valueType = CFGetTypeID(cfValue); 117 if(valueType == CFStringGetTypeID()) { 118 uint32 tmpValue = 0; 119 CSSM_RETURN crtn = MDSStringToUint32((CFStringRef)cfValue, 120 nameValues, tmpValue); 121 if(crtn) { 122 MPDebug("cfTypeToInt: key %s uint32 form, string data (%s), " 123 "bad conv", key, 124 CFStringGetCStringPtr((CFStringRef)cfValue, 125 kCFStringEncodingUTF8)); 126 return false; 127 } 128 iValue = tmpValue; 129 iValueLen = sizeof(tmpValue); 130 return true; 131 } /* stored as string */ 132 else if(valueType == CFNumberGetTypeID()) { 133 int64_t tmpValue = 0; 134 /* be paranoid - there is no unsigned type for CFNumber */ 135 CFNumberRef cfNum = (CFNumberRef)cfValue; 136 CFNumberType numType = CFNumberGetType(cfNum); 137 switch(numType) { 138 case kCFNumberSInt8Type: 139 iValueLen = 1; break; 140 case kCFNumberSInt16Type: 141 iValueLen = 2; break; 142 case kCFNumberSInt32Type: 143 iValueLen = 4; break; 144 case kCFNumberSInt64Type: // apparently the default 145 // There are no 64-bit types in CDSA, so assume this is how 146 // CF encoded an unsigned 32-bit int whose high bit was set. 147 iValueLen = 4; break; 148 case kCFNumberCharType: 149 iValueLen = sizeof(char); break; 150 case kCFNumberShortType: 151 iValueLen = sizeof(short); break; 152 case kCFNumberIntType: 153 iValueLen = sizeof(int); break; 154 case kCFNumberLongType: 155 MPDebug("Warning: MDS key %s encoded kCFNumberLongType", key); 156 iValueLen = sizeof(long); break; 157 default: 158 MPDebug("MDS cfTypeToInt: Bad CFNumber type (%ld) key %s", numType, key); 159 return false; 160 } 161 Boolean brtn = CFNumberGetValue(cfNum, numType, &tmpValue); 162 if(!brtn) { 163 MPDebug("MDS cfTypeToInt: Bad CFNumber conversion"); 164 return false; 165 } 166 iValue = uint32(tmpValue); 167 return true; 168 } /* stored as number */ 169 else if(valueType == CFBooleanGetTypeID()) { 170 Boolean b = CFBooleanGetValue((CFBooleanRef)cfValue); 171 iValue = b ? 1 : 0; 172 iValueLen = sizeof(iValue); 173 return true; 174 } 175 else { 176 MPDebug("MDS cfTypeToInt: key %s, uint64 form, bad CF type (%d)", 177 key, (int)valueType); 178 return false; 179 } 180} 181 182/* 183 * Insert a record, defined by a CSSM_DB_ATTRIBUTE_DATA array, into specified 184 * DL and DB. Returns true on success. 185 */ 186bool MDSInsertRecord( 187 const CSSM_DB_ATTRIBUTE_DATA *inAttr, 188 unsigned numAttrs, 189 CSSM_DB_RECORDTYPE recordType, 190 MDSSession &dl, 191 CSSM_DB_HANDLE dbHand) 192{ 193 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrData; 194 CSSM_DB_UNIQUE_RECORD_PTR uid = NULL; 195 bool ourRtn = true; 196 197 recordAttrData.DataRecordType = recordType; 198 recordAttrData.SemanticInformation = 0; 199 recordAttrData.NumberOfAttributes = numAttrs; 200 recordAttrData.AttributeData = 201 const_cast<CSSM_DB_ATTRIBUTE_DATA_PTR>(inAttr); 202 203 try { 204 dl.DataInsert(dbHand, 205 recordType, 206 &recordAttrData, 207 NULL, 208 uid); 209 } 210 catch (const CssmError &cerr) { 211 MPDebug("MDSInsertRecord: DataInsert: %d", cerr.error); 212 ourRtn = false; 213 } 214 catch(...) { 215 MPDebug("MDSInsertRecord: DataInsert: unknown exception"); 216 ourRtn = false; 217 } 218 if(uid != NULL) { 219 dl.FreeUniqueRecord(dbHand, *uid); 220 } 221 return ourRtn; 222} 223 224/* 225 * Convert a number expressed as a CFString to a uint32 using the specified 226 * name/value conversion table. The string may have multiple fields from that 227 * table, ORd together in normal C syntax. Like 228 * 229 * CSSM_SERVICE_CSP | CSSM_SERVICE_DL 230 * 231 * Individual tokens can also be expressed numerically, either in decimal or 232 * (if prefaced by "0x" hex. Numeric tokens and symbolic string tokens can 233 * be intermixed in the same incoming string. 234 * 235 * Individual tokens can be prefixed with "<<" indicating that the indicated 236 * value is to be shifted 16 bits. Cf. CL Primary Relation, {Cert,Crl}TypeFormat. 237 * This applies to both numeric and string tokens. 238 */ 239CSSM_RETURN MDSStringToUint32( 240 CFStringRef str, 241 const MDSNameValuePair *table, // optional, string must be decimal 242 uint32 &value) 243{ 244 char *cstr = MDSCFStringToCString(str); 245 if(cstr == NULL) { 246 /* should "never" happen...right? */ 247 MPDebug("MDSStringToUint32: CFString conversion error"); 248 return CSSMERR_CSSM_MDS_ERROR; 249 } 250 251 char tokenStr[200]; 252 char *src = cstr; 253 char *dst = tokenStr; 254 char c; 255 CSSM_RETURN crtn = CSSM_OK; 256 257 value = 0; 258 while(*src != '\0') { 259 /* Get one token from src --> tokenStr[] */ 260 /* First skip whitespace and '|' */ 261 for( ; *src != '\0'; src++) { 262 c = *src; 263 if(!isspace(c) && (c != '|')) { 264 /* first char of token */ 265 *dst++ = c; 266 src++; 267 break; 268 } 269 } 270 if((*src == '\0') && (dst == tokenStr)) { 271 /* done */ 272 break; 273 } 274 275 /* dst[-1] is the first good character of token; copy until 276 * space or '|' */ 277 for( ; *src != '\0'; src++) { 278 c = *src; 279 if(isspace(c) || (c == '|')) { 280 break; 281 } 282 else { 283 *dst++ = c; 284 } 285 } 286 287 /* NULL terminate token string, convert to numeric value */ 288 *dst = '\0'; 289 uint32 tokenVal = 0; 290 CSSM_RETURN crtn = MDSAttrNameToValue(tokenStr, table, tokenVal); 291 if(crtn) { 292 /* punt */ 293 break; 294 } 295 value |= tokenVal; 296 297 /* restart */ 298 dst = tokenStr; 299 } 300 delete [] cstr; 301 return crtn; 302} 303 304} // end namespace Security 305