X-Git-Url: https://git.saurik.com/apple/securityd.git/blobdiff_plain/6f458ca86da2b5a0249ba2fcca5d1e5f8f18858d..4cd1cad0dea00daa03e1b54fdf2797a02373ad5b:/src/token.cpp diff --git a/src/token.cpp b/src/token.cpp index faf7172..55198c1 100644 --- a/src/token.cpp +++ b/src/token.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved. + * Copyright (c) 2004,2007 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -67,7 +67,7 @@ Token::Token() Token::~Token() { - secdebug("token", "%p (%s:%ld) destroyed", + secdebug("token", "%p (%s:%d) destroyed", this, mGuid.toString().c_str(), mSubservice); } @@ -128,6 +128,27 @@ RefPointer Token::find(uint32 ssid) } +// +// We override getAcl to provide PIN state feedback +// +void Token::getAcl(const char *tag, uint32 &count, AclEntryInfo *&acls) +{ + if (pinFromAclTag(tag, "?")) { // read from tokend - do not cache + AclEntryInfo *racls; + token().tokend().getAcl(aclKind(), tokenHandle(), tag, count, racls); + // make a chunk-copy because that's the contract we have with the caller + acls = Allocator::standard().alloc(count * sizeof(AclEntryInfo)); + memcpy(acls, racls, count * sizeof(AclEntryInfo)); + ChunkCopyWalker copy; + for (uint32 n = 0; n < count; n++) + walk(copy, acls[n]); + return; + } + + TokenAcl::cssmGetAcl(tag, count, acls); +} + + // // Reset management. // A Token has a "reset level", a number that is incremented whenever a token @@ -145,23 +166,30 @@ Token::ResetGeneration Token::resetGeneration() const void Token::resetAcls() { - StLock _(*this); - mResetLevel++; - secdebug("token", "%p reset (level=%d, propagating to %ld common(s)", - this, mResetLevel, mCommons.size()); - for (CommonSet::const_iterator it = mCommons.begin(); it != mCommons.end(); it++) - RefPointer(*it)->resetAcls(); + CommonSet tmpCommons; + { + StLock _(*this); + mResetLevel++; + secdebug("token", "%p reset (level=%d, propagating to %ld common(s)", + this, mResetLevel, mCommons.size()); + // Make a copy to avoid deadlock with TokenDbCommon lock + tmpCommons = mCommons; + } + for (CommonSet::const_iterator it = tmpCommons.begin(); it != tmpCommons.end();) + RefPointer(*it++)->resetAcls(); } void Token::addCommon(TokenDbCommon &dbc) { + secdebug("token", "%p addCommon TokenDbCommon %p", this, &dbc); mCommons.insert(&dbc); } void Token::removeCommon(TokenDbCommon &dbc) { - assert(mCommons.find(&dbc) != mCommons.end()); - mCommons.erase(&dbc); + secdebug("token", "%p removeCommon TokenDbCommon %p", this, &dbc); + if (mCommons.find(&dbc) != mCommons.end()) + mCommons.erase(&dbc); } @@ -172,11 +200,21 @@ void Token::removeCommon(TokenDbCommon &dbc) // we're analyzing the token, determine its characteristics, and get ready to // use it. // -void Token::insert(::Reader &slot) +void Token::insert(::Reader &slot, RefPointer tokend) { try { // this might take a while... Server::active().longTermActivity(); + referent(slot); + mState = slot.pcscState(); + + if (tokend == NULL) { + // no pre-determined Tokend - search for one + if (!(tokend = chooseTokend())) { + secdebug("token", "%p no token daemons available - faulting this card", this); + fault(false); // throws + } + } // take Token lock and hold throughout insertion StLock _(*this); @@ -184,26 +222,18 @@ void Token::insert(::Reader &slot) Syslog::debug("token inserted into reader %s", slot.name().c_str()); secdebug("token", "%p begin insertion into slot %p (reader %s)", this, &slot, slot.name().c_str()); - referent(slot); - mState = slot.pcscState(); - - RefPointer tokend = chooseTokend(); - if (!tokend) { - secdebug("token", "%p no token daemons available - faulting this card", this); - fault(false); - } // tell the tokend object to relay faults to us tokend->faultRelay(this); // locate or establish cache directories if (tokend->hasTokenUid()) { - secdebug("token", "%p CHOOSING %s (score=%ld, uid=\"%s\")", + secdebug("token", "%p using %s (score=%d, uid=\"%s\")", this, tokend->bundlePath().c_str(), tokend->score(), tokend->tokenUid().c_str()); mCache = new TokenCache::Token(reader().cache, tokend->bundleIdentifier() + ":" + tokend->tokenUid()); } else { - secdebug("token", "%p CHOOSING %s (score=%ld, temporary)", + secdebug("token", "%p using %s (score=%d, temporary)", this, tokend->bundlePath().c_str(), tokend->score()); mCache = new TokenCache::Token(reader().cache); } @@ -230,7 +260,7 @@ void Token::insert(::Reader &slot) mPrintName = printName; if (mPrintName.empty()) { // last resort - new card and tokend didn't give us one - snprintf(printName, sizeof(printName), "smart card #%ld", mSubservice); + snprintf(printName, sizeof(printName), "smart card #%d", mSubservice); mPrintName = printName; } if (mCache->type() != TokenCache::Token::existing) @@ -240,12 +270,16 @@ void Token::insert(::Reader &slot) secdebug("token", "%p installing MDS from %s(%s)", this, tokend->bundlePath().c_str(), mdsDirectory[0] ? mdsDirectory : "ALL"); - string holdGuid = mGuid.toString(); // extend lifetime of .toString() + string holdGuid = mGuid.toString(); // extend lifetime of std::string + string holdTokenUid; + if (tokend->hasTokenUid()) + holdTokenUid = tokend->tokenUid(); + string holdPrintName = this->printName(); MDS_InstallDefaults mdsDefaults = { holdGuid.c_str(), mSubservice, - tokend->hasTokenUid() ? tokend->tokenUid().c_str() : "", - this->printName().c_str() + holdTokenUid.c_str(), + holdPrintName.c_str() }; mds().install(&mdsDefaults, tokend->bundlePath().c_str(), @@ -269,7 +303,7 @@ void Token::insert(::Reader &slot) slot.name().c_str(), mPrintName.c_str(), mTokend->hasTokenUid() ? mTokend->tokenUid().c_str() : "NO UID", mSubservice, mTokend->bundleIdentifier().c_str()); - secdebug("token", "%p inserted as %s:%ld", this, mGuid.toString().c_str(), mSubservice); + secdebug("token", "%p inserted as %s:%d", this, mGuid.toString().c_str(), mSubservice); } catch (const CommonError &err) { Syslog::notice("token in reader %s cannot be used (error %ld)", slot.name().c_str(), err.osStatus()); secdebug("token", "exception during insertion processing"); @@ -307,9 +341,11 @@ void Token::remove() this, &reader(), reader().name().c_str()); if (mTokend) mTokend->faultRelay(NULL); // unregister (no more faults, please) - notify(kNotificationCDSARemoval); mds().uninstall(mGuid.toString().c_str(), mSubservice); + secdebug("token", "%p mds uninstall complete", this); this->kill(); + secdebug("token", "%p kill complete", this); + notify(kNotificationCDSARemoval); secdebug("token", "%p removal complete", this); } @@ -336,7 +372,7 @@ void Token::fault(bool async) notify(kNotificationCDSAFailure); // cast off our TokenDaemon for good - mTokend = NULL; +//>>> mTokend = NULL; } // if this is a synchronous fault, abort this operation now @@ -357,18 +393,22 @@ void Token::relayFault(bool async) // void Token::kill() { - StLock _(*this); - if (mTokend) + // Avoid holding the lock across call to resetAcls + // This can cause deadlock on card removal { - mTokend = NULL; // cast loose our tokend (if any) - // Take us out of the map - StLock _(mSSIDLock); - SSIDMap::iterator it = mSubservices.find(mSubservice); - assert(it != mSubservices.end() && it->second == this); - if (it != mSubservices.end() && it->second == this) - mSubservices.erase(it); + StLock _(*this); + if (mTokend) + { + mTokend = NULL; // cast loose our tokend (if any) + // Take us out of the map + StLock _(mSSIDLock); + SSIDMap::iterator it = mSubservices.find(mSubservice); + assert(it != mSubservices.end() && it->second == this); + if (it != mSubservices.end() && it->second == this) + mSubservices.erase(it); + } } - + resetAcls(); // release our TokenDbCommons PerGlobal::kill(); // generic action @@ -382,8 +422,8 @@ void Token::kill() void Token::notify(NotificationEvent event) { NameValueDictionary nvd; - CssmSubserviceUid ssuid(mGuid, NULL, mSubservice, - CSSM_SERVICE_DL | CSSM_SERVICE_CSP); + CssmSubserviceUid ssuid(mGuid, NULL, h2n (mSubservice), + h2n(CSSM_SERVICE_DL | CSSM_SERVICE_CSP)); nvd.Insert(new NameValuePair(SSUID_KEY, CssmData::wrap(ssuid))); CssmData data; nvd.Export(data); @@ -407,17 +447,22 @@ void Token::notify(NotificationEvent event) RefPointer Token::chooseTokend() { //@@@ CodeRepository should learn to update from disk changes to be re-usable - CodeRepository candidates("Security/tokend", ".tokend", "TOKENDAEMONPATH", false); + CodeRepository candidates("Security/tokend", ".tokend", "TOKENDAEMONPATH", false); candidates.update(); //@@@ we could sort by reverse "maxScore" and avoid launching those who won't cut it anyway... RefPointer leader; - for (CodeRepository::const_iterator it = candidates.begin(); + for (CodeRepository::const_iterator it = candidates.begin(); it != candidates.end(); it++) { + RefPointer candidate = *it; try { - // any pre-launch screening of candidate *it goes here - - RefPointer tokend = new TokenDaemon(*it, + // skip software token daemons - ineligible for automatic choosing + if (CFTypeRef type = (*it)->infoPlistItem("TokendType")) + if (CFEqual(type, CFSTR("software"))) + continue; + + // okay, launch it and let it try + RefPointer tokend = new TokenDaemon(candidate, reader().name(), reader().pcscState(), reader().cache); if (tokend->state() == ServerChild::dead) // ah well, this one's no good @@ -431,7 +476,7 @@ RefPointer Token::chooseTokend() if (!leader || tokend->score() > leader->score()) leader = tokend; // a new front runner, he is... } catch (...) { - secdebug("token", "exception setting up %s (moving on)", (*it)->canonicalPath().c_str()); + secdebug("token", "exception setting up %s (moving on)", candidate->canonicalPath().c_str()); } } return leader; @@ -460,7 +505,7 @@ Token::Access::~Access() void Token::dumpNode() { PerGlobal::dumpNode(); - Debug::dump(" %s[%ld] tokend=%p", + Debug::dump(" %s[%d] tokend=%p", mGuid.toString().c_str(), mSubservice, mTokend.get()); }