#include "authority.h"
#include "server.h"
#include "connection.h"
#include "session.h"
#include "process.h"
#include <security_cdsa_utilities/AuthorizationWalkers.h>
#include <security_utilities/ccaudit.h> // AuditToken
#include <sandbox.h>
using Authorization::AuthItemSet;
using Authorization::AuthItemRef;
using Authorization::AuthValue;
using Authorization::AuthValueOverlay;
AuthorizationToken::AuthMap &AuthorizationToken::authMap = *new AuthMap; Mutex AuthorizationToken::authMapLock;
AuthorizationToken::AuthorizationToken(Session &ssn, const CredentialSet &base,
const audit_token_t &auditToken, bool operateAsLeastPrivileged)
: mBaseCreds(base), mTransferCount(INT_MAX),
mCreatorPid(Server::process().pid()),
mCreatorAuditToken(auditToken),
mOperatesAsLeastPrivileged(operateAsLeastPrivileged)
{
mCreatorUid = mCreatorAuditToken.euid();
mCreatorGid = mCreatorAuditToken.egid();
if (sandbox_check(mCreatorPid, "authorization-right-obtain", SANDBOX_CHECK_NO_REPORT) != 0)
mCreatorSandboxed = true;
else
mCreatorSandboxed = false;
{
Process &thisProcess = Server::process();
StLock<Mutex> _(thisProcess);
if (SecCodeRef code = thisProcess.currentGuest())
MacOSError::check(SecCodeCopyStaticCode(code, kSecCSDefaultFlags, &mCreatorCode.aref()));
}
referent(ssn);
Server::active().random(mHandle);
StLock<Mutex> _(authMapLock);
authMap[mHandle] = this;
secdebug("SSauth", "Authorization %p created using %d credentials; owner=%p",
this, int(mBaseCreds.size()), mCreatorCode.get());
}
AuthorizationToken::~AuthorizationToken()
{
assert(mUsingProcesses.empty());
secdebug("SSauth", "Authorization %p destroyed", this);
}
Session &AuthorizationToken::session() const
{
return referent<Session>();
}
std::string AuthorizationToken::creatorPath() const
{
if (mCreatorCode) {
StLock<Mutex> _(mLock);
CFRef<CFURLRef> path;
if (SecCodeCopyPath(mCreatorCode, kSecCSDefaultFlags, &path.aref()) == noErr)
return cfString(path);
}
return "unknown";
}
AuthorizationToken &AuthorizationToken::find(const AuthorizationBlob &blob)
{
StLock<Mutex> _(authMapLock);
AuthMap::iterator it = authMap.find(blob);
if (it == authMap.end())
Authorization::Error::throwMe(errAuthorizationInvalidRef);
return *it->second;
}
AuthorizationToken::Deleter::Deleter(const AuthorizationBlob &blob)
: lock(authMapLock)
{
AuthMap::iterator it = authMap.find(blob);
if (it == authMap.end())
Authorization::Error::throwMe(errAuthorizationInvalidRef);
mAuth = it->second;
}
void AuthorizationToken::Deleter::remove()
{
if (mAuth) {
authMap.erase(mAuth->handle());
mAuth = NULL;
}
}
CredentialSet AuthorizationToken::effectiveCreds() const
{
secdebug("SSauth", "Authorization %p grabbing session %p creds %p",
this, &session(), &session().authCredentials());
CredentialSet result = session().authCredentials();
for (CredentialSet::const_iterator it = mBaseCreds.begin(); it != mBaseCreds.end(); it++)
if (!(*it)->isShared())
result.insert(*it);
return result;
}
void AuthorizationToken::mergeCredentials(const CredentialSet &add)
{
secdebug("SSauth", "Authorization %p merge creds %p", this, &add);
for (CredentialSet::const_iterator it = add.begin(); it != add.end(); it++) {
mBaseCreds.erase(*it);
mBaseCreds.insert(*it);
}
secdebug("SSauth", "Authorization %p merged %d new credentials for %d total",
this, int(add.size()), int(mBaseCreds.size()));
}
void AuthorizationToken::addProcess(Process &proc)
{
StLock<Mutex> _(mLock);
mUsingProcesses.insert(&proc);
secdebug("SSauth", "Authorization %p added process %p(%d)", this, &proc, proc.pid());
}
bool AuthorizationToken::endProcess(Process &proc)
{
StLock<Mutex> _(mLock);
assert(mUsingProcesses.find(&proc) != mUsingProcesses.end());
mUsingProcesses.erase(&proc);
secdebug("SSauth", "Authorization %p removed process %p(%d)%s",
this, &proc, proc.pid(), mUsingProcesses.empty() ? " FINAL" : "");
return mUsingProcesses.empty();
}
bool AuthorizationToken::mayExternalize(Process &) const
{
return mTransferCount > 0;
}
bool AuthorizationToken::mayInternalize(Process &, bool countIt)
{
StLock<Mutex> _(mLock);
if (mTransferCount > 0) {
if (countIt) {
mTransferCount--;
secdebug("SSauth", "Authorization %p decrement intcount to %d", this, mTransferCount);
}
return true;
}
return false;
}
AuthItemSet
AuthorizationToken::infoSet(AuthorizationString tag)
{
StLock<Mutex> _(mLock);
AuthItemSet tempSet;
if (tag)
{
AuthItemSet::iterator found = find_if(mInfoSet.begin(), mInfoSet.end(),
Authorization::FindAuthItemByRightName(tag));
if (found != mInfoSet.end())
tempSet.insert(AuthItemRef(*found));
}
else
tempSet = mInfoSet;
secdebug("SSauth", "Authorization %p returning copy of context %s%s.", this, tag ? "for tag " : "", tag ? "" : tag);
return tempSet;
}
void
AuthorizationToken::setInfoSet(AuthItemSet &newInfoSet, bool savePassword)
{
StLock<Mutex> _(mLock); secdebug("SSauth", "Authorization %p setting new context", this);
AuthItemSet::const_iterator end = mInfoSet.end();
for (AuthItemSet::const_iterator it = mInfoSet.begin(); it != end; ++it) {
const AuthItemRef &item = *it;
if (0 == strcmp(item->name(), "password")) {
mSavedPassword.clear();
mSavedPassword.insert(item);
}
}
if (true == savePassword)
newInfoSet.insert(mSavedPassword.begin(), mSavedPassword.end());
mInfoSet = newInfoSet;
}
void
AuthorizationToken::setCredentialInfo(const Credential &inCred, bool savePassword)
{
AuthItemSet dstInfoSet;
uid_t uid = inCred->uid();
AuthItemRef uidHint("uid", AuthValueOverlay(sizeof(uid), &uid));
dstInfoSet.insert(uidHint);
AuthItemRef userHint("username", AuthValueOverlay(inCred->name()), 0);
dstInfoSet.insert(userHint);
setInfoSet(dstInfoSet, savePassword);
}
void
AuthorizationToken::clearInfoSet()
{
AuthItemSet dstInfoSet;
secdebug("SSauth", "Authorization %p clearing context", this);
setInfoSet(dstInfoSet, false);
}
void
AuthorizationToken::scrubInfoSet(bool savePassword)
{
AuthItemSet srcInfoSet = infoSet(), dstInfoSet;
AuthItemSet::const_iterator end = srcInfoSet.end();
for (AuthItemSet::const_iterator it = srcInfoSet.begin(); it != end; ++it)
{
const AuthItemRef &item = *it;
if (item->flags() == kAuthorizationContextFlagExtractable)
dstInfoSet.insert(item);
}
secdebug("SSauth", "Authorization %p scrubbing context", this);
setInfoSet(dstInfoSet, savePassword);
}