]> git.saurik.com Git - apple/security.git/blob - libsecurity_cdsa_client/lib/cssmclient.cpp
Security-55471.14.18.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 #include <syslog.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 syslog(LOG_ALERT, "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;
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 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
126 void
127 ObjectImpl::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.
134 bool
135 ObjectImpl::operator <(const ObjectImpl &other) const
136 {
137 return this < &other;
138 }
139
140 bool
141 ObjectImpl::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 //
152 ModuleNexus<CssmImpl::StandardCssm> CssmImpl::mStandard;
153
154 CssmImpl::CssmImpl() : ObjectImpl()
155 {
156 setup();
157 mStandard().setCssm(this);
158 }
159
160 CssmImpl::CssmImpl(bool) : ObjectImpl()
161 {
162 setup();
163 // implicitly constructed - caller responsible for standard session management
164 }
165
166 CssmImpl::~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
179 void
180 CssmImpl::setup()
181 {
182 // set default configuration
183 mVersion.Major = 2;
184 mVersion.Minor = 0;
185 mScope = CSSM_PRIVILEGE_SCOPE_PROCESS;
186 }
187
188
189 Cssm
190 CssmImpl::standard()
191 {
192 return Cssm(mStandard().get());
193 }
194
195
196 void
197 CssmImpl::activate()
198 {
199 StLock<Mutex> _(mActivateMutex);
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
217 void
218 CssmImpl::deactivate()
219 {
220 StLock<Mutex> _(mActivateMutex);
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
233 void
234 CssmImpl::atExitHandler()
235 {
236 try {
237 mStandard.reset();
238 } catch (...) {
239 }
240 }
241
242 void
243 CssmImpl::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 //
258 void CssmImpl::StandardCssm::setCssm(CssmImpl *cssm)
259 {
260 StLock<Mutex> _(*this);
261 if (mCssm == NULL)
262 mCssm = cssm;
263 }
264
265 void CssmImpl::StandardCssm::unsetCssm(CssmImpl *cssm)
266 {
267 StLock<Mutex> _(*this);
268 if (mCssm == cssm)
269 mCssm = NULL;
270 }
271
272 CssmImpl *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
281 CssmImpl::StandardCssm::~StandardCssm()
282 {
283 if (mCssm) {
284 mCssm->deactivate();
285 delete mCssm;
286 }
287 }
288
289
290 //
291 // Auto-module management
292 //
293 Module
294 CssmImpl::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 //
318 ModuleImpl::ModuleImpl(const Guid &guid) : ObjectImpl(Cssm::standard()),
319 mAppNotifyCallback(NULL),
320 mAppNotifyCallbackCtx(NULL)
321 {
322 setGuid(guid);
323 }
324
325 ModuleImpl::ModuleImpl(const Guid &guid, const Cssm &session) : ObjectImpl(session),
326 mAppNotifyCallback(NULL),
327 mAppNotifyCallbackCtx(NULL)
328 {
329 setGuid(guid);
330 }
331
332 ModuleImpl::~ModuleImpl()
333 {
334 unload();
335 }
336
337
338 //
339 // RawModuleEvent objects encapsulate CSSM module callbacks
340 //
341 RawModuleEvents::~RawModuleEvents()
342 { }
343
344 CSSM_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 //
361 void 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
378 void ModuleEvents::insertion(uint32 subService, CSSM_SERVICE_TYPE type) { }
379 void ModuleEvents::removal(uint32 subService, CSSM_SERVICE_TYPE type) { }
380 void ModuleEvents::fault(uint32 subService, CSSM_SERVICE_TYPE type) { }
381
382
383 void
384 ModuleImpl::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
395 void
396 ModuleImpl::appNotifyCallback(RawModuleEvents *handler)
397 {
398 appNotifyCallback(RawModuleEvents::sendNotify, handler);
399 }
400
401 void
402 ModuleImpl::activate()
403 {
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 }
416
417 session()->catchExit();
418 }
419
420 void
421 ModuleImpl::deactivate()
422 {
423 if (!isIdle())
424 Error::throwMe(Error::objectBusy);
425
426 StLock<Mutex> _(mActivateMutex);
427 if (mActive)
428 {
429 mActive = false;
430 check(CSSM_ModuleUnload(&guid(), mAppNotifyCallback, mAppNotifyCallbackCtx));
431 }
432 }
433
434 Cssm
435 ModuleImpl::session() const
436 {
437 return parent<Cssm>();
438 }
439
440
441 //
442 // CssmAttachment objects.
443 // parent ::= the loaded module object.
444 // active ::= attached.
445 //
446 AttachmentImpl::AttachmentImpl(const Guid &guid, CSSM_SERVICE_TYPE subserviceType)
447 : ObjectImpl(CssmImpl::standard()->autoModule(guid))
448 {
449 make(subserviceType);
450 }
451
452 AttachmentImpl::AttachmentImpl(const Module &module, CSSM_SERVICE_TYPE subserviceType)
453 : ObjectImpl(module)
454 {
455 make(subserviceType);
456 }
457
458 AttachmentImpl::~AttachmentImpl()
459 {
460 detach();
461 }
462
463 void
464 AttachmentImpl::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
474 void
475 AttachmentImpl::activate()
476 {
477 StLock<Mutex> _(mActivateMutex);
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
495 void
496 AttachmentImpl::deactivate()
497 {
498 StLock<Mutex> _(mActivateMutex);
499 if (mActive)
500 {
501 mActive = false;
502 check(CSSM_ModuleDetach(mHandle));
503 }
504 }
505
506 CSSM_SERVICE_MASK
507 AttachmentImpl::subserviceMask() const
508 {
509 return mSubserviceType;
510 }
511
512 void
513 AttachmentImpl::subserviceId(uint32 id)
514 {
515 mSubserviceId = id;
516 }
517
518 CssmSubserviceUid
519 AttachmentImpl::subserviceUid() const
520 {
521 return CssmSubserviceUid(guid(), &mVersion, mSubserviceId, subserviceMask());
522 }
523
524 Module
525 AttachmentImpl::module() const
526 {
527 return parent<Module>();
528 }