]> git.saurik.com Git - apple/security.git/blobdiff - cdsa/cdsa_utilities/cssmacl.cpp
Security-177.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / cssmacl.cpp
index cc700e22d3567c7f37d60a705e75d1d72b22429b..5f5af270b60054b473f8039cb53fb9a430bb8499 100644 (file)
 //
 // 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;
 
@@ -102,13 +99,15 @@ ObjectAcl::~ObjectAcl()
 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()
@@ -137,8 +136,11 @@ public:
 };
 
 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);
 
@@ -146,7 +148,7 @@ void ObjectAcl::validate(AclAuthorization auth, const AccessCredentials *cred,
     // 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;
@@ -162,8 +164,9 @@ void ObjectAcl::validate(AclAuthorization auth, const AccessCredentials *cred,
 }
 
 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;
@@ -178,7 +181,7 @@ void ObjectAcl::validateOwner(AclAuthorization authorizationHint,
 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++)
@@ -190,6 +193,7 @@ void ObjectAcl::exportBlob(CssmData &publicBlob, CssmData &privateBlob)
        pubWriter(entryCount);
     for (Iterator it = begin(); it != end(); it++)
         it->second.exportBlob(pubWriter, privWriter);
+       IFDUMPING("acl", debugDump("exported"));
 }
 
 
@@ -203,7 +207,9 @@ void ObjectAcl::importBlob(const void *publicBlob, const void *privateBlob)
 {
     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;
@@ -214,18 +220,44 @@ void ObjectAcl::importBlob(const void *publicBlob, const void *privateBlob)
 }
 
 
+//
+// 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();
@@ -246,6 +278,7 @@ ObjectAcl::Iterator ObjectAcl::findEntryHandle(CSSM_ACL_HANDLE handle)
 //
 void ObjectAcl::cssmGetAcl(const char *tag, uint32 &count, AclEntryInfo * &acls)
 {
+       instantiateAcl();
     pair<ConstIterator, ConstIterator> range;
     count = getRange(tag, range);
     acls = allocator.alloc<AclEntryInfo>(count);
@@ -262,6 +295,9 @@ void ObjectAcl::cssmChangeAcl(const AclEdit &edit,
 {
        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);
     
@@ -288,12 +324,16 @@ void ObjectAcl::cssmChangeAcl(const AclEdit &edit,
     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;
 }
@@ -303,11 +343,15 @@ void ObjectAcl::cssmChangeOwner(const AclOwnerPrototype &newOwner,
 {
        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"));
 }
@@ -324,12 +368,11 @@ void ObjectAcl::Entry::init(const AclSubjectPointer &subject, bool delegate)
 
 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);
 }
 
 
@@ -396,12 +439,19 @@ void ObjectAcl::AclEntry::importBlob(Reader &pub, Reader &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);
         }
     }
@@ -424,9 +474,10 @@ AclSubject *ObjectAcl::make(const TypedList &list)
     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)
@@ -461,7 +512,7 @@ void AclSubject::Maker::crack(const CssmList &list, uint32 count, ListElement **
 }
 
 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);
@@ -473,12 +524,14 @@ CSSM_WORDID_TYPE AclSubject::Maker::getWord(const ListElement &elem,
 
 
 //
-// 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()));
@@ -490,10 +543,29 @@ void ObjectAcl::debugDump(const char *what) const
                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");
@@ -513,16 +585,4 @@ void ObjectAcl::AclEntry::debugDump() const
        }
 }
 
-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