X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5c19dc3ae3bd8e40a9c028b0deddd50ff337692c..dd5fb164cf5b32c462296bc65e289e100f74b59a:/OSX/libsecurity_cdsa_utilities/lib/objectacl.cpp?ds=sidebyside diff --git a/OSX/libsecurity_cdsa_utilities/lib/objectacl.cpp b/OSX/libsecurity_cdsa_utilities/lib/objectacl.cpp index c89cb273..80989e2d 100644 --- a/OSX/libsecurity_cdsa_utilities/lib/objectacl.cpp +++ b/OSX/libsecurity_cdsa_utilities/lib/objectacl.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -42,6 +43,7 @@ using namespace DataWalkers; // These are the kinds of ACL subjects we can deal with. // ModuleNexus ObjectAcl::makers; +NormalMutex ObjectAcl::makersMutex; // @@ -90,21 +92,6 @@ ObjectAcl::Entry::~Entry() // Returns normally if 'auth' is granted to the bearer of 'cred'. // Otherwise, throws a suitable (ACL-related) CssmError exception. // -class BaseValidationContext : public AclValidationContext { -public: - BaseValidationContext(const AccessCredentials *cred, - AclAuthorization auth, AclValidationEnvironment *env) - : AclValidationContext(cred, auth, env) { } - - uint32 count() const { return cred() ? cred()->samples().length() : 0; } - uint32 size() const { return count(); } - const TypedList &sample(uint32 n) const - { assert(n < count()); return cred()->samples()[n]; } - - void matched(const TypedList *) const { } // ignore match info -}; - - bool ObjectAcl::validates(AclAuthorization auth, const AccessCredentials *cred, AclValidationEnvironment *env) { @@ -123,14 +110,17 @@ bool ObjectAcl::validates(AclValidationContext &ctx) #if defined(ACL_OMNIPOTENT_OWNER) // try owner (owner can do anything) - if (mOwner.validate(ctx)) + if (mOwner.validates(ctx)) return; #endif //ACL_OMNIPOTENT_OWNER // try applicable ACLs pair range; - if (getRange(ctx.s_credTag(), range) == 0) // no such tag + if (getRange(ctx.s_credTag(), range) == 0) { + // no such tag + secinfo("SecAccess", "no tag for cred tag: \"%s\"", ctx.s_credTag().c_str()); CssmError::throwMe(CSSM_ERRCODE_ACL_ENTRY_TAG_NOT_FOUND); + } // try each entry in turn for (EntryMap::const_iterator it = range.first; it != range.second; it++) { const AclEntry &slot = it->second; @@ -138,7 +128,7 @@ bool ObjectAcl::validates(AclValidationContext &ctx) if (slot.authorizes(ctx.authorization())) { ctx.init(this, slot.subject); ctx.entryTag(slot.tag); - if (slot.validate(ctx)) { + if (slot.validates(ctx)) { IFDUMPING("acleval", Debug::dump(">PASS>>\n")); return true; // passed } @@ -175,7 +165,7 @@ void ObjectAcl::validateOwner(AclValidationContext &ctx) instantiateAcl(); ctx.init(this, mOwner.subject); - if (mOwner.validate(ctx)) + if (mOwner.validates(ctx)) return; CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED); } @@ -258,15 +248,17 @@ void ObjectAcl::changedAcl() // ACL utility methods // unsigned int ObjectAcl::getRange(const std::string &tag, - pair &range) const + pair &range, bool tolerant /* = false */) const { if (!tag.empty()) { // tag restriction in effect + secinfo("SecAccess", "looking for ACL entries matching tag: \"%s\"", tag.c_str()); range = mEntries.equal_range(tag); unsigned int count = (unsigned int)mEntries.count(tag); - if (count == 0) - CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_ENTRY_TAG); + if (count == 0 && !tolerant) + CssmError::throwMe(CSSM_ERRCODE_ACL_ENTRY_TAG_NOT_FOUND); return count; } else { // try all tags + secinfo("SecAccess", "no tag given; looking for all ACL entries"); range.first = mEntries.begin(); range.second = mEntries.end(); return (unsigned int)mEntries.size(); @@ -292,15 +284,19 @@ void ObjectAcl::cssmGetAcl(const char *tag, uint32 &count, AclEntryInfo * &acls) count = getRange(tag ? tag : "", range); acls = allocator.alloc(count); uint32 n = 0; + + secinfo("SecAccess", "getting the ACL for %p (%d entries) tag: %s", this, count, tag ? tag : ""); + for (EntryMap::const_iterator it = range.first; it != range.second; it++, n++) { acls[n].EntryHandle = it->second.handle; it->second.toEntryInfo(acls[n].EntryPublicInfo, allocator); + secinfo("SecAccess", "found an entry of type %d", acls[n].EntryPublicInfo.TypedSubject.Head->WordID); } count = n; } void ObjectAcl::cssmChangeAcl(const AclEdit &edit, - const AccessCredentials *cred, AclValidationEnvironment *env) + const AccessCredentials *cred, AclValidationEnvironment *env, const char *preserveTag) { IFDUMPING("acl", debugDump("acl-change-from")); @@ -309,26 +305,51 @@ void ObjectAcl::cssmChangeAcl(const AclEdit &edit, // validate access credentials validateOwner(CSSM_ACL_AUTHORIZATION_CHANGE_ACL, cred, env); - + // what is Thy wish, effendi? switch (edit.EditMode) { case CSSM_ACL_EDIT_MODE_ADD: { + secinfo("SecAccess", "adding ACL for %p (%ld) while preserving: %s", this, edit.handle(), preserveTag); const AclEntryInput &input = Required(edit.newEntry()); + if (preserveTag && input.proto().s_tag() == preserveTag) + MacOSError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED); add(input.proto().s_tag(), input.proto()); + secinfo("SecAccess", "subject type is %d", input.proto().TypedSubject.Head->WordID); } break; case CSSM_ACL_EDIT_MODE_REPLACE: { + secinfo("SecAccess", "replacing ACL for %p (%ld to %p) while preserving: %s", this, edit.handle(), edit.newEntry(), preserveTag); // keep the handle, and try for some modicum of atomicity EntryMap::iterator it = findEntryHandle(edit.handle()); + if (preserveTag && it->second.tag == preserveTag) + MacOSError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED); + AclEntryPrototype proto2; + it->second.toEntryInfo(proto2, allocator); + secinfo("SecAccess", "subject type was %d", proto2.TypedSubject.Head->WordID); + DataWalkers::chunkFree(proto2, allocator); + AclEntryPrototype proto = Required(edit.newEntry()).proto(); // (bypassing callbacks) add(proto.s_tag(), proto, edit.handle()); + secinfo("SecAccess", "new subject type is %d", proto.TypedSubject.Head->WordID); mEntries.erase(it); } break; - case CSSM_ACL_EDIT_MODE_DELETE: - mEntries.erase(findEntryHandle(edit.OldEntryHandle)); + case CSSM_ACL_EDIT_MODE_DELETE: { + secinfo("SecAccess", "deleting ACL for %p (%ld) while preserving: %s", this, edit.handle(), preserveTag); + EntryMap::iterator it = findEntryHandle(edit.handle()); + if (preserveTag && it->second.tag == preserveTag) + MacOSError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED); + + AclEntryPrototype proto; + it->second.toEntryInfo(proto, allocator); + secinfo("SecAccess", "subject type was %d", proto.TypedSubject.Head->WordID); + DataWalkers::chunkFree(proto, allocator); + + mEntries.erase(it); break; + } default: + secinfo("SecAccess", "no idea what this CSSM_ACL_EDIT type is: %d", edit.EditMode); CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_EDIT_MODE); } @@ -343,6 +364,8 @@ void ObjectAcl::cssmGetOwner(AclOwnerPrototype &outOwner) instantiateAcl(); outOwner.TypedSubject = mOwner.subject->toList(allocator); outOwner.Delegate = mOwner.delegate; + + secinfo("SecAccess", "%p: getting the owner ACL: type %d", this, outOwner.TypedSubject.Head->WordID); } void ObjectAcl::cssmChangeOwner(const AclOwnerPrototype &newOwner, @@ -357,6 +380,8 @@ void ObjectAcl::cssmChangeOwner(const AclOwnerPrototype &newOwner, // okay, replace it mOwner = newOwner; + + secinfo("SecAccess", "%p: new owner's type is %d", this, newOwner.subject().Head->WordID); changedAcl(); @@ -399,7 +424,7 @@ void ObjectAcl::clear() { mOwner = OwnerEntry(); mEntries.erase(mEntries.begin(), mEntries.end()); - secdebug("acl", "%p cleared", this); + secinfo("acl", "%p cleared", this); } @@ -413,6 +438,7 @@ void ObjectAcl::add(const std::string &tag, const AclEntry &newEntry) void ObjectAcl::add(const std::string &tag, AclEntry newEntry, CSSM_ACL_HANDLE handle) { + newEntry.tag = tag; //@@@ This should use a hook-registry mechanism. But for now, we are explicit: if (!newEntry.authorizesAnything) { for (AclAuthorizationSet::const_iterator it = newEntry.authorizations.begin(); @@ -460,9 +486,12 @@ bool ObjectAcl::OwnerEntry::authorizes(AclAuthorization) const return true; // owner can do anything } -bool ObjectAcl::OwnerEntry::validate(const AclValidationContext &ctx) const +bool ObjectAcl::OwnerEntry::validates(const AclValidationContext &ctx) const { - return subject->validate(ctx); // simple subject match - no strings attached + if (AclValidationEnvironment* env = ctx.environment()) + if (env->forceSuccess) + return true; + return subject->validates(ctx); // simple subject match - no strings attached } @@ -507,12 +536,19 @@ bool ObjectAcl::AclEntry::authorizes(AclAuthorization auth) const return authorizesAnything || authorizations.find(auth) != authorizations.end(); } -bool ObjectAcl::AclEntry::validate(const AclValidationContext &ctx) const +bool ObjectAcl::AclEntry::validates(const AclValidationContext &ctx) const { //@@@ not checking time ranges - return subject->validate(ctx); + return subject->validates(ctx); } +void ObjectAcl::AclEntry::addAuthorization(AclAuthorization auth) +{ + authorizations.insert(auth); + authorizesAnything = false; +} + + void ObjectAcl::AclEntry::importBlob(Reader &pub, Reader &priv) { Entry::importBlob(pub, priv); @@ -543,6 +579,7 @@ void ObjectAcl::AclEntry::importBlob(Reader &pub, Reader &priv) AclSubject::Maker::Maker(CSSM_ACL_SUBJECT_TYPE type) : mType(type) { + StLock _(ObjectAcl::makersMutex); ObjectAcl::makers()[type] = this; } @@ -561,6 +598,7 @@ AclSubject *ObjectAcl::make(uint32 typeAndVersion, Reader &pub, Reader &priv) AclSubject::Maker &ObjectAcl::makerFor(CSSM_ACL_SUBJECT_TYPE type) { + StLock _(ObjectAcl::makersMutex); AclSubject::Maker *maker = makers()[type]; if (maker == NULL) CssmError::throwMe(CSSM_ERRCODE_ACL_SUBJECT_TYPE_NOT_SUPPORTED);