AuthorizationEngine.cpp [plain text]
#include "AuthorizationEngine.h"
#include <Security/AuthorizationWalkers.h>
#include "AuthorizationPriv.h"
#include "AuthorizationDB.h"
#include "authority.h"
#include <Security/AuthorizationTags.h>
#include <Security/logging.h>
#include <Security/cfutilities.h>
#include <Security/debugging.h>
#include "session.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>
namespace Authorization {
Error::Error(int err) : error(err)
{
}
const char *Error::what() const throw()
{ return "Authorization error"; }
CSSM_RETURN Error::cssmError() 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;
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;
AuthItemSet::const_iterator end = inRights.end();
for (AuthItemSet::const_iterator it = inRights.begin(); it != end; ++it)
{
const Rule &toplevelRule = mAuthdb.getRule(*it);
OSStatus result = toplevelRule->evaluate(*it, toplevelRule, environmentToClient, flags, now, inCredentials, credentials, auth);
secdebug("autheval", "evaluate rule %s for right %s returned %ld.", toplevelRule->name().c_str(), (*it)->name(), result);
{
CodeSigning::OSXCode *processCode = Server::connection().process.clientCode();
string processName = processCode ? processCode->canonicalPath() : "unknown";
CodeSigning::OSXCode *authCreatorCode = auth.creatorCode();
string authCreatorName = authCreatorCode ? authCreatorCode->canonicalPath() : "unknown";
if (result == errAuthorizationSuccess)
Syslog::info("Succeeded authorizing right %s by process %s for authorization created by %s.", (*it)->name(), processName.c_str(), authCreatorName.c_str());
else if (result == errAuthorizationDenied)
Syslog::notice("Failed to authorize right %s by process %s for authorization created by %s.", (*it)->name(), processName.c_str(), authCreatorName.c_str());
}
if (result == errAuthorizationSuccess)
outRights.insert(*it);
else if (result == errAuthorizationDenied || result == errAuthorizationInteractionNotAllowed)
{
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 (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)
{
CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
mAuthdb.sync(now);
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;
}
}