]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cdsa_utilities/lib/objectacl.cpp
Security-59754.41.1.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 <security_utilities/threading.h>
33 #include <algorithm>
34 #include <cstdarg>
35
36 #include <security_cdsa_utilities/acl_preauth.h> //@@@ impure - will be removed
37
38 using namespace DataWalkers;
39
40
41 //
42 // The static map of available ACL subject makers.
43 // These are the kinds of ACL subjects we can deal with.
44 //
45 ModuleNexus<ObjectAcl::MakerMap> ObjectAcl::makers;
46 ModuleNexus<NormalMutex> ObjectAcl::makersMutex;
47
48
49 //
50 // Create an ObjectAcl
51 //
52 ObjectAcl::ObjectAcl(Allocator &alloc) : allocator(alloc), mNextHandle(1)
53 {
54 }
55
56 ObjectAcl::ObjectAcl(const AclEntryPrototype &proto, Allocator &alloc)
57 : allocator(alloc), mNextHandle(1)
58 {
59 cssmSetInitial(proto);
60 }
61
62 ObjectAcl::~ObjectAcl()
63 { }
64
65
66 //
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.
70 //
71 void ObjectAcl::cssmSetInitial(const AclEntryPrototype &proto)
72 {
73 mOwner = OwnerEntry(proto);
74 add(proto.s_tag(), proto);
75 IFDUMPING("acl", debugDump("create/proto"));
76 }
77
78 void ObjectAcl::cssmSetInitial(const AclSubjectPointer &subject)
79 {
80 mOwner = OwnerEntry(subject);
81 add("", subject);
82 IFDUMPING("acl", debugDump("create/subject"));
83 }
84
85 ObjectAcl::Entry::~Entry()
86 {
87 }
88
89
90 //
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.
94 //
95 bool ObjectAcl::validates(AclAuthorization auth, const AccessCredentials *cred,
96 AclValidationEnvironment *env)
97 {
98 BaseValidationContext ctx(cred, auth, env);
99 return validates(ctx);
100 }
101
102 bool ObjectAcl::validates(AclValidationContext &ctx)
103 {
104 // make sure we are ready to go
105 instantiateAcl();
106
107 IFDUMPING("acleval", Debug::dump("<<WANT(%d)<", ctx.authorization()));
108
109 //@@@ should pre-screen based on requested auth, maybe?
110
111 #if defined(ACL_OMNIPOTENT_OWNER)
112 // try owner (owner can do anything)
113 if (mOwner.validates(ctx))
114 return;
115 #endif //ACL_OMNIPOTENT_OWNER
116
117 // try applicable ACLs
118 pair<EntryMap::const_iterator, EntryMap::const_iterator> range;
119 if (getRange(ctx.s_credTag(), range) == 0) {
120 // no such tag
121 secinfo("SecAccess", "no tag for cred tag: \"%s\"", ctx.s_credTag().c_str());
122 CssmError::throwMe(CSSM_ERRCODE_ACL_ENTRY_TAG_NOT_FOUND);
123 }
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
134 }
135 IFDUMPING("acleval", Debug::dump(" NO"));
136 }
137 }
138 IFDUMPING("acleval", Debug::dump(">FAIL>>\n"));
139 return false; // no joy
140 }
141
142 void ObjectAcl::validate(AclAuthorization auth, const AccessCredentials *cred,
143 AclValidationEnvironment *env)
144 {
145 if (!validates(auth, cred, env))
146 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
147 }
148
149 void ObjectAcl::validate(AclValidationContext &ctx)
150 {
151 if (!validates(ctx))
152 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
153 }
154
155
156 void ObjectAcl::validateOwner(AclAuthorization authorizationHint,
157 const AccessCredentials *cred, AclValidationEnvironment *env)
158 {
159 BaseValidationContext ctx(cred, authorizationHint, env);
160 validateOwner(ctx);
161 }
162
163 void ObjectAcl::validateOwner(AclValidationContext &ctx)
164 {
165 instantiateAcl();
166
167 ctx.init(this, mOwner.subject);
168 if (mOwner.validates(ctx))
169 return;
170 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
171 }
172
173
174 //
175 // Export an ObjectAcl to two memory blobs: public and private data separated.
176 // This is a standard two-pass size+copy operation.
177 //
178 void ObjectAcl::exportBlob(CssmData &publicBlob, CssmData &privateBlob)
179 {
180 instantiateAcl();
181 Writer::Counter pubSize, privSize;
182 Endian<uint32> entryCount = (uint32)mEntries.size();
183 mOwner.exportBlob(pubSize, privSize);
184 pubSize(entryCount);
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"));
195 }
196
197
198 //
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
201 // export method.
202 // Prior contents (if any) are deleted and replaced.
203 //
204 void ObjectAcl::importBlob(const void *publicBlob, const void *privateBlob)
205 {
206 Reader pubReader(publicBlob), privReader(privateBlob);
207 mOwner.importBlob(pubReader, privReader);
208 Endian<uint32> entryCountIn; pubReader(entryCountIn);
209 uint32 entryCount = entryCountIn;
210
211 mEntries.erase(begin(), end());
212 for (uint32 n = 0; n < entryCount; n++) {
213 AclEntry newEntry;
214 newEntry.importBlob(pubReader, privReader);
215 add(newEntry.tag, newEntry);
216 }
217 IFDUMPING("acl", debugDump("imported"));
218 }
219
220
221 //
222 // Import/export helpers for subjects.
223 // This is exported to (subject implementation) callers to maintain consistency
224 // in binary format handling.
225 //
226 AclSubject *ObjectAcl::importSubject(Reader &pub, Reader &priv)
227 {
228 Endian<uint32> typeAndVersion; pub(typeAndVersion);
229 return make(typeAndVersion, pub, priv);
230 }
231
232
233 //
234 // Setup/update hooks
235 //
236 void ObjectAcl::instantiateAcl()
237 {
238 // nothing by default
239 }
240
241 void ObjectAcl::changedAcl()
242 {
243 // nothing by default
244 }
245
246
247 //
248 // ACL utility methods
249 //
250 unsigned int ObjectAcl::getRange(const std::string &tag,
251 pair<EntryMap::const_iterator, EntryMap::const_iterator> &range, bool tolerant /* = false */) const
252 {
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);
259 return count;
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();
265 }
266 }
267
268 ObjectAcl::EntryMap::iterator ObjectAcl::findEntryHandle(CSSM_ACL_HANDLE handle)
269 {
270 for (EntryMap::iterator it = mEntries.begin(); it != mEntries.end(); it++)
271 if (it->second.handle == handle)
272 return it;
273 CssmError::throwMe(CSSMERR_CSSM_INVALID_HANDLE_USAGE); //%%% imprecise error code
274 }
275
276
277 //
278 // CSSM style ACL access and modification functions.
279 //
280 void ObjectAcl::cssmGetAcl(const char *tag, uint32 &count, AclEntryInfo * &acls)
281 {
282 instantiateAcl();
283 pair<EntryMap::const_iterator, EntryMap::const_iterator> range;
284 count = getRange(tag ? tag : "", range);
285 acls = allocator.alloc<AclEntryInfo>(count);
286 uint32 n = 0;
287
288 secinfo("SecAccess", "getting the ACL for %p (%d entries) tag: %s", this, count, tag ? tag : "<none>");
289
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);
294 }
295 count = n;
296 }
297
298 void ObjectAcl::cssmChangeAcl(const AclEdit &edit,
299 const AccessCredentials *cred, AclValidationEnvironment *env, const char *preserveTag)
300 {
301 IFDUMPING("acl", debugDump("acl-change-from"));
302
303 // make sure we're ready to go
304 instantiateAcl();
305
306 // validate access credentials
307 validateOwner(CSSM_ACL_AUTHORIZATION_CHANGE_ACL, cred, env);
308
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);
318 }
319 break;
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);
330
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);
334 mEntries.erase(it);
335 }
336 break;
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);
342
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);
347
348 mEntries.erase(it);
349 break;
350 }
351 default:
352 secinfo("SecAccess", "no idea what this CSSM_ACL_EDIT type is: %d", edit.EditMode);
353 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_EDIT_MODE);
354 }
355
356 // notify change
357 changedAcl();
358
359 IFDUMPING("acl", debugDump("acl-change-to"));
360 }
361
362 void ObjectAcl::cssmGetOwner(AclOwnerPrototype &outOwner)
363 {
364 instantiateAcl();
365 outOwner.TypedSubject = mOwner.subject->toList(allocator);
366 outOwner.Delegate = mOwner.delegate;
367
368 secinfo("SecAccess", "%p: getting the owner ACL: type %d", this, outOwner.TypedSubject.Head->WordID);
369 }
370
371 void ObjectAcl::cssmChangeOwner(const AclOwnerPrototype &newOwner,
372 const AccessCredentials *cred, AclValidationEnvironment *env)
373 {
374 IFDUMPING("acl", debugDump("owner-change-from"));
375
376 instantiateAcl();
377
378 // only the owner entry can match
379 validateOwner(CSSM_ACL_AUTHORIZATION_CHANGE_OWNER, cred, env);
380
381 // okay, replace it
382 mOwner = newOwner;
383
384 secinfo("SecAccess", "%p: new owner's type is %d", this, newOwner.subject().Head->WordID);
385
386 changedAcl();
387
388 IFDUMPING("acl", debugDump("owner-change-to"));
389 }
390
391
392 //
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).
397 //
398 template <class Input>
399 void ObjectAcl::owner(const Input &input)
400 {
401 IFDUMPING("acl", debugDump("owner-load-old"));
402 mOwner = OwnerEntry(input);
403 IFDUMPING("acl", debugDump("owner-load-new"));
404 }
405
406 template void ObjectAcl::owner(const AclOwnerPrototype &);
407 template void ObjectAcl::owner(const AclSubjectPointer &);
408
409
410 void ObjectAcl::entries(uint32 count, const AclEntryInfo *info)
411 {
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"));
417 }
418
419
420 //
421 // Clear out the ACL and return it to un-initialized state
422 //
423 void ObjectAcl::clear()
424 {
425 mOwner = OwnerEntry();
426 mEntries.erase(mEntries.begin(), mEntries.end());
427 secinfo("acl", "%p cleared", this);
428 }
429
430
431 //
432 // Common gate to add an ACL entry
433 //
434 void ObjectAcl::add(const std::string &tag, const AclEntry &newEntry)
435 {
436 add(tag, newEntry, mNextHandle++);
437 }
438
439 void ObjectAcl::add(const std::string &tag, AclEntry newEntry, CSSM_ACL_HANDLE handle)
440 {
441 newEntry.tag = tag;
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)
450 newEntry.subject =
451 new PreAuthorizationAcls::SourceAclSubject(newEntry.subject);
452 }
453 }
454
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)
458 }
459
460
461 //
462 // Common features of ACL entries/owners
463 //
464 void ObjectAcl::Entry::init(const AclSubjectPointer &subject, bool delegate)
465 {
466 this->subject = subject;
467 this->delegate = delegate;
468 }
469
470 void ObjectAcl::Entry::importBlob(Reader &pub, Reader &priv)
471 {
472 // the delegation flag is 4 bytes for historic reasons
473 Endian<uint32> del;
474 pub(del);
475 delegate = del;
476
477 subject = importSubject(pub, priv);
478 }
479
480
481 //
482 // An OwnerEntry is a restricted EntryPrototype for use as the ACL owner.
483 //
484 bool ObjectAcl::OwnerEntry::authorizes(AclAuthorization) const
485 {
486 return true; // owner can do anything
487 }
488
489 bool ObjectAcl::OwnerEntry::validates(const AclValidationContext &ctx) const
490 {
491 if (AclValidationEnvironment* env = ctx.environment())
492 if (env->forceSuccess)
493 return true;
494 return subject->validates(ctx); // simple subject match - no strings attached
495 }
496
497
498 //
499 // An AclEntry has some extra goodies
500 //
501 ObjectAcl::AclEntry::AclEntry(const AclEntryPrototype &proto) : Entry(proto)
502 {
503 tag = proto.s_tag();
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
508 else {
509 authorizesAnything = false;
510 authorizations = proto.authorization();
511 }
512 //@@@ not setting time range
513 // handle = not set here. Set by caller when the AclEntry is created.
514 }
515
516 ObjectAcl::AclEntry::AclEntry(const AclSubjectPointer &subject) : Entry(subject)
517 {
518 authorizesAnything = true; // by default, everything
519 //@@@ not setting time range
520 }
521
522 void ObjectAcl::AclEntry::toEntryInfo(CSSM_ACL_ENTRY_PROTOTYPE &info, Allocator &alloc) const
523 {
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);
532 }
533
534 bool ObjectAcl::AclEntry::authorizes(AclAuthorization auth) const
535 {
536 return authorizesAnything || authorizations.find(auth) != authorizations.end();
537 }
538
539 bool ObjectAcl::AclEntry::validates(const AclValidationContext &ctx) const
540 {
541 //@@@ not checking time ranges
542 return subject->validates(ctx);
543 }
544
545 void ObjectAcl::AclEntry::addAuthorization(AclAuthorization auth)
546 {
547 authorizations.insert(auth);
548 authorizesAnything = false;
549 }
550
551
552 void ObjectAcl::AclEntry::importBlob(Reader &pub, Reader &priv)
553 {
554 Entry::importBlob(pub, priv);
555 const char *s; pub(s); tag = s;
556
557 // authorizesAnything is on disk as a 4-byte flag
558 Endian<uint32> tmpAuthorizesAnything;
559 pub(tmpAuthorizesAnything);
560 authorizesAnything = tmpAuthorizesAnything;
561
562 authorizations.erase(authorizations.begin(), authorizations.end());
563 if (!authorizesAnything) {
564 Endian<uint32> countIn; pub(countIn);
565 uint32 count = countIn;
566
567 for (uint32 n = 0; n < count; n++) {
568 Endian<AclAuthorization> auth; pub(auth);
569 authorizations.insert(auth);
570 }
571 }
572 //@@@ import time range
573 }
574
575
576 //
577 // Subject factory and makers
578 //
579 AclSubject::Maker::Maker(CSSM_ACL_SUBJECT_TYPE type)
580 : mType(type)
581 {
582 StLock<Mutex> _(ObjectAcl::makersMutex());
583 ObjectAcl::makers()[type] = this;
584 }
585
586 AclSubject *ObjectAcl::make(const TypedList &list)
587 {
588 if (!list.isProper())
589 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE);
590 return makerFor(list.type()).make(list);
591 }
592
593 AclSubject *ObjectAcl::make(uint32 typeAndVersion, Reader &pub, Reader &priv)
594 {
595 // this type is encoded as (version << 24) | type
596 return makerFor(typeAndVersion & ~AclSubject::versionMask).make(typeAndVersion >> AclSubject::versionShift, pub, priv);
597 }
598
599 AclSubject::Maker &ObjectAcl::makerFor(CSSM_ACL_SUBJECT_TYPE type)
600 {
601 StLock<Mutex> _(ObjectAcl::makersMutex());
602 AclSubject::Maker *maker = makers()[type];
603 if (maker == NULL)
604 CssmError::throwMe(CSSM_ERRCODE_ACL_SUBJECT_TYPE_NOT_SUPPORTED);
605 return *maker;
606 }
607
608
609 //
610 // Parsing helper for subject makers.
611 // Note that count/array exclude the first element of list, which is the subject type wordid.
612 //
613 void AclSubject::Maker::crack(const CssmList &list, uint32 count, ListElement **array, ...)
614 {
615 if (count != list.length() - 1)
616 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE);
617 if (count > 0) {
618 va_list args;
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);
625 array[n] = elem;
626 }
627 va_end(args);
628 }
629 }
630
631 CSSM_WORDID_TYPE AclSubject::Maker::getWord(const ListElement &elem,
632 int min /*= 0*/, int max /*= INT_MAX*/)
633 {
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);
639 return value;
640 }
641
642
643 //
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.
648 //
649 void ObjectAcl::debugDump(const char *what) const
650 {
651 #if defined(DEBUGDUMP)
652 if (!what)
653 what = "Dump";
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());
659 ent.debugDump();
660 Debug::dump("]\n");
661 }
662 Debug::dump("%p ACL END\n", this);
663 #endif //DEBUGDUMP
664 }
665
666 #if defined(DEBUGDUMP)
667
668 void ObjectAcl::Entry::debugDump() const
669 {
670 if (subject) {
671 if (AclSubject::Version v = subject->version())
672 Debug::dump("V=%d ", v);
673 subject->debugDump();
674 } else {
675 Debug::dump("NULL subject");
676 }
677 if (delegate)
678 Debug::dump(" DELEGATE");
679 }
680
681 void ObjectAcl::AclEntry::debugDump() const
682 {
683 Entry::debugDump();
684 if (authorizesAnything) {
685 Debug::dump(" auth(ALL)");
686 } else {
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);
693 else
694 Debug::dump(" %d", *it);
695 }
696 Debug::dump(")");
697 }
698 }
699
700 #endif //DEBUGDUMP