]> git.saurik.com Git - apple/security.git/blob - libsecurity_cdsa_client/lib/cssmclient.cpp
ec3fb44da7ff99b5e6e3179b95592f54ae28493f
[apple/security.git] / libsecurity_cdsa_client / lib / 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_cdsa_client/cssmclient.h>
33
34
35 using namespace CssmClient;
36
37 //
38 // Exception model
39 //
40 const char *
41 Error::what () const throw()
42 {
43 return "CSSM client library error";
44 }
45
46
47 //
48 // General utilities
49 //
50 void
51 ObjectImpl::check(CSSM_RETURN status)
52 {
53 if (status != CSSM_OK)
54 {
55 CssmError::throwMe(status);
56 }
57 }
58
59
60 //
61 // Common features of Objects
62 //
63 ObjectImpl::ObjectImpl() : mParent(), mChildCount(0)
64 {
65 mActive = false; // not activated
66 mAllocator = NULL; // allocator to be determined
67 }
68
69 ObjectImpl::ObjectImpl(const Object &mommy) : mParent(mommy.mImpl), mChildCount(0)
70 {
71 mActive = false; // not activated
72 mAllocator = NULL; // allocator to be determined
73 if (mParent)
74 mParent->addChild();
75 }
76
77 ObjectImpl::~ObjectImpl()
78 try
79 {
80 assert(!mActive); // subclass must have deactivated us
81 assert(isIdle());
82
83 // release parent from her obligations (if we still have one)
84 if (mParent)
85 mParent->removeChild();
86 }
87 catch(...)
88 {
89 return;
90 }
91
92 void
93 ObjectImpl::addChild()
94 {
95 mChildCount++; // atomic
96 }
97
98 void
99 ObjectImpl::removeChild()
100 {
101 mChildCount--; // atomic
102 }
103
104
105 //
106 // Manage allocators in the Object tree
107 //
108 Allocator &
109 ObjectImpl::allocator() const
110 {
111 if (mAllocator == NULL)
112 {
113 // fix allocator now
114 if (mParent)
115 mAllocator = &mParent->allocator();
116 else
117 mAllocator = &Allocator::standard();
118 }
119
120 return *mAllocator;
121 }
122
123 void
124 ObjectImpl::allocator(Allocator &alloc)
125 {
126 assert(mAllocator == NULL); // cannot redefine allocator once set
127 mAllocator = &alloc;
128 }
129
130 // Comparison operators use pointer comparison by default. Subclasses may override.
131 bool
132 ObjectImpl::operator <(const ObjectImpl &other) const
133 {
134 return this < &other;
135 }
136
137 bool
138 ObjectImpl::operator ==(const ObjectImpl &other) const
139 {
140 return this == &other;
141 }
142
143
144 //
145 // CSSMSession objects.
146 // parent ::= NULL (none)
147 // active ::= CSSM initialized
148 //
149 ModuleNexus<CssmImpl::StandardCssm> CssmImpl::mStandard;
150
151 CssmImpl::CssmImpl() : ObjectImpl()
152 {
153 setup();
154 mStandard().setCssm(this);
155 }
156
157 CssmImpl::CssmImpl(bool) : ObjectImpl()
158 {
159 setup();
160 // implicitly constructed - caller responsible for standard session management
161 }
162
163 CssmImpl::~CssmImpl()
164 {
165 try
166 {
167 deactivate();
168 }
169 catch(...) {}
170
171 // this may be the standard session...
172 mStandard().unsetCssm(this);
173 }
174
175
176 void
177 CssmImpl::setup()
178 {
179 // set default configuration
180 mVersion.Major = 2;
181 mVersion.Minor = 0;
182 mScope = CSSM_PRIVILEGE_SCOPE_PROCESS;
183 }
184
185
186 Cssm
187 CssmImpl::standard()
188 {
189 return Cssm(mStandard().get());
190 }
191
192
193 void
194 CssmImpl::activate()
195 {
196 if (!mActive)
197 {
198 // currently, no choices on PVC mode and key hierarchy
199 CSSM_PVC_MODE pvc = CSSM_PVC_NONE;
200 switch (CSSM_RETURN rc = CSSM_Init(&mVersion,
201 mScope, &mCallerGuid,
202 CSSM_KEY_HIERARCHY_NONE, &pvc, NULL)) {
203 case CSSMERR_CSSM_PVC_ALREADY_CONFIGURED:
204 case CSSM_OK:
205 break;
206 default:
207 check(rc);
208 }
209 mActive = true;
210 }
211 }
212
213 void
214 CssmImpl::deactivate()
215 {
216 if (mActive)
217 {
218 mActive = false;
219
220 // clear module map (all gone now)
221 moduleMap.erase(moduleMap.begin(), moduleMap.end());
222
223 // now terminate CSSM
224 check(CSSM_Terminate());
225 }
226 }
227
228 void
229 CssmImpl::atExitHandler()
230 {
231 try {
232 mStandard.reset();
233 } catch (...) {
234 }
235 }
236
237 void
238 CssmImpl::catchExit()
239 {
240 // @@@ Even though this is the "right thing" to do. This only causes
241 // exceptions during exit and doesn't really help cleanup correctly.
242 #if 0
243 if (::atexit(atExitHandler))
244 UnixError::throwMe();
245 #endif
246 }
247
248
249 //
250 // Manage the automatic Cssm object.
251 // This is a program global.
252 //
253 void CssmImpl::StandardCssm::setCssm(CssmImpl *cssm)
254 {
255 StLock<Mutex> _(*this);
256 if (mCssm == NULL)
257 mCssm = cssm;
258 }
259
260 void CssmImpl::StandardCssm::unsetCssm(CssmImpl *cssm)
261 {
262 StLock<Mutex> _(*this);
263 if (mCssm == cssm)
264 mCssm = NULL;
265 }
266
267 CssmImpl *CssmImpl::StandardCssm::get()
268 {
269 StLock<Mutex> _(*this);
270 if (mCssm == NULL) { // make the default instance
271 mCssm = new CssmImpl(true);
272 }
273 return mCssm;
274 }
275
276 CssmImpl::StandardCssm::~StandardCssm()
277 {
278 if (mCssm) {
279 mCssm->deactivate();
280 delete mCssm;
281 }
282 }
283
284
285 //
286 // Auto-module management
287 //
288 Module
289 CssmImpl::autoModule(const Guid &guid)
290 {
291 StLock<Mutex> _(mapLock);
292 ModuleMap::iterator it = moduleMap.find(guid);
293 if (it == moduleMap.end())
294 {
295 // no automodule for this guid yet, create one
296 Module module(guid, Cssm(this));
297 moduleMap.insert(ModuleMap::value_type(guid, module));
298 return module;
299 }
300 else
301 {
302 // existing automodule - use it
303 return it->second;
304 }
305 }
306
307
308 //
309 // Module objects.
310 // parent ::= the session object (usually Cssm::standard)
311 // active ::= module is loaded.
312 //
313 ModuleImpl::ModuleImpl(const Guid &guid) : ObjectImpl(Cssm::standard()),
314 mAppNotifyCallback(NULL),
315 mAppNotifyCallbackCtx(NULL)
316 {
317 setGuid(guid);
318 }
319
320 ModuleImpl::ModuleImpl(const Guid &guid, const Cssm &session) : ObjectImpl(session),
321 mAppNotifyCallback(NULL),
322 mAppNotifyCallbackCtx(NULL)
323 {
324 setGuid(guid);
325 }
326
327 ModuleImpl::~ModuleImpl()
328 {
329 unload();
330 }
331
332
333 //
334 // RawModuleEvent objects encapsulate CSSM module callbacks
335 //
336 RawModuleEvents::~RawModuleEvents()
337 { }
338
339 CSSM_RETURN RawModuleEvents::sendNotify(const CSSM_GUID *, void *context,
340 uint32 subService, CSSM_SERVICE_TYPE type, CSSM_MODULE_EVENT event)
341 {
342 try {
343 reinterpret_cast<RawModuleEvents *>(context)->notify(subService, type, event);
344 return CSSM_OK;
345 } catch (const CommonError &error) {
346 return CssmError::cssmError(error, CSSM_CSSM_BASE_ERROR);
347 } catch (...) {
348 return CSSMERR_CSSM_INTERNAL_ERROR; // whatever...
349 }
350 }
351
352
353 //
354 // ModuleEvents enhance RawModuleEvents by splitting the callback up by type
355 //
356 void ModuleEvents::notify(uint32 subService,
357 CSSM_SERVICE_TYPE type, CSSM_MODULE_EVENT event)
358 {
359 switch (event) {
360 case CSSM_NOTIFY_INSERT:
361 insertion(subService, type);
362 break;
363 case CSSM_NOTIFY_REMOVE:
364 removal(subService, type);
365 break;
366 case CSSM_NOTIFY_FAULT:
367 fault(subService, type);
368 break;
369 }
370 }
371
372 // default callbacks do nothing
373 void ModuleEvents::insertion(uint32 subService, CSSM_SERVICE_TYPE type) { }
374 void ModuleEvents::removal(uint32 subService, CSSM_SERVICE_TYPE type) { }
375 void ModuleEvents::fault(uint32 subService, CSSM_SERVICE_TYPE type) { }
376
377
378 void
379 ModuleImpl::appNotifyCallback(CSSM_API_ModuleEventHandler appNotifyCallback, void *appNotifyCallbackCtx)
380 {
381 secdebug("callback","In ModuleImpl::appNotifyCallback, appNotifyCallback=%p, appNotifyCallbackCtx=%p",
382 appNotifyCallback, appNotifyCallbackCtx);
383 if (mActive)
384 Error::throwMe(Error::objectBusy);
385
386 mAppNotifyCallback = appNotifyCallback;
387 mAppNotifyCallbackCtx = appNotifyCallbackCtx;
388 }
389
390 void
391 ModuleImpl::appNotifyCallback(RawModuleEvents *handler)
392 {
393 appNotifyCallback(RawModuleEvents::sendNotify, handler);
394 }
395
396 void
397 ModuleImpl::activate()
398 {
399 if (!mActive)
400 {
401 session()->init();
402 // @@@ install handler here (use central dispatch with override)
403 secdebug("callback","In ModuleImpl::activate, mAppNotifyCallback=%p, mAppNotifyCallbackCtx=%p",
404 mAppNotifyCallback, mAppNotifyCallbackCtx);
405 check(CSSM_ModuleLoad(&guid(), CSSM_KEY_HIERARCHY_NONE, mAppNotifyCallback, mAppNotifyCallbackCtx));
406 mActive = true;
407 session()->catchExit();
408 }
409 }
410
411 void
412 ModuleImpl::deactivate()
413 {
414 if (!isIdle())
415 Error::throwMe(Error::objectBusy);
416 if (mActive)
417 {
418 mActive = false;
419 check(CSSM_ModuleUnload(&guid(), mAppNotifyCallback, mAppNotifyCallbackCtx));
420 }
421 }
422
423 Cssm
424 ModuleImpl::session() const
425 {
426 return parent<Cssm>();
427 }
428
429
430 //
431 // CssmAttachment objects.
432 // parent ::= the loaded module object.
433 // active ::= attached.
434 //
435 AttachmentImpl::AttachmentImpl(const Guid &guid, CSSM_SERVICE_TYPE subserviceType)
436 : ObjectImpl(CssmImpl::standard()->autoModule(guid))
437 {
438 make(subserviceType);
439 }
440
441 AttachmentImpl::AttachmentImpl(const Module &module, CSSM_SERVICE_TYPE subserviceType)
442 : ObjectImpl(module)
443 {
444 make(subserviceType);
445 }
446
447 AttachmentImpl::~AttachmentImpl()
448 {
449 detach();
450 }
451
452 void
453 AttachmentImpl::make(CSSM_SERVICE_TYPE subserviceType)
454 {
455 // default configuration
456 mVersion.Major = 2;
457 mVersion.Minor = 0;
458 mSubserviceType = subserviceType;
459 mSubserviceId = 0;
460 mAttachFlags = 0;
461 }
462
463 void
464 AttachmentImpl::activate()
465 {
466 if (!mActive)
467 {
468 module()->load();
469 mMemoryFunctions = CssmAllocatorMemoryFunctions(allocator());
470 check(CSSM_ModuleAttach(&guid(), &mVersion,
471 &mMemoryFunctions,
472 mSubserviceId,
473 mSubserviceType,
474 mAttachFlags,
475 CSSM_KEY_HIERARCHY_NONE,
476 NULL, 0, // no function pointer table return
477 NULL, // reserved
478 &mHandle));
479 mActive = true;
480 }
481 }
482
483 void
484 AttachmentImpl::deactivate()
485 {
486 if (mActive)
487 {
488 mActive = false;
489 check(CSSM_ModuleDetach(mHandle));
490 }
491 }
492
493 CSSM_SERVICE_MASK
494 AttachmentImpl::subserviceMask() const
495 {
496 return mSubserviceType;
497 }
498
499 void
500 AttachmentImpl::subserviceId(uint32 id)
501 {
502 mSubserviceId = id;
503 }
504
505 CssmSubserviceUid
506 AttachmentImpl::subserviceUid() const
507 {
508 return CssmSubserviceUid(guid(), &mVersion, mSubserviceId, subserviceMask());
509 }
510
511 Module
512 AttachmentImpl::module() const
513 {
514 return parent<Module>();
515 }