]> git.saurik.com Git - apple/security.git/blob - libsecurity_cdsa_client/lib/cssmclient.cpp
Security-55179.1.tar.gz
[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 StLock<Mutex> _(mActivateMutex);
197 if (!mActive)
198 {
199 // currently, no choices on PVC mode and key hierarchy
200 CSSM_PVC_MODE pvc = CSSM_PVC_NONE;
201 switch (CSSM_RETURN rc = CSSM_Init(&mVersion,
202 mScope, &mCallerGuid,
203 CSSM_KEY_HIERARCHY_NONE, &pvc, NULL)) {
204 case CSSMERR_CSSM_PVC_ALREADY_CONFIGURED:
205 case CSSM_OK:
206 break;
207 default:
208 check(rc);
209 }
210 mActive = true;
211 }
212 }
213
214 void
215 CssmImpl::deactivate()
216 {
217 StLock<Mutex> _(mActivateMutex);
218 if (mActive)
219 {
220 mActive = false;
221
222 // clear module map (all gone now)
223 moduleMap.erase(moduleMap.begin(), moduleMap.end());
224
225 // now terminate CSSM
226 check(CSSM_Terminate());
227 }
228 }
229
230 void
231 CssmImpl::atExitHandler()
232 {
233 try {
234 mStandard.reset();
235 } catch (...) {
236 }
237 }
238
239 void
240 CssmImpl::catchExit()
241 {
242 // @@@ Even though this is the "right thing" to do. This only causes
243 // exceptions during exit and doesn't really help cleanup correctly.
244 #if 0
245 if (::atexit(atExitHandler))
246 UnixError::throwMe();
247 #endif
248 }
249
250
251 //
252 // Manage the automatic Cssm object.
253 // This is a program global.
254 //
255 void CssmImpl::StandardCssm::setCssm(CssmImpl *cssm)
256 {
257 StLock<Mutex> _(*this);
258 if (mCssm == NULL)
259 mCssm = cssm;
260 }
261
262 void CssmImpl::StandardCssm::unsetCssm(CssmImpl *cssm)
263 {
264 StLock<Mutex> _(*this);
265 if (mCssm == cssm)
266 mCssm = NULL;
267 }
268
269 CssmImpl *CssmImpl::StandardCssm::get()
270 {
271 StLock<Mutex> _(*this);
272 if (mCssm == NULL) { // make the default instance
273 mCssm = new CssmImpl(true);
274 }
275 return mCssm;
276 }
277
278 CssmImpl::StandardCssm::~StandardCssm()
279 {
280 if (mCssm) {
281 mCssm->deactivate();
282 delete mCssm;
283 }
284 }
285
286
287 //
288 // Auto-module management
289 //
290 Module
291 CssmImpl::autoModule(const Guid &guid)
292 {
293 StLock<Mutex> _(mapLock);
294 ModuleMap::iterator it = moduleMap.find(guid);
295 if (it == moduleMap.end())
296 {
297 // no automodule for this guid yet, create one
298 Module module(guid, Cssm(this));
299 moduleMap.insert(ModuleMap::value_type(guid, module));
300 return module;
301 }
302 else
303 {
304 // existing automodule - use it
305 return it->second;
306 }
307 }
308
309
310 //
311 // Module objects.
312 // parent ::= the session object (usually Cssm::standard)
313 // active ::= module is loaded.
314 //
315 ModuleImpl::ModuleImpl(const Guid &guid) : ObjectImpl(Cssm::standard()),
316 mAppNotifyCallback(NULL),
317 mAppNotifyCallbackCtx(NULL)
318 {
319 setGuid(guid);
320 }
321
322 ModuleImpl::ModuleImpl(const Guid &guid, const Cssm &session) : ObjectImpl(session),
323 mAppNotifyCallback(NULL),
324 mAppNotifyCallbackCtx(NULL)
325 {
326 setGuid(guid);
327 }
328
329 ModuleImpl::~ModuleImpl()
330 {
331 unload();
332 }
333
334
335 //
336 // RawModuleEvent objects encapsulate CSSM module callbacks
337 //
338 RawModuleEvents::~RawModuleEvents()
339 { }
340
341 CSSM_RETURN RawModuleEvents::sendNotify(const CSSM_GUID *, void *context,
342 uint32 subService, CSSM_SERVICE_TYPE type, CSSM_MODULE_EVENT event)
343 {
344 try {
345 reinterpret_cast<RawModuleEvents *>(context)->notify(subService, type, event);
346 return CSSM_OK;
347 } catch (const CommonError &error) {
348 return CssmError::cssmError(error, CSSM_CSSM_BASE_ERROR);
349 } catch (...) {
350 return CSSMERR_CSSM_INTERNAL_ERROR; // whatever...
351 }
352 }
353
354
355 //
356 // ModuleEvents enhance RawModuleEvents by splitting the callback up by type
357 //
358 void ModuleEvents::notify(uint32 subService,
359 CSSM_SERVICE_TYPE type, CSSM_MODULE_EVENT event)
360 {
361 switch (event) {
362 case CSSM_NOTIFY_INSERT:
363 insertion(subService, type);
364 break;
365 case CSSM_NOTIFY_REMOVE:
366 removal(subService, type);
367 break;
368 case CSSM_NOTIFY_FAULT:
369 fault(subService, type);
370 break;
371 }
372 }
373
374 // default callbacks do nothing
375 void ModuleEvents::insertion(uint32 subService, CSSM_SERVICE_TYPE type) { }
376 void ModuleEvents::removal(uint32 subService, CSSM_SERVICE_TYPE type) { }
377 void ModuleEvents::fault(uint32 subService, CSSM_SERVICE_TYPE type) { }
378
379
380 void
381 ModuleImpl::appNotifyCallback(CSSM_API_ModuleEventHandler appNotifyCallback, void *appNotifyCallbackCtx)
382 {
383 secdebug("callback","In ModuleImpl::appNotifyCallback, appNotifyCallback=%p, appNotifyCallbackCtx=%p",
384 appNotifyCallback, appNotifyCallbackCtx);
385 if (mActive)
386 Error::throwMe(Error::objectBusy);
387
388 mAppNotifyCallback = appNotifyCallback;
389 mAppNotifyCallbackCtx = appNotifyCallbackCtx;
390 }
391
392 void
393 ModuleImpl::appNotifyCallback(RawModuleEvents *handler)
394 {
395 appNotifyCallback(RawModuleEvents::sendNotify, handler);
396 }
397
398 void
399 ModuleImpl::activate()
400 {
401 StLock<Mutex> _(mActivateMutex);
402 if (!mActive)
403 {
404 session()->init();
405 // @@@ install handler here (use central dispatch with override)
406 secdebug("callback","In ModuleImpl::activate, mAppNotifyCallback=%p, mAppNotifyCallbackCtx=%p",
407 mAppNotifyCallback, mAppNotifyCallbackCtx);
408 check(CSSM_ModuleLoad(&guid(), CSSM_KEY_HIERARCHY_NONE, mAppNotifyCallback, mAppNotifyCallbackCtx));
409 mActive = true;
410 session()->catchExit();
411 }
412 }
413
414 void
415 ModuleImpl::deactivate()
416 {
417 StLock<Mutex> _(mActivateMutex);
418 if (!isIdle())
419 Error::throwMe(Error::objectBusy);
420 if (mActive)
421 {
422 mActive = false;
423 check(CSSM_ModuleUnload(&guid(), mAppNotifyCallback, mAppNotifyCallbackCtx));
424 }
425 }
426
427 Cssm
428 ModuleImpl::session() const
429 {
430 return parent<Cssm>();
431 }
432
433
434 //
435 // CssmAttachment objects.
436 // parent ::= the loaded module object.
437 // active ::= attached.
438 //
439 AttachmentImpl::AttachmentImpl(const Guid &guid, CSSM_SERVICE_TYPE subserviceType)
440 : ObjectImpl(CssmImpl::standard()->autoModule(guid))
441 {
442 make(subserviceType);
443 }
444
445 AttachmentImpl::AttachmentImpl(const Module &module, CSSM_SERVICE_TYPE subserviceType)
446 : ObjectImpl(module)
447 {
448 make(subserviceType);
449 }
450
451 AttachmentImpl::~AttachmentImpl()
452 {
453 detach();
454 }
455
456 void
457 AttachmentImpl::make(CSSM_SERVICE_TYPE subserviceType)
458 {
459 // default configuration
460 mVersion.Major = 2;
461 mVersion.Minor = 0;
462 mSubserviceType = subserviceType;
463 mSubserviceId = 0;
464 mAttachFlags = 0;
465 }
466
467 void
468 AttachmentImpl::activate()
469 {
470 StLock<Mutex> _(mActivateMutex);
471 if (!mActive)
472 {
473 module()->load();
474 mMemoryFunctions = CssmAllocatorMemoryFunctions(allocator());
475 check(CSSM_ModuleAttach(&guid(), &mVersion,
476 &mMemoryFunctions,
477 mSubserviceId,
478 mSubserviceType,
479 mAttachFlags,
480 CSSM_KEY_HIERARCHY_NONE,
481 NULL, 0, // no function pointer table return
482 NULL, // reserved
483 &mHandle));
484 mActive = true;
485 }
486 }
487
488 void
489 AttachmentImpl::deactivate()
490 {
491 StLock<Mutex> _(mActivateMutex);
492 if (mActive)
493 {
494 mActive = false;
495 check(CSSM_ModuleDetach(mHandle));
496 }
497 }
498
499 CSSM_SERVICE_MASK
500 AttachmentImpl::subserviceMask() const
501 {
502 return mSubserviceType;
503 }
504
505 void
506 AttachmentImpl::subserviceId(uint32 id)
507 {
508 mSubserviceId = id;
509 }
510
511 CssmSubserviceUid
512 AttachmentImpl::subserviceUid() const
513 {
514 return CssmSubserviceUid(guid(), &mVersion, mSubserviceId, subserviceMask());
515 }
516
517 Module
518 AttachmentImpl::module() const
519 {
520 return parent<Module>();
521 }