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