X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_transform/lib/SecCollectTransform.cpp diff --git a/Security/libsecurity_transform/lib/SecCollectTransform.cpp b/Security/libsecurity_transform/lib/SecCollectTransform.cpp new file mode 100644 index 00000000..6cc471dc --- /dev/null +++ b/Security/libsecurity_transform/lib/SecCollectTransform.cpp @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2010-2011 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The 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. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include "Transform.h" +#include "SecTransform.h" +#include "SecCollectTransform.h" +#include "SecCustomTransform.h" +#include "misc.h" +#include "c++utils.h" +#include "Utilities.h" + +static CFStringRef kCollectTransformName = CFSTR("com.apple.security.seccollecttransform"); + +static SecTransformInstanceBlock CollectTransform(CFStringRef name, + SecTransformRef newTransform, + SecTransformImplementationRef ref) +{ + SecTransformInstanceBlock instanceBlock = + ^{ + __block CFMutableArrayRef allValues = + CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + __block Boolean isSameType = TRUE; + CFTypeRef input_ah = SecTranformCustomGetAttribute(ref, kSecTransformInputAttributeName, kSecTransformMetaAttributeRef); + ah2ta(input_ah)->direct_error_handling = 1; + + dispatch_block_t no_more_output = ^ + { + SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, input_ah, ^(SecTransformStringOrAttributeRef a, CFTypeRef v) { return v; }); + }; + + // Create a block to deal with out of memory errors + dispatch_block_t oom = ^ + { + CFTypeRefHolder localErr(GetNoMemoryError()); + SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, + kSecTransformMetaAttributeValue, localErr.Get()); + no_more_output(); + }; + + SecTransformSetTransformAction(ref, kSecTransformActionFinalize, + ^() + { + if (NULL != allValues) + { + CFRelease(allValues); + } + + return (CFTypeRef) NULL; + }); + + SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, + input_ah, + ^(SecTransformStringOrAttributeRef attribute, CFTypeRef value) + { + CFIndex len = CFArrayGetCount(allValues); + +#if 0 + if (NULL == value && 0 == len) + { + SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, + kSecTransformMetaAttributeValue, NULL); + no_more_output(); + return value; + } +#endif + + if (value && isSameType && len > 0) + { + isSameType = CFGetTypeID(CFArrayGetValueAtIndex(allValues, 0)) == CFGetTypeID(value); + } + + if (value) + { + + if (CFGetTypeID(value) == CFErrorGetTypeID()) + { + SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, + kSecTransformMetaAttributeValue, value); + no_more_output(); + return value; + } + + // For mutable types, we want an immutable copy. + /// XXX: write a more general CFImutableCopy and use it here. + if (CFGetTypeID(value) == CFDataGetTypeID()) + { + CFDataRef copy = CFDataCreateCopy(NULL, (CFDataRef)value); + + CFArrayAppendValue(allValues, copy); + CFRelease(copy); + } + else + { + CFArrayAppendValue(allValues, value); + } + + if (CFArrayGetCount(allValues) != len +1) + { + oom(); + return value; + } + } + else + { + if (isSameType) + { + // Deal with data or no items at all + CFTypeID type = CFArrayGetCount(allValues) ? + CFGetTypeID(CFArrayGetValueAtIndex(allValues, 0)) : CFDataGetTypeID(); + if (CFDataGetTypeID() == type) + { + CFIndex total_len = 0; + CFIndex prev_total_len = 0; + CFIndex i; + const CFIndex n_datas = CFArrayGetCount(allValues); + + for(i = 0; i < n_datas; i++) + { + total_len += + CFDataGetLength((CFDataRef)CFArrayGetValueAtIndex(allValues, i)); + if (total_len < prev_total_len) + { + oom(); + return value; + } + prev_total_len = total_len; + } + + CFMutableDataRef result = CFDataCreateMutable(NULL, total_len); + if (!result) + { + oom(); + return value; + } + + for(i = 0; i < n_datas; i++) + { + CFDataRef d = (CFDataRef)CFArrayGetValueAtIndex(allValues, i); + CFDataAppendBytes(result, CFDataGetBytePtr(d), CFDataGetLength(d)); + } + + if (CFDataGetLength(result) != total_len) + { + oom(); + return value; + } + + CFDataRef resultData = CFDataCreateCopy(NULL, result); + + SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, + kSecTransformMetaAttributeValue, (CFTypeRef)resultData); + + CFRelease(resultData); + + SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, + kSecTransformMetaAttributeValue, (CFTypeRef)value); + no_more_output(); + + CFRelease(result); + return value; + } + else if (CFStringGetTypeID() == type) + { + // deal with strings + CFStringRef resultStr = CFStringCreateByCombiningStrings(NULL, allValues, CFSTR("")); + + SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, + kSecTransformMetaAttributeValue, (CFTypeRef)resultStr); + SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, + kSecTransformMetaAttributeValue, (CFTypeRef)value); + no_more_output(); + + return value; + } + else + { + // special case the singleton + if (1 == CFArrayGetCount(allValues)) + { + CFTypeRef result = (CFTypeRef)CFRetain(CFArrayGetValueAtIndex(allValues, 0)); + + SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, + kSecTransformMetaAttributeValue, (CFTypeRef)result); + SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, + kSecTransformMetaAttributeValue, (CFTypeRef)value); + no_more_output(); + + return value; + } + } + } + // Fall through for non-homogenous or un-mergable type + CFArrayRef resultArray = CFArrayCreateCopy(kCFAllocatorDefault, allValues); + SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, + kSecTransformMetaAttributeValue, (CFTypeRef)resultArray); + SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, + kSecTransformMetaAttributeValue, (CFTypeRef)value); + no_more_output(); + + return value; + } + + return value; + + }); + + return (CFErrorRef)NULL; + }; + + return Block_copy(instanceBlock); +} + +SecTransformRef SecCreateCollectTransform(CFErrorRef* error) +{ + static dispatch_once_t once; + __block Boolean ok = TRUE; + + dispatch_block_t aBlock = ^ + { + ok = SecTransformRegister(kCollectTransformName, &CollectTransform, error); + }; + + dispatch_once(&once, aBlock); + + if (!ok) + { + return NULL; + } + + SecTransformRef yatz = SecTransformCreate(kCollectTransformName, error); + return yatz; +}