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 // Statement of strategy:
23 // Beyond the enhanced POD Wrappers for the various CSSM types, we find pure C++ classes
24 // that implement ACLs in the local address space. ObjectAcl is the abstract interface
25 // to an implementation of a CSSM ACL. It supports the CSSM interfaces for ACL manipulation.
31 #include <Security/cssmaclpod.h>
32 #include <Security/cssmcred.h>
33 #include <Security/refcount.h>
34 #include <Security/globalizer.h>
35 #include <Security/memutils.h>
48 class AclValidationContext
;
52 // The AclSubject class models an ACL "subject" object.
53 // This is an abstract polymorphic class implementing various ACL subject types.
54 // Note that it does contain some common code to make everybody's life easier.
56 class AclSubject
: public RefCount
{
57 typedef LowLevelMemoryUtilities::Writer Writer
;
58 typedef LowLevelMemoryUtilities::Reader Reader
;
60 AclSubject(uint32 type
) : mType(type
) { }
61 virtual ~AclSubject();
62 uint32
type() const { return mType
; }
64 virtual bool validate(const AclValidationContext
&ctx
) const = 0;
66 // export to CSSM interface
67 virtual CssmList
toList(CssmAllocator
&alloc
) const = 0;
69 // export/import for save/restore interface
70 virtual void exportBlob(Writer::Counter
&pub
, Writer::Counter
&priv
);
71 virtual void exportBlob(Writer
&pub
, Writer
&priv
);
72 virtual void importBlob(Reader
&pub
, Reader
&priv
);
75 IFDUMP(virtual void debugDump() const);
78 CSSM_ACL_SUBJECT_TYPE mType
;
83 Maker(CSSM_ACL_SUBJECT_TYPE type
);
86 uint32
type() const { return myType
; }
87 virtual AclSubject
*make(const TypedList
&list
) const = 0;
88 virtual AclSubject
*make(Reader
&pub
, Reader
&priv
) const = 0;
91 // list parsing helpers
92 static void crack(const CssmList
&list
, uint32 count
,
93 ListElement
**array
= NULL
, ...);
94 static CSSM_WORDID_TYPE
getWord(const ListElement
&list
,
95 int min
= 0, int max
= INT_MAX
);
98 CSSM_ACL_SUBJECT_TYPE myType
;
104 // A SimpleAclSubject validates a credential by scanning its samples
105 // one at a time, without any interactions between them. Thus its validate()
106 // can be a lot simpler.
108 class SimpleAclSubject
: public AclSubject
{
110 SimpleAclSubject(CSSM_ACL_SUBJECT_TYPE su
, CSSM_SAMPLE_TYPE sa
)
111 : AclSubject(su
), acceptingSamples(sa
) { }
113 bool validate(const AclValidationContext
&ctx
) const;
114 virtual bool validate(const AclValidationContext
&baseCtx
,
115 const TypedList
&sample
) const = 0;
117 const CSSM_SAMPLE_TYPE acceptingSamples
;
122 // An AclValidationEnvironment can be subclassed to add context access to ACL subject
123 // validation. If you use ACL subject classes that need context beyond the credential
124 // structure itself, add that context to (a subclass of) CredentialsContext, pass that
125 // to ObjectAcl::validate() along with the credentials, and have the Subject implementation
126 // access validationContext.environment().
128 class AclValidationEnvironment
{
130 virtual ~AclValidationEnvironment(); // ensure virtual methods (need dynamic_cast)
135 // An AclValidationContext holds credential information in a semi-transparent
136 // form. It's designed to provide a uniform representation of credentials, plus
137 // any (trusted path and/or implicit) context information useful for ACL validation.
139 class AclValidationContext
{
141 AclValidationContext(const AccessCredentials
*cred
,
142 AclAuthorization auth
, AclValidationEnvironment
*env
= NULL
)
143 : mCred(cred
), mAuth(auth
), mEnv(env
) { }
144 AclValidationContext(const AclValidationContext
&ctx
)
145 : mCred(ctx
.mCred
), mAuth(ctx
.mAuth
), mEnv(ctx
.mEnv
) { }
146 virtual ~AclValidationContext();
148 // access to (suitably focused) sample set
149 virtual uint32
count() const = 0; // number of samples
150 virtual const TypedList
&sample(uint32 n
) const = 0; // retrieve one sample
151 const TypedList
&operator [] (uint32 n
) const { return sample(n
); }
154 AclAuthorization
authorization() const { return mAuth
; }
156 Env
*environment() const { return dynamic_cast<Env
*>(mEnv
); }
158 //@@@ add certificate access functions
159 //@@@ add callback management
162 const AccessCredentials
*mCred
; // original credentials
163 AclAuthorization mAuth
; // action requested
164 AclValidationEnvironment
*mEnv
; // environmental context (if any)
169 // An in-memory ACL object.
170 // This class implements an ACL-for-a-protected-object. It is complete in that
171 // it provides full ACL management functionality. You still need to (globally)
172 // register makers for the ACL subject types you want to use.
173 // Note that ObjectAcl does no integrity checking. ObjectAcl objects need to be
174 // protected from hostile access (by e.g. address space separation), and exported
175 // ACLs need to be protected somehow (by hiding, signing, or whatever works in
179 friend AclSubject::Maker::Maker(CSSM_ACL_SUBJECT_TYPE
);
182 typedef RefPointer
<AclSubject
> AclSubjectPointer
;
184 typedef LowLevelMemoryUtilities::Writer Writer
;
185 typedef LowLevelMemoryUtilities::Reader Reader
;
188 ObjectAcl(CssmAllocator
&alloc
);
189 ObjectAcl(const AclEntryPrototype
&proto
, CssmAllocator
&alloc
);
190 virtual ~ObjectAcl();
192 CssmAllocator
&allocator
;
194 // access control validation: succeed or throw exception
195 void validate(AclAuthorization auth
, const AccessCredentials
*cred
,
196 AclValidationEnvironment
*env
= NULL
) const;
197 void validateOwner(AclAuthorization authorizationHint
, const AccessCredentials
*cred
,
198 AclValidationEnvironment
*env
= NULL
) const;
200 // CSSM-style ACL access operations
201 // (Gets are not const because underlying implementations usually want them writable)
202 void cssmGetAcl(const char *tag
, uint32
&count
, AclEntryInfo
* &acls
);
203 void cssmChangeAcl(const AclEdit
&edit
, const AccessCredentials
*cred
,
204 AclValidationEnvironment
*env
= NULL
);
205 void cssmGetOwner(AclOwnerPrototype
&owner
);
206 void cssmChangeOwner(const AclOwnerPrototype
&newOwner
, const AccessCredentials
*cred
,
207 AclValidationEnvironment
*env
= NULL
);
209 void cssmSetInitial(const AclEntryPrototype
&proto
);
210 void cssmSetInitial(const AclSubjectPointer
&subject
);
212 // Acl I/O (to/from memory blobs)
213 void exportBlob(CssmData
&publicBlob
, CssmData
&privateBlob
);
214 void importBlob(const void *publicBlob
, const void *privateBlob
);
217 IFDUMP(virtual void debugDump(const char *what
= NULL
) const);
222 AclSubjectPointer subject
; // subject representation
223 bool delegate
; // delegation flag
225 Entry() { } // make invalid Entry
227 void toOwnerInfo(CSSM_ACL_OWNER_PROTOTYPE
&info
,
228 CssmAllocator
&alloc
) const; // encode copy in CSSM format
230 virtual bool authorizes(AclAuthorization auth
) const = 0;
231 virtual bool validate(const AclValidationContext
&ctx
) const = 0;
233 template <class Action
>
234 void exportBlob(Action
&pub
, Action
&priv
)
237 CSSM_ACL_SUBJECT_TYPE type
= subject
->type(); pub(type
);
238 subject
->exportBlob(pub
, priv
);
240 void importBlob(Reader
&pub
, Reader
&priv
);
242 IFDUMP(virtual void debugDump() const);
245 void init(const AclSubjectPointer
&subject
, bool delegate
= false);
246 void init(const TypedList
&subject
, bool delegate
= false) { init(make(subject
), delegate
); }
249 Entry(const AclEntryPrototype
&proto
) { init(proto
.subject(), proto
.delegate()); }
250 Entry(const AclOwnerPrototype
&proto
) { init(proto
.subject()); }
251 Entry(const AclSubjectPointer
&subject
) { init(subject
); }
255 class OwnerEntry
: public Entry
{
257 OwnerEntry() { } // invalid OwnerEntry
258 template <class Input
>
259 OwnerEntry(const Input
&owner
) : Entry(owner
) { }
260 OwnerEntry(const AclSubjectPointer
&subject
) : Entry(subject
) { }
262 bool authorizes(AclAuthorization auth
) const;
263 bool validate(const AclValidationContext
&ctx
) const;
266 class AclEntry
: public Entry
{
268 string tag
; // entry tag
269 AclAuthorizationSet authorizations
; // set of authorizations
270 bool authorizesAnything
; // has the _ANY authorization tag
271 //@@@ time range not yet implemented
272 uint32 handle
; // entry handle
274 AclEntry() { } // invalid AclEntry
275 AclEntry(const AclSubjectPointer
&subject
);
276 AclEntry(const AclEntryPrototype
&proto
);
278 void toEntryInfo(CSSM_ACL_ENTRY_PROTOTYPE
&info
,
279 CssmAllocator
&alloc
) const; // encode copy in CSSM format
281 bool authorizes(AclAuthorization auth
) const;
282 bool validate(const AclValidationContext
&ctx
) const;
284 template <class Action
>
285 void exportBlob(Action
&pub
, Action
&priv
)
287 Entry::exportBlob(pub
, priv
);
288 const char *s
= tag
.c_str(); pub(s
);
289 pub(authorizesAnything
);
290 if (!authorizesAnything
) {
291 uint32 count
= authorizations
.size(); pub(count
);
292 for (AclAuthorizationSet::iterator it
= authorizations
.begin();
293 it
!= authorizations
.end(); it
++) {
294 AclAuthorization auth
= *it
; pub(auth
);
297 //@@@ export time range
299 void importBlob(Reader
&pub
, Reader
&priv
);
301 IFDUMP(void debugDump() const);
304 typedef multimap
<string
, AclEntry
> EntryMap
;
305 typedef EntryMap::iterator Iterator
;
306 typedef EntryMap::const_iterator ConstIterator
;
308 Iterator
begin() { return entries
.begin(); }
309 Iterator
end() { return entries
.end(); }
310 ConstIterator
begin() const { return entries
.begin(); }
311 ConstIterator
end() const { return entries
.end(); }
313 unsigned int getRange(const char *tag
, pair
<ConstIterator
, ConstIterator
> &range
) const;
314 Iterator
findEntryHandle(CSSM_ACL_HANDLE handle
);
316 // construct an AclSubject through the Maker registry (by subject type)
317 static AclSubject
*make(const TypedList
&list
); // make from CSSM form
318 static AclSubject
*make(CSSM_ACL_SUBJECT_TYPE type
,
319 Reader
&pub
, Reader
&priv
); // make from export form
322 EntryMap entries
; // ACL entries indexed by tag
323 OwnerEntry owner
; // ACL owner entry
324 uint32 nextHandle
; // next unused entry handle value
327 typedef map
<CSSM_ACL_SUBJECT_TYPE
, AclSubject::Maker
*> MakerMap
;
328 static ModuleNexus
<MakerMap
> makers
; // registered subject Makers
330 static AclSubject::Maker
&makerFor(CSSM_ACL_SUBJECT_TYPE type
);
335 // This bastard child of two different data structure sets has no natural home.
336 // We'll take pity on it here.
338 class ResourceControlContext
: public PodWrapper
<ResourceControlContext
, CSSM_RESOURCE_CONTROL_CONTEXT
> {
340 ResourceControlContext() { }
341 ResourceControlContext(const AclEntryInput
&initial
, AccessCredentials
*cred
= NULL
)
342 { InitialAclEntry
= initial
; AccessCred
= cred
; }
344 operator AclEntryInput
&() { return AclEntryInput::overlay(InitialAclEntry
); }
345 AccessCredentials
*credentials() { return AccessCredentials::overlay(AccessCred
); }
348 } // end namespace Security