X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/72a12576750f52947eb043106ba5c12c0d07decf..b1ab9ed8d0e0f1c3b66d7daa8fd5564444c56195:/libsecurity_cdsa_client/lib/cssmclient.cpp?ds=sidebyside diff --git a/libsecurity_cdsa_client/lib/cssmclient.cpp b/libsecurity_cdsa_client/lib/cssmclient.cpp new file mode 100644 index 00000000..ec3fb44d --- /dev/null +++ b/libsecurity_cdsa_client/lib/cssmclient.cpp @@ -0,0 +1,515 @@ +/* + * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. + * + * The contents of this file constitute Original Code as defined in and are + * subject to the Apple Public Source License Version 1.2 (the 'License'). + * You may not use this file except in compliance with the License. Please obtain + * a copy of the License at http://www.apple.com/publicsource and read it before + * using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS + * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT + * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the + * specific language governing rights and limitations under the License. + */ + + +// +// cssmclient - common client interface to CSSM and MDS. +// +// Locking Strategy (preliminary): +// XXX This is obsolete update this --mb +// A CssmObject is a CountingMutex. Its count represents the number of children that have registered +// themselves (using addChild/removeChild). The lock controls the internal management fields of the +// various subclasses to protect them against corruption. It does NOT control attribute and argument +// fields and operations, not does it control object-constant fields. +// This means that if you use an object from multiple threads, you (the caller) must lock the object +// during set/get calls of attributes. Note that the CSSM operations themselves are safely multithreaded +// and thus don't need to be interlocked explicitly. +// +#include + + +using namespace CssmClient; + +// +// Exception model +// +const char * +Error::what () const throw() +{ + return "CSSM client library error"; +} + + +// +// General utilities +// +void +ObjectImpl::check(CSSM_RETURN status) +{ + if (status != CSSM_OK) + { + CssmError::throwMe(status); + } +} + + +// +// Common features of Objects +// +ObjectImpl::ObjectImpl() : mParent(), mChildCount(0) +{ + mActive = false; // not activated + mAllocator = NULL; // allocator to be determined +} + +ObjectImpl::ObjectImpl(const Object &mommy) : mParent(mommy.mImpl), mChildCount(0) +{ + mActive = false; // not activated + mAllocator = NULL; // allocator to be determined + if (mParent) + mParent->addChild(); +} + +ObjectImpl::~ObjectImpl() +try +{ + assert(!mActive); // subclass must have deactivated us + assert(isIdle()); + + // release parent from her obligations (if we still have one) + if (mParent) + mParent->removeChild(); +} +catch(...) +{ + return; +} + +void +ObjectImpl::addChild() +{ + mChildCount++; // atomic +} + +void +ObjectImpl::removeChild() +{ + mChildCount--; // atomic +} + + +// +// Manage allocators in the Object tree +// +Allocator & +ObjectImpl::allocator() const +{ + if (mAllocator == NULL) + { + // fix allocator now + if (mParent) + mAllocator = &mParent->allocator(); + else + mAllocator = &Allocator::standard(); + } + + return *mAllocator; +} + +void +ObjectImpl::allocator(Allocator &alloc) +{ + assert(mAllocator == NULL); // cannot redefine allocator once set + mAllocator = &alloc; +} + +// Comparison operators use pointer comparison by default. Subclasses may override. +bool +ObjectImpl::operator <(const ObjectImpl &other) const +{ + return this < &other; +} + +bool +ObjectImpl::operator ==(const ObjectImpl &other) const +{ + return this == &other; +} + + +// +// CSSMSession objects. +// parent ::= NULL (none) +// active ::= CSSM initialized +// +ModuleNexus CssmImpl::mStandard; + +CssmImpl::CssmImpl() : ObjectImpl() +{ + setup(); + mStandard().setCssm(this); +} + +CssmImpl::CssmImpl(bool) : ObjectImpl() +{ + setup(); + // implicitly constructed - caller responsible for standard session management +} + +CssmImpl::~CssmImpl() +{ + try + { + deactivate(); + } + catch(...) {} + + // this may be the standard session... + mStandard().unsetCssm(this); +} + + +void +CssmImpl::setup() +{ + // set default configuration + mVersion.Major = 2; + mVersion.Minor = 0; + mScope = CSSM_PRIVILEGE_SCOPE_PROCESS; +} + + +Cssm +CssmImpl::standard() +{ + return Cssm(mStandard().get()); +} + + +void +CssmImpl::activate() +{ + if (!mActive) + { + // currently, no choices on PVC mode and key hierarchy + CSSM_PVC_MODE pvc = CSSM_PVC_NONE; + switch (CSSM_RETURN rc = CSSM_Init(&mVersion, + mScope, &mCallerGuid, + CSSM_KEY_HIERARCHY_NONE, &pvc, NULL)) { + case CSSMERR_CSSM_PVC_ALREADY_CONFIGURED: + case CSSM_OK: + break; + default: + check(rc); + } + mActive = true; + } +} + +void +CssmImpl::deactivate() +{ + if (mActive) + { + mActive = false; + + // clear module map (all gone now) + moduleMap.erase(moduleMap.begin(), moduleMap.end()); + + // now terminate CSSM + check(CSSM_Terminate()); + } +} + +void +CssmImpl::atExitHandler() +{ + try { + mStandard.reset(); + } catch (...) { + } +} + +void +CssmImpl::catchExit() +{ + // @@@ Even though this is the "right thing" to do. This only causes + // exceptions during exit and doesn't really help cleanup correctly. +#if 0 + if (::atexit(atExitHandler)) + UnixError::throwMe(); +#endif +} + + +// +// Manage the automatic Cssm object. +// This is a program global. +// +void CssmImpl::StandardCssm::setCssm(CssmImpl *cssm) +{ + StLock _(*this); + if (mCssm == NULL) + mCssm = cssm; +} + +void CssmImpl::StandardCssm::unsetCssm(CssmImpl *cssm) +{ + StLock _(*this); + if (mCssm == cssm) + mCssm = NULL; +} + +CssmImpl *CssmImpl::StandardCssm::get() +{ + StLock _(*this); + if (mCssm == NULL) { // make the default instance + mCssm = new CssmImpl(true); + } + return mCssm; +} + +CssmImpl::StandardCssm::~StandardCssm() +{ + if (mCssm) { + mCssm->deactivate(); + delete mCssm; + } +} + + +// +// Auto-module management +// +Module +CssmImpl::autoModule(const Guid &guid) +{ + StLock _(mapLock); + ModuleMap::iterator it = moduleMap.find(guid); + if (it == moduleMap.end()) + { + // no automodule for this guid yet, create one + Module module(guid, Cssm(this)); + moduleMap.insert(ModuleMap::value_type(guid, module)); + return module; + } + else + { + // existing automodule - use it + return it->second; + } +} + + +// +// Module objects. +// parent ::= the session object (usually Cssm::standard) +// active ::= module is loaded. +// +ModuleImpl::ModuleImpl(const Guid &guid) : ObjectImpl(Cssm::standard()), + mAppNotifyCallback(NULL), + mAppNotifyCallbackCtx(NULL) +{ + setGuid(guid); +} + +ModuleImpl::ModuleImpl(const Guid &guid, const Cssm &session) : ObjectImpl(session), + mAppNotifyCallback(NULL), + mAppNotifyCallbackCtx(NULL) +{ + setGuid(guid); +} + +ModuleImpl::~ModuleImpl() +{ + unload(); +} + + +// +// RawModuleEvent objects encapsulate CSSM module callbacks +// +RawModuleEvents::~RawModuleEvents() +{ } + +CSSM_RETURN RawModuleEvents::sendNotify(const CSSM_GUID *, void *context, + uint32 subService, CSSM_SERVICE_TYPE type, CSSM_MODULE_EVENT event) +{ + try { + reinterpret_cast(context)->notify(subService, type, event); + return CSSM_OK; + } catch (const CommonError &error) { + return CssmError::cssmError(error, CSSM_CSSM_BASE_ERROR); + } catch (...) { + return CSSMERR_CSSM_INTERNAL_ERROR; // whatever... + } +} + + +// +// ModuleEvents enhance RawModuleEvents by splitting the callback up by type +// +void ModuleEvents::notify(uint32 subService, + CSSM_SERVICE_TYPE type, CSSM_MODULE_EVENT event) +{ + switch (event) { + case CSSM_NOTIFY_INSERT: + insertion(subService, type); + break; + case CSSM_NOTIFY_REMOVE: + removal(subService, type); + break; + case CSSM_NOTIFY_FAULT: + fault(subService, type); + break; + } +} + +// default callbacks do nothing +void ModuleEvents::insertion(uint32 subService, CSSM_SERVICE_TYPE type) { } +void ModuleEvents::removal(uint32 subService, CSSM_SERVICE_TYPE type) { } +void ModuleEvents::fault(uint32 subService, CSSM_SERVICE_TYPE type) { } + + +void +ModuleImpl::appNotifyCallback(CSSM_API_ModuleEventHandler appNotifyCallback, void *appNotifyCallbackCtx) +{ + secdebug("callback","In ModuleImpl::appNotifyCallback, appNotifyCallback=%p, appNotifyCallbackCtx=%p", + appNotifyCallback, appNotifyCallbackCtx); + if (mActive) + Error::throwMe(Error::objectBusy); + + mAppNotifyCallback = appNotifyCallback; + mAppNotifyCallbackCtx = appNotifyCallbackCtx; +} + +void +ModuleImpl::appNotifyCallback(RawModuleEvents *handler) +{ + appNotifyCallback(RawModuleEvents::sendNotify, handler); +} + +void +ModuleImpl::activate() +{ + if (!mActive) + { + session()->init(); + // @@@ install handler here (use central dispatch with override) + secdebug("callback","In ModuleImpl::activate, mAppNotifyCallback=%p, mAppNotifyCallbackCtx=%p", + mAppNotifyCallback, mAppNotifyCallbackCtx); + check(CSSM_ModuleLoad(&guid(), CSSM_KEY_HIERARCHY_NONE, mAppNotifyCallback, mAppNotifyCallbackCtx)); + mActive = true; + session()->catchExit(); + } +} + +void +ModuleImpl::deactivate() +{ + if (!isIdle()) + Error::throwMe(Error::objectBusy); + if (mActive) + { + mActive = false; + check(CSSM_ModuleUnload(&guid(), mAppNotifyCallback, mAppNotifyCallbackCtx)); + } +} + +Cssm +ModuleImpl::session() const +{ + return parent(); +} + + +// +// CssmAttachment objects. +// parent ::= the loaded module object. +// active ::= attached. +// +AttachmentImpl::AttachmentImpl(const Guid &guid, CSSM_SERVICE_TYPE subserviceType) +: ObjectImpl(CssmImpl::standard()->autoModule(guid)) +{ + make(subserviceType); +} + +AttachmentImpl::AttachmentImpl(const Module &module, CSSM_SERVICE_TYPE subserviceType) +: ObjectImpl(module) +{ + make(subserviceType); +} + +AttachmentImpl::~AttachmentImpl() +{ + detach(); +} + +void +AttachmentImpl::make(CSSM_SERVICE_TYPE subserviceType) +{ + // default configuration + mVersion.Major = 2; + mVersion.Minor = 0; + mSubserviceType = subserviceType; + mSubserviceId = 0; + mAttachFlags = 0; +} + +void +AttachmentImpl::activate() +{ + if (!mActive) + { + module()->load(); + mMemoryFunctions = CssmAllocatorMemoryFunctions(allocator()); + check(CSSM_ModuleAttach(&guid(), &mVersion, + &mMemoryFunctions, + mSubserviceId, + mSubserviceType, + mAttachFlags, + CSSM_KEY_HIERARCHY_NONE, + NULL, 0, // no function pointer table return + NULL, // reserved + &mHandle)); + mActive = true; + } +} + +void +AttachmentImpl::deactivate() +{ + if (mActive) + { + mActive = false; + check(CSSM_ModuleDetach(mHandle)); + } +} + +CSSM_SERVICE_MASK +AttachmentImpl::subserviceMask() const +{ + return mSubserviceType; +} + +void +AttachmentImpl::subserviceId(uint32 id) +{ + mSubserviceId = id; +} + +CssmSubserviceUid +AttachmentImpl::subserviceUid() const +{ + return CssmSubserviceUid(guid(), &mVersion, mSubserviceId, subserviceMask()); +} + +Module +AttachmentImpl::module() const +{ + return parent(); +}