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// cssmplugin - adapter framework for C++-based CDSA plugin modules 21// 22// A note on locking: Attachments are effectively reference counted in CSSM. 23// CSSM will not let a client detach an attachment that has a(nother) thread 24// active in its code. Thus, our locks merely protect global maps; they do not 25// need (or try) to close the classic use-and-delete window. 26// 27#include <security_cdsa_plugin/cssmplugin.h> 28#include <security_cdsa_plugin/pluginsession.h> 29#include <memory> 30 31 32ModuleNexus<CssmPlugin::SessionMap> CssmPlugin::sessionMap; 33 34 35CssmPlugin::CssmPlugin() 36 : mLoaded(false) 37{ 38} 39 40CssmPlugin::~CssmPlugin() 41{ 42 // Note: if mLoaded, we're being unloaded forcibly. 43 // (CSSM wouldn't do this to us in normal operation.) 44} 45 46 47// 48// Load processing. 49// CSSM only calls this once for a module, and multiplexes any additional 50// CSSM_ModuleLoad calls internally. So this is only called when we have just 51// been loaded (and not yet attached). 52// 53void CssmPlugin::moduleLoad(const Guid &cssmGuid, 54 const Guid &moduleGuid, 55 const ModuleCallback &newCallback) 56{ 57 if (mLoaded) 58 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); 59 60 mMyGuid = moduleGuid; 61 62 // let the implementation know that we're loading 63 this->load(); 64 65 // commit 66 mCallback = newCallback; 67 mLoaded = true; 68} 69 70 71// 72// Unload processing. 73// The callback passed here will be the same passed to load. 74// CSSM only calls this on a "final" CSSM_ModuleUnload, after all attachments 75// are destroyed and (just) before we are physically unloaded. 76// 77void CssmPlugin::moduleUnload(const Guid &cssmGuid, 78 const Guid &moduleGuid, 79 const ModuleCallback &oldCallback) 80{ 81 // check the callback vector 82 if (!mLoaded || oldCallback != mCallback) 83 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); 84 85 // tell our subclass that we're closing down 86 this->unload(); 87 88 // commit closure 89 mLoaded = false; 90} 91 92 93// 94// Create one attachment session. This is what CSSM calls to process 95// a CSSM_ModuleAttach call. moduleLoad() has already been called and has 96// returned successfully. 97// 98void CssmPlugin::moduleAttach(CSSM_MODULE_HANDLE theHandle, 99 const Guid &newCssmGuid, 100 const Guid &moduleGuid, 101 const Guid &moduleManagerGuid, 102 const Guid &callerGuid, 103 const CSSM_VERSION &version, 104 uint32 subserviceId, 105 CSSM_SERVICE_TYPE subserviceType, 106 CSSM_ATTACH_FLAGS attachFlags, 107 CSSM_KEY_HIERARCHY keyHierarchy, 108 const CSSM_UPCALLS &upcalls, 109 CSSM_MODULE_FUNCS_PTR &funcTbl) 110{ 111 // basic (in)sanity checks 112 if (moduleGuid != mMyGuid) 113 CssmError::throwMe(CSSM_ERRCODE_INVALID_GUID); 114 115 // make the new session object, hanging in thin air 116 auto_ptr<PluginSession> session(this->makeSession(theHandle, 117 version, 118 subserviceId, subserviceType, 119 attachFlags, 120 upcalls)); 121 122 // haggle with the implementor 123 funcTbl = session->construct(); 124 125 // commit this session creation 126 StLock<Mutex> _(sessionMap()); 127 sessionMap()[theHandle] = session.release(); 128} 129 130 131// 132// Undo a (single) module attachment. This calls the detach() method on 133// the Session object representing the attachment. This is only called 134// if session->construct() has succeeded previously. 135// If session->detach() fails, we do not destroy the session and it continues 136// to live, though its handle may have (briefly) been invalid. This is for 137// desperate "mustn't go right now" situations and should not be abused. 138// CSSM always has the ability to ditch you without your consent if you are 139// obstreporous. 140// 141void CssmPlugin::moduleDetach(CSSM_MODULE_HANDLE handle) 142{ 143 // locate the plugin and hold the sessionMapLock 144 PluginSession *session; 145 { 146 StLock<Mutex> _(sessionMap()); 147 SessionMap::iterator it = sessionMap().find(handle); 148 if (it == sessionMap().end()) 149 CssmError::throwMe(CSSMERR_CSSM_INVALID_ADDIN_HANDLE); 150 session = it->second; 151 sessionMap().erase(it); 152 } 153 154 // let the session know it is going away 155 try { 156 session->detach(); 157 delete session; 158 } catch (...) { 159 // session detach failed - put the plugin back and fail 160 StLock<Mutex> _(sessionMap()); 161 sessionMap()[handle] = session; 162 throw; 163 } 164} 165 166 167// 168// Send an official CSSM module callback message upstream 169// 170void CssmPlugin::sendCallback(CSSM_MODULE_EVENT event, uint32 ssid, 171 CSSM_SERVICE_TYPE serviceType) const 172{ 173 assert(mLoaded); 174 mCallback(event, mMyGuid, ssid, serviceType); 175} 176 177 178// 179// Default subclass hooks. 180// The default implementations succeed without doing anything. 181// 182void CssmPlugin::load() { } 183 184void CssmPlugin::unload() { } 185