//
// cssmacl - core ACL management interface
//
-#ifdef __MWERKS__
-#define _CPP_CSSMACL
-#endif
-
#include <Security/cssmacl.h>
#include <Security/debugging.h>
#include <algorithm>
#include <cstdarg>
+#include <endian.h>
using namespace DataWalkers;
void ObjectAcl::cssmSetInitial(const AclEntryPrototype &proto)
{
owner = OwnerEntry(proto);
- entries.insert(EntryMap::value_type("", proto))->second.handle = nextHandle++;
+ entries.insert(EntryMap::value_type(proto.tag(), proto))->second.handle = nextHandle++;
+ IFDUMPING("acl", debugDump("create/proto"));
}
void ObjectAcl::cssmSetInitial(const AclSubjectPointer &subject)
{
owner = OwnerEntry(subject);
entries.insert(EntryMap::value_type("", subject))->second.handle = nextHandle++;
+ IFDUMPING("acl", debugDump("create/subject"));
}
ObjectAcl::Entry::~Entry()
};
void ObjectAcl::validate(AclAuthorization auth, const AccessCredentials *cred,
- AclValidationEnvironment *env) const
+ AclValidationEnvironment *env)
{
+ // make sure we are ready to go
+ instantiateAcl();
+
//@@@ should pre-screen based on requested auth, maybe?
BaseValidationContext ctx(cred, auth, env);
// try owner (owner can do anything)
if (owner.validate(ctx))
return;
-#endif ACL_OMNIPOTENT_OWNER
+#endif //ACL_OMNIPOTENT_OWNER
// try applicable ACLs
pair<ConstIterator, ConstIterator> range;
}
void ObjectAcl::validateOwner(AclAuthorization authorizationHint,
- const AccessCredentials *cred, AclValidationEnvironment *env) const
+ const AccessCredentials *cred, AclValidationEnvironment *env)
{
+ instantiateAcl();
BaseValidationContext ctx(cred, authorizationHint, env);
if (owner.validate(ctx))
return;
void ObjectAcl::exportBlob(CssmData &publicBlob, CssmData &privateBlob)
{
Writer::Counter pubSize, privSize;
- uint32 entryCount = entries.size();
+ Endian<uint32> entryCount = entries.size();
owner.exportBlob(pubSize, privSize);
pubSize(entryCount);
for (Iterator it = begin(); it != end(); it++)
pubWriter(entryCount);
for (Iterator it = begin(); it != end(); it++)
it->second.exportBlob(pubWriter, privWriter);
+ IFDUMPING("acl", debugDump("exported"));
}
{
Reader pubReader(publicBlob), privReader(privateBlob);
owner.importBlob(pubReader, privReader);
- uint32 entryCount; pubReader(entryCount);
+ Endian<uint32> entryCountIn; pubReader(entryCountIn);
+ uint32 entryCount = entryCountIn;
+
entries.erase(begin(), end());
for (uint32 n = 0; n < entryCount; n++) {
AclEntry newEntry;
}
+//
+// Import/export helpers for subjects.
+// This is exported to (subject implementation) callers to maintain consistency
+// in binary format handling.
+//
+AclSubject *ObjectAcl::importSubject(Reader &pub, Reader &priv)
+{
+ Endian<uint32> typeAndVersion; pub(typeAndVersion);
+ return make(typeAndVersion, pub, priv);
+}
+
+
+//
+// Setup/update hooks
+//
+void ObjectAcl::instantiateAcl()
+{
+ // nothing by default
+}
+
+void ObjectAcl::changedAcl()
+{
+ // nothing by default
+}
+
+
//
// ACL utility methods
//
unsigned int ObjectAcl::getRange(const char *tag, pair<ConstIterator, ConstIterator> &range) const
{
- if (tag) {
+ if (tag && tag[0]) { // tag restriction in effect
range = entries.equal_range(tag);
uint32 count = entries.count(tag);
if (count == 0)
CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_ENTRY_TAG);
return count;
- } else {
+ } else { // try all tags
range.first = entries.begin();
range.second = entries.end();
return entries.size();
//
void ObjectAcl::cssmGetAcl(const char *tag, uint32 &count, AclEntryInfo * &acls)
{
+ instantiateAcl();
pair<ConstIterator, ConstIterator> range;
count = getRange(tag, range);
acls = allocator.alloc<AclEntryInfo>(count);
{
IFDUMPING("acl", debugDump("acl-change-from"));
+ // make sure we're ready to go
+ instantiateAcl();
+
// validate access credentials
validateOwner(CSSM_ACL_AUTHORIZATION_CHANGE_ACL, cred, env);
default:
CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_EDIT_MODE);
}
+
+ // notify change
+ changedAcl();
- IFDUMPING("acl", debugDump("owner-change-to"));
+ IFDUMPING("acl", debugDump("acl-change-to"));
}
void ObjectAcl::cssmGetOwner(AclOwnerPrototype &outOwner)
{
+ instantiateAcl();
outOwner.TypedSubject = owner.subject->toList(allocator);
outOwner.Delegate = owner.delegate;
}
{
IFDUMPING("acl", debugDump("owner-change-from"));
+ instantiateAcl();
+
// only the owner entry can match
validateOwner(CSSM_ACL_AUTHORIZATION_CHANGE_OWNER, cred, env);
// okay, replace it
owner = newOwner;
+
+ changedAcl();
IFDUMPING("acl", debugDump("owner-change-to"));
}
void ObjectAcl::Entry::importBlob(Reader &pub, Reader &priv)
{
- // delegate is trivial
- pub(delegate);
-
- // now reconstruct the (polymorphic) subject
- CSSM_ACL_SUBJECT_TYPE subjectType; pub(subjectType);
- subject = make(subjectType, pub, priv);
+ Endian<uint32> del;
+ pub(del); // read del from the public blob
+
+ delegate = del; // 4 bytes delegate flag
+ subject = importSubject(pub, priv);
}
{
Entry::importBlob(pub, priv);
const char *s; pub(s); tag = s;
- pub(authorizesAnything);
+
+ // authorizesAnything is on disk as a 4-byte flag
+ Endian<uint32> tmpAuthorizesAnything;
+ pub(tmpAuthorizesAnything);
+ authorizesAnything = tmpAuthorizesAnything;
+
authorizations.erase(authorizations.begin(), authorizations.end());
if (!authorizesAnything) {
- uint32 count; pub(count);
+ Endian<uint32> countIn; pub(countIn);
+ uint32 count = countIn;
+
for (uint32 n = 0; n < count; n++) {
- AclAuthorization auth; pub(auth);
+ Endian<AclAuthorization> auth; pub(auth);
authorizations.insert(auth);
}
}
return makerFor(list.type()).make(list);
}
-AclSubject *ObjectAcl::make(CSSM_ACL_SUBJECT_TYPE type, Reader &pub, Reader &priv)
+AclSubject *ObjectAcl::make(uint32 typeAndVersion, Reader &pub, Reader &priv)
{
- return makerFor(type).make(pub, priv);
+ // this type is encoded as (version << 24) | type
+ return makerFor(typeAndVersion & ~AclSubject::versionMask).make(typeAndVersion >> AclSubject::versionShift, pub, priv);
}
AclSubject::Maker &ObjectAcl::makerFor(CSSM_ACL_SUBJECT_TYPE type)
}
CSSM_WORDID_TYPE AclSubject::Maker::getWord(const ListElement &elem,
- int min = 0, int max = INT_MAX)
+ int min /*= 0*/, int max /*= INT_MAX*/)
{
if (elem.type() != CSSM_LIST_ELEMENT_WORDID)
CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE);
//
-// Debug dumping support
+// Debug dumping support.
+// Leave the ObjectAcl::debugDump method in (stubbed out)
+// to keep the virtual table layout stable, and to allow
+// proper linking in weird mix-and-match scenarios.
//
-#if defined(DEBUGDUMP)
-
void ObjectAcl::debugDump(const char *what) const
{
+#if defined(DEBUGDUMP)
if (!what)
what = "Dump";
Debug::dump("%p ACL %s: %d entries\n", this, what, int(entries.size()));
Debug::dump("]\n");
}
Debug::dump("%p ACL END\n", this);
+#endif //DEBUGDUMP
}
+void AclSubject::debugDump() const
+{
+#if defined(DEBUGDUMP)
+ switch (type()) {
+ case CSSM_ACL_SUBJECT_TYPE_ANY:
+ Debug::dump("ANY");
+ break;
+ default:
+ Debug::dump("subject type=%d", int(type()));
+ break;
+ }
+#endif //DEBUGDUMP
+}
+
+#if defined(DEBUGDUMP)
+
void ObjectAcl::Entry::debugDump() const
{
+ if (AclSubject::Version v = subject->version())
+ Debug::dump("V=%d ", v);
subject->debugDump();
if (delegate)
Debug::dump(" DELEGATE");
}
}
-void AclSubject::debugDump() const
-{
- switch (type()) {
- case CSSM_ACL_SUBJECT_TYPE_ANY:
- Debug::dump("ANY");
- break;
- default:
- Debug::dump("subject type=%d", int(type()));
- break;
- }
-}
-
#endif //DEBUGDUMP