X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/securityd/src/authority.cpp diff --git a/securityd/src/authority.cpp b/securityd/src/authority.cpp new file mode 100644 index 00000000..5817e517 --- /dev/null +++ b/securityd/src/authority.cpp @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2000-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@ + */ + + +// +// authority - authorization manager +// +#include "authority.h" +#include "server.h" +#include "connection.h" +#include "session.h" +#include "process.h" + +#include + +#include // AuditToken + +#include + +using Authorization::AuthItemSet; +using Authorization::AuthItemRef; +using Authorization::AuthValue; +using Authorization::AuthValueOverlay; + +// +// The global dictionary of extant AuthorizationTokens +// +//AuthorizationToken::AuthMap AuthorizationToken::authMap; // set of extant authorizations +//@@@ Workaround ONLY! Don't destruct this map on termination +AuthorizationToken::AuthMap &AuthorizationToken::authMap = *new AuthMap; // set of extant authorizations +Mutex AuthorizationToken::authMapLock; // lock for mAuthorizations (only) + + + +// +// Create an authorization token. +// +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 _(thisProcess); + if (SecCodeRef code = thisProcess.currentGuest()) + MacOSError::check(SecCodeCopyStaticCode(code, kSecCSDefaultFlags, &mCreatorCode.aref())); + } + + // link to session + referent(ssn); + + // generate our (random) handle + Server::active().random(mHandle); + + // register handle in the global map + StLock _(authMapLock); + authMap[mHandle] = this; + + // all ready + secdebug("SSauth", "Authorization %p created using %d credentials; owner=%p", + this, int(mBaseCreds.size()), mCreatorCode.get()); +} + +AuthorizationToken::~AuthorizationToken() +{ + // we better be clean + assert(mUsingProcesses.empty()); + + secdebug("SSauth", "Authorization %p destroyed", this); +} + + +Session &AuthorizationToken::session() const +{ + return referent(); +} + + +std::string AuthorizationToken::creatorPath() const +{ + if (mCreatorCode) { + StLock _(mLock); + CFRef path; + if (SecCodeCopyPath(mCreatorCode, kSecCSDefaultFlags, &path.aref()) == noErr) + return cfString(path); + } + return "unknown"; +} + + +// +// Locate an authorization given its blob. +// +AuthorizationToken &AuthorizationToken::find(const AuthorizationBlob &blob) +{ + StLock _(authMapLock); + AuthMap::iterator it = authMap.find(blob); + if (it == authMap.end()) + Authorization::Error::throwMe(errAuthorizationInvalidRef); + return *it->second; +} + + +// +// Handle atomic deletion of AuthorizationToken objects +// +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; + } +} + + +// +// Given a set of credentials, add it to our private credentials and return the result +// +// must hold Session::mCredsLock +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; +} + + +// +// Add more credential dependencies to an authorization +// +// must hold Session::mCredsLock +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())); +} + + +// +// Register a new process that uses this authorization token. +// This is an idempotent operation. +// +void AuthorizationToken::addProcess(Process &proc) +{ + StLock _(mLock); + mUsingProcesses.insert(&proc); + secdebug("SSauth", "Authorization %p added process %p(%d)", this, &proc, proc.pid()); +} + + +// +// Completely unregister client process. +// It does not matter how often it was registered with addProcess before. +// This returns true if no more processes use this token. Presumably you +// would then want to clean up, though that's up to you. +// +bool AuthorizationToken::endProcess(Process &proc) +{ + StLock _(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(); +} + + +// +// Check whether internalization/externalization is allowed +// +bool AuthorizationToken::mayExternalize(Process &) const +{ + return mTransferCount > 0; +} + +bool AuthorizationToken::mayInternalize(Process &, bool countIt) +{ + StLock _(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 _(mLock); // consider a separate lock + + 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 _(mLock); // consider a separate lock + 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; +} + +// This is destructive (non-merging) +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); +}