AuthorizationEngine.cpp [plain text]
#include "AuthorizationEngine.h"
#include <security_cdsa_utilities/AuthorizationWalkers.h>
#include <Security/AuthorizationPriv.h>
#include <Security/AuthorizationDB.h>
#include "authority.h"
#include <Security/AuthorizationTags.h>
#include <Security/AuthorizationTagsPriv.h>
#include <security_utilities/logging.h>
#include <security_utilities/cfutilities.h>
#include <security_utilities/debugging.h>
#include "server.h"
#include <CoreFoundation/CFData.h>
#include <CoreFoundation/CFNumber.h>
#include <CoreFoundation/CFPropertyList.h>
#include <errno.h>
#include <fcntl.h>
#include <float.h>
#include <sandbox.h>
#include <bsm/audit_uevents.h> // AUE_ssauth*
#include "ccaudit_extensions.h"
namespace Authorization {
using namespace CommonCriteria::Securityd;
Error::Error(int err) : error(err)
{
}
const char *Error::what() const throw()
{ return "Authorization error"; }
int Error::unixError() const throw()
{ return error; }
OSStatus Error::osStatus() const throw()
{ return error; }
void Error::throwMe(int err) { throw Error(err); }
Engine::Engine(const char *configFile) : mAuthdb(configFile)
{
}
Engine::~Engine()
{
}
OSStatus
Engine::authorize(const AuthItemSet &inRights, const AuthItemSet &environment,
AuthorizationFlags flags, const CredentialSet *inCredentials, CredentialSet *outCredentials,
AuthItemSet &outRights, AuthorizationToken &auth)
{
CredentialSet credentials;
OSStatus status = errAuthorizationSuccess;
SecurityAgent::Reason reason = SecurityAgent::noReason;
CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
mAuthdb.sync(now);
if (flags & kAuthorizationFlagExtendRights)
{
string username, password;
bool shared = false;
for (AuthItemSet::iterator item = environment.begin(); item != environment.end(); item ++)
{
if (!strcmp((*item)->name(), kAuthorizationEnvironmentUsername))
username = (*item)->stringValue();
else if (!strcmp((*item)->name(), kAuthorizationEnvironmentPassword))
password = (*item)->stringValue();
else if (!strcmp((*item)->name(), kAuthorizationEnvironmentShared))
shared = true;
}
if (username.length())
{
Credential newCredential(username, password, shared);
if (newCredential->isValid())
credentials.insert(newCredential);
}
}
AuthItemSet environmentToClient = environment;
RightAuthenticationLogger logger(auth.creatorAuditToken(), AUE_ssauthorize);
std::vector<AuthItemRef> tempRights;
for (AuthItemSet::const_iterator it = inRights.begin(); it != inRights.end(); ++it) {
if (inRights.firstItemName != NULL && strcmp((*it)->name(), inRights.firstItemName) == 0)
tempRights.insert(tempRights.begin(), *it);
else
tempRights.push_back(*it);
}
bool authExtractPassword = false;
std::vector<AuthItemRef>::const_iterator end = tempRights.end();
for (std::vector<AuthItemRef>::const_iterator it = tempRights.begin(); it != end; ++it)
{
const Rule &toplevelRule = mAuthdb.getRule(*it);
if (false == authExtractPassword)
authExtractPassword = toplevelRule->extractPassword();
string processName = "unknown";
string authCreatorName = "unknown";
{
StLock<Mutex> _(Server::process());
if (SecCodeRef code = Server::process().currentGuest()) {
CFRef<CFURLRef> path;
if (!SecCodeCopyPath(code, kSecCSDefaultFlags, &path.aref()))
processName = cfString(path);
}
}
authCreatorName = auth.creatorPath();
if (sandbox_check(Server::process().pid(), "authorization-right-obtain", SANDBOX_FILTER_RIGHT_NAME, (*it)->name())) {
Syslog::error("Sandbox denied authorizing right '%s' by client '%s' [%d]", (*it)->name(), processName.c_str(), Server::process().pid());
return errAuthorizationDenied;
}
if (auth.creatorSandboxed() && sandbox_check(auth.creatorPid(), "authorization-right-obtain", SANDBOX_FILTER_RIGHT_NAME, (*it)->name())) {
Syslog::error("Sandbox denied authorizing right '%s' for authorization created by '%s' [%d]", (*it)->name(), authCreatorName.c_str(), auth.creatorPid());
return errAuthorizationDenied;
}
OSStatus result = toplevelRule->evaluate(*it, toplevelRule, environmentToClient, flags, now, inCredentials, credentials, auth, reason, authExtractPassword);
secdebug("autheval", "evaluate rule %s for right %s returned %d.", toplevelRule->name().c_str(), (*it)->name(), int(result));
SECURITYD_AUTH_EVALRIGHT(&auth, (char *)(*it)->name(), result);
logger.setRight((*it)->name());
logger.logAuthorizationResult(processName.c_str(), authCreatorName.c_str(), result);
if (result == errAuthorizationSuccess)
{
outRights.insert(*it);
Syslog::info("Succeeded authorizing right '%s' by client '%s' [%d] for authorization created by '%s' [%d] (%X,%d)", (*it)->name(), processName.c_str(), Server::process().pid(), authCreatorName.c_str(), auth.creatorPid(), uint32_t(flags), auth.operatesAsLeastPrivileged());
}
else if (result == errAuthorizationDenied || result == errAuthorizationInteractionNotAllowed)
{
if (result == errAuthorizationDenied)
{
secdebug("autheval", "Failed to authorize right '%s' by client '%s' [%d] for authorization created by '%s' [%d] (%X,%d)", (*it)->name(), processName.c_str(), Server::process().pid(), authCreatorName.c_str(), auth.creatorPid(), uint32_t(flags), auth.operatesAsLeastPrivileged());
}
if (!(flags & kAuthorizationFlagPartialRights))
{
status = result;
break;
}
}
else if (result == errAuthorizationCanceled)
{
status = result;
break;
}
else
{
Syslog::error("Engine::authorize: Rule::evaluate returned %ld returning errAuthorizationInternal", result);
status = errAuthorizationInternal;
break;
}
}
if (auth.operatesAsLeastPrivileged()) {
CredentialSet::const_iterator current, it = outCredentials->begin();
while(it != outCredentials->end()) {
current = it++;
if (!(*current)->isRight()) {
outCredentials->erase(current);
}
}
}
if (outCredentials)
outCredentials->swap(credentials);
return status;
}
OSStatus
Engine::verifyModification(string inRightName, bool remove,
const CredentialSet *inCredentials, CredentialSet *outCredentials, AuthorizationToken &auth)
{
string rightnameToCheck;
if (inRightName.length() == 0)
return errAuthorizationDenied;
if ( *(inRightName.rbegin()) == '.')
return errAuthorizationDenied;
if (inRightName.find(kConfigRight, 0) != string::npos)
{
rightnameToCheck = string(kConfigRight) + inRightName;
}
else
{
bool existingRule = mAuthdb.existRule(inRightName);
if (!remove)
{
if (existingRule)
rightnameToCheck = string(kAuthorizationConfigRightModify) + inRightName;
else
rightnameToCheck = string(kAuthorizationConfigRightAdd) + inRightName;
}
else
{
if (existingRule)
rightnameToCheck = string(kAuthorizationConfigRightRemove) + inRightName;
else
{
secdebug("engine", "rule %s doesn't exist.", inRightName.c_str());
return errAuthorizationSuccess; }
}
}
AuthItemSet rights, environment, outRights;
rights.insert(AuthItemRef(rightnameToCheck.c_str()));
secdebug("engine", "authorizing %s for db modification.", rightnameToCheck.c_str());
return authorize(rights, environment, kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights, inCredentials, outCredentials, outRights, auth);
}
OSStatus
Engine::getRule(string &inRightName, CFDictionaryRef *outRuleDefinition)
{
CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
mAuthdb.sync(now);
CFDictionaryRef definition = mAuthdb.getRuleDefinition(inRightName);
if (definition)
{
if (outRuleDefinition)
*outRuleDefinition = definition;
else
CFRelease(definition);
return errAuthorizationSuccess;
}
return errAuthorizationDenied;
}
OSStatus
Engine::setRule(const char *inRightName, CFDictionaryRef inRuleDefinition, const CredentialSet *inCredentials, CredentialSet *outCredentials, AuthorizationToken &auth)
{
if (!mAuthdb.validateRule(inRightName, inRuleDefinition))
return errAuthorizationDenied;
OSStatus result = verifyModification(inRightName, false , inCredentials, outCredentials, auth);
if (result != errAuthorizationSuccess)
return result;
mAuthdb.setRule(inRightName, inRuleDefinition);
return errAuthorizationSuccess;
}
OSStatus
Engine::removeRule(const char *inRightName, const CredentialSet *inCredentials, CredentialSet *outCredentials, AuthorizationToken &auth)
{
CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
mAuthdb.sync(now);
OSStatus result = verifyModification(inRightName, true , inCredentials, outCredentials, auth);
if (result != errAuthorizationSuccess)
return result;
mAuthdb.removeRule(inRightName);
return errAuthorizationSuccess;
}
}