]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_client/cssmclient.cpp
587aa44da3993f48eef0ce8b6cf9f723abf83538
[apple/security.git] / cdsa / cdsa_client / cssmclient.cpp
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 // cssmclient - common client interface to CSSM and MDS.
21 //
22 // Locking Strategy (preliminary):
23 // XXX This is obsolete update this --mb
24 // A CssmObject is a CountingMutex. Its count represents the number of children that have registered
25 // themselves (using addChild/removeChild). The lock controls the internal management fields of the
26 // various subclasses to protect them against corruption. It does NOT control attribute and argument
27 // fields and operations, not does it control object-constant fields.
28 // This means that if you use an object from multiple threads, you (the caller) must lock the object
29 // during set/get calls of attributes. Note that the CSSM operations themselves are safely multithreaded
30 // and thus don't need to be interlocked explicitly.
31 //
32 #include <Security/cssmclient.h>
33 #include <Security/cssmerrno.h>
34
35
36 using namespace CssmClient;
37
38 //
39 // Exception model
40 //
41 CSSM_RETURN
42 Error::cssmError() const
43 {
44 //@@@ munge in client-side error codes here?
45 return CssmError::cssmError();
46 }
47
48 const char *
49 Error::what () const
50 {
51 return "CSSM client library error";
52 }
53
54
55 //
56 // General utilities
57 //
58 void
59 ObjectImpl::check(CSSM_RETURN status)
60 {
61 if (status != CSSM_OK)
62 {
63 CssmError::throwMe(status);
64 }
65 }
66
67
68 //
69 // Common features of Objects
70 //
71 ObjectImpl::ObjectImpl() : mParent(), mChildCount(0)
72 {
73 mActive = false; // not activated
74 mAllocator = NULL; // allocator to be determined
75 }
76
77 ObjectImpl::ObjectImpl(const Object &mommy) : mParent(mommy.mImpl), mChildCount(0)
78 {
79 mActive = false; // not activated
80 mAllocator = NULL; // allocator to be determined
81 if (mParent)
82 mParent->addChild();
83 }
84
85 ObjectImpl::~ObjectImpl()
86 {
87 assert(!mActive); // subclass must have deactivated us
88 if (!isIdle())
89 Error::throwMe(Error::objectBusy);
90
91 // release parent from her obligations (if we still have one)
92 if (mParent)
93 mParent->removeChild();
94 }
95
96 void
97 ObjectImpl::addChild()
98 {
99 mChildCount++; // atomic
100 }
101
102 void
103 ObjectImpl::removeChild()
104 {
105 mChildCount--; // atomic
106 }
107
108
109 //
110 // Manage allocators in the Object tree
111 //
112 CssmAllocator &
113 ObjectImpl::allocator() const
114 {
115 if (mAllocator == NULL)
116 {
117 // fix allocator now
118 if (mParent)
119 mAllocator = &mParent->allocator();
120 else
121 mAllocator = &CssmAllocator::standard();
122 }
123
124 return *mAllocator;
125 }
126
127 void
128 ObjectImpl::allocator(CssmAllocator &alloc)
129 {
130 assert(mAllocator == NULL); // cannot redefine allocator once set
131 mAllocator = &alloc;
132 }
133
134 // Comparison operators use pointer comparison by default. Subclasses may override.
135 bool
136 ObjectImpl::operator <(const ObjectImpl &other) const
137 {
138 return this < &other;
139 }
140
141 bool
142 ObjectImpl::operator ==(const ObjectImpl &other) const
143 {
144 return this == &other;
145 }
146
147
148 //
149 // CSSMSession objects.
150 // parent ::= NULL (none)
151 // active ::= CSSM initialized
152 //
153 ModuleNexus<CssmImpl::StandardCssm> CssmImpl::mStandard;
154
155 CssmImpl::CssmImpl() : ObjectImpl()
156 {
157 setup();
158 mStandard().setCssm(this);
159 }
160
161 CssmImpl::CssmImpl(bool) : ObjectImpl()
162 {
163 setup();
164 // implicitly constructed - caller responsible for standard session management
165 }
166
167 CssmImpl::~CssmImpl()
168 {
169 try
170 {
171 deactivate();
172 }
173 catch(...) {}
174
175 // this may be the standard session...
176 mStandard().unsetCssm(this);
177 }
178
179
180 void
181 CssmImpl::setup()
182 {
183 // set default configuration
184 mVersion.Major = 2;
185 mVersion.Minor = 0;
186 mScope = CSSM_PRIVILEGE_SCOPE_PROCESS;
187 }
188
189
190 Cssm
191 CssmImpl::standard()
192 {
193 return Cssm(mStandard().get());
194 }
195
196
197 void
198 CssmImpl::activate()
199 {
200 if (!mActive)
201 {
202 // currently, no choices on PVC mode and key hierarchy
203 CSSM_PVC_MODE pvc = CSSM_PVC_NONE;
204 //@@@ should handle PVC_ALREADY... non-error
205 check(CSSM_Init(&mVersion, mScope, &mCallerGuid,
206 CSSM_KEY_HIERARCHY_NONE, &pvc, NULL));
207 mActive = true;
208 }
209 }
210
211 void
212 CssmImpl::deactivate()
213 {
214 if (mActive)
215 {
216 mActive = false;
217
218 // clear module map (all gone now)
219 moduleMap.erase(moduleMap.begin(), moduleMap.end());
220
221 // now terminate CSSM
222 check(CSSM_Terminate());
223 }
224 }
225
226 void
227 CssmImpl::atExitHandler()
228 {
229 try {
230 mStandard.reset();
231 } catch (...) {
232 }
233 }
234
235 void
236 CssmImpl::catchExit()
237 {
238 // @@@ Even though this is the "right thing" to do. This only causes
239 // exceptions during exit and doesn't really help cleanup correctly.
240 #if 0
241 if (::atexit(atExitHandler))
242 UnixError::throwMe();
243 #endif
244 }
245
246
247 //
248 // Manage the automatic Cssm object.
249 // This is a program global.
250 //
251 void CssmImpl::StandardCssm::setCssm(CssmImpl *cssm)
252 {
253 StLock<Mutex> _(*this);
254 if (mCssm == NULL)
255 mCssm = cssm;
256 }
257
258 void CssmImpl::StandardCssm::unsetCssm(CssmImpl *cssm)
259 {
260 StLock<Mutex> _(*this);
261 if (mCssm == cssm)
262 mCssm = NULL;
263 }
264
265 CssmImpl *CssmImpl::StandardCssm::get()
266 {
267 StLock<Mutex> _(*this);
268 if (mCssm == NULL) { // make the default instance
269 mCssm = new CssmImpl(true);
270 }
271 return mCssm;
272 }
273
274 CssmImpl::StandardCssm::~StandardCssm()
275 {
276 if (mCssm) {
277 mCssm->deactivate();
278 delete mCssm;
279 }
280 }
281
282
283 //
284 // Auto-module management
285 //
286 Module
287 CssmImpl::autoModule(const Guid &guid)
288 {
289 StLock<Mutex> _(mapLock);
290 ModuleMap::iterator it = moduleMap.find(guid);
291 if (it == moduleMap.end())
292 {
293 // no automodule for this guid yet, create one
294 Module module(guid, Cssm(this));
295 moduleMap.insert(ModuleMap::value_type(guid, module));
296 return module;
297 }
298 else
299 {
300 // existing automodule - use it
301 return it->second;
302 }
303 }
304
305
306 //
307 // Module objects.
308 // parent ::= the session object (usually Cssm::standard)
309 // active ::= module is loaded.
310 //
311 ModuleImpl::ModuleImpl(const Guid &guid) : ObjectImpl(Cssm::standard())
312 {
313 setGuid(guid);
314 }
315
316 ModuleImpl::ModuleImpl(const Guid &guid, const Cssm &session) : ObjectImpl(session)
317 {
318 setGuid(guid);
319 }
320
321 ModuleImpl::~ModuleImpl()
322 {
323 unload();
324 }
325
326
327 void
328 ModuleImpl::activate()
329 {
330 if (!mActive)
331 {
332 session()->init();
333 // @@@ install handler here (use central dispatch with override)
334 check(CSSM_ModuleLoad(&guid(), CSSM_KEY_HIERARCHY_NONE, NULL, NULL));
335 mActive = true;
336 session()->catchExit();
337 }
338 }
339
340 void
341 ModuleImpl::deactivate()
342 {
343 if (!isIdle())
344 Error::throwMe(Error::objectBusy);
345 if (mActive)
346 {
347 mActive = false;
348 check(CSSM_ModuleUnload(&guid(), NULL, NULL));
349 }
350 }
351
352 Cssm
353 ModuleImpl::session() const
354 {
355 return parent<Cssm>();
356 }
357
358
359 //
360 // CssmAttachment objects.
361 // parent ::= the loaded module object.
362 // active ::= attached.
363 //
364 AttachmentImpl::AttachmentImpl(const Guid &guid, CSSM_SERVICE_TYPE subserviceType)
365 : ObjectImpl(CssmImpl::standard()->autoModule(guid))
366 {
367 make(subserviceType);
368 }
369
370 AttachmentImpl::AttachmentImpl(const Module &module, CSSM_SERVICE_TYPE subserviceType)
371 : ObjectImpl(module)
372 {
373 make(subserviceType);
374 }
375
376 AttachmentImpl::~AttachmentImpl()
377 {
378 detach();
379 }
380
381 void
382 AttachmentImpl::make(CSSM_SERVICE_TYPE subserviceType)
383 {
384 // default configuration
385 mVersion.Major = 2;
386 mVersion.Minor = 0;
387 mSubserviceType = subserviceType;
388 mSubserviceId = 0;
389 mAttachFlags = 0;
390 }
391
392 void
393 AttachmentImpl::activate()
394 {
395 if (!mActive)
396 {
397 module()->load();
398 mMemoryFunctions = CssmAllocatorMemoryFunctions(allocator());
399 check(CSSM_ModuleAttach(&guid(), &mVersion,
400 &mMemoryFunctions,
401 mSubserviceId,
402 mSubserviceType,
403 mAttachFlags,
404 CSSM_KEY_HIERARCHY_NONE,
405 NULL, 0, // no function pointer table return
406 NULL, // reserved
407 &mHandle));
408 mActive = true;
409 }
410 }
411
412 void
413 AttachmentImpl::deactivate()
414 {
415 if (mActive)
416 {
417 mActive = false;
418 check(CSSM_ModuleDetach(mHandle));
419 }
420 }
421
422 CSSM_SERVICE_MASK
423 AttachmentImpl::subserviceMask() const
424 {
425 return mSubserviceType;
426 }
427
428 void
429 AttachmentImpl::subserviceId(uint32 id)
430 {
431 mSubserviceId = id;
432 }
433
434 CssmSubserviceUid
435 AttachmentImpl::subserviceUid() const
436 {
437 return CssmSubserviceUid(guid(), &mVersion, mSubserviceId, subserviceMask());
438 }
439
440 Module
441 AttachmentImpl::module() const
442 {
443 return parent<Module>();
444 }