X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/72a12576750f52947eb043106ba5c12c0d07decf..b1ab9ed8d0e0f1c3b66d7daa8fd5564444c56195:/libsecurity_cdsa_plugin/lib/cssmplugin.cpp?ds=inline diff --git a/libsecurity_cdsa_plugin/lib/cssmplugin.cpp b/libsecurity_cdsa_plugin/lib/cssmplugin.cpp new file mode 100644 index 00000000..36597e7e --- /dev/null +++ b/libsecurity_cdsa_plugin/lib/cssmplugin.cpp @@ -0,0 +1,184 @@ +/* + * 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. + */ + + +// +// cssmplugin - adapter framework for C++-based CDSA plugin modules +// +// A note on locking: Attachments are effectively reference counted in CSSM. +// CSSM will not let a client detach an attachment that has a(nother) thread +// active in its code. Thus, our locks merely protect global maps; they do not +// need (or try) to close the classic use-and-delete window. +// +#include +#include +#include + + +ModuleNexus CssmPlugin::sessionMap; + + +CssmPlugin::CssmPlugin() + : mLoaded(false) +{ +} + +CssmPlugin::~CssmPlugin() +{ + // Note: if mLoaded, we're being unloaded forcibly. + // (CSSM wouldn't do this to us in normal operation.) +} + + +// +// Load processing. +// CSSM only calls this once for a module, and multiplexes any additional +// CSSM_ModuleLoad calls internally. So this is only called when we have just +// been loaded (and not yet attached). +// +void CssmPlugin::moduleLoad(const Guid &cssmGuid, + const Guid &moduleGuid, + const ModuleCallback &newCallback) +{ + if (mLoaded) + CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); + + mMyGuid = moduleGuid; + + // let the implementation know that we're loading + this->load(); + + // commit + mCallback = newCallback; + mLoaded = true; +} + + +// +// Unload processing. +// The callback passed here will be the same passed to load. +// CSSM only calls this on a "final" CSSM_ModuleUnload, after all attachments +// are destroyed and (just) before we are physically unloaded. +// +void CssmPlugin::moduleUnload(const Guid &cssmGuid, + const Guid &moduleGuid, + const ModuleCallback &oldCallback) +{ + // check the callback vector + if (!mLoaded || oldCallback != mCallback) + CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); + + // tell our subclass that we're closing down + this->unload(); + + // commit closure + mLoaded = false; +} + + +// +// Create one attachment session. This is what CSSM calls to process +// a CSSM_ModuleAttach call. moduleLoad() has already been called and has +// returned successfully. +// +void CssmPlugin::moduleAttach(CSSM_MODULE_HANDLE theHandle, + const Guid &newCssmGuid, + const Guid &moduleGuid, + const Guid &moduleManagerGuid, + const Guid &callerGuid, + const CSSM_VERSION &version, + uint32 subserviceId, + CSSM_SERVICE_TYPE subserviceType, + CSSM_ATTACH_FLAGS attachFlags, + CSSM_KEY_HIERARCHY keyHierarchy, + const CSSM_UPCALLS &upcalls, + CSSM_MODULE_FUNCS_PTR &funcTbl) +{ + // basic (in)sanity checks + if (moduleGuid != mMyGuid) + CssmError::throwMe(CSSM_ERRCODE_INVALID_GUID); + + // make the new session object, hanging in thin air + auto_ptr session(this->makeSession(theHandle, + version, + subserviceId, subserviceType, + attachFlags, + upcalls)); + + // haggle with the implementor + funcTbl = session->construct(); + + // commit this session creation + StLock _(sessionMap()); + sessionMap()[theHandle] = session.release(); +} + + +// +// Undo a (single) module attachment. This calls the detach() method on +// the Session object representing the attachment. This is only called +// if session->construct() has succeeded previously. +// If session->detach() fails, we do not destroy the session and it continues +// to live, though its handle may have (briefly) been invalid. This is for +// desperate "mustn't go right now" situations and should not be abused. +// CSSM always has the ability to ditch you without your consent if you are +// obstreporous. +// +void CssmPlugin::moduleDetach(CSSM_MODULE_HANDLE handle) +{ + // locate the plugin and hold the sessionMapLock + PluginSession *session; + { + StLock _(sessionMap()); + SessionMap::iterator it = sessionMap().find(handle); + if (it == sessionMap().end()) + CssmError::throwMe(CSSMERR_CSSM_INVALID_ADDIN_HANDLE); + session = it->second; + sessionMap().erase(it); + } + + // let the session know it is going away + try { + session->detach(); + delete session; + } catch (...) { + // session detach failed - put the plugin back and fail + StLock _(sessionMap()); + sessionMap()[handle] = session; + throw; + } +} + + +// +// Send an official CSSM module callback message upstream +// +void CssmPlugin::sendCallback(CSSM_MODULE_EVENT event, uint32 ssid, + CSSM_SERVICE_TYPE serviceType) const +{ + assert(mLoaded); + mCallback(event, mMyGuid, ssid, serviceType); +} + + +// +// Default subclass hooks. +// The default implementations succeed without doing anything. +// +void CssmPlugin::load() { } + +void CssmPlugin::unload() { }