#include "tokend.h"
#include <security_utilities/logging.h>
TokenDaemon::TokenDaemon(RefPointer<Bundle> code,
const string &reader, const PCSC::ReaderState &readerState, TokenCache &cache)
: Tokend::ClientSession(Allocator::standard(), Allocator::standard()),
mMe(code), mReaderName(reader), mState(readerState),
mFaultRelay(NULL), mFaulted(false), mProbed(false),
mUid(cache.tokendUid()), mGid(cache.tokendGid())
{
this->fork();
switch (ServerChild::state()) {
case alive:
Tokend::ClientSession::servicePort(ServerChild::servicePort());
secinfo("tokend", "%p (pid %d) %s has launched", this, pid(), bundlePath().c_str());
break;
case dead:
secinfo("tokend", "%p (pid %d) %s failed on startup", this, pid(), bundlePath().c_str());
break;
default:
assert(false);
}
}
TokenDaemon::~TokenDaemon()
{
secinfo("tokend", "%p (pid %d) %s is being destroyed", this, pid(), bundlePath().c_str());
}
std::string TokenDaemon::tokenUid() const
{
assert(hasTokenUid());
return mTokenUid;
}
uint32 TokenDaemon::maxScore() const
{
return cfNumber(CFNumberRef(mMe->infoPlistItem("TokendBestScore")), INT_MAX);
}
void TokenDaemon::childAction()
{
#if defined(NDEBUG)
UnixError::check(::setgid(mGid));
UnixError::check(::setuid(mUid));
#else //NDEBUG
#ifndef __clang_analyzer__
::setgid(mGid);
::setuid(mUid);
#endif // clang_analyzer
#endif //NDEBUG
secinfo("tokend", "uid=%d gid=%d", getuid(), getgid());
char protocol[20]; snprintf(protocol, sizeof(protocol), "%d", TDPROTOVERSION);
secinfo("tokend", "executing %s(\"%s\",%s)",
mMe->executablePath().c_str(), mReaderName.c_str(), protocol);
execl(mMe->executablePath().c_str(),
mMe->executablePath().c_str(),
protocol, mReaderName.c_str(), CssmData::wrap(mState).toHex().c_str(), NULL);
}
void TokenDaemon::dying()
{
ServerChild::dying(); fault(true, "token daemon has died"); }
void TokenDaemon::fault(bool async, const char *reason)
{
if (!mFaulted) {
secinfo("tokend", "%p declaring %s FAULT condition: %s",
this, async ? "ASYNCHRONOUS" : "SYNCHRONOUS", reason);
Syslog::notice("card in reader %s has faulted (%s)",
mReaderName.c_str(), reason);
mFaulted = true;
if (mFaultRelay)
mFaultRelay->relayFault(async);
}
if (!async)
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_FAILED);
}
void TokenDaemon::fault()
{
this->fault(false, "tokend service failed");
}
bool TokenDaemon::probe()
{
secinfo("tokend", "%p probing", this);
ClientSession::probe(mScore, mTokenUid);
secinfo("tokend", "%p probed score=%d tokenUid=\"%s\"", this, mScore, mTokenUid.c_str());
mProbed = true;
return mScore > 0;
}
FaultRelay::~FaultRelay()
{ }
#if defined(DEBUGDUMP)
void TokenDaemon::dumpNode()
{
PerGlobal::dumpNode();
if (mFaulted)
Debug::dump(" FAULT");
Debug::dump(" service=%d/%d",
ClientSession::servicePort().port(), ServerChild::servicePort().port());
}
#endif //DEBUGDUMP