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