]> git.saurik.com Git - apple/security.git/blob - Security/libsecurity_cdsa_utilities/lib/objectacl.cpp
Security-57031.40.6.tar.gz
[apple/security.git] / Security / libsecurity_cdsa_utilities / lib / objectacl.cpp
1 /*
2 * Copyright (c) 2000-2004,2006,2011-2014 Apple 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 #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 <algorithm>
33 #include <cstdarg>
34
35 #include <security_cdsa_utilities/acl_preauth.h> //@@@ impure - will be removed
36
37 using namespace DataWalkers;
38
39
40 //
41 // The static map of available ACL subject makers.
42 // These are the kinds of ACL subjects we can deal with.
43 //
44 ModuleNexus<ObjectAcl::MakerMap> ObjectAcl::makers;
45
46
47 //
48 // Create an ObjectAcl
49 //
50 ObjectAcl::ObjectAcl(Allocator &alloc) : allocator(alloc), mNextHandle(1)
51 {
52 }
53
54 ObjectAcl::ObjectAcl(const AclEntryPrototype &proto, Allocator &alloc)
55 : allocator(alloc), mNextHandle(1)
56 {
57 cssmSetInitial(proto);
58 }
59
60 ObjectAcl::~ObjectAcl()
61 { }
62
63
64 //
65 // Set an "initial ACL" from a CSSM-style initial ACL argument.
66 // This will replace the owner, as well as replace the entire ACL
67 // with a single-item slot, as per CSSM specification.
68 //
69 void ObjectAcl::cssmSetInitial(const AclEntryPrototype &proto)
70 {
71 mOwner = OwnerEntry(proto);
72 add(proto.s_tag(), proto);
73 IFDUMPING("acl", debugDump("create/proto"));
74 }
75
76 void ObjectAcl::cssmSetInitial(const AclSubjectPointer &subject)
77 {
78 mOwner = OwnerEntry(subject);
79 add("", subject);
80 IFDUMPING("acl", debugDump("create/subject"));
81 }
82
83 ObjectAcl::Entry::~Entry()
84 {
85 }
86
87
88 //
89 // ObjectAcl::validate validates an access authorization claim.
90 // Returns normally if 'auth' is granted to the bearer of 'cred'.
91 // Otherwise, throws a suitable (ACL-related) CssmError exception.
92 //
93 class BaseValidationContext : public AclValidationContext {
94 public:
95 BaseValidationContext(const AccessCredentials *cred,
96 AclAuthorization auth, AclValidationEnvironment *env)
97 : AclValidationContext(cred, auth, env) { }
98
99 uint32 count() const { return cred() ? cred()->samples().length() : 0; }
100 uint32 size() const { return count(); }
101 const TypedList &sample(uint32 n) const
102 { assert(n < count()); return cred()->samples()[n]; }
103
104 void matched(const TypedList *) const { } // ignore match info
105 };
106
107
108 bool ObjectAcl::validates(AclAuthorization auth, const AccessCredentials *cred,
109 AclValidationEnvironment *env)
110 {
111 BaseValidationContext ctx(cred, auth, env);
112 return validates(ctx);
113 }
114
115 bool ObjectAcl::validates(AclValidationContext &ctx)
116 {
117 // make sure we are ready to go
118 instantiateAcl();
119
120 IFDUMPING("acleval", Debug::dump("<<WANT(%d)<", ctx.authorization()));
121
122 //@@@ should pre-screen based on requested auth, maybe?
123
124 #if defined(ACL_OMNIPOTENT_OWNER)
125 // try owner (owner can do anything)
126 if (mOwner.validate(ctx))
127 return;
128 #endif //ACL_OMNIPOTENT_OWNER
129
130 // try applicable ACLs
131 pair<EntryMap::const_iterator, EntryMap::const_iterator> range;
132 if (getRange(ctx.s_credTag(), range) == 0) // no such tag
133 CssmError::throwMe(CSSM_ERRCODE_ACL_ENTRY_TAG_NOT_FOUND);
134 // try each entry in turn
135 for (EntryMap::const_iterator it = range.first; it != range.second; it++) {
136 const AclEntry &slot = it->second;
137 IFDUMPING("acleval", (Debug::dump(" EVAL["), slot.debugDump(), Debug::dump("]")));
138 if (slot.authorizes(ctx.authorization())) {
139 ctx.init(this, slot.subject);
140 ctx.entryTag(slot.tag);
141 if (slot.validate(ctx)) {
142 IFDUMPING("acleval", Debug::dump(">PASS>>\n"));
143 return true; // passed
144 }
145 IFDUMPING("acleval", Debug::dump(" NO"));
146 }
147 }
148 IFDUMPING("acleval", Debug::dump(">FAIL>>\n"));
149 return false; // no joy
150 }
151
152 void ObjectAcl::validate(AclAuthorization auth, const AccessCredentials *cred,
153 AclValidationEnvironment *env)
154 {
155 if (!validates(auth, cred, env))
156 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
157 }
158
159 void ObjectAcl::validate(AclValidationContext &ctx)
160 {
161 if (!validates(ctx))
162 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
163 }
164
165
166 void ObjectAcl::validateOwner(AclAuthorization authorizationHint,
167 const AccessCredentials *cred, AclValidationEnvironment *env)
168 {
169 BaseValidationContext ctx(cred, authorizationHint, env);
170 validateOwner(ctx);
171 }
172
173 void ObjectAcl::validateOwner(AclValidationContext &ctx)
174 {
175 instantiateAcl();
176
177 ctx.init(this, mOwner.subject);
178 if (mOwner.validate(ctx))
179 return;
180 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
181 }
182
183
184 //
185 // Export an ObjectAcl to two memory blobs: public and private data separated.
186 // This is a standard two-pass size+copy operation.
187 //
188 void ObjectAcl::exportBlob(CssmData &publicBlob, CssmData &privateBlob)
189 {
190 instantiateAcl();
191 Writer::Counter pubSize, privSize;
192 Endian<uint32> entryCount = (uint32)mEntries.size();
193 mOwner.exportBlob(pubSize, privSize);
194 pubSize(entryCount);
195 for (EntryMap::iterator it = begin(); it != end(); it++)
196 it->second.exportBlob(pubSize, privSize);
197 publicBlob = CssmData(allocator.malloc(pubSize), pubSize);
198 privateBlob = CssmData(allocator.malloc(privSize), privSize);
199 Writer pubWriter(publicBlob), privWriter(privateBlob);
200 mOwner.exportBlob(pubWriter, privWriter);
201 pubWriter(entryCount);
202 for (EntryMap::iterator it = begin(); it != end(); it++)
203 it->second.exportBlob(pubWriter, privWriter);
204 IFDUMPING("acl", debugDump("exported"));
205 }
206
207
208 //
209 // Import an ObjectAcl's contents from two memory blobs representing public and
210 // private contents, respectively. These blobs must have been generated by the
211 // export method.
212 // Prior contents (if any) are deleted and replaced.
213 //
214 void ObjectAcl::importBlob(const void *publicBlob, const void *privateBlob)
215 {
216 Reader pubReader(publicBlob), privReader(privateBlob);
217 mOwner.importBlob(pubReader, privReader);
218 Endian<uint32> entryCountIn; pubReader(entryCountIn);
219 uint32 entryCount = entryCountIn;
220
221 mEntries.erase(begin(), end());
222 for (uint32 n = 0; n < entryCount; n++) {
223 AclEntry newEntry;
224 newEntry.importBlob(pubReader, privReader);
225 add(newEntry.tag, newEntry);
226 }
227 IFDUMPING("acl", debugDump("imported"));
228 }
229
230
231 //
232 // Import/export helpers for subjects.
233 // This is exported to (subject implementation) callers to maintain consistency
234 // in binary format handling.
235 //
236 AclSubject *ObjectAcl::importSubject(Reader &pub, Reader &priv)
237 {
238 Endian<uint32> typeAndVersion; pub(typeAndVersion);
239 return make(typeAndVersion, pub, priv);
240 }
241
242
243 //
244 // Setup/update hooks
245 //
246 void ObjectAcl::instantiateAcl()
247 {
248 // nothing by default
249 }
250
251 void ObjectAcl::changedAcl()
252 {
253 // nothing by default
254 }
255
256
257 //
258 // ACL utility methods
259 //
260 unsigned int ObjectAcl::getRange(const std::string &tag,
261 pair<EntryMap::const_iterator, EntryMap::const_iterator> &range) const
262 {
263 if (!tag.empty()) { // tag restriction in effect
264 range = mEntries.equal_range(tag);
265 unsigned int count = (unsigned int)mEntries.count(tag);
266 if (count == 0)
267 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_ENTRY_TAG);
268 return count;
269 } else { // try all tags
270 range.first = mEntries.begin();
271 range.second = mEntries.end();
272 return (unsigned int)mEntries.size();
273 }
274 }
275
276 ObjectAcl::EntryMap::iterator ObjectAcl::findEntryHandle(CSSM_ACL_HANDLE handle)
277 {
278 for (EntryMap::iterator it = mEntries.begin(); it != mEntries.end(); it++)
279 if (it->second.handle == handle)
280 return it;
281 CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE); //%%% imprecise error code
282 }
283
284
285 //
286 // CSSM style ACL access and modification functions.
287 //
288 void ObjectAcl::cssmGetAcl(const char *tag, uint32 &count, AclEntryInfo * &acls)
289 {
290 instantiateAcl();
291 pair<EntryMap::const_iterator, EntryMap::const_iterator> range;
292 count = getRange(tag ? tag : "", range);
293 acls = allocator.alloc<AclEntryInfo>(count);
294 uint32 n = 0;
295 for (EntryMap::const_iterator it = range.first; it != range.second; it++, n++) {
296 acls[n].EntryHandle = it->second.handle;
297 it->second.toEntryInfo(acls[n].EntryPublicInfo, allocator);
298 }
299 count = n;
300 }
301
302 void ObjectAcl::cssmChangeAcl(const AclEdit &edit,
303 const AccessCredentials *cred, AclValidationEnvironment *env)
304 {
305 IFDUMPING("acl", debugDump("acl-change-from"));
306
307 // make sure we're ready to go
308 instantiateAcl();
309
310 // validate access credentials
311 validateOwner(CSSM_ACL_AUTHORIZATION_CHANGE_ACL, cred, env);
312
313 // what is Thy wish, effendi?
314 switch (edit.EditMode) {
315 case CSSM_ACL_EDIT_MODE_ADD: {
316 const AclEntryInput &input = Required(edit.newEntry());
317 add(input.proto().s_tag(), input.proto());
318 }
319 break;
320 case CSSM_ACL_EDIT_MODE_REPLACE: {
321 // keep the handle, and try for some modicum of atomicity
322 EntryMap::iterator it = findEntryHandle(edit.handle());
323 AclEntryPrototype proto = Required(edit.newEntry()).proto(); // (bypassing callbacks)
324 add(proto.s_tag(), proto, edit.handle());
325 mEntries.erase(it);
326 }
327 break;
328 case CSSM_ACL_EDIT_MODE_DELETE:
329 mEntries.erase(findEntryHandle(edit.OldEntryHandle));
330 break;
331 default:
332 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_EDIT_MODE);
333 }
334
335 // notify change
336 changedAcl();
337
338 IFDUMPING("acl", debugDump("acl-change-to"));
339 }
340
341 void ObjectAcl::cssmGetOwner(AclOwnerPrototype &outOwner)
342 {
343 instantiateAcl();
344 outOwner.TypedSubject = mOwner.subject->toList(allocator);
345 outOwner.Delegate = mOwner.delegate;
346 }
347
348 void ObjectAcl::cssmChangeOwner(const AclOwnerPrototype &newOwner,
349 const AccessCredentials *cred, AclValidationEnvironment *env)
350 {
351 IFDUMPING("acl", debugDump("owner-change-from"));
352
353 instantiateAcl();
354
355 // only the owner entry can match
356 validateOwner(CSSM_ACL_AUTHORIZATION_CHANGE_OWNER, cred, env);
357
358 // okay, replace it
359 mOwner = newOwner;
360
361 changedAcl();
362
363 IFDUMPING("acl", debugDump("owner-change-to"));
364 }
365
366
367 //
368 // Load a set of ACL entries from an AclEntryInfo array.
369 // This completely replaces the ACL's entries.
370 // Note that we will adopt the handles in the infos, so they better be proper
371 // (unique, nonzero).
372 //
373 template <class Input>
374 void ObjectAcl::owner(const Input &input)
375 {
376 IFDUMPING("acl", debugDump("owner-load-old"));
377 mOwner = OwnerEntry(input);
378 IFDUMPING("acl", debugDump("owner-load-new"));
379 }
380
381 template void ObjectAcl::owner(const AclOwnerPrototype &);
382 template void ObjectAcl::owner(const AclSubjectPointer &);
383
384
385 void ObjectAcl::entries(uint32 count, const AclEntryInfo *info)
386 {
387 IFDUMPING("acl", debugDump("entries-load-old"));
388 mEntries.erase(mEntries.begin(), mEntries.end());
389 for (uint32 n = 0; n < count; n++, info++)
390 add(info->proto().s_tag(), info->proto());
391 IFDUMPING("acl", debugDump("entries-load-new"));
392 }
393
394
395 //
396 // Clear out the ACL and return it to un-initialized state
397 //
398 void ObjectAcl::clear()
399 {
400 mOwner = OwnerEntry();
401 mEntries.erase(mEntries.begin(), mEntries.end());
402 secdebug("acl", "%p cleared", this);
403 }
404
405
406 //
407 // Common gate to add an ACL entry
408 //
409 void ObjectAcl::add(const std::string &tag, const AclEntry &newEntry)
410 {
411 add(tag, newEntry, mNextHandle++);
412 }
413
414 void ObjectAcl::add(const std::string &tag, AclEntry newEntry, CSSM_ACL_HANDLE handle)
415 {
416 //@@@ This should use a hook-registry mechanism. But for now, we are explicit:
417 if (!newEntry.authorizesAnything) {
418 for (AclAuthorizationSet::const_iterator it = newEntry.authorizations.begin();
419 it != newEntry.authorizations.end(); it++)
420 if (*it >= CSSM_ACL_AUTHORIZATION_PREAUTH_BASE &&
421 *it < CSSM_ACL_AUTHORIZATION_PREAUTH_END) {
422 // preauthorization right - special handling
423 if (newEntry.subject->type() != CSSM_ACL_SUBJECT_TYPE_PREAUTH_SOURCE)
424 newEntry.subject =
425 new PreAuthorizationAcls::SourceAclSubject(newEntry.subject);
426 }
427 }
428
429 mEntries.insert(make_pair(tag, newEntry))->second.handle = handle;
430 if (handle >= mNextHandle)
431 mNextHandle = handle + 1; // don't reuse this handle (in this ACL)
432 }
433
434
435 //
436 // Common features of ACL entries/owners
437 //
438 void ObjectAcl::Entry::init(const AclSubjectPointer &subject, bool delegate)
439 {
440 this->subject = subject;
441 this->delegate = delegate;
442 }
443
444 void ObjectAcl::Entry::importBlob(Reader &pub, Reader &priv)
445 {
446 // the delegation flag is 4 bytes for historic reasons
447 Endian<uint32> del;
448 pub(del);
449 delegate = del;
450
451 subject = importSubject(pub, priv);
452 }
453
454
455 //
456 // An OwnerEntry is a restricted EntryPrototype for use as the ACL owner.
457 //
458 bool ObjectAcl::OwnerEntry::authorizes(AclAuthorization) const
459 {
460 return true; // owner can do anything
461 }
462
463 bool ObjectAcl::OwnerEntry::validate(const AclValidationContext &ctx) const
464 {
465 return subject->validate(ctx); // simple subject match - no strings attached
466 }
467
468
469 //
470 // An AclEntry has some extra goodies
471 //
472 ObjectAcl::AclEntry::AclEntry(const AclEntryPrototype &proto) : Entry(proto)
473 {
474 tag = proto.s_tag();
475 if (proto.authorization().contains(CSSM_ACL_AUTHORIZATION_ANY))
476 authorizesAnything = true; // anything else wouldn't add anything
477 else if (proto.authorization().empty())
478 authorizesAnything = true; // not in standard, but common sense
479 else {
480 authorizesAnything = false;
481 authorizations = proto.authorization();
482 }
483 //@@@ not setting time range
484 // handle = not set here. Set by caller when the AclEntry is created.
485 }
486
487 ObjectAcl::AclEntry::AclEntry(const AclSubjectPointer &subject) : Entry(subject)
488 {
489 authorizesAnything = true; // by default, everything
490 //@@@ not setting time range
491 }
492
493 void ObjectAcl::AclEntry::toEntryInfo(CSSM_ACL_ENTRY_PROTOTYPE &info, Allocator &alloc) const
494 {
495 info.TypedSubject = subject->toList(alloc);
496 info.Delegate = delegate;
497 info.Authorization = authorizesAnything ?
498 AuthorizationGroup(CSSM_ACL_AUTHORIZATION_ANY, alloc) :
499 AuthorizationGroup(authorizations, alloc);
500 //@@@ info.TimeRange =
501 assert(tag.length() <= CSSM_MODULE_STRING_SIZE);
502 memcpy(info.EntryTag, tag.c_str(), tag.length() + 1);
503 }
504
505 bool ObjectAcl::AclEntry::authorizes(AclAuthorization auth) const
506 {
507 return authorizesAnything || authorizations.find(auth) != authorizations.end();
508 }
509
510 bool ObjectAcl::AclEntry::validate(const AclValidationContext &ctx) const
511 {
512 //@@@ not checking time ranges
513 return subject->validate(ctx);
514 }
515
516 void ObjectAcl::AclEntry::importBlob(Reader &pub, Reader &priv)
517 {
518 Entry::importBlob(pub, priv);
519 const char *s; pub(s); tag = s;
520
521 // authorizesAnything is on disk as a 4-byte flag
522 Endian<uint32> tmpAuthorizesAnything;
523 pub(tmpAuthorizesAnything);
524 authorizesAnything = tmpAuthorizesAnything;
525
526 authorizations.erase(authorizations.begin(), authorizations.end());
527 if (!authorizesAnything) {
528 Endian<uint32> countIn; pub(countIn);
529 uint32 count = countIn;
530
531 for (uint32 n = 0; n < count; n++) {
532 Endian<AclAuthorization> auth; pub(auth);
533 authorizations.insert(auth);
534 }
535 }
536 //@@@ import time range
537 }
538
539
540 //
541 // Subject factory and makers
542 //
543 AclSubject::Maker::Maker(CSSM_ACL_SUBJECT_TYPE type)
544 : mType(type)
545 {
546 ObjectAcl::makers()[type] = this;
547 }
548
549 AclSubject *ObjectAcl::make(const TypedList &list)
550 {
551 if (!list.isProper())
552 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE);
553 return makerFor(list.type()).make(list);
554 }
555
556 AclSubject *ObjectAcl::make(uint32 typeAndVersion, Reader &pub, Reader &priv)
557 {
558 // this type is encoded as (version << 24) | type
559 return makerFor(typeAndVersion & ~AclSubject::versionMask).make(typeAndVersion >> AclSubject::versionShift, pub, priv);
560 }
561
562 AclSubject::Maker &ObjectAcl::makerFor(CSSM_ACL_SUBJECT_TYPE type)
563 {
564 AclSubject::Maker *maker = makers()[type];
565 if (maker == NULL)
566 CssmError::throwMe(CSSM_ERRCODE_ACL_SUBJECT_TYPE_NOT_SUPPORTED);
567 return *maker;
568 }
569
570
571 //
572 // Parsing helper for subject makers.
573 // Note that count/array exclude the first element of list, which is the subject type wordid.
574 //
575 void AclSubject::Maker::crack(const CssmList &list, uint32 count, ListElement **array, ...)
576 {
577 if (count != list.length() - 1)
578 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE);
579 if (count > 0) {
580 va_list args;
581 va_start(args, array);
582 ListElement *elem = list.first()->next();
583 for (uint32 n = 0; n < count; n++, elem = elem->next()) {
584 CSSM_LIST_ELEMENT_TYPE expectedType = va_arg(args, CSSM_LIST_ELEMENT_TYPE);
585 if (elem->type() != expectedType)
586 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE);
587 array[n] = elem;
588 }
589 va_end(args);
590 }
591 }
592
593 CSSM_WORDID_TYPE AclSubject::Maker::getWord(const ListElement &elem,
594 int min /*= 0*/, int max /*= INT_MAX*/)
595 {
596 if (elem.type() != CSSM_LIST_ELEMENT_WORDID)
597 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE);
598 CSSM_WORDID_TYPE value = elem;
599 if (value < min || value > max)
600 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE);
601 return value;
602 }
603
604
605 //
606 // Debug dumping support.
607 // Leave the ObjectAcl::debugDump method in (stubbed out)
608 // to keep the virtual table layout stable, and to allow
609 // proper linking in weird mix-and-match scenarios.
610 //
611 void ObjectAcl::debugDump(const char *what) const
612 {
613 #if defined(DEBUGDUMP)
614 if (!what)
615 what = "Dump";
616 Debug::dump("%p ACL %s: %d entries\n", this, what, int(mEntries.size()));
617 Debug::dump(" OWNER ["); mOwner.debugDump(); Debug::dump("]\n");
618 for (EntryMap::const_iterator it = begin(); it != end(); it++) {
619 const AclEntry &ent = it->second;
620 Debug::dump(" (%ld:%s) [", ent.handle, ent.tag.c_str());
621 ent.debugDump();
622 Debug::dump("]\n");
623 }
624 Debug::dump("%p ACL END\n", this);
625 #endif //DEBUGDUMP
626 }
627
628 #if defined(DEBUGDUMP)
629
630 void ObjectAcl::Entry::debugDump() const
631 {
632 if (subject) {
633 if (AclSubject::Version v = subject->version())
634 Debug::dump("V=%d ", v);
635 subject->debugDump();
636 } else {
637 Debug::dump("NULL subject");
638 }
639 if (delegate)
640 Debug::dump(" DELEGATE");
641 }
642
643 void ObjectAcl::AclEntry::debugDump() const
644 {
645 Entry::debugDump();
646 if (authorizesAnything) {
647 Debug::dump(" auth(ALL)");
648 } else {
649 Debug::dump(" auth(");
650 for (AclAuthorizationSet::iterator it = authorizations.begin();
651 it != authorizations.end(); it++) {
652 if (*it >= CSSM_ACL_AUTHORIZATION_PREAUTH_BASE
653 && *it < CSSM_ACL_AUTHORIZATION_PREAUTH_END)
654 Debug::dump(" PRE(%d)", *it - CSSM_ACL_AUTHORIZATION_PREAUTH_BASE);
655 else
656 Debug::dump(" %d", *it);
657 }
658 Debug::dump(")");
659 }
660 }
661
662 #endif //DEBUGDUMP