#include "process.h"
#include "server.h"
#include "session.h"
#include "tempdatabase.h"
#include "authority.h"
#include "flippers.h"
Process::Process(Port servicePort, TaskPort taskPort,
const ClientSetupInfo *info, const char *identity, const CommonCriteria::AuditToken &audit)
: mTaskPort(taskPort), mByteFlipped(false), mPid(audit.pid()), mUid(audit.euid()), mGid(audit.egid())
{
parent(Session::find(servicePort));
if (mTaskPort.pid() != mPid) {
secdebug("SS", "Task/pid setup mismatch pid=%d task=%d(%d) for %s",
mPid, mTaskPort.port(), mTaskPort.pid(),
(identity && identity[0]) ? identity : "(unknown)");
CssmError::throwMe(CSSMERR_CSSM_ADDIN_AUTHENTICATE_FAILED); }
setup(info, identity);
secdebug("SS", "New process %p(%d) uid=%d gid=%d session=%p TP=%d %sfor %s",
this, mPid, mUid, mGid, &session(),
mTaskPort.port(),
mByteFlipped ? "FLIP " : "",
(identity && identity[0]) ? identity : "(unknown)");
}
void Process::reset(Port servicePort, TaskPort taskPort,
const ClientSetupInfo *info, const char *identity, const CommonCriteria::AuditToken &audit)
{
if (servicePort != session().servicePort() || taskPort != mTaskPort) {
secdebug("SS", "Process %p(%d) reset mismatch (sp %d-%d, tp %d-%d) for %s",
this, pid(), servicePort.port(), session().servicePort().port(), taskPort.port(), mTaskPort.port(),
(identity && identity[0]) ? identity : "(unknown)");
CssmError::throwMe(CSSMERR_CSSM_ADDIN_AUTHENTICATE_FAILED); }
setup(info, identity);
secdebug("SS", "process %p(%d) has reset; now %sfor %s",
this, mPid, mByteFlipped ? "FLIP " : "",
(identity && identity[0]) ? identity : "(unknown)");
}
void Process::setup(const ClientSetupInfo *info, const char *identity)
{
assert(info);
uint32 pversion;
if (info->order == 0x1234) { pversion = info->version;
} else if (info->order == 0x34120000) { pversion = ntohl(info->version);
mByteFlipped = true;
} else CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION);
if (pversion != SSPROTOVERSION)
CssmError::throwMe(CSSM_ERRCODE_INCOMPATIBLE_VERSION);
try {
mClientCode = OSXCode::decode(identity);
mClientIdent = deferred; } catch (...) {
secdebug("SS", "process %p(%d) identity decode threw exception", this, pid());
mClientCode = NULL;
mClientIdent = unknown; secdebug("SS", "process %p(%d) no clientCode - marked anonymous", this, pid());
}
}
Process::~Process()
{
IFDEBUG(if (!mAuthorizations.empty())
secdebug("SS", "Process %p(%d) clearing %d authorizations",
this, mPid, int(mAuthorizations.size())));
for (AuthorizationSet::iterator it = mAuthorizations.begin();
it != mAuthorizations.end(); ) {
AuthorizationToken *auth = *it;
while (++it != mAuthorizations.end() && *it == auth) ; if (auth->endProcess(*this))
delete auth;
}
secdebug("SS", "Process %p(%d) has died", this, mPid);
if (mTaskPort)
mTaskPort.destroy();
}
void Process::kill()
{
StLock<Mutex> _(*this);
mLocalStore = NULL;
PerProcess::kill();
}
Session& Process::session() const
{
return parent<Session>();
}
LocalDatabase &Process::localStore()
{
StLock<Mutex> _(*this);
if (!mLocalStore)
mLocalStore = new TempDatabase(*this);
return *mLocalStore;
}
Key *Process::makeTemporaryKey(const CssmKey &key, CSSM_KEYATTR_FLAGS moreAttributes,
const AclEntryPrototype *owner)
{
return safer_cast<TempDatabase&>(localStore()).makeKey(key, moreAttributes, owner);
}
void Process::changeSession(Port servicePort)
{
parent(Session::find(servicePort));
secdebug("SS", "process %p(%d) changed session to %p", this, pid(), &session());
}
string Process::getPath() const
{
assert(mClientCode);
return mClientCode->canonicalPath();
}
const CssmData Process::getHash(CodeSigning::OSXSigner &signer) const
{
switch (mClientIdent) {
case deferred:
try {
mCachedSignature.reset(mClientCode->sign(signer));
assert(mCachedSignature.get());
mClientIdent = known;
secdebug("SS", "process %p(%d) code signature computed", this, pid());
break;
} catch (...) {
mClientIdent = unknown;
secdebug("SS", "process %p(%d) no code signature - anonymous", this, pid());
CssmError::throwMe(CSSM_ERRCODE_INSUFFICIENT_CLIENT_IDENTIFICATION);
}
case known:
assert(mCachedSignature.get());
break;
case unknown:
CssmError::throwMe(CSSM_ERRCODE_INSUFFICIENT_CLIENT_IDENTIFICATION);
}
return CssmData(*mCachedSignature);
}
void Process::addAuthorization(AuthorizationToken *auth)
{
assert(auth);
StLock<Mutex> _(*this);
mAuthorizations.insert(auth);
auth->addProcess(*this);
}
void Process::checkAuthorization(AuthorizationToken *auth)
{
assert(auth);
StLock<Mutex> _(*this);
if (mAuthorizations.find(auth) == mAuthorizations.end())
MacOSError::throwMe(errAuthorizationInvalidRef);
}
bool Process::removeAuthorization(AuthorizationToken *auth)
{
assert(auth);
StLock<Mutex> _(*this);
typedef AuthorizationSet::iterator Iter;
Iter it = mAuthorizations.lower_bound(auth);
bool isLast;
if (it == mAuthorizations.end() || auth != *it) {
isLast = true;
} else {
Iter next = it; ++next; isLast = (next == mAuthorizations.end()) || auth != *next;
mAuthorizations.erase(it); }
if (isLast) {
if (auth->endProcess(*this)) return true; }
return false; }
void Process::requestNotifications(Port port, SecurityServer::NotificationDomain domain, SecurityServer::NotificationMask events)
{
new ProcessListener(*this, port, domain, events);
}
void Process::stopNotifications(Port port)
{
if (!Listener::remove(port))
CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE); }
#if defined(DEBUGDUMP)
void Process::dumpNode()
{
PerProcess::dumpNode();
if (mByteFlipped)
Debug::dump(" FLIPPED");
Debug::dump(" task=%d pid=%d uid/gid=%d/%d",
mTaskPort.port(), mPid, mUid, mGid);
if (mClientCode) {
Debug::dump(" client=%s", mClientCode->canonicalPath().c_str());
switch (mClientIdent) {
case deferred:
break;
case known:
Debug::dump("[OK]");
break;
case unknown:
Debug::dump("[UNKNOWN]");
break;
}
} else {
Debug::dump(" NO CLIENT ID");
}
}
#endif //DEBUGDUMP