X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_transform/lib/Transform.h?ds=inline diff --git a/Security/libsecurity_transform/lib/Transform.h b/Security/libsecurity_transform/lib/Transform.h new file mode 100644 index 00000000..4fd1ab9f --- /dev/null +++ b/Security/libsecurity_transform/lib/Transform.h @@ -0,0 +1,241 @@ +#ifndef __TRANSFORM__ +#define __TRANSFORM__ + +#include +#include "CoreFoundationBasics.h" +#include "SecTransform.h" +#include "SecCustomTransform.h" +#include +#include "misc.h" + +// Since we are doing everything in CF, we just define an +// attribute as a CFDictionary containing a value and +// a CFArray of objects which need notification when that +// value changes + +// defines for transform externalization +#define EXTERN_TRANSFORM_TRANSFORM_ARRAY CFSTR("TRANSFORMS") +#define EXTERN_TRANSFORM_CONNECTION_ARRAY CFSTR("ARRAY") +#define EXTERN_TRANSFORM_CUSTOM_EXPORTS_DICTIONARY CFSTR("CUSTOM_EXPORTS") + +#define EXTERN_TRANSFORM_NAME CFSTR("NAME") +#define EXTERN_TRANSFORM_TYPE CFSTR("TYPE") +#define EXTERN_TRANSFORM_STATE CFSTR("STATE") +#define EXTERN_TRANSFORM_FROM_NAME CFSTR("FROM_NAME") +#define EXTERN_TRANSFORM_FROM_ATTRIBUTE CFSTR("FROM_ATTRIBUTE") +#define EXTERN_TRANSFORM_TO_NAME CFSTR("TO_NAME") +#define EXTERN_TRANSFORM_TO_ATTRIBUTE CFSTR("TO_ATTRIBUTE") + +#ifndef __clang__ +#define GCC_BUG_WORKAROUND :: +#else +#define GCC_BUG_WORKAROUND +#endif + + +class Monitor; +typedef CFTypeRef SecMonitorRef; + +struct transform_attribute { + CFStringRef name; + CFTypeRef value; + CFMutableArrayRef connections; + // NOTE: this does NOT have a reference. + class Transform *transform; + static CFTypeID cftype; + + // NOTE: NULL is a valid value to pushback, so we can't just use pushback_value==NULL for "nothing pushed back" + // pb_empty => no value currently pushed back + // pb_value => we have a value, we havn't presented it yet (if pushback_value==NULL we won't present again until another attribute changes) + // pb_repush => pushed back value currently being re-processed + // pb_presented_once => we have a value, and tried to process it and got it back again (don't present until another attribute changes) + // + enum pushback_states { pb_empty, pb_value, pb_repush, pb_presented_once, pb_discard } pushback_state; + CFTypeRef pushback_value; + + // (for pushback support; also need pushback state & value) + dispatch_queue_t q; + dispatch_semaphore_t semaphore; + + // This attribute needs a value set, or to have something connected to it before running the transform + unsigned int required:1; + // This attribute needs to have an outgoing connection before running the transform + unsigned int requires_outbound_connection:1; + // This attribute should not be presented to the transform until after execution starts + unsigned int deferred:1; + // This attribute comes in N chunks followed by a NULL + unsigned int stream:1; + // This attribute should be saved when externalizing + unsigned int ignore_while_externalizing:1; + // Set by Transform::Connect + unsigned int has_incoming_connection:1; + // CustomTransform should't special case CFErrors for this attribute + unsigned int direct_error_handling:1; + // External sets are problematic, I think they should be disallowed full stop, but 7947393 says we need them sometimes + unsigned int allow_external_sets:1; + // Value has been created as a source (therefore deferred), give it special treatment + unsigned int has_been_deferred:1; + + void *attribute_changed_block; + void *attribute_validate_block; +}; + +typedef void (^ActivityMonitor)(CFStringRef name, CFTypeRef value); + +class GroupTransform; // Forward reference so we do not have to include + // the header and break a circular dependency +class BlockMonitor; + +class Transform : public CoreFoundationObject +{ + friend CFTypeRef SecTransformExecute(SecTransformRef tranformRef, CFErrorRef* errorRef); + friend CFTypeRef SecTransformGetAttribute(SecTransformRef transformRef, CFStringRef key); + friend class BlockMonitor; +protected: + dispatch_queue_t mDispatchQueue, mActivationQueue; + dispatch_group_t mActivationPending; + CFMutableSetRef mAttributes; + CFMutableArrayRef mPushedback; + Boolean mIsActive; + Boolean mIsFinalizing; + Boolean mAlwaysSelfNotify, mProcessingPushbacks; + GroupTransform *mGroup; + CFErrorRef mAbortError; + CFStringRef mTypeName; + + SecTransformAttributeRef AbortAH, DebugAH; + + Transform(CFStringRef transformType, CFStringRef CFobjectType = CFSTR("SecTransform")); + + transform_attribute *getTA(SecTransformStringOrAttributeRef attr, bool create_ok); + void TAGetAll(transform_attribute **attributes); + CFIndex GetAttributeCount(); + + CFDictionaryRef GetAHDictForSaveState(SecTransformStringOrAttributeRef key); + + CFTypeRef ValueForNewAttribute(CFStringRef key, CFTypeRef value); + CFMutableDictionaryRef AddNewAttribute(CFStringRef key, CFTypeRef value); + CFErrorRef SetAttributeNoCallback(SecTransformStringOrAttributeRef key, CFTypeRef value); + + CFErrorRef ProcessExecute(CFStringRef &outputAttached, SecMonitorRef monitor); + typedef void (^AccumulateDictonary)(CFDictionaryRef d); + CFErrorRef ProcessExternalize(CFMutableArrayRef transforms, CFMutableArrayRef connections); + + void FinalizeForClang(); + + virtual void Finalize(); + // subclasses with non-trivial finalization can implement this (default: delete this) + virtual void FinalizePhase2(); + // subclasses that want to reject some connections can use this + virtual bool validConnectionPoint(CFStringRef attributeName); + + void try_pushbacks(); + + void Initialize(); + + void ActivateInputs(); + + virtual std::string DebugDescription(); + + typedef CFErrorRef (^TransformOperation)(Transform*); + typedef void (^TransformAsyncOperation)(Transform*); + CFErrorRef ForAllNodes(bool parallel, bool includeOwningGroup, TransformOperation op); + + CFErrorRef TraverseTransform(CFMutableSetRef visited, TransformOperation t); + + + CFErrorRef SendAttribute(SecTransformStringOrAttributeRef key, CFTypeRef value); + CFErrorRef SendMetaAttribute(SecTransformStringOrAttributeRef key, SecTransformMetaAttributeType type, CFTypeRef value); + + // Abort all transforms in this transform's RootGroup, including this transform + virtual void AbortAllTransforms(CFTypeRef error); + // Abort just this transform (and maybe schedule a later call to AbortAllTransforms), should only be + // called via AbortAllTransforms + virtual void AbortJustThisTransform(CFErrorRef abortMsg); + + void phase3Activation(); + void DoPhase3Activation(); + + bool HasNoInboundConnections(); + bool HasNoOutboundConnections(); + +private: + CFErrorRef ExecuteOperation(CFStringRef &outputAttached, SecMonitorRef output, dispatch_queue_t phase2, dispatch_queue_t phase3); + SecTransformAttributeRef makeAH(transform_attribute *ta); + +public: + + static CFTypeID GetCFTypeID(); + + // these functions are overloaded to implement the functionality of your transform + virtual ~Transform(); + + // this is called when one of your attributes (e.g. input) changes + virtual void AttributeChanged(SecTransformAttributeRef ah, CFTypeRef value); + // this is for backwards compatibility only (XXX: convert all existing Transform subclasses to not use it then remove) + virtual void AttributeChanged(CFStringRef name, CFTypeRef value); + + // overload to return true if your transform can be externalized (generally true unless you are a monitor) + virtual bool IsExternalizable(); + + // Base implementation saves all attributes that have kSecTransformMetaAttributeExternalize TRUE (which is the default). + // If that isn't useful for your transform overload to return a CFDictionary that contains the state of + // your transform. Values returned should be serializable. Remember that this state will be restored + // before SecTransformExecute is called. Do not include the transform name in your state (this will be + // done for you by SecTransformCopyExternalRep). + virtual CFDictionaryRef CopyState(); + + // overload to restore the state of your transform + virtual void RestoreState(CFDictionaryRef state); + virtual void SetCustomExternalData(CFDictionaryRef customData); + + virtual Boolean TransformCanExecute(); + virtual CFErrorRef TransformStartingExecution(); + + SecTransformAttributeRef getAH(SecTransformStringOrAttributeRef attr, bool create_ok =true, bool create_undesrscore_ok =false); + CFArrayRef GetAllAH(); + + CFStringRef GetName(); + + // Output debugging information if the DEBUG attribute is set for this transform + void Debug(const char *fmt, ...); + + CFErrorRef RefactorErrorToIncludeAbortingTransform(CFErrorRef sourceError); + +public: + CFErrorRef Connect(GroupTransform *group, Transform* destinationTransform, CFStringRef myKey, CFStringRef hisKey); + CFErrorRef Disconnect(Transform* destinationTransform, CFStringRef myKey, CFStringRef hisKey); + + CFErrorRef ExternalSetAttribute(SecTransformStringOrAttributeRef key, CFTypeRef value); + CFErrorRef SetAttribute(SecTransformStringOrAttributeRef key, CFTypeRef value); + CFTypeRef GetAttribute(SecTransformStringOrAttributeRef key); + CFTypeRef GetMetaAttribute(SecTransformStringOrAttributeRef key, SecTransformMetaAttributeType type); + + CFErrorRef Pushback(SecTransformAttributeRef ah, CFTypeRef value); + + void Do(SecTransformAttributeRef name, CFTypeRef value); + + CFTypeRef Execute(dispatch_queue_t deliveryQueue, SecMessageBlock deliveryBlock, CFErrorRef* errorRef); + + // set to get notified every time this transform does something -- used for debugging + void SetActivityMonitor(ActivityMonitor am); + + virtual CFDictionaryRef Externalize(CFErrorRef *error); + + // Returns NULL if not in a group; can return this + GroupTransform* GetRootGroup(); + + friend class GroupTransform; + friend Transform::TransformOperation makeIdleOp(dispatch_group_t idle_group); + + void SetGroup(GroupTransform* group) {mGroup = group;} + CFDictionaryRef GetCustomExternalData(); +}; + + +inline struct transform_attribute *ah2ta(SecTransformAttributeRef ah) { + // CF stores our data just after the CFRuntimeBase, we just have a single pointer there. + return *(struct transform_attribute **)(1 + (CFRuntimeBase*)ah); +} + +#endif