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