2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 // cssmacl - core ACL management interface.
22 // This file contains a set of C++ classes that implement ACLs in the local address space.
23 // ObjectAcl is the abstract interface to an implementation of a CSSM ACL. It supports
24 // the CSSM interfaces for ACL manipulation. AclSubject is the common parent of all
25 // types of ACL Subjects (in the CSSM sense); subclass this to implement a new subject type.
26 // AclValidationContext is an extensible, structured way of passing context information
27 // from the evaluation environment into particular subjects whose validation is context sensitive.
32 #include <Security/cssmaclpod.h>
33 #include <Security/cssmcred.h>
34 #include <Security/refcount.h>
35 #include <Security/globalizer.h>
36 #include <Security/memutils.h>
45 class AclValidationContext
;
49 // The AclSubject class models an ACL "subject" object.
50 // This is an abstract polymorphic class implementing various ACL subject types.
51 // Note that it does contain some common code to make everybody's life easier.
53 class AclSubject
: public RefCount
{
55 typedef LowLevelMemoryUtilities::Writer Writer
;
56 typedef LowLevelMemoryUtilities::Reader Reader
;
58 typedef uint8 Version
; // binary version marker
59 static const int versionShift
= 24; // highest-order byte of type is version
60 static const uint32 versionMask
= 0xff000000;
62 AclSubject(uint32 type
) : mType(type
), mVersion(0) { assert(!(type
& versionMask
)); }
63 virtual ~AclSubject();
64 uint32
type() const { return mType
; }
66 virtual bool validate(const AclValidationContext
&ctx
) const = 0;
68 // export to CSSM interface
69 virtual CssmList
toList(CssmAllocator
&alloc
) const = 0;
71 // export/import for save/restore interface
72 virtual void exportBlob(Writer::Counter
&pub
, Writer::Counter
&priv
);
73 virtual void exportBlob(Writer
&pub
, Writer
&priv
);
74 virtual void importBlob(Reader
&pub
, Reader
&priv
);
76 // binary compatibility version management. The version defaults to zero
77 Version
version() const { return mVersion
; }
78 void version(Version v
) { mVersion
= v
; }
80 // debug suupport (dummied out but present for -UDEBUGDUMP)
81 virtual void debugDump() const;
84 CSSM_ACL_SUBJECT_TYPE mType
;
90 Maker(CSSM_ACL_SUBJECT_TYPE type
);
93 uint32
type() const { return myType
; }
94 virtual AclSubject
*make(const TypedList
&list
) const = 0;
95 virtual AclSubject
*make(Version version
, Reader
&pub
, Reader
&priv
) const = 0;
98 // list parsing helpers
99 static void crack(const CssmList
&list
, uint32 count
,
100 ListElement
**array
= NULL
, ...);
101 static CSSM_WORDID_TYPE
getWord(const ListElement
&list
,
102 int min
= 0, int max
= INT_MAX
);
105 CSSM_ACL_SUBJECT_TYPE myType
;
111 // A SimpleAclSubject validates a credential by scanning its samples
112 // one at a time, without any interactions between them. Thus its validate()
113 // can be a lot simpler.
115 class SimpleAclSubject
: public AclSubject
{
117 SimpleAclSubject(CSSM_ACL_SUBJECT_TYPE su
, CSSM_SAMPLE_TYPE sa
)
118 : AclSubject(su
), acceptingSamples(sa
) { }
120 bool validate(const AclValidationContext
&ctx
) const;
121 virtual bool validate(const AclValidationContext
&baseCtx
,
122 const TypedList
&sample
) const = 0;
124 const CSSM_SAMPLE_TYPE acceptingSamples
;
129 // An AclValidationEnvironment can be subclassed to add context access to ACL subject
130 // validation. If you use ACL subject classes that need context beyond the credential
131 // structure itself, add that context to (a subclass of) CredentialsContext, pass that
132 // to ObjectAcl::validate() along with the credentials, and have the Subject implementation
133 // access validationContext.environment().
135 class AclValidationEnvironment
{
137 virtual ~AclValidationEnvironment(); // ensure virtual methods (need dynamic_cast)
142 // An AclValidationContext holds credential information in a semi-transparent
143 // form. It's designed to provide a uniform representation of credentials, plus
144 // any (trusted path and/or implicit) context information useful for ACL validation.
146 class AclValidationContext
{
148 AclValidationContext(const AccessCredentials
*cred
,
149 AclAuthorization auth
, AclValidationEnvironment
*env
= NULL
)
150 : mCred(cred
), mAuth(auth
), mEnv(env
) { }
151 AclValidationContext(const AclValidationContext
&ctx
)
152 : mCred(ctx
.mCred
), mAuth(ctx
.mAuth
), mEnv(ctx
.mEnv
) { }
153 virtual ~AclValidationContext();
155 // access to (suitably focused) sample set
156 virtual uint32
count() const = 0; // number of samples
157 virtual const TypedList
&sample(uint32 n
) const = 0; // retrieve one sample
158 const TypedList
&operator [] (uint32 n
) const { return sample(n
); }
161 AclAuthorization
authorization() const { return mAuth
; }
163 Env
*environment() const { return dynamic_cast<Env
*>(mEnv
); }
165 //@@@ add certificate access functions
166 //@@@ add callback management
169 const AccessCredentials
*mCred
; // original credentials
170 AclAuthorization mAuth
; // action requested
171 AclValidationEnvironment
*mEnv
; // environmental context (if any)
176 // An in-memory ACL object.
177 // This class implements an ACL-for-a-protected-object. It is complete in that
178 // it provides full ACL management functionality. You still need to (globally)
179 // register makers for the ACL subject types you want to use.
180 // Note that ObjectAcl does no integrity checking. ObjectAcl objects need to be
181 // protected from hostile access (by e.g. address space separation), and exported
182 // ACLs need to be protected somehow (by hiding, signing, or whatever works in
186 friend AclSubject::Maker::Maker(CSSM_ACL_SUBJECT_TYPE
);
189 typedef RefPointer
<AclSubject
> AclSubjectPointer
;
191 typedef LowLevelMemoryUtilities::Writer Writer
;
192 typedef LowLevelMemoryUtilities::Reader Reader
;
195 ObjectAcl(CssmAllocator
&alloc
);
196 ObjectAcl(const AclEntryPrototype
&proto
, CssmAllocator
&alloc
);
197 virtual ~ObjectAcl();
199 CssmAllocator
&allocator
;
201 // access control validation: succeed or throw exception
202 void validate(AclAuthorization auth
, const AccessCredentials
*cred
,
203 AclValidationEnvironment
*env
= NULL
) const;
204 void validateOwner(AclAuthorization authorizationHint
, const AccessCredentials
*cred
,
205 AclValidationEnvironment
*env
= NULL
) const;
207 // CSSM-style ACL access operations
208 // (Gets are not const because underlying implementations usually want them writable)
209 void cssmGetAcl(const char *tag
, uint32
&count
, AclEntryInfo
* &acls
);
210 void cssmChangeAcl(const AclEdit
&edit
, const AccessCredentials
*cred
,
211 AclValidationEnvironment
*env
= NULL
);
212 void cssmGetOwner(AclOwnerPrototype
&owner
);
213 void cssmChangeOwner(const AclOwnerPrototype
&newOwner
, const AccessCredentials
*cred
,
214 AclValidationEnvironment
*env
= NULL
);
216 void cssmSetInitial(const AclEntryPrototype
&proto
);
217 void cssmSetInitial(const AclSubjectPointer
&subject
);
219 // Acl I/O (to/from memory blobs)
220 void exportBlob(CssmData
&publicBlob
, CssmData
&privateBlob
);
221 void importBlob(const void *publicBlob
, const void *privateBlob
);
223 // debugging support (always there but stubbed out unless DEBUGDUMP)
224 virtual void debugDump(const char *what
= NULL
) const;
229 AclSubjectPointer subject
; // subject representation
230 bool delegate
; // delegation flag
232 Entry() { } // make invalid Entry
234 void toOwnerInfo(CSSM_ACL_OWNER_PROTOTYPE
&info
,
235 CssmAllocator
&alloc
) const; // encode copy in CSSM format
237 virtual bool authorizes(AclAuthorization auth
) const = 0;
238 virtual bool validate(const AclValidationContext
&ctx
) const = 0;
240 template <class Action
>
241 void ObjectAcl::Entry::exportBlob(Action
&pub
, Action
&priv
)
243 uint32 del
= delegate
; pub(del
); // 4 bytes delegate flag
244 exportSubject(subject
, pub
, priv
); // subject itself (polymorphic)
246 void importBlob(Reader
&pub
, Reader
&priv
);
248 IFDUMP(virtual void debugDump() const);
251 void init(const AclSubjectPointer
&subject
, bool delegate
= false);
252 void init(const TypedList
&subject
, bool delegate
= false) { init(make(subject
), delegate
); }
255 Entry(const AclEntryPrototype
&proto
) { init(proto
.subject(), proto
.delegate()); }
256 Entry(const AclOwnerPrototype
&proto
) { init(proto
.subject()); }
257 Entry(const AclSubjectPointer
&subject
) { init(subject
); }
261 class OwnerEntry
: public Entry
{
263 OwnerEntry() { } // invalid OwnerEntry
264 template <class Input
>
265 OwnerEntry(const Input
&owner
) : Entry(owner
) { }
266 OwnerEntry(const AclSubjectPointer
&subject
) : Entry(subject
) { }
268 bool authorizes(AclAuthorization auth
) const;
269 bool validate(const AclValidationContext
&ctx
) const;
272 class AclEntry
: public Entry
{
274 std::string tag
; // entry tag
275 AclAuthorizationSet authorizations
; // set of authorizations
276 bool authorizesAnything
; // has the _ANY authorization tag
277 //@@@ time range not yet implemented
278 uint32 handle
; // entry handle
280 AclEntry() { } // invalid AclEntry
281 AclEntry(const AclSubjectPointer
&subject
);
282 AclEntry(const AclEntryPrototype
&proto
);
284 void toEntryInfo(CSSM_ACL_ENTRY_PROTOTYPE
&info
,
285 CssmAllocator
&alloc
) const; // encode copy in CSSM format
287 bool authorizes(AclAuthorization auth
) const;
288 bool validate(const AclValidationContext
&ctx
) const;
290 template <class Action
>
291 void exportBlob(Action
&pub
, Action
&priv
)
293 Entry::exportBlob(pub
, priv
);
294 const char *s
= tag
.c_str(); pub(s
);
295 uint32 aa
= authorizesAnything
; pub(aa
);
296 if (!authorizesAnything
) {
297 uint32 count
= authorizations
.size(); pub(count
);
298 for (AclAuthorizationSet::iterator it
= authorizations
.begin();
299 it
!= authorizations
.end(); it
++) {
300 AclAuthorization auth
= *it
; pub(auth
);
303 //@@@ export time range
305 void importBlob(Reader
&pub
, Reader
&priv
);
307 IFDUMP(void debugDump() const);
311 // These helpers deal with transferring one subject from/to reader/writer streams.
312 // You'd usually only call those from complex subject implementations (e.g. threshold)
313 template <class Action
>
314 static void ObjectAcl::exportSubject(AclSubject
*subject
, Action
&pub
, Action
&priv
)
316 uint32 typeAndVersion
= subject
->type() | subject
->version() << AclSubject::versionShift
;
318 subject
->exportBlob(pub
, priv
);
320 static AclSubject
*importSubject(Reader
&pub
, Reader
&priv
);
323 typedef std::multimap
<string
, AclEntry
> EntryMap
;
324 typedef EntryMap::iterator Iterator
;
325 typedef EntryMap::const_iterator ConstIterator
;
327 Iterator
begin() { return entries
.begin(); }
328 Iterator
end() { return entries
.end(); }
329 ConstIterator
begin() const { return entries
.begin(); }
330 ConstIterator
end() const { return entries
.end(); }
332 unsigned int getRange(const char *tag
, pair
<ConstIterator
, ConstIterator
> &range
) const;
333 Iterator
findEntryHandle(CSSM_ACL_HANDLE handle
);
335 // construct an AclSubject through the Maker registry (by subject type)
336 static AclSubject
*make(const TypedList
&list
); // make from CSSM form
337 static AclSubject
*make(uint32 typeAndVersion
,
338 Reader
&pub
, Reader
&priv
); // make from export form
341 EntryMap entries
; // ACL entries indexed by tag
342 OwnerEntry owner
; // ACL owner entry
343 uint32 nextHandle
; // next unused entry handle value
346 typedef map
<CSSM_ACL_SUBJECT_TYPE
, AclSubject::Maker
*> MakerMap
;
347 static ModuleNexus
<MakerMap
> makers
; // registered subject Makers
349 static AclSubject::Maker
&makerFor(CSSM_ACL_SUBJECT_TYPE type
);
354 // This bastard child of two different data structure sets has no natural home.
355 // We'll take pity on it here.
357 class ResourceControlContext
: public PodWrapper
<ResourceControlContext
, CSSM_RESOURCE_CONTROL_CONTEXT
> {
359 ResourceControlContext() { }
360 ResourceControlContext(const AclEntryInput
&initial
, AccessCredentials
*cred
= NULL
)
361 { InitialAclEntry
= initial
; AccessCred
= cred
; }
363 AclEntryInput
&input() { return AclEntryInput::overlay(InitialAclEntry
); }
364 operator AclEntryInput
&() { return input(); }
365 AccessCredentials
*credentials() const { return AccessCredentials::overlay(AccessCred
); }
366 void credentials(const CSSM_ACCESS_CREDENTIALS
*creds
)
367 { AccessCred
= const_cast<CSSM_ACCESS_CREDENTIALS
*>(creds
); }
370 } // end namespace Security