+++ /dev/null
-/*
- * Copyright (c) 2000-2004,2006-2012 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#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;
-
-
-//
-// Errors to be thrown
-//
-Error::Error(int err) : error(err)
-{
-}
-
-const char *Error::what() const throw()
-{ return "Authorization error"; }
-
-int Error::unixError() const throw()
-{ return error; } // @@@ eventually...
-
-OSStatus Error::osStatus() const throw()
-{ return error; }
-
-void Error::throwMe(int err) { throw Error(err); }
-
-//
-// Engine class
-//
-Engine::Engine(const char *configFile) : mAuthdb(configFile)
-{
-}
-
-Engine::~Engine()
-{
-}
-
-
-/*!
- @function AuthorizationEngine::authorize
-
- @@@.
-
- @param inRights (input) List of rights being requested for authorization.
- @param environment (optional/input) Environment containing information to be used during evaluation.
- @param flags (input) Optional flags @@@ see AuthorizationCreate for a description.
- @param inCredentials (input) Credentials already held by the caller.
- @param outCredentials (output/optional) Credentials obtained, used or refreshed during this call to authorize the requested rights.
- @param outRights (output/optional) Subset of inRights which were actually authorized.
-
- @results Returns errAuthorizationSuccess if all rights requested are authorized, or if the kAuthorizationFlagPartialRights flag was specified. Might return other status values like errAuthorizationDenied, errAuthorizationCanceled or errAuthorizationInteractionNotAllowed
-*/
-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;
-
- // Get current time of day.
- CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
-
- // Update rules from database if needed
- mAuthdb.sync(now);
-
- // Check if a credential was passed into the environment and we were asked to extend the rights
- 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())
- {
- // Let's create a credential from the passed in username and password.
- Credential newCredential(username, password, shared);
- // If it's valid insert it into the credentials list. Normally this is
- // only done if it actually authorizes a requested right, but for this
- // special case (environment) we do it even when no rights are being requested.
- if (newCredential->isValid())
- credentials.insert(newCredential);
- }
- }
-
- // generate hints for every authorization
- AuthItemSet environmentToClient = environment;
-
- RightAuthenticationLogger logger(auth.creatorAuditToken(), AUE_ssauthorize);
-
- // create a vector with the first right first
- 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)
- {
- // Get the rule for each right we are trying to obtain.
- 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());
- }
-
- // add creator pid to authorization token
- 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;
- }
- }
-
- // purge all uid credentials from the outCredentials for least privileged mode
- 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)
-{
- // Validate right
-
- // meta rights are constructed as follows:
- // we don't allow setting of wildcard rights, so you can only be more specific
- // note that you should never restrict things with a wildcard right without disallowing
- // changes to the entire domain. ie.
- // system.privilege. -> never
- // config.add.system.privilege. -> never
- // config.modify.system.privilege. -> never
- // config.delete.system.privilege. -> never
- // For now we don't allow any configuration of configuration rules
- // config.config. -> never
-
- string rightnameToCheck;
-
- // @@@ verify right name is is not NULL or zero length
- if (inRightName.length() == 0)
- return errAuthorizationDenied;
-
- // @@@ make sure it isn't a wildcard right by checking trailing "."
- if ( *(inRightName.rbegin()) == '.')
- return errAuthorizationDenied;
-
- // @@@ make sure it isn't a configure right by checking it doesn't start with config.
- if (inRightName.find(kConfigRight, 0) != string::npos)
- {
- // special handling of meta right change:
- // config.add. config.modify. config.remove. config.{}.
- // check for config.<right> (which always starts with config.config.)
- rightnameToCheck = string(kConfigRight) + inRightName;
- }
- else
- {
- // regular check of rights
- 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; // doesn't exist, done
- }
- }
- }
-
-
- 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)
-{
- // Get current time of day.
- CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
-
- // Update rules from database if needed
- 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)
-{
- // Validate rule by constructing it from the passed dictionary
- if (!mAuthdb.validateRule(inRightName, inRuleDefinition))
- return errAuthorizationDenied; // @@@ separate error for this?
-
- OSStatus result = verifyModification(inRightName, false /*setting, not removing*/, inCredentials, outCredentials, auth);
- if (result != errAuthorizationSuccess)
- return result;
-
- // set the rule for the right and save the database
- mAuthdb.setRule(inRightName, inRuleDefinition);
-
- return errAuthorizationSuccess;
-}
-
-OSStatus
-Engine::removeRule(const char *inRightName, const CredentialSet *inCredentials, CredentialSet *outCredentials, AuthorizationToken &auth)
-{
- // Get current time of day.
- CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
-
- // Update rules from database if needed
- mAuthdb.sync(now);
-
- OSStatus result = verifyModification(inRightName, true /*removing*/, inCredentials, outCredentials, auth);
- if (result != errAuthorizationSuccess)
- return result;
-
- // set the rule for the right and save the database
- mAuthdb.removeRule(inRightName);
-
- return errAuthorizationSuccess;
-}
-
-} // end namespace Authorization