/* * Copyright (c) 2000-2004 Apple Computer, 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@ */ // // objectacl - core implementation of an ACL-bearing object // #ifndef _OBJECTACL #define _OBJECTACL #include #include #include #include #include namespace Security { // // An in-memory ACL object. // This class implements an ACL-for-a-protected-object. It is complete in that // it provides full ACL management functionality. You still need to (globally) // register makers for the ACL subject types you want to use. // Note that ObjectAcl does no integrity checking. ObjectAcl objects need to be // protected from hostile access (by e.g. address space separation), and exported // ACLs need to be protected somehow (by hiding, signing, or whatever works in // your situation). // class ObjectAcl { friend AclSubject::Maker::Maker(CSSM_ACL_SUBJECT_TYPE); public: typedef RefPointer AclSubjectPointer; typedef LowLevelMemoryUtilities::Writer Writer; typedef LowLevelMemoryUtilities::Reader Reader; public: ObjectAcl(Allocator &alloc); ObjectAcl(const AclEntryPrototype &proto, Allocator &alloc); virtual ~ObjectAcl(); Allocator &allocator; // // access control validation (evaluation) // // validate(): succeed or throw exception void validate(AclAuthorization auth, const AccessCredentials *cred, AclValidationEnvironment *env = NULL); void validate(AclValidationContext &ctx); // validates(): return true or false (or throw on error) bool validates(AclAuthorization auth, const AccessCredentials *cred, AclValidationEnvironment *env = NULL); bool validates(AclValidationContext &ctx); // owner validation (simpler) void validateOwner(AclAuthorization authorizationHint, const AccessCredentials *cred, AclValidationEnvironment *env = NULL); void validateOwner(AclValidationContext &ctx); // CSSM-style ACL access operations // (Gets are not const because underlying implementations usually want them writable) void cssmGetAcl(const char *tag, uint32 &count, AclEntryInfo * &acls); void cssmChangeAcl(const AclEdit &edit, const AccessCredentials *cred, AclValidationEnvironment *env = NULL); void cssmGetOwner(AclOwnerPrototype &owner); void cssmChangeOwner(const AclOwnerPrototype &newOwner, const AccessCredentials *cred, AclValidationEnvironment *env = NULL); void cssmSetInitial(const AclEntryPrototype &proto); void cssmSetInitial(const AclSubjectPointer &subject); // Acl I/O (to/from memory blobs) void exportBlob(CssmData &publicBlob, CssmData &privateBlob); void importBlob(const void *publicBlob, const void *privateBlob); // clear everything from this ACL (return it to un-initialized state) void clear(); // setup hooks (called to delayed-construct the contents before use) - empty defaults virtual void instantiateAcl(); // called before ACL contents are used by external calls virtual void changedAcl(); // called after an ACL has been (possibly) changed // debug dump support (always there but stubbed out unless DEBUGDUMP) virtual void debugDump(const char *what = NULL) const; public: class Entry { public: AclSubjectPointer subject; // subject representation bool delegate; // delegation flag Entry() { } // make invalid Entry void toOwnerInfo(CSSM_ACL_OWNER_PROTOTYPE &info, Allocator &alloc) const; // encode copy in CSSM format virtual bool authorizes(AclAuthorization auth) const = 0; virtual bool validate(const AclValidationContext &ctx) const = 0; template void ObjectAcl::Entry::exportBlob(Action &pub, Action &priv) { Endian del = delegate; pub(del); // 4 bytes delegate flag exportSubject(subject, pub, priv); // subject itself (polymorphic) } void importBlob(Reader &pub, Reader &priv); IFDUMP(virtual void debugDump() const); private: void init(const AclSubjectPointer &subject, bool delegate = false); void init(const TypedList &subject, bool delegate = false) { init(make(subject), delegate); } protected: Entry(const AclEntryPrototype &proto) { init(proto.subject(), proto.delegate()); } Entry(const AclOwnerPrototype &proto) { init(proto.subject()); } Entry(const AclSubjectPointer &subject) { init(subject); } virtual ~Entry(); }; class OwnerEntry : public Entry { public: OwnerEntry() { } // invalid OwnerEntry template OwnerEntry(const Input &owner) : Entry(owner) { } bool authorizes(AclAuthorization auth) const; bool validate(const AclValidationContext &ctx) const; }; class AclEntry : public Entry { public: std::string tag; // entry tag AclAuthorizationSet authorizations; // set of authorizations bool authorizesAnything; // has the _ANY authorization tag //@@@ time range not yet implemented uint32 handle; // entry handle AclEntry() { } // invalid AclEntry AclEntry(const AclSubjectPointer &subject); AclEntry(const AclEntryPrototype &proto); void toEntryInfo(CSSM_ACL_ENTRY_PROTOTYPE &info, Allocator &alloc) const; // encode copy in CSSM format bool authorizes(AclAuthorization auth) const; bool validate(const AclValidationContext &ctx) const; template void exportBlob(Action &pub, Action &priv) { Entry::exportBlob(pub, priv); const char *s = tag.c_str(); pub(s); uint32 aa = authorizesAnything; pub(aa); if (!authorizesAnything) { Endian count = authorizations.size(); pub(count); for (AclAuthorizationSet::iterator it = authorizations.begin(); it != authorizations.end(); it++) { Endian auth = *it; pub(auth); } } //@@@ export time range } void importBlob(Reader &pub, Reader &priv); IFDUMP(void debugDump() const); }; public: // These helpers deal with transferring one subject from/to reader/writer streams. // You'd usually only call those from complex subject implementations (e.g. threshold) template static void ObjectAcl::exportSubject(AclSubject *subject, Action &pub, Action &priv) { Endian typeAndVersion = subject->type() | subject->version() << AclSubject::versionShift; pub(typeAndVersion); subject->exportBlob(pub, priv); } static AclSubject *importSubject(Reader &pub, Reader &priv); public: typedef std::multimap EntryMap; EntryMap::iterator begin() { return mEntries.begin(); } EntryMap::iterator end() { return mEntries.end(); } EntryMap::const_iterator begin() const { return mEntries.begin(); } EntryMap::const_iterator end() const { return mEntries.end(); } unsigned int getRange(const std::string &tag, pair &range) const; EntryMap::iterator findEntryHandle(CSSM_ACL_HANDLE handle); // construct an AclSubject through the Maker registry (by subject type) static AclSubject *make(const TypedList &list); // make from CSSM form static AclSubject *make(uint32 typeAndVersion, Reader &pub, Reader &priv); // make from export form protected: template void owner(const Input &input); void entries(uint32 count, const AclEntryInfo *infos); private: void add(const std::string &tag, const AclEntry &newEntry); void add(const std::string &tag, AclEntry newEntry, uint32 handle); private: EntryMap mEntries; // ACL entries indexed by tag OwnerEntry mOwner; // ACL owner entry uint32 mNextHandle; // next unused entry handle value private: typedef map MakerMap; static ModuleNexus makers; // registered subject Makers static AclSubject::Maker &makerFor(CSSM_ACL_SUBJECT_TYPE type); }; } // end namespace Security #endif //_OBJECTACL