]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cdsa_client/lib/cssmclient.cpp
Security-58286.1.32.tar.gz
[apple/security.git] / OSX / libsecurity_cdsa_client / lib / cssmclient.cpp
1 /*
2 * Copyright (c) 2000-2001,2011-2014 Apple 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 #include <utilities/debugging.h>
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 if (!isIdle())
81 {
82 int i = mChildCount;
83 secerror("Object %p still has %d children at delete.\n", this, i);
84 }
85
86 // release parent from her obligations (if we still have one)
87 if (mParent)
88 mParent->removeChild();
89 }
90 catch(...)
91 {
92 return; // Prevent re-throw of exception [function-try-block]
93 }
94
95 void
96 ObjectImpl::addChild()
97 {
98 mChildCount++; // atomic
99 }
100
101 void
102 ObjectImpl::removeChild()
103 {
104 mChildCount--; // atomic
105 }
106
107
108 //
109 // Manage allocators in the Object tree
110 //
111 Allocator &
112 ObjectImpl::allocator() const
113 {
114 StLock<Mutex> _(mAllocatorMutex);
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
127 void
128 ObjectImpl::allocator(Allocator &alloc)
129 {
130 StLock<Mutex> _(mAllocatorMutex);
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.
136 bool
137 ObjectImpl::operator <(const ObjectImpl &other) const
138 {
139 return this < &other;
140 }
141
142 bool
143 ObjectImpl::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 //
154 ModuleNexus<CssmImpl::StandardCssm> CssmImpl::mStandard;
155
156 CssmImpl::CssmImpl() : ObjectImpl()
157 {
158 setup();
159 mStandard().setCssm(this);
160 }
161
162 CssmImpl::CssmImpl(bool) : ObjectImpl()
163 {
164 setup();
165 // implicitly constructed - caller responsible for standard session management
166 }
167
168 CssmImpl::~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
181 void
182 CssmImpl::setup()
183 {
184 // set default configuration
185 mVersion.Major = 2;
186 mVersion.Minor = 0;
187 mScope = CSSM_PRIVILEGE_SCOPE_PROCESS;
188 }
189
190
191 Cssm
192 CssmImpl::standard()
193 {
194 return Cssm(mStandard().get());
195 }
196
197
198 void
199 CssmImpl::activate()
200 {
201 StLock<Mutex> _(mActivateMutex);
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
219 void
220 CssmImpl::deactivate()
221 {
222 StLock<Mutex> _(mActivateMutex);
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
235 void
236 CssmImpl::atExitHandler()
237 {
238 try {
239 mStandard.reset();
240 } catch (...) {
241 }
242 }
243
244 void
245 CssmImpl::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 //
260 void CssmImpl::StandardCssm::setCssm(CssmImpl *cssm)
261 {
262 StLock<Mutex> _(*this);
263 if (mCssm == NULL)
264 mCssm = cssm;
265 }
266
267 void CssmImpl::StandardCssm::unsetCssm(CssmImpl *cssm)
268 {
269 StLock<Mutex> _(*this);
270 if (mCssm == cssm)
271 mCssm = NULL;
272 }
273
274 Cssm CssmImpl::StandardCssm::get()
275 {
276 StLock<Mutex> _(*this);
277 if (mCssm == NULL) { // make the default instance
278 mCssm = new CssmImpl(true);
279 }
280 return Cssm(mCssm);
281 }
282
283 CssmImpl::StandardCssm::~StandardCssm()
284 {
285 if (mCssm) {
286 mCssm->deactivate();
287 delete mCssm;
288 }
289 }
290
291
292 //
293 // Auto-module management
294 //
295 Module
296 CssmImpl::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 //
320 ModuleImpl::ModuleImpl(const Guid &guid) : ObjectImpl(Cssm::standard()),
321 mAppNotifyCallback(NULL),
322 mAppNotifyCallbackCtx(NULL)
323 {
324 setGuid(guid);
325 }
326
327 ModuleImpl::ModuleImpl(const Guid &guid, const Cssm &session) : ObjectImpl(session),
328 mAppNotifyCallback(NULL),
329 mAppNotifyCallbackCtx(NULL)
330 {
331 setGuid(guid);
332 }
333
334 ModuleImpl::~ModuleImpl()
335 {
336 unload();
337 }
338
339
340 //
341 // RawModuleEvent objects encapsulate CSSM module callbacks
342 //
343 RawModuleEvents::~RawModuleEvents()
344 { }
345
346 CSSM_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 //
363 void 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
380 void ModuleEvents::insertion(uint32 subService, CSSM_SERVICE_TYPE type) { }
381 void ModuleEvents::removal(uint32 subService, CSSM_SERVICE_TYPE type) { }
382 void ModuleEvents::fault(uint32 subService, CSSM_SERVICE_TYPE type) { }
383
384
385 void
386 ModuleImpl::appNotifyCallback(CSSM_API_ModuleEventHandler appNotifyCallback, void *appNotifyCallbackCtx)
387 {
388 secinfo("callback","In ModuleImpl::appNotifyCallback, appNotifyCallback=%p, appNotifyCallbackCtx=%p",
389 appNotifyCallback, appNotifyCallbackCtx);
390 if (mActive)
391 Error::throwMe(Error::objectBusy);
392
393 mAppNotifyCallback = appNotifyCallback;
394 mAppNotifyCallbackCtx = appNotifyCallbackCtx;
395 }
396
397 void
398 ModuleImpl::appNotifyCallback(RawModuleEvents *handler)
399 {
400 appNotifyCallback(RawModuleEvents::sendNotify, handler);
401 }
402
403 void
404 ModuleImpl::activate()
405 {
406 {
407 StLock<Mutex> _(mActivateMutex);
408 if (!mActive)
409 {
410 session()->init();
411 // @@@ install handler here (use central dispatch with override)
412 secinfo("callback","In ModuleImpl::activate, mAppNotifyCallback=%p, mAppNotifyCallbackCtx=%p",
413 mAppNotifyCallback, mAppNotifyCallbackCtx);
414 check(CSSM_ModuleLoad(&guid(), CSSM_KEY_HIERARCHY_NONE, mAppNotifyCallback, mAppNotifyCallbackCtx));
415 mActive = true;
416 }
417 }
418
419 session()->catchExit();
420 }
421
422 void
423 ModuleImpl::deactivate()
424 {
425 if (!isIdle())
426 Error::throwMe(Error::objectBusy);
427
428 StLock<Mutex> _(mActivateMutex);
429 if (mActive)
430 {
431 mActive = false;
432 check(CSSM_ModuleUnload(&guid(), mAppNotifyCallback, mAppNotifyCallbackCtx));
433 }
434 }
435
436 Cssm
437 ModuleImpl::session() const
438 {
439 return parent<Cssm>();
440 }
441
442
443 //
444 // CssmAttachment objects.
445 // parent ::= the loaded module object.
446 // active ::= attached.
447 //
448 AttachmentImpl::AttachmentImpl(const Guid &guid, CSSM_SERVICE_TYPE subserviceType)
449 : ObjectImpl(CssmImpl::standard()->autoModule(guid))
450 {
451 make(subserviceType);
452 }
453
454 AttachmentImpl::AttachmentImpl(const Module &module, CSSM_SERVICE_TYPE subserviceType)
455 : ObjectImpl(module)
456 {
457 make(subserviceType);
458 }
459
460 AttachmentImpl::~AttachmentImpl()
461 try
462 {
463 detach();
464 }
465 catch (...) {
466 return;
467 }
468
469 void
470 AttachmentImpl::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
480 void
481 AttachmentImpl::activate()
482 {
483 StLock<Mutex> _(mActivateMutex);
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
501 void
502 AttachmentImpl::deactivate()
503 {
504 StLock<Mutex> _(mActivateMutex);
505 if (mActive)
506 {
507 mActive = false;
508 check(CSSM_ModuleDetach(mHandle));
509 }
510 }
511
512 CSSM_SERVICE_MASK
513 AttachmentImpl::subserviceMask() const
514 {
515 return mSubserviceType;
516 }
517
518 void
519 AttachmentImpl::subserviceId(uint32 id)
520 {
521 mSubserviceId = id;
522 }
523
524 CssmSubserviceUid
525 AttachmentImpl::subserviceUid() const
526 {
527 return CssmSubserviceUid(guid(), &mVersion, mSubserviceId, subserviceMask());
528 }
529
530 Module
531 AttachmentImpl::module() const
532 {
533 return parent<Module>();
534 }