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 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
);