]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_client/cssmclient.cpp
Security-164.1.tar.gz
[apple/security.git] / cdsa / cdsa_client / 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/cssmclient.h>
33 #include <Security/cssmerrno.h>
34
35
36 using namespace CssmClient;
37
38 //
39 // Exception model
40 //
41 CSSM_RETURN
42 Error::cssmError() const
43 {
44 //@@@ munge in client-side error codes here?
45 return CssmError::cssmError();
46 }
47
48 const char *
49 Error::what () const throw()
50 {
51 return "CSSM client library error";
52 }
53
54
55 //
56 // General utilities
57 //
58 void
59 ObjectImpl::check(CSSM_RETURN status)
60 {
61 if (status != CSSM_OK)
62 {
63 CssmError::throwMe(status);
64 }
65 }
66
67
68 //
69 // Common features of Objects
70 //
71 ObjectImpl::ObjectImpl() : mParent(), mChildCount(0)
72 {
73 mActive = false; // not activated
74 mAllocator = NULL; // allocator to be determined
75 }
76
77 ObjectImpl::ObjectImpl(const Object &mommy) : mParent(mommy.mImpl), mChildCount(0)
78 {
79 mActive = false; // not activated
80 mAllocator = NULL; // allocator to be determined
81 if (mParent)
82 mParent->addChild();
83 }
84
85 ObjectImpl::~ObjectImpl()
86 {
87 assert(!mActive); // subclass must have deactivated us
88 if (!isIdle())
89 Error::throwMe(Error::objectBusy);
90
91 // release parent from her obligations (if we still have one)
92 if (mParent)
93 mParent->removeChild();
94 }
95
96 void
97 ObjectImpl::addChild()
98 {
99 mChildCount++; // atomic
100 }
101
102 void
103 ObjectImpl::removeChild()
104 {
105 mChildCount--; // atomic
106 }
107
108
109 //
110 // Manage allocators in the Object tree
111 //
112 CssmAllocator &
113 ObjectImpl::allocator() const
114 {
115 if (mAllocator == NULL)
116 {
117 // fix allocator now
118 if (mParent)
119 mAllocator = &mParent->allocator();
120 else
121 mAllocator = &CssmAllocator::standard();
122 }
123
124 return *mAllocator;
125 }
126
127 void
128 ObjectImpl::allocator(CssmAllocator &alloc)
129 {
130 assert(mAllocator == NULL); // cannot redefine allocator once set
131 mAllocator = &alloc;
132 }
133
134 // Comparison operators use pointer comparison by default. Subclasses may override.
135 bool
136 ObjectImpl::operator <(const ObjectImpl &other) const
137 {
138 return this < &other;
139 }
140
141 bool
142 ObjectImpl::operator ==(const ObjectImpl &other) const
143 {
144 return this == &other;
145 }
146
147
148 //
149 // CSSMSession objects.
150 // parent ::= NULL (none)
151 // active ::= CSSM initialized
152 //
153 ModuleNexus<CssmImpl::StandardCssm> CssmImpl::mStandard;
154
155 CssmImpl::CssmImpl() : ObjectImpl()
156 {
157 setup();
158 mStandard().setCssm(this);
159 }
160
161 CssmImpl::CssmImpl(bool) : ObjectImpl()
162 {
163 setup();
164 // implicitly constructed - caller responsible for standard session management
165 }
166
167 CssmImpl::~CssmImpl()
168 {
169 try
170 {
171 deactivate();
172 }
173 catch(...) {}
174
175 // this may be the standard session...
176 mStandard().unsetCssm(this);
177 }
178
179
180 void
181 CssmImpl::setup()
182 {
183 // set default configuration
184 mVersion.Major = 2;
185 mVersion.Minor = 0;
186 mScope = CSSM_PRIVILEGE_SCOPE_PROCESS;
187 }
188
189
190 Cssm
191 CssmImpl::standard()
192 {
193 return Cssm(mStandard().get());
194 }
195
196
197 void
198 CssmImpl::activate()
199 {
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 if (mActive)
221 {
222 mActive = false;
223
224 // clear module map (all gone now)
225 moduleMap.erase(moduleMap.begin(), moduleMap.end());
226
227 // now terminate CSSM
228 check(CSSM_Terminate());
229 }
230 }
231
232 void
233 CssmImpl::atExitHandler()
234 {
235 try {
236 mStandard.reset();
237 } catch (...) {
238 }
239 }
240
241 void
242 CssmImpl::catchExit()
243 {
244 // @@@ Even though this is the "right thing" to do. This only causes
245 // exceptions during exit and doesn't really help cleanup correctly.
246 #if 0
247 if (::atexit(atExitHandler))
248 UnixError::throwMe();
249 #endif
250 }
251
252
253 //
254 // Manage the automatic Cssm object.
255 // This is a program global.
256 //
257 void CssmImpl::StandardCssm::setCssm(CssmImpl *cssm)
258 {
259 StLock<Mutex> _(*this);
260 if (mCssm == NULL)
261 mCssm = cssm;
262 }
263
264 void CssmImpl::StandardCssm::unsetCssm(CssmImpl *cssm)
265 {
266 StLock<Mutex> _(*this);
267 if (mCssm == cssm)
268 mCssm = NULL;
269 }
270
271 CssmImpl *CssmImpl::StandardCssm::get()
272 {
273 StLock<Mutex> _(*this);
274 if (mCssm == NULL) { // make the default instance
275 mCssm = new CssmImpl(true);
276 }
277 return mCssm;
278 }
279
280 CssmImpl::StandardCssm::~StandardCssm()
281 {
282 if (mCssm) {
283 mCssm->deactivate();
284 delete mCssm;
285 }
286 }
287
288
289 //
290 // Auto-module management
291 //
292 Module
293 CssmImpl::autoModule(const Guid &guid)
294 {
295 StLock<Mutex> _(mapLock);
296 ModuleMap::iterator it = moduleMap.find(guid);
297 if (it == moduleMap.end())
298 {
299 // no automodule for this guid yet, create one
300 Module module(guid, Cssm(this));
301 moduleMap.insert(ModuleMap::value_type(guid, module));
302 return module;
303 }
304 else
305 {
306 // existing automodule - use it
307 return it->second;
308 }
309 }
310
311
312 //
313 // Module objects.
314 // parent ::= the session object (usually Cssm::standard)
315 // active ::= module is loaded.
316 //
317 ModuleImpl::ModuleImpl(const Guid &guid) : ObjectImpl(Cssm::standard())
318 {
319 setGuid(guid);
320 }
321
322 ModuleImpl::ModuleImpl(const Guid &guid, const Cssm &session) : ObjectImpl(session)
323 {
324 setGuid(guid);
325 }
326
327 ModuleImpl::~ModuleImpl()
328 {
329 unload();
330 }
331
332
333 void
334 ModuleImpl::activate()
335 {
336 if (!mActive)
337 {
338 session()->init();
339 // @@@ install handler here (use central dispatch with override)
340 check(CSSM_ModuleLoad(&guid(), CSSM_KEY_HIERARCHY_NONE, NULL, NULL));
341 mActive = true;
342 session()->catchExit();
343 }
344 }
345
346 void
347 ModuleImpl::deactivate()
348 {
349 if (!isIdle())
350 Error::throwMe(Error::objectBusy);
351 if (mActive)
352 {
353 mActive = false;
354 check(CSSM_ModuleUnload(&guid(), NULL, NULL));
355 }
356 }
357
358 Cssm
359 ModuleImpl::session() const
360 {
361 return parent<Cssm>();
362 }
363
364
365 //
366 // CssmAttachment objects.
367 // parent ::= the loaded module object.
368 // active ::= attached.
369 //
370 AttachmentImpl::AttachmentImpl(const Guid &guid, CSSM_SERVICE_TYPE subserviceType)
371 : ObjectImpl(CssmImpl::standard()->autoModule(guid))
372 {
373 make(subserviceType);
374 }
375
376 AttachmentImpl::AttachmentImpl(const Module &module, CSSM_SERVICE_TYPE subserviceType)
377 : ObjectImpl(module)
378 {
379 make(subserviceType);
380 }
381
382 AttachmentImpl::~AttachmentImpl()
383 {
384 detach();
385 }
386
387 void
388 AttachmentImpl::make(CSSM_SERVICE_TYPE subserviceType)
389 {
390 // default configuration
391 mVersion.Major = 2;
392 mVersion.Minor = 0;
393 mSubserviceType = subserviceType;
394 mSubserviceId = 0;
395 mAttachFlags = 0;
396 }
397
398 void
399 AttachmentImpl::activate()
400 {
401 if (!mActive)
402 {
403 module()->load();
404 mMemoryFunctions = CssmAllocatorMemoryFunctions(allocator());
405 check(CSSM_ModuleAttach(&guid(), &mVersion,
406 &mMemoryFunctions,
407 mSubserviceId,
408 mSubserviceType,
409 mAttachFlags,
410 CSSM_KEY_HIERARCHY_NONE,
411 NULL, 0, // no function pointer table return
412 NULL, // reserved
413 &mHandle));
414 mActive = true;
415 }
416 }
417
418 void
419 AttachmentImpl::deactivate()
420 {
421 if (mActive)
422 {
423 mActive = false;
424 check(CSSM_ModuleDetach(mHandle));
425 }
426 }
427
428 CSSM_SERVICE_MASK
429 AttachmentImpl::subserviceMask() const
430 {
431 return mSubserviceType;
432 }
433
434 void
435 AttachmentImpl::subserviceId(uint32 id)
436 {
437 mSubserviceId = id;
438 }
439
440 CssmSubserviceUid
441 AttachmentImpl::subserviceUid() const
442 {
443 return CssmSubserviceUid(guid(), &mVersion, mSubserviceId, subserviceMask());
444 }
445
446 Module
447 AttachmentImpl::module() const
448 {
449 return parent<Module>();
450 }