Exemplo n.º 1
0
//
// Process the logical insertion of a Token into a Reader.
// From the client's point of view, this is where the CSSM subservice is created,
// characterized, and activated. From tokend's point of view, this is where
// we're analyzing the token, determine its characteristics, and get ready to
// use it.
//
void Token::insert(::Reader &slot, RefPointer<TokenDaemon> 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<Mutex> _(*this);

		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());
		
		// tell the tokend object to relay faults to us
		tokend->faultRelay(this);

		// locate or establish cache directories
		if (tokend->hasTokenUid()) {
			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 using %s (score=%d, temporary)",
				this, tokend->bundlePath().c_str(), tokend->score());
			mCache = new TokenCache::Token(reader().cache);
		}
		secdebug("token", "%p token cache at %s", this, mCache->root().c_str());
		
		// here's the primary parameters of the new subservice
		mGuid = gGuidAppleSdCSPDL;
		mSubservice = mCache->subservice();
		
		// establish work areas with tokend
		char mdsDirectory[PATH_MAX];
		char printName[PATH_MAX];
		tokend->establish(mGuid, mSubservice,
			(mCache->type() != TokenCache::Token::existing ? kSecTokendEstablishNewCache : 0) | kSecTokendEstablishMakeMDS,
			mCache->cachePath().c_str(), mCache->workPath().c_str(),
			mdsDirectory, printName);
		
		// establish print name
		if (mCache->type() == TokenCache::Token::existing) {
			mPrintName = mCache->printName();
			if (mPrintName.empty())
				mPrintName = printName;
		} else
			mPrintName = printName;
		if (mPrintName.empty()) {
			// last resort - new card and tokend didn't give us one
			snprintf(printName, sizeof(printName), "smart card #%d", mSubservice);
			mPrintName = printName;
		}
		if (mCache->type() != TokenCache::Token::existing)
			mCache->printName(mPrintName);		// store in cache

		// install MDS
		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()
		MDS_InstallDefaults mdsDefaults = {
			holdGuid.c_str(),
			mSubservice,
			tokend->hasTokenUid() ? tokend->tokenUid().c_str() : "",
			this->printName().c_str()
		};
		mds().install(&mdsDefaults,
			tokend->bundlePath().c_str(),
			mdsDirectory[0] ? mdsDirectory : NULL,
			NULL);

		{
			// commit to insertion
			StLock<Mutex> _(mSSIDLock);
			assert(mSubservices.find(mSubservice) == mSubservices.end());
			mSubservices.insert(make_pair(mSubservice, this));
		}

		// assign mTokend right before notification - mustn't be set if
		// anything goes wrong during insertion
		mTokend = tokend;

		notify(kNotificationCDSAInsertion);
		
		Syslog::notice("reader %s inserted token \"%s\" (%s) subservice %ld using driver %s",
			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:%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");
		fault(false);
	} catch (...) {
		// exception thrown during insertion processing. Mark faulted
		Syslog::notice("token in reader %s cannot be used", slot.name().c_str());
		secdebug("token", "exception during insertion processing");
		fault(false);
	}
}