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