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