// CardCtx.cpp -- Card ConTeXt class definition // (c) Copyright Schlumberger Technology Corp., unpublished work, created // 1999. This computer program includes Confidential, Proprietary // Information and is a Trade Secret of Schlumberger Technology Corp. All // use, disclosure, and/or reproduction is prohibited unless authorized // in writing. All Rights Reserved. // Don't allow the min & max macros in WINDEF.H to be defined so the // min/max methods declared in limits are accessible. #define NOMINMAX #include "NoWarning.h" #include "ForceLib.h" #include #include #include #include #include #include "HCardCtx.h" #include "LoginCtx.h" #include "Procedural.h" #include "HAdptvCntr.h" #include "Guarded.h" #include // always last for now using namespace std; using namespace cci; /////////////////////////// LOCAL/HELPER ///////////////////////////////// namespace { class StaleContainerKeyAccumulator : public binary_function, AdaptiveContainerRegistrar::RegistryType::CollectionType::value_type, vector > { public: explicit StaleContainerKeyAccumulator(HCardContext const &rhcardctx) : m_rhcardctx(rhcardctx) {} result_type operator()(first_argument_type &rvStaleCntrs, second_argument_type const &rvt) const { if (rvt.second->CardContext(false) == m_rhcardctx) rvStaleCntrs.push_back(rvt.second); return rvStaleCntrs; } private: HCardContext const &m_rhcardctx; }; void ClearAdaptiveContainerCache(AdaptiveContainerRegistrar::EnrolleeType enrollee, HCardContext hcardctx) { if (enrollee->CardContext(false) == hcardctx) { enrollee->ClearCache(); } } void DeleteAdaptiveContainerCache(AdaptiveContainerRegistrar::EnrolleeType enrollee, HCardContext hcardctx) { if (enrollee->CardContext(false) == hcardctx) enrollee->DeleteCache(); } void DeactivateLoginContext(auto_ptr const &raplc) { raplc->Deactivate(); } } /////////////////////////// PUBLIC ///////////////////////////////// // Types // C'tors/D'tors CardContext::CardContext(std::string const &rsReaderName) : RCObject(), Lockable(), Securable(), CachingObject(), CardContextRegistrar(rsReaderName), m_stkapGuards(), m_aptwCard(), m_cSecurers(0), m_card(CCard(rsReaderName)), m_mloginctx(), m_nMrkLastWrite() {} CardContext::~CardContext() throw() {} // Operators // Operations void CardContext::ClearLogin(LoginIdentity const &rlid) { Guarded guard(this); auto_ptr &raplc = m_mloginctx[rlid]; if (raplc.get()) raplc = auto_ptr(0); } void CardContext::Login(LoginIdentity const &rlid, LoginTask &rlt, bool fForceLogin) { Guarded guard(this); auto_ptr &raplc = m_mloginctx[rlid]; if (!raplc.get()) raplc = auto_ptr(new LoginContext(HCardContext(this), rlid)); if (fForceLogin || !raplc->IsActive()) raplc->Activate(rlt); } void CardContext::Logout() { ForEachMappedValue(m_mloginctx.begin(), m_mloginctx.end(), DeactivateLoginContext); } // Access CCard CardContext::Card() { return m_card; } // Predicates // Static Variables /////////////////////////// PROTECTED ///////////////////////////////// // C'tors/D'tors // Operators // Operations void CardContext::DiscardHook() { DeleteCache(); RemoveReference(); } CardContext * CardContext::DoInstantiation(std::string const &rsReaderName) { return new CardContext(rsReaderName); } void CardContext::EnrollHook() { AddReference(); } // Access // Predicates bool CardContext::KeepEnrolled() { return (m_card && m_card->IsAvailable()) ? true : false; } // Static Variables /////////////////////////// PRIVATE ///////////////////////////////// // C'tors/D'tors // Operators // Operations void CardContext::Abandon() { // Simplifying assumptions: (1) Abandon is only called by the // Secured destructor, (2) once the object is constructed, Secure // and Abandon are the only routines that access the count, and // (3) Abandon is called by a thread within the scope of a Retain // (e.g. using Retained) which the Secured class enforces. // Because of (1) and (2), an underflow check on the count is not // necessary since Secure will have already been called. Because // of (3), protection against race conditions accessing count // isn't necessary since Retain acts as a lock. --m_cSecurers; if (0 == m_cSecurers) { // Security: markers are moved to the card. Updating them // requires authentication by the user pin. // Notify any changes to this card during this transaction // before letting someone else have access and before loggin // out. try { UpdateMarkers(); } catch(...) { // do not leave the card in authenticated state Logout(); throw; } Logout(); } } // Optionally clear the cached info void CardContext::ClearCache() { // Security: markers reside on the card. We trade off performance for // security because any update of the marker requires // authentication by the user pin. On the other hand, reading // markers from the card is considerably slower than reading from // memory. if(!Card()->IsMarkerOnCard() || m_nMrkLastWrite != Card()->MarkerOnCard()) { ForEachEnrollee(AdaptiveContainerRegistrar::Registry(), ProcedureBind2nd(PointerProcedure(ClearAdaptiveContainerCache), HCardContext(this))); Card()->InvalidateCache(); } } // Delete any cached info, never to be refreshed void CardContext::DeleteCache() { m_mloginctx.clear(); Guarded guard(&AdaptiveContainerRegistrar::Registry()); // serialize registry access AdaptiveContainerRegistrar::ConstRegistryType &rRegistry = AdaptiveContainerRegistrar::Registry(); AdaptiveContainerRegistrar::ConstRegistryType::CollectionType &rcollection = rRegistry(); HCardContext hcardctx(this); // Any containers associated with this card should be marked stale // now because on Whistler (W2K Upgrade) trying to access them // later when another context has a begin transaction on the same // reader will cause a wait. On earlier platforms, the RM would // return an error (e.g. card removed) when attempting to access // the container. vector vStaleCntrs(accumulate(rcollection.begin(), rcollection.end(), vector(), StaleContainerKeyAccumulator(hcardctx))); for (vector::iterator iCurrent(vStaleCntrs.begin()); iCurrent != vStaleCntrs.end(); ++iCurrent) { (*iCurrent)->NullifyCard(); } } void CardContext::Relinquish() { // Simplifying assumptions: (1) Relinquish is only called by the // Retained destructor and (2) once the object is constructed, // Retain and Relinquish are the only routines that access the // m_stkapGuards and m_aptwCard. Because of (1) and (2), an // underflow check on m_stkRetainedCardContexts is not necessary // since Retain will have already been called. // Protect against exceptions by fist assigning the newly acquired // "locks" to temporary variables until all the actions necessary // are successfully completed before assigning transfering // ownership of the locks to the associated member variables. auto_ptr > apgcardctx(m_stkapGuards.front()); m_stkapGuards.pop_front(); if (m_stkapGuards.empty()) { try { m_aptwCard = auto_ptr(0); } catch (...) { } } } void CardContext::Retain() { // Simplifying assumptions: (1) Retain is only called by the // Retained constructor and (2) once the object is constructed, // Retain and Relinquish are the only routines that access the // m_stkapGuards and m_aptwCard. Because of (1) and (2), an // underflow check on m_stkRetainedCardContexts is not necessary // since Retain will have already been called. // Protect against exceptions by fist assigning the newly acquired // "locks" to temporary variables until all the actions necessary // are successfully completed before assigning transfering // ownership of the locks to the associated member variables. auto_ptr > apgcardctx(new Guarded(this)); auto_ptr aptwCard; if (m_stkapGuards.empty()) { aptwCard = auto_ptr(new CTransactionWrap(m_card)); ClearCache(); } m_stkapGuards.push_front(apgcardctx); if (aptwCard.get()) m_aptwCard = aptwCard; } void CardContext::UpdateMarkers() { // Security: there is only one marker and it resides on the // card. The marker indicates if any data on the card changed. m_nMrkLastWrite = Card()->MarkerOnCard(); } void CardContext::Secure() { // Simplifying assumptions: (1) Secure is always called by a thread // within the scope of a Retain (e.g. using Retained). The // Secured template enforces this allowing Retain to act as a lock // to prevent race conditions updating m_cSecurers. (2) Once the // object is constructed, Secure and Abandon are the only routines // that access m_cSecurers. if (0 >= (m_cSecurers + 1)) throw scu::OsException(ERROR_INVALID_HANDLE_STATE); ++m_cSecurers; } // Access // Predicates // Static Variables