X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/Security/libsecurity_keychain/lib/ACL.cpp?ds=inline diff --git a/Security/libsecurity_keychain/lib/ACL.cpp b/Security/libsecurity_keychain/lib/ACL.cpp deleted file mode 100644 index 9b655a69..00000000 --- a/Security/libsecurity_keychain/lib/ACL.cpp +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Copyright (c) 2002-2004,2011-2012,2014 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@ - */ - -// -// ACL.cpp -// -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -using namespace KeychainCore; -using namespace DataWalkers; - - -// -// The default form of a prompt selector -// -const CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR ACL::defaultSelector = { - CSSM_ACL_KEYCHAIN_PROMPT_CURRENT_VERSION, 0 -}; - - -// -// ACL static constants -// -const CSSM_ACL_HANDLE ACL::ownerHandle; - - -// -// Create an ACL object from the result of a CSSM ACL query -// -ACL::ACL(Access &acc, const AclEntryInfo &info, Allocator &alloc) - : allocator(alloc), access(acc), mState(unchanged), mSubjectForm(NULL), mMutex(Mutex::recursive) -{ - // parse the subject - parse(info.proto().subject()); - - // fill in AclEntryInfo layer information - const AclEntryPrototype &proto = info.proto(); - mAuthorizations = proto.authorization(); - mDelegate = proto.delegate(); - mEntryTag = proto.s_tag(); - - // take CSSM entry handle from info layer - mCssmHandle = info.handle(); -} - -ACL::ACL(Access &acc, const AclOwnerPrototype &owner, Allocator &alloc) - : allocator(alloc), access(acc), mState(unchanged), mSubjectForm(NULL), mMutex(Mutex::recursive) -{ - // parse subject - parse(owner.subject()); - - // for an owner "entry", the next-layer information is fixed (and fake) - mAuthorizations.insert(CSSM_ACL_AUTHORIZATION_CHANGE_ACL); - mDelegate = owner.delegate(); - mEntryTag[0] = '\0'; - - // use fixed (fake) entry handle - mCssmHandle = ownerHandle; -} - - -// -// Create a new ACL that authorizes anyone to do anything. -// This constructor produces a "pure" ANY ACL, without descriptor or selector. -// To generate a "standard" form of ANY, use the appListForm constructor below, -// then change its form to allowAnyForm. -// -ACL::ACL(Access &acc, Allocator &alloc) - : allocator(alloc), access(acc), mSubjectForm(NULL), mMutex(Mutex::recursive) -{ - mState = inserted; // new - mForm = allowAllForm; // everybody - mAuthorizations.insert(CSSM_ACL_AUTHORIZATION_ANY); // anything - mDelegate = false; - - //mPromptDescription stays empty - mPromptSelector = defaultSelector; - - // randomize the CSSM handle - UniformRandomBlobs().random(mCssmHandle); -} - - -// -// Create a new ACL in standard form. -// As created, it authorizes all activities. -// -ACL::ACL(Access &acc, string description, const CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR &promptSelector, - Allocator &alloc) - : allocator(alloc), access(acc), mSubjectForm(NULL), mMutex(Mutex::recursive) -{ - mState = inserted; // new - mForm = appListForm; - mAuthorizations.insert(CSSM_ACL_AUTHORIZATION_ANY); // anything - mDelegate = false; - - mPromptDescription = description; - mPromptSelector = promptSelector; - - // randomize the CSSM handle - UniformRandomBlobs().random(mCssmHandle); -} - - -// -// Destroy an ACL -// -ACL::~ACL() -{ - // release subject form (if any) - chunkFree(mSubjectForm, allocator); -} - - -// -// Does this ACL authorize a particular right? -// -bool ACL::authorizes(AclAuthorization right) -{ - StLock_(mMutex); - return mAuthorizations.find(right) != mAuthorizations.end() - || mAuthorizations.find(CSSM_ACL_AUTHORIZATION_ANY) != mAuthorizations.end() - || mAuthorizations.empty(); -} - - -// -// Add an application to the trusted-app list of this ACL. -// Will fail unless this is a standard "simple" form ACL. -// -void ACL::addApplication(TrustedApplication *app) -{ - StLock_(mMutex); - switch (mForm) { - case appListForm: // simple... - mAppList.push_back(app); - modify(); - break; - case allowAllForm: // hmm... - if (!mPromptDescription.empty()) { - // verbose "any" form (has description, "any" override) - mAppList.push_back(app); - modify(); - break; - } - // pure "any" form without description. Cannot convert to appListForm - default: - MacOSError::throwMe(errSecACLNotSimple); - } -} - - -// -// Mark an ACL as modified. -// -void ACL::modify() -{ - StLock_(mMutex); - if (mState == unchanged) { - secdebug("SecAccess", "ACL %p marked modified", this); - mState = modified; - } -} - - -// -// Mark an ACL as "removed" -// Removed ACLs have no valid contents (they are invalid on their face). -// When "updated" to the originating item, they will cause the corresponding -// ACL entry to be deleted. Otherwise, they are irrelevant. -// Note: Removing an ACL does not actually remove it from its Access's map. -// -void ACL::remove() -{ - StLock_(mMutex); - mAppList.clear(); - mForm = invalidForm; - mState = deleted; -} - - -// -// Produce CSSM-layer form (ACL prototype) copies of our content. -// Note that the result is chunk-allocated, and becomes owned by the caller. -// -void ACL::copyAclEntry(AclEntryPrototype &proto, Allocator &alloc) -{ - StLock_(mMutex); - proto.clearPod(); // preset - - // carefully copy the subject - makeSubject(); - assert(mSubjectForm); - proto = AclEntryPrototype(*mSubjectForm, mDelegate); // shares subject - ChunkCopyWalker w(alloc); - walk(w, proto.subject()); // copy subject in-place - - // the rest of a prototype - proto.tag(mEntryTag); - AuthorizationGroup tags(mAuthorizations, allocator); - proto.authorization() = tags; -} - -void ACL::copyAclOwner(AclOwnerPrototype &proto, Allocator &alloc) -{ - StLock_(mMutex); - proto.clearPod(); - - makeSubject(); - assert(mSubjectForm); - proto = AclOwnerPrototype(*mSubjectForm, mDelegate); // shares subject - ChunkCopyWalker w(alloc); - walk(w, proto.subject()); // copy subject in-place -} - - -// -// (Re)place this ACL's setting into the AclBearer specified. -// If update, assume this is an update operation and the ACL was -// originally derived from this object; specifically, assume the -// CSSM handle is valid. If not update, assume this is a different -// object that has no related ACL entry (yet). -// -void ACL::setAccess(AclBearer &target, bool update, - const AccessCredentials *cred) -{ - StLock_(mMutex); - // determine what action we need to perform - State action = state(); - if (!update) - action = (action == deleted) ? unchanged : inserted; - - // the owner acl (pseudo) "entry" is a special case - if (isOwner()) { - switch (action) { - case unchanged: - secdebug("SecAccess", "ACL %p owner unchanged", this); - return; - case inserted: // means modify the initial owner - case modified: - { - secdebug("SecAccess", "ACL %p owner modified", this); - makeSubject(); - assert(mSubjectForm); - AclOwnerPrototype proto(*mSubjectForm, mDelegate); - target.changeOwner(proto, cred); - return; - } - default: - assert(false); - return; - } - } - - // simple cases - switch (action) { - case unchanged: // ignore - secdebug("SecAccess", "ACL %p handle 0x%lx unchanged", this, entryHandle()); - return; - case deleted: // delete - secdebug("SecAccess", "ACL %p handle 0x%lx deleted", this, entryHandle()); - target.deleteAcl(entryHandle(), cred); - return; - default: - break; - } - - // build the byzantine data structures that CSSM loves so much - makeSubject(); - assert(mSubjectForm); - AclEntryPrototype proto(*mSubjectForm, mDelegate); - proto.tag(mEntryTag); - AutoAuthorizationGroup tags(mAuthorizations, allocator); - proto.authorization() = tags; - AclEntryInput input(proto); - switch (action) { - case inserted: // insert - secdebug("SecAccess", "ACL %p inserted", this); - target.addAcl(input, cred); - break; - case modified: // update - secdebug("SecAccess", "ACL %p handle 0x%lx modified", this, entryHandle()); - target.changeAcl(entryHandle(), input, cred); - break; - default: - assert(false); - } -} - - -// -// Parse an AclEntryPrototype (presumably from a CSSM "Get" ACL operation -// into internal form. -// -void ACL::parse(const TypedList &subject) -{ - StLock_(mMutex); - try { - switch (subject.type()) { - case CSSM_ACL_SUBJECT_TYPE_ANY: - // subsume an "any" as a standard form - mForm = allowAllForm; - return; - case CSSM_ACL_SUBJECT_TYPE_KEYCHAIN_PROMPT: - // pure keychain prompt - interpret as applist form with no apps - parsePrompt(subject); - mForm = appListForm; - return; - case CSSM_ACL_SUBJECT_TYPE_THRESHOLD: - { - // app-list format: THRESHOLD(1, n): sign(1), ..., sign(n), PROMPT - if (subject[1] != 1) - throw ParseError(); - uint32 count = subject[2]; - - // parse final (PROMPT) element - TypedList &end = subject[count + 2]; // last choice - if (end.type() != CSSM_ACL_SUBJECT_TYPE_KEYCHAIN_PROMPT) - throw ParseError(); // not PROMPT at end - parsePrompt(end); - - // check for leading ANY - TypedList &first = subject[3]; - if (first.type() == CSSM_ACL_SUBJECT_TYPE_ANY) { - mForm = allowAllForm; - return; - } - - // parse other (code signing) elements - for (uint32 n = 0; n < count - 1; n++) - mAppList.push_back(new TrustedApplication(TypedList(subject[n + 3].list()))); - } - mForm = appListForm; - return; - default: - mForm = customForm; - mSubjectForm = chunkCopy(&subject); - return; - } - } catch (const ParseError &) { - secdebug("SecAccess", "acl compile failed; marking custom"); - mForm = customForm; - mSubjectForm = chunkCopy(&subject); - mAppList.clear(); - } -} - -void ACL::parsePrompt(const TypedList &subject) -{ - StLock_(mMutex); - assert(subject.length() == 3); - mPromptSelector = - *subject[1].data().interpretedAs(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); - mPromptDescription = subject[2].toString(); -} - - -// -// Take this ACL and produce its meaning as a CSSM ACL subject in mSubjectForm -// -void ACL::makeSubject() -{ - StLock_(mMutex); - switch (form()) { - case allowAllForm: - chunkFree(mSubjectForm, allocator); // release previous - if (mPromptDescription.empty()) { - // no description -> pure ANY - mSubjectForm = new(allocator) TypedList(allocator, CSSM_ACL_SUBJECT_TYPE_ANY); - } else { - // have description -> threshold(1 of 2) of { ANY, PROMPT } - mSubjectForm = new(allocator) TypedList(allocator, CSSM_ACL_SUBJECT_TYPE_THRESHOLD, - new(allocator) ListElement(1), - new(allocator) ListElement(2)); - *mSubjectForm += new(allocator) ListElement(TypedList(allocator, CSSM_ACL_SUBJECT_TYPE_ANY)); - TypedList prompt(allocator, CSSM_ACL_SUBJECT_TYPE_KEYCHAIN_PROMPT, - new(allocator) ListElement(allocator, CssmData::wrap(mPromptSelector)), - new(allocator) ListElement(allocator, mPromptDescription)); - *mSubjectForm += new(allocator) ListElement(prompt); - } - return; - case appListForm: { - // threshold(1 of n+1) of { app1, ..., appn, PROMPT } - chunkFree(mSubjectForm, allocator); // release previous - uint32 appCount = (uint32)mAppList.size(); - mSubjectForm = new(allocator) TypedList(allocator, CSSM_ACL_SUBJECT_TYPE_THRESHOLD, - new(allocator) ListElement(1), - new(allocator) ListElement(appCount + 1)); - for (uint32 n = 0; n < appCount; n++) - *mSubjectForm += - new(allocator) ListElement(mAppList[n]->makeSubject(allocator)); - TypedList prompt(allocator, CSSM_ACL_SUBJECT_TYPE_KEYCHAIN_PROMPT, - new(allocator) ListElement(allocator, CssmData::wrap(mPromptSelector)), - new(allocator) ListElement(allocator, mPromptDescription)); - *mSubjectForm += new(allocator) ListElement(prompt); - } - return; - case customForm: - assert(mSubjectForm); // already set; keep it - return; - default: - assert(false); // unexpected - } -}