#include "clientid.h"
#include "server.h"
#include <Security/SecCodePriv.h>
ClientIdentification::ClientIdentification()
{
}
void ClientIdentification::setup(pid_t pid)
{
StLock<Mutex> _(mLock);
if (OSStatus rc = SecCodeCreateWithPID(pid, kSecCSDefaultFlags,
&mClientProcess.aref()))
secdebug("clientid", "could not get code for process %d: OSStatus=%d",
pid, int32_t(rc));
mGuests.erase(mGuests.begin(), mGuests.end());
}
SecCodeRef ClientIdentification::processCode() const
{
return mClientProcess;
}
SecCodeRef ClientIdentification::currentGuest() const
{
if (GuestState *guest = current())
return guest->code;
else
return mClientProcess;
}
ClientIdentification::GuestState *ClientIdentification::current() const
{
if (!processCode())
return NULL;
SecGuestRef guestRef = Server::connection().guestRef();
{
StLock<Mutex> _(mLock);
GuestMap::iterator it = mGuests.find(guestRef);
if (it != mGuests.end())
return &it->second;
}
CFRef<CFDictionaryRef> attributes = (guestRef == kSecNoGuest)
? NULL
: makeCFDictionary(1, kSecGuestAttributeCanonical, CFTempNumber(guestRef).get());
Server::active().longTermActivity();
CFRef<SecCodeRef> code;
switch (OSStatus rc = SecCodeCopyGuestWithAttributes(processCode(),
attributes, kSecCSDefaultFlags, &code.aref())) {
case noErr:
break;
case errSecCSUnsigned: case errSecCSNotAHost: code = mClientProcess;
break;
case errSecCSNoSuchCode: if (guestRef == kSecNoGuest) { code = mClientProcess;
break;
}
default:
MacOSError::throwMe(rc);
}
StLock<Mutex> _(mLock);
GuestState &slot = mGuests[guestRef];
if (!slot.code) slot.code = code;
return &slot;
}
string ClientIdentification::getPath() const
{
assert(mClientProcess);
return codePath(currentGuest());
}
const CssmData ClientIdentification::getHash() const
{
if (GuestState *guest = current()) {
if (!guest->gotHash) {
RefPointer<OSXCode> clientCode = new OSXCodeWrap(guest->code);
OSXVerifier::makeLegacyHash(clientCode, guest->legacyHash);
guest->gotHash = true;
}
return CssmData::wrap(guest->legacyHash, SHA1::digestLength);
} else
return CssmData();
}
const bool ClientIdentification::checkAppleSigned() const
{
if (GuestState *guest = current()) {
if (!guest->checkedSignature) {
CFStringRef requirementString = CFSTR("(anchor apple) or (anchor apple generic and certificate leaf[field.1.2.840.113635.100.6.1.9])");
SecRequirementRef secRequirementRef = NULL;
OSStatus status = SecRequirementCreateWithString(requirementString, kSecCSDefaultFlags, &secRequirementRef);
if (status == errSecSuccess) {
OSStatus status = SecCodeCheckValidity(guest->code, kSecCSDefaultFlags, secRequirementRef);
if (status != errSecSuccess) {
secdebug("SecurityAgentXPCQuery", "code requirement check failed (%d)", (int32_t)status);
} else {
guest->appleSigned = true;
}
guest->checkedSignature = true;
}
CFRelease(secRequirementRef);
}
return guest->appleSigned;
} else
return false;
}
std::string codePath(SecStaticCodeRef code)
{
CFRef<CFURLRef> path;
MacOSError::check(SecCodeCopyPath(code, kSecCSDefaultFlags, &path.aref()));
return cfString(path);
}
#if defined(DEBUGDUMP)
static void dumpCode(SecCodeRef code)
{
CFRef<CFURLRef> path;
if (OSStatus rc = SecCodeCopyPath(code, kSecCSDefaultFlags, &path.aref()))
Debug::dump("unknown(rc=%d)", int32_t(rc));
else
Debug::dump("%s", cfString(path).c_str());
}
void ClientIdentification::dump()
{
Debug::dump(" client=");
dumpCode(mClientProcess);
for (GuestMap::const_iterator it = mGuests.begin(); it != mGuests.end(); ++it) {
Debug::dump(" guest(0x%x)=", it->first);
dumpCode(it->second.code);
if (it->second.gotHash)
Debug::dump(" [got hash]");
}
}
#endif //DEBUGDUMP