2 * Copyright (c) 2000-2004,2006,2011-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 // objectacl - core implementation of an ACL-bearing object
28 #include <security_cdsa_utilities/objectacl.h>
29 #include <security_cdsa_utilities/cssmbridge.h>
30 #include <security_utilities/endian.h>
31 #include <security_utilities/debugging.h>
32 #include <security_utilities/threading.h>
36 #include <security_cdsa_utilities/acl_preauth.h> //@@@ impure - will be removed
38 using namespace DataWalkers
;
42 // The static map of available ACL subject makers.
43 // These are the kinds of ACL subjects we can deal with.
45 ModuleNexus
<ObjectAcl::MakerMap
> ObjectAcl::makers
;
46 ModuleNexus
<NormalMutex
> ObjectAcl::makersMutex
;
50 // Create an ObjectAcl
52 ObjectAcl::ObjectAcl(Allocator
&alloc
) : allocator(alloc
), mNextHandle(1)
56 ObjectAcl::ObjectAcl(const AclEntryPrototype
&proto
, Allocator
&alloc
)
57 : allocator(alloc
), mNextHandle(1)
59 cssmSetInitial(proto
);
62 ObjectAcl::~ObjectAcl()
67 // Set an "initial ACL" from a CSSM-style initial ACL argument.
68 // This will replace the owner, as well as replace the entire ACL
69 // with a single-item slot, as per CSSM specification.
71 void ObjectAcl::cssmSetInitial(const AclEntryPrototype
&proto
)
73 mOwner
= OwnerEntry(proto
);
74 add(proto
.s_tag(), proto
);
75 IFDUMPING("acl", debugDump("create/proto"));
78 void ObjectAcl::cssmSetInitial(const AclSubjectPointer
&subject
)
80 mOwner
= OwnerEntry(subject
);
82 IFDUMPING("acl", debugDump("create/subject"));
85 ObjectAcl::Entry::~Entry()
91 // ObjectAcl::validate validates an access authorization claim.
92 // Returns normally if 'auth' is granted to the bearer of 'cred'.
93 // Otherwise, throws a suitable (ACL-related) CssmError exception.
95 bool ObjectAcl::validates(AclAuthorization auth
, const AccessCredentials
*cred
,
96 AclValidationEnvironment
*env
)
98 BaseValidationContext
ctx(cred
, auth
, env
);
99 return validates(ctx
);
102 bool ObjectAcl::validates(AclValidationContext
&ctx
)
104 // make sure we are ready to go
107 IFDUMPING("acleval", Debug::dump("<<WANT(%d)<", ctx
.authorization()));
109 //@@@ should pre-screen based on requested auth, maybe?
111 #if defined(ACL_OMNIPOTENT_OWNER)
112 // try owner (owner can do anything)
113 if (mOwner
.validates(ctx
))
115 #endif //ACL_OMNIPOTENT_OWNER
117 // try applicable ACLs
118 pair
<EntryMap::const_iterator
, EntryMap::const_iterator
> range
;
119 if (getRange(ctx
.s_credTag(), range
) == 0) {
121 secinfo("SecAccess", "no tag for cred tag: \"%s\"", ctx
.s_credTag().c_str());
122 CssmError::throwMe(CSSM_ERRCODE_ACL_ENTRY_TAG_NOT_FOUND
);
124 // try each entry in turn
125 for (EntryMap::const_iterator it
= range
.first
; it
!= range
.second
; it
++) {
126 const AclEntry
&slot
= it
->second
;
127 IFDUMPING("acleval", (Debug::dump(" EVAL["), slot
.debugDump(), Debug::dump("]")));
128 if (slot
.authorizes(ctx
.authorization())) {
129 ctx
.init(this, slot
.subject
);
130 ctx
.entryTag(slot
.tag
);
131 if (slot
.validates(ctx
)) {
132 IFDUMPING("acleval", Debug::dump(">PASS>>\n"));
133 return true; // passed
135 IFDUMPING("acleval", Debug::dump(" NO"));
138 IFDUMPING("acleval", Debug::dump(">FAIL>>\n"));
139 return false; // no joy
142 void ObjectAcl::validate(AclAuthorization auth
, const AccessCredentials
*cred
,
143 AclValidationEnvironment
*env
)
145 if (!validates(auth
, cred
, env
))
146 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
149 void ObjectAcl::validate(AclValidationContext
&ctx
)
152 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
156 void ObjectAcl::validateOwner(AclAuthorization authorizationHint
,
157 const AccessCredentials
*cred
, AclValidationEnvironment
*env
)
159 BaseValidationContext
ctx(cred
, authorizationHint
, env
);
163 void ObjectAcl::validateOwner(AclValidationContext
&ctx
)
167 ctx
.init(this, mOwner
.subject
);
168 if (mOwner
.validates(ctx
))
170 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
175 // Export an ObjectAcl to two memory blobs: public and private data separated.
176 // This is a standard two-pass size+copy operation.
178 void ObjectAcl::exportBlob(CssmData
&publicBlob
, CssmData
&privateBlob
)
181 Writer::Counter pubSize
, privSize
;
182 Endian
<uint32
> entryCount
= (uint32
)mEntries
.size();
183 mOwner
.exportBlob(pubSize
, privSize
);
185 for (EntryMap::iterator it
= begin(); it
!= end(); it
++)
186 it
->second
.exportBlob(pubSize
, privSize
);
187 publicBlob
= CssmData(allocator
.malloc(pubSize
), pubSize
);
188 privateBlob
= CssmData(allocator
.malloc(privSize
), privSize
);
189 Writer
pubWriter(publicBlob
), privWriter(privateBlob
);
190 mOwner
.exportBlob(pubWriter
, privWriter
);
191 pubWriter(entryCount
);
192 for (EntryMap::iterator it
= begin(); it
!= end(); it
++)
193 it
->second
.exportBlob(pubWriter
, privWriter
);
194 IFDUMPING("acl", debugDump("exported"));
199 // Import an ObjectAcl's contents from two memory blobs representing public and
200 // private contents, respectively. These blobs must have been generated by the
202 // Prior contents (if any) are deleted and replaced.
204 void ObjectAcl::importBlob(const void *publicBlob
, const void *privateBlob
)
206 Reader
pubReader(publicBlob
), privReader(privateBlob
);
207 mOwner
.importBlob(pubReader
, privReader
);
208 Endian
<uint32
> entryCountIn
; pubReader(entryCountIn
);
209 uint32 entryCount
= entryCountIn
;
211 mEntries
.erase(begin(), end());
212 for (uint32 n
= 0; n
< entryCount
; n
++) {
214 newEntry
.importBlob(pubReader
, privReader
);
215 add(newEntry
.tag
, newEntry
);
217 IFDUMPING("acl", debugDump("imported"));
222 // Import/export helpers for subjects.
223 // This is exported to (subject implementation) callers to maintain consistency
224 // in binary format handling.
226 AclSubject
*ObjectAcl::importSubject(Reader
&pub
, Reader
&priv
)
228 Endian
<uint32
> typeAndVersion
; pub(typeAndVersion
);
229 return make(typeAndVersion
, pub
, priv
);
234 // Setup/update hooks
236 void ObjectAcl::instantiateAcl()
238 // nothing by default
241 void ObjectAcl::changedAcl()
243 // nothing by default
248 // ACL utility methods
250 unsigned int ObjectAcl::getRange(const std::string
&tag
,
251 pair
<EntryMap::const_iterator
, EntryMap::const_iterator
> &range
, bool tolerant
/* = false */) const
253 if (!tag
.empty()) { // tag restriction in effect
254 secinfo("SecAccess", "looking for ACL entries matching tag: \"%s\"", tag
.c_str());
255 range
= mEntries
.equal_range(tag
);
256 unsigned int count
= (unsigned int)mEntries
.count(tag
);
257 if (count
== 0 && !tolerant
)
258 CssmError::throwMe(CSSM_ERRCODE_ACL_ENTRY_TAG_NOT_FOUND
);
260 } else { // try all tags
261 secinfo("SecAccess", "no tag given; looking for all ACL entries");
262 range
.first
= mEntries
.begin();
263 range
.second
= mEntries
.end();
264 return (unsigned int)mEntries
.size();
268 ObjectAcl::EntryMap::iterator
ObjectAcl::findEntryHandle(CSSM_ACL_HANDLE handle
)
270 for (EntryMap::iterator it
= mEntries
.begin(); it
!= mEntries
.end(); it
++)
271 if (it
->second
.handle
== handle
)
273 CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE
); //%%% imprecise error code
278 // CSSM style ACL access and modification functions.
280 void ObjectAcl::cssmGetAcl(const char *tag
, uint32
&count
, AclEntryInfo
* &acls
)
283 pair
<EntryMap::const_iterator
, EntryMap::const_iterator
> range
;
284 count
= getRange(tag
? tag
: "", range
);
285 acls
= allocator
.alloc
<AclEntryInfo
>(count
);
288 secinfo("SecAccess", "getting the ACL for %p (%d entries) tag: %s", this, count
, tag
? tag
: "<none>");
290 for (EntryMap::const_iterator it
= range
.first
; it
!= range
.second
; it
++, n
++) {
291 acls
[n
].EntryHandle
= it
->second
.handle
;
292 it
->second
.toEntryInfo(acls
[n
].EntryPublicInfo
, allocator
);
293 secinfo("SecAccess", "found an entry of type %d", acls
[n
].EntryPublicInfo
.TypedSubject
.Head
->WordID
);
298 void ObjectAcl::cssmChangeAcl(const AclEdit
&edit
,
299 const AccessCredentials
*cred
, AclValidationEnvironment
*env
, const char *preserveTag
)
301 IFDUMPING("acl", debugDump("acl-change-from"));
303 // make sure we're ready to go
306 // validate access credentials
307 validateOwner(CSSM_ACL_AUTHORIZATION_CHANGE_ACL
, cred
, env
);
309 // what is Thy wish, effendi?
310 switch (edit
.EditMode
) {
311 case CSSM_ACL_EDIT_MODE_ADD
: {
312 secinfo("SecAccess", "adding ACL for %p (%ld) while preserving: %s", this, edit
.handle(), preserveTag
);
313 const AclEntryInput
&input
= Required(edit
.newEntry());
314 if (preserveTag
&& input
.proto().s_tag() == preserveTag
)
315 MacOSError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
316 add(input
.proto().s_tag(), input
.proto());
317 secinfo("SecAccess", "subject type is %d", input
.proto().TypedSubject
.Head
->WordID
);
320 case CSSM_ACL_EDIT_MODE_REPLACE
: {
321 secinfo("SecAccess", "replacing ACL for %p (%ld to %p) while preserving: %s", this, edit
.handle(), edit
.newEntry(), preserveTag
);
322 // keep the handle, and try for some modicum of atomicity
323 EntryMap::iterator it
= findEntryHandle(edit
.handle());
324 if (preserveTag
&& it
->second
.tag
== preserveTag
)
325 MacOSError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
326 AclEntryPrototype proto2
;
327 it
->second
.toEntryInfo(proto2
, allocator
);
328 secinfo("SecAccess", "subject type was %d", proto2
.TypedSubject
.Head
->WordID
);
329 DataWalkers::chunkFree(proto2
, allocator
);
331 AclEntryPrototype proto
= Required(edit
.newEntry()).proto(); // (bypassing callbacks)
332 add(proto
.s_tag(), proto
, edit
.handle());
333 secinfo("SecAccess", "new subject type is %d", proto
.TypedSubject
.Head
->WordID
);
337 case CSSM_ACL_EDIT_MODE_DELETE
: {
338 secinfo("SecAccess", "deleting ACL for %p (%ld) while preserving: %s", this, edit
.handle(), preserveTag
);
339 EntryMap::iterator it
= findEntryHandle(edit
.handle());
340 if (preserveTag
&& it
->second
.tag
== preserveTag
)
341 MacOSError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
343 AclEntryPrototype proto
;
344 it
->second
.toEntryInfo(proto
, allocator
);
345 secinfo("SecAccess", "subject type was %d", proto
.TypedSubject
.Head
->WordID
);
346 DataWalkers::chunkFree(proto
, allocator
);
352 secinfo("SecAccess", "no idea what this CSSM_ACL_EDIT type is: %d", edit
.EditMode
);
353 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_EDIT_MODE
);
359 IFDUMPING("acl", debugDump("acl-change-to"));
362 void ObjectAcl::cssmGetOwner(AclOwnerPrototype
&outOwner
)
365 outOwner
.TypedSubject
= mOwner
.subject
->toList(allocator
);
366 outOwner
.Delegate
= mOwner
.delegate
;
368 secinfo("SecAccess", "%p: getting the owner ACL: type %d", this, outOwner
.TypedSubject
.Head
->WordID
);
371 void ObjectAcl::cssmChangeOwner(const AclOwnerPrototype
&newOwner
,
372 const AccessCredentials
*cred
, AclValidationEnvironment
*env
)
374 IFDUMPING("acl", debugDump("owner-change-from"));
378 // only the owner entry can match
379 validateOwner(CSSM_ACL_AUTHORIZATION_CHANGE_OWNER
, cred
, env
);
384 secinfo("SecAccess", "%p: new owner's type is %d", this, newOwner
.subject().Head
->WordID
);
388 IFDUMPING("acl", debugDump("owner-change-to"));
393 // Load a set of ACL entries from an AclEntryInfo array.
394 // This completely replaces the ACL's entries.
395 // Note that we will adopt the handles in the infos, so they better be proper
396 // (unique, nonzero).
398 template <class Input
>
399 void ObjectAcl::owner(const Input
&input
)
401 IFDUMPING("acl", debugDump("owner-load-old"));
402 mOwner
= OwnerEntry(input
);
403 IFDUMPING("acl", debugDump("owner-load-new"));
406 template void ObjectAcl::owner(const AclOwnerPrototype
&);
407 template void ObjectAcl::owner(const AclSubjectPointer
&);
410 void ObjectAcl::entries(uint32 count
, const AclEntryInfo
*info
)
412 IFDUMPING("acl", debugDump("entries-load-old"));
413 mEntries
.erase(mEntries
.begin(), mEntries
.end());
414 for (uint32 n
= 0; n
< count
; n
++, info
++)
415 add(info
->proto().s_tag(), info
->proto());
416 IFDUMPING("acl", debugDump("entries-load-new"));
421 // Clear out the ACL and return it to un-initialized state
423 void ObjectAcl::clear()
425 mOwner
= OwnerEntry();
426 mEntries
.erase(mEntries
.begin(), mEntries
.end());
427 secinfo("acl", "%p cleared", this);
432 // Common gate to add an ACL entry
434 void ObjectAcl::add(const std::string
&tag
, const AclEntry
&newEntry
)
436 add(tag
, newEntry
, mNextHandle
++);
439 void ObjectAcl::add(const std::string
&tag
, AclEntry newEntry
, CSSM_ACL_HANDLE handle
)
442 //@@@ This should use a hook-registry mechanism. But for now, we are explicit:
443 if (!newEntry
.authorizesAnything
) {
444 for (AclAuthorizationSet::const_iterator it
= newEntry
.authorizations
.begin();
445 it
!= newEntry
.authorizations
.end(); it
++)
446 if (*it
>= CSSM_ACL_AUTHORIZATION_PREAUTH_BASE
&&
447 *it
< CSSM_ACL_AUTHORIZATION_PREAUTH_END
) {
448 // preauthorization right - special handling
449 if (newEntry
.subject
->type() != CSSM_ACL_SUBJECT_TYPE_PREAUTH_SOURCE
)
451 new PreAuthorizationAcls::SourceAclSubject(newEntry
.subject
);
455 mEntries
.insert(make_pair(tag
, newEntry
))->second
.handle
= handle
;
456 if (handle
>= mNextHandle
)
457 mNextHandle
= handle
+ 1; // don't reuse this handle (in this ACL)
462 // Common features of ACL entries/owners
464 void ObjectAcl::Entry::init(const AclSubjectPointer
&subject
, bool delegate
)
466 this->subject
= subject
;
467 this->delegate
= delegate
;
470 void ObjectAcl::Entry::importBlob(Reader
&pub
, Reader
&priv
)
472 // the delegation flag is 4 bytes for historic reasons
477 subject
= importSubject(pub
, priv
);
482 // An OwnerEntry is a restricted EntryPrototype for use as the ACL owner.
484 bool ObjectAcl::OwnerEntry::authorizes(AclAuthorization
) const
486 return true; // owner can do anything
489 bool ObjectAcl::OwnerEntry::validates(const AclValidationContext
&ctx
) const
491 if (AclValidationEnvironment
* env
= ctx
.environment())
492 if (env
->forceSuccess
)
494 return subject
->validates(ctx
); // simple subject match - no strings attached
499 // An AclEntry has some extra goodies
501 ObjectAcl::AclEntry::AclEntry(const AclEntryPrototype
&proto
) : Entry(proto
)
504 if (proto
.authorization().contains(CSSM_ACL_AUTHORIZATION_ANY
))
505 authorizesAnything
= true; // anything else wouldn't add anything
506 else if (proto
.authorization().empty())
507 authorizesAnything
= true; // not in standard, but common sense
509 authorizesAnything
= false;
510 authorizations
= proto
.authorization();
512 //@@@ not setting time range
513 // handle = not set here. Set by caller when the AclEntry is created.
516 ObjectAcl::AclEntry::AclEntry(const AclSubjectPointer
&subject
) : Entry(subject
)
518 authorizesAnything
= true; // by default, everything
519 //@@@ not setting time range
522 void ObjectAcl::AclEntry::toEntryInfo(CSSM_ACL_ENTRY_PROTOTYPE
&info
, Allocator
&alloc
) const
524 info
.TypedSubject
= subject
->toList(alloc
);
525 info
.Delegate
= delegate
;
526 info
.Authorization
= authorizesAnything
?
527 AuthorizationGroup(CSSM_ACL_AUTHORIZATION_ANY
, alloc
) :
528 AuthorizationGroup(authorizations
, alloc
);
529 //@@@ info.TimeRange =
530 assert(tag
.length() <= CSSM_MODULE_STRING_SIZE
);
531 memcpy(info
.EntryTag
, tag
.c_str(), tag
.length() + 1);
534 bool ObjectAcl::AclEntry::authorizes(AclAuthorization auth
) const
536 return authorizesAnything
|| authorizations
.find(auth
) != authorizations
.end();
539 bool ObjectAcl::AclEntry::validates(const AclValidationContext
&ctx
) const
541 //@@@ not checking time ranges
542 return subject
->validates(ctx
);
545 void ObjectAcl::AclEntry::addAuthorization(AclAuthorization auth
)
547 authorizations
.insert(auth
);
548 authorizesAnything
= false;
552 void ObjectAcl::AclEntry::importBlob(Reader
&pub
, Reader
&priv
)
554 Entry::importBlob(pub
, priv
);
555 const char *s
; pub(s
); tag
= s
;
557 // authorizesAnything is on disk as a 4-byte flag
558 Endian
<uint32
> tmpAuthorizesAnything
;
559 pub(tmpAuthorizesAnything
);
560 authorizesAnything
= tmpAuthorizesAnything
;
562 authorizations
.erase(authorizations
.begin(), authorizations
.end());
563 if (!authorizesAnything
) {
564 Endian
<uint32
> countIn
; pub(countIn
);
565 uint32 count
= countIn
;
567 for (uint32 n
= 0; n
< count
; n
++) {
568 Endian
<AclAuthorization
> auth
; pub(auth
);
569 authorizations
.insert(auth
);
572 //@@@ import time range
577 // Subject factory and makers
579 AclSubject::Maker::Maker(CSSM_ACL_SUBJECT_TYPE type
)
582 StLock
<Mutex
> _(ObjectAcl::makersMutex());
583 ObjectAcl::makers()[type
] = this;
586 AclSubject
*ObjectAcl::make(const TypedList
&list
)
588 if (!list
.isProper())
589 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE
);
590 return makerFor(list
.type()).make(list
);
593 AclSubject
*ObjectAcl::make(uint32 typeAndVersion
, Reader
&pub
, Reader
&priv
)
595 // this type is encoded as (version << 24) | type
596 return makerFor(typeAndVersion
& ~AclSubject::versionMask
).make(typeAndVersion
>> AclSubject::versionShift
, pub
, priv
);
599 AclSubject::Maker
&ObjectAcl::makerFor(CSSM_ACL_SUBJECT_TYPE type
)
601 StLock
<Mutex
> _(ObjectAcl::makersMutex());
602 AclSubject::Maker
*maker
= makers()[type
];
604 CssmError::throwMe(CSSM_ERRCODE_ACL_SUBJECT_TYPE_NOT_SUPPORTED
);
610 // Parsing helper for subject makers.
611 // Note that count/array exclude the first element of list, which is the subject type wordid.
613 void AclSubject::Maker::crack(const CssmList
&list
, uint32 count
, ListElement
**array
, ...)
615 if (count
!= list
.length() - 1)
616 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE
);
619 va_start(args
, array
);
620 ListElement
*elem
= list
.first()->next();
621 for (uint32 n
= 0; n
< count
; n
++, elem
= elem
->next()) {
622 CSSM_LIST_ELEMENT_TYPE expectedType
= va_arg(args
, CSSM_LIST_ELEMENT_TYPE
);
623 if (elem
->type() != expectedType
)
624 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE
);
631 CSSM_WORDID_TYPE
AclSubject::Maker::getWord(const ListElement
&elem
,
632 int min
/*= 0*/, int max
/*= INT_MAX*/)
634 if (elem
.type() != CSSM_LIST_ELEMENT_WORDID
)
635 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE
);
636 CSSM_WORDID_TYPE value
= elem
;
637 if (value
< min
|| value
> max
)
638 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE
);
644 // Debug dumping support.
645 // Leave the ObjectAcl::debugDump method in (stubbed out)
646 // to keep the virtual table layout stable, and to allow
647 // proper linking in weird mix-and-match scenarios.
649 void ObjectAcl::debugDump(const char *what
) const
651 #if defined(DEBUGDUMP)
654 Debug::dump("%p ACL %s: %d entries\n", this, what
, int(mEntries
.size()));
655 Debug::dump(" OWNER ["); mOwner
.debugDump(); Debug::dump("]\n");
656 for (EntryMap::const_iterator it
= begin(); it
!= end(); it
++) {
657 const AclEntry
&ent
= it
->second
;
658 Debug::dump(" (%ld:%s) [", ent
.handle
, ent
.tag
.c_str());
662 Debug::dump("%p ACL END\n", this);
666 #if defined(DEBUGDUMP)
668 void ObjectAcl::Entry::debugDump() const
671 if (AclSubject::Version v
= subject
->version())
672 Debug::dump("V=%d ", v
);
673 subject
->debugDump();
675 Debug::dump("NULL subject");
678 Debug::dump(" DELEGATE");
681 void ObjectAcl::AclEntry::debugDump() const
684 if (authorizesAnything
) {
685 Debug::dump(" auth(ALL)");
687 Debug::dump(" auth(");
688 for (AclAuthorizationSet::iterator it
= authorizations
.begin();
689 it
!= authorizations
.end(); it
++) {
690 if (*it
>= CSSM_ACL_AUTHORIZATION_PREAUTH_BASE
691 && *it
< CSSM_ACL_AUTHORIZATION_PREAUTH_END
)
692 Debug::dump(" PRE(%d)", *it
- CSSM_ACL_AUTHORIZATION_PREAUTH_BASE
);
694 Debug::dump(" %d", *it
);