1/*
2 * Copyright (c) 2000-2004,2006 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25//
26// objectacl - core implementation of an ACL-bearing object
27//
28#ifndef _OBJECTACL
29#define _OBJECTACL
30
31#include <security_cdsa_utilities/aclsubject.h>
32#include <security_utilities/globalizer.h>
33#include <map>
34#include <set>
35#include <limits.h>
36
37
38namespace Security {
39
40
41//
42// An in-memory ACL object.
43// This class implements an ACL-for-a-protected-object. It is complete in that
44// it provides full ACL management functionality. You still need to (globally)
45// register makers for the ACL subject types you want to use.
46// Note that ObjectAcl does no integrity checking. ObjectAcl objects need to be
47// protected from hostile access (by e.g. address space separation), and exported
48// ACLs need to be protected somehow (by hiding, signing, or whatever works in
49// your situation).
50//
51class ObjectAcl {
52    friend AclSubject::Maker::Maker(CSSM_ACL_SUBJECT_TYPE);
53
54public:
55    typedef RefPointer<AclSubject> AclSubjectPointer;
56
57    typedef LowLevelMemoryUtilities::Writer Writer;
58    typedef LowLevelMemoryUtilities::Reader Reader;
59
60public:
61    ObjectAcl(Allocator &alloc);
62    ObjectAcl(const AclEntryPrototype &proto, Allocator &alloc);
63	virtual ~ObjectAcl();
64
65    Allocator &allocator;
66
67
68	//
69    // access control validation (evaluation)
70	//
71
72	// validate(): succeed or throw exception
73    void validate(AclAuthorization auth, const AccessCredentials *cred,
74        AclValidationEnvironment *env = NULL);
75	void validate(AclValidationContext &ctx);
76
77	// validates(): return true or false (or throw on error)
78    bool validates(AclAuthorization auth, const AccessCredentials *cred,
79        AclValidationEnvironment *env = NULL);
80	bool validates(AclValidationContext &ctx);
81
82	// owner validation (simpler)
83    void validateOwner(AclAuthorization authorizationHint, const AccessCredentials *cred,
84		AclValidationEnvironment *env = NULL);
85	void validateOwner(AclValidationContext &ctx);
86
87    // CSSM-style ACL access operations
88	// (Gets are not const because underlying implementations usually want them writable)
89    void cssmGetAcl(const char *tag, uint32 &count, AclEntryInfo * &acls);
90    void cssmChangeAcl(const AclEdit &edit, const AccessCredentials *cred,
91		AclValidationEnvironment *env = NULL);
92    void cssmGetOwner(AclOwnerPrototype &owner);
93    void cssmChangeOwner(const AclOwnerPrototype &newOwner, const AccessCredentials *cred,
94		AclValidationEnvironment *env = NULL);
95
96    void cssmSetInitial(const AclEntryPrototype &proto);
97    void cssmSetInitial(const AclSubjectPointer &subject);
98
99    // Acl I/O (to/from memory blobs)
100    void exportBlob(CssmData &publicBlob, CssmData &privateBlob);
101    void importBlob(const void *publicBlob, const void *privateBlob);
102
103	// clear everything from this ACL (return it to un-initialized state)
104	void clear();
105
106	// setup hooks (called to delayed-construct the contents before use) - empty defaults
107	virtual void instantiateAcl();	// called before ACL contents are used by external calls
108	virtual void changedAcl();		// called after an ACL has been (possibly) changed
109
110	// debug dump support (always there but stubbed out unless DEBUGDUMP)
111	virtual void debugDump(const char *what = NULL) const;
112
113public:
114    class Entry {
115    public:
116        AclSubjectPointer subject;		// subject representation
117        bool delegate;					// delegation flag
118
119        Entry() { }						// make invalid Entry
120
121        void toOwnerInfo(CSSM_ACL_OWNER_PROTOTYPE &info,
122                        Allocator &alloc) const; // encode copy in CSSM format
123
124        virtual bool authorizes(AclAuthorization auth) const = 0;
125        virtual bool validate(const AclValidationContext &ctx) const = 0;
126
127		template <class Action>
128		void exportBlob(Action &pub, Action &priv)
129		{
130			Endian<uint32> del = delegate; pub(del);	// 4 bytes delegate flag
131			exportSubject(subject, pub, priv);	// subject itself (polymorphic)
132		}
133        void importBlob(Reader &pub, Reader &priv);
134
135		IFDUMP(virtual void debugDump() const);
136
137    private:
138        void init(const AclSubjectPointer &subject, bool delegate = false);
139        void init(const TypedList &subject, bool delegate = false) { init(make(subject), delegate); }
140
141    protected:
142        Entry(const AclEntryPrototype &proto) { init(proto.subject(), proto.delegate()); }
143        Entry(const AclOwnerPrototype &proto) { init(proto.subject()); }
144        Entry(const AclSubjectPointer &subject) { init(subject); }
145        virtual ~Entry();
146    };
147
148    class OwnerEntry : public Entry {
149    public:
150        OwnerEntry() { }	// invalid OwnerEntry
151        template <class Input>
152        OwnerEntry(const Input &owner) : Entry(owner) { }
153
154        bool authorizes(AclAuthorization auth) const;
155        bool validate(const AclValidationContext &ctx) const;
156    };
157
158    class AclEntry : public Entry {
159    public:
160        std::string tag;						// entry tag
161		AclAuthorizationSet authorizations;		// set of authorizations
162        bool authorizesAnything;				// has the _ANY authorization tag
163        //@@@ time range not yet implemented
164        CSSM_ACL_HANDLE handle;					// entry handle
165
166		AclEntry() { }							// invalid AclEntry
167        AclEntry(const AclSubjectPointer &subject);
168        AclEntry(const AclEntryPrototype &proto);
169
170        void toEntryInfo(CSSM_ACL_ENTRY_PROTOTYPE &info,
171                        Allocator &alloc) const; // encode copy in CSSM format
172
173        bool authorizes(AclAuthorization auth) const;
174        bool validate(const AclValidationContext &ctx) const;
175
176        template <class Action>
177        void exportBlob(Action &pub, Action &priv)
178        {
179            Entry::exportBlob(pub, priv);
180            const char *s = tag.c_str(); pub(s);
181            uint32 aa = authorizesAnything; pub(aa);
182            if (!authorizesAnything) {
183                Endian<uint32> count = (uint32)authorizations.size(); pub(count);
184                for (AclAuthorizationSet::iterator it = authorizations.begin();
185                    it != authorizations.end(); it++) {
186                    Endian<AclAuthorization> auth = *it; pub(auth);
187                }
188            }
189            //@@@ export time range
190        }
191        void importBlob(Reader &pub, Reader &priv);
192
193		IFDUMP(void debugDump() const);
194    };
195
196public:
197	// These helpers deal with transferring one subject from/to reader/writer streams.
198	// You'd usually only call those from complex subject implementations (e.g. threshold)
199	template <class Action>
200	static void exportSubject(AclSubject *subject, Action &pub, Action &priv)
201	{
202		Endian<uint32> typeAndVersion = subject->type() | subject->version() << AclSubject::versionShift;
203		pub(typeAndVersion);
204		subject->exportBlob(pub, priv);
205	}
206	static AclSubject *importSubject(Reader &pub, Reader &priv);
207
208public:
209    typedef std::multimap<string, AclEntry> EntryMap;
210
211    EntryMap::iterator begin() { return mEntries.begin(); }
212	EntryMap::iterator end() { return mEntries.end(); }
213    EntryMap::const_iterator begin() const { return mEntries.begin(); }
214    EntryMap::const_iterator end() const { return mEntries.end(); }
215
216    unsigned int getRange(const std::string &tag,
217		pair<EntryMap::const_iterator, EntryMap::const_iterator> &range) const;
218    EntryMap::iterator findEntryHandle(CSSM_ACL_HANDLE handle);
219
220    // construct an AclSubject through the Maker registry (by subject type)
221    static AclSubject *make(const TypedList &list);	// make from CSSM form
222    static AclSubject *make(uint32 typeAndVersion,
223                            Reader &pub, Reader &priv); // make from export form
224
225protected:
226	template <class Input>
227	void owner(const Input &input);
228	void entries(uint32 count, const AclEntryInfo *infos);
229
230private:
231	void add(const std::string &tag, const AclEntry &newEntry);
232	void add(const std::string &tag, AclEntry newEntry, CSSM_ACL_HANDLE handle);
233
234private:
235    EntryMap mEntries;				// ACL entries indexed by tag
236    OwnerEntry mOwner;				// ACL owner entry
237    CSSM_ACL_HANDLE mNextHandle;	// next unused entry handle value
238
239private:
240    typedef map<CSSM_ACL_SUBJECT_TYPE, AclSubject::Maker *> MakerMap;
241    static ModuleNexus<MakerMap> makers;	// registered subject Makers
242
243    static AclSubject::Maker &makerFor(CSSM_ACL_SUBJECT_TYPE type);
244};
245
246
247} // end namespace Security
248
249
250#endif //_OBJECTACL
251