/* * Copyright (c) 2000-2001,2003-2004 Apple Computer, 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@ */ // // attachment - CSSM module attachment objects // #ifndef _H_ATTACHMENT #define _H_ATTACHMENT #include "cssmint.h" #include "module.h" #include #include // // This type represents a single Attachment of any kind. // Attachments are formed by the CSSM_ModuleAttach call and represent a "session" // between a caller client and a particular plugin module. Any number of attachments // can exist for a particular caller and a particular module. // Attachment is an abstract class. You must subclass it to implement a concrete // type of plugin. For the standard ones, see the end of this header. // Key recovery does not use Attachments. // EMMs are not Attachments, but the plugins they manage are. // And yes, an Attachment *is* a lock. The API transition layer functions need // to lock Attachments from the "outside", so there's no point in being coy about it. // Locking the Attachment is equivalent to locking all its members except for // instance-constant ones. // class Attachment : public HandleObject, // has a handle public CssmMemoryFunctionsAllocator, // is an allocator public CountingMutex { // is a counting lock NOCOPY(Attachment) public: Attachment(Module *theModule, const CSSM_VERSION &version, uint32 subserviceId, CSSM_SERVICE_TYPE subserviceType, const CSSM_API_MEMORY_FUNCS &memoryOps, CSSM_ATTACH_FLAGS attachFlags, CSSM_KEY_HIERARCHY keyHierarchy); virtual ~Attachment(); Module &module; // feature inquiries. These features are constant for the life of the Attachment const Guid &myGuid() const { return module.myGuid(); } CSSM_SERVICE_TYPE subserviceType() const { return mSubserviceType; } uint32 subserviceId() const { return mSubserviceId; } const CSSM_VERSION &pluginVersion() const { return mVersion; } CSSM_ATTACH_FLAGS attachFlags() const { return mAttachFlags; } bool isThreadSafe() const { return module.isThreadSafe(); } // service a symbol table inquiry against our attachment virtual void resolveSymbols(CSSM_FUNC_NAME_ADDR *FunctionTable, uint32 NumFunctions) = 0; // terminate the live attachment and prepare to die void detach(bool isLocked); template friend Sub &enterAttachment(CSSM_HANDLE); // need to redefine lock/trylock to implement HandleObject protocol void lock() { CountingMutex::lock(); } bool tryLock() { return CountingMutex::tryLock(); } private: bool mIsActive; // successfully attached to plugin uint32 mSubserviceId; // subservice ID in use CSSM_SERVICE_TYPE mSubserviceType; // service type // how we were created CSSM_VERSION mVersion; // plugin version requested CSSM_ATTACH_FLAGS mAttachFlags; // attach flags requested CSSM_KEY_HIERARCHY mKeyHierarchy; // key hierarchy verified protected: CSSM_MODULE_FUNCS *spiFunctionTable; // entry table as returned by plugin on attach private: CSSM_UPCALLS upcalls; // upcall functions for our module // upcall implementors - these are handed to the plugin in `upcalls' static void *upcallMalloc(CSSM_HANDLE handle, uint32 size); static void upcallFree(CSSM_HANDLE handle, void *mem); static void *upcallRealloc(CSSM_HANDLE handle, void *mem,uint32 size); static void *upcallCalloc(CSSM_HANDLE handle, uint32 num, uint32 size); static CSSM_RETURN upcallCcToHandle(CSSM_CC_HANDLE handle, CSSM_MODULE_HANDLE *modHandle); static CSSM_RETURN upcallGetModuleInfo(CSSM_MODULE_HANDLE Module, CSSM_GUID_PTR Guid, CSSM_VERSION_PTR Version, uint32 *SubServiceId, CSSM_SERVICE_TYPE *SubServiceType, CSSM_ATTACH_FLAGS *AttachFlags, CSSM_KEY_HIERARCHY *KeyHierarchy, CSSM_API_MEMORY_FUNCS_PTR AttachedMemFuncs, CSSM_FUNC_NAME_ADDR_PTR FunctionTable, uint32 NumFunctions); }; // this should be a member template, but egcs barfs on its invocation // @@@ pass module code in to get better "invalid handle" diag? // @@@ or use template specializations here? template inline AttachmentSubclass &enterAttachment(CSSM_HANDLE h) { AttachmentSubclass &attachment = findHandleAndLock(h); attachment.finishEnter(); return attachment; } // // For the standard attachment types, function dispatch to the plugin // is done based on the CSSM_SPI_xxx_FUNCS structures describing the // types and ordering of entry points. The StandardAttachment class // implements this by holding a copy of these tables for the use of // the transition layer. // You are free to subclass from Attachment directly if that makes better // sense to your kind of plugin. // template class StandardAttachment : public Attachment { public: typedef map NameMap; StandardAttachment(Module *theModule, const NameMap &names, const CSSM_VERSION &version, uint32 subserviceId, CSSM_SERVICE_TYPE subserviceType, const CSSM_API_MEMORY_FUNCS &memoryOps, CSSM_ATTACH_FLAGS attachFlags, CSSM_KEY_HIERARCHY keyHierarchy) : Attachment(theModule, version, subserviceId, subserviceType, memoryOps, attachFlags, keyHierarchy), nameMap(names) { try { if (spiFunctionTable->NumberOfServiceFuncs < sizeof(FunctionTable) / sizeof(CSSM_PROC_ADDR)) CssmError::throwMe(CSSMERR_CSSM_INVALID_ADDIN_FUNCTION_TABLE); // tolerate a table that's TOO large - perhaps it's a newer version // @@@ with the new spec, we could just store the pointer memcpy(&downcalls, spiFunctionTable->ServiceFuncs, sizeof(downcalls)); } catch (...) { // we are attached to the plugin, so tell it the show is off detach(false); throw; } } void resolveSymbols(CSSM_FUNC_NAME_ADDR *inFunctionTable, uint32 NumFunctions) { for (unsigned n = 0; n < NumFunctions; n++) { NameMap::const_iterator it = nameMap.find(inFunctionTable[n].Name); inFunctionTable[n].Address = (it == nameMap.end()) ? NULL : downcallNumber(it->second); } } FunctionTable downcalls; CSSM_PROC_ADDR downcallNumber(uint32 index) const { assert(index < sizeof(downcalls) / sizeof(CSSM_PROC_ADDR)); return reinterpret_cast(&downcalls)[index]; } private: const NameMap &nameMap; }; #endif //_H_ATTACHMENT