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 _NOEXCEPT 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 }