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// acl_threshold - Threshold-based group ACL subjects 27// 28#include <security_cdsa_utilities/acl_threshold.h> 29#include <algorithm> 30#include <security_utilities/endian.h> 31 32 33// 34// Validate a credential set against this subject. 35// 36// With STRICTCOUNTING set, we assume that every match in the threshold ACL 37// "consumes" one sample in the corresponding threshold sample. This will not 38// work as expected for subject types that may succeed without a sample (e.g. ANY) 39// or subject types that may multiply match against a single sample. You have been 40// warned. 41// 42class SublistValidationContext : public AclValidationContext { 43public: 44 SublistValidationContext(const AclValidationContext &ctx, const TypedList &list) 45 : AclValidationContext(ctx), sampleList(list) { } 46 47 uint32 count() const { return sampleList.length() - 1; } 48 const TypedList &sample(uint32 n) const 49 { return TypedList::overlay(sampleList[n+1].list()); } 50 51 void matched(const TypedList *) const { } //@@@ ignore sub-matches for now 52 53 const TypedList &sampleList; 54}; 55 56bool ThresholdAclSubject::validate(const AclValidationContext &baseCtx, 57 const TypedList &sample) const 58{ 59#ifdef STRICTCOUNTING 60 // Pre-screen for reasonable number of subsamples. 61 // We could more strictly require subSampleCount == elements.length(); 62 // this is more flexible in that it allows the caller to abbreviate. 63 uint32 subSampleCount = sample.length() - 1; // (drop type header) 64 if (subSampleCount < minimumNeeded) // can't possibly satisfy 65 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE); 66 if (subSampleCount > totalSubjects) // reject attempt at sample stuffing 67 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE); 68#endif //STRICTCOUNTING 69 70 // evaluate 71 SublistValidationContext ctx(baseCtx, sample); 72 uint32 matched = 0; 73 for (uint32 n = 0; n < totalSubjects; n++) { 74 if ((matched += elements[n]->validate(ctx)) >= minimumNeeded) 75 return true; 76#ifdef STRICTCOUNTING 77 else if (matched + subSampleCount - n <= minimumNeeded) 78 return false; // can't get there anymore 79#endif //STRICTCOUNTING 80 } 81 return false; 82} 83 84 85// 86// Make a copy of this subject in CSSM_LIST form 87// 88CssmList ThresholdAclSubject::toList(Allocator &alloc) const 89{ 90 TypedList result(alloc, CSSM_ACL_SUBJECT_TYPE_THRESHOLD, 91 new(alloc) ListElement(minimumNeeded), 92 new(alloc) ListElement(totalSubjects)); 93 for (uint32 n = 0; n < totalSubjects; n++) 94 result += new(alloc) ListElement(elements[n]->toList(alloc)); 95 return result; 96} 97 98 99// 100// Create a ThresholdAclSubject 101// 102ThresholdAclSubject *ThresholdAclSubject::Maker::make(const TypedList &list) const 103{ 104 // pick apart the input list 105 if (list.length() < 4) // head + "n" + "k" + at least one subSubject 106 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); 107 uint32 minimumNeeded = getWord(list[1], 1); 108 uint32 totalSubjects = getWord(list[2], minimumNeeded); 109 if (list.length() != 3 + totalSubjects) 110 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); 111 112 // now compile the subSubjects 113 AclSubjectVector elements(totalSubjects); 114 const ListElement *subSubject = &list[3]; 115 for (uint32 n = 0; n < totalSubjects; n++, subSubject = subSubject->next()) 116 elements[n] = ObjectAcl::make(subSubject->typedList()); 117 return new ThresholdAclSubject(totalSubjects, minimumNeeded, elements); 118} 119 120ThresholdAclSubject *ThresholdAclSubject::Maker::make(Version, Reader &pub, Reader &priv) const 121{ 122 Endian<uint32> totalSubjects; pub(totalSubjects); 123 Endian<uint32> minimumNeeded; pub(minimumNeeded); 124 AclSubjectVector subSubjects(totalSubjects); 125 for (uint32 n = 0; n < totalSubjects; n++) 126 subSubjects[n] = ObjectAcl::importSubject(pub, priv); 127 return new ThresholdAclSubject(totalSubjects, minimumNeeded, subSubjects); 128} 129 130ThresholdAclSubject::ThresholdAclSubject(uint32 n, uint32 k, 131 const AclSubjectVector &subSubjects) 132: SimpleAclSubject(CSSM_ACL_SUBJECT_TYPE_THRESHOLD), 133 minimumNeeded(k), totalSubjects(n), elements(subSubjects) 134{ 135} 136 137 138// 139// Export the subject to a memory blob 140// 141template <class Action> 142void ThresholdAclSubject::exportBlobForm(Action &pub, Action &priv) 143{ 144 pub(h2n(totalSubjects)); 145 pub(h2n(minimumNeeded)); 146 for (uint32 n = 0; n < totalSubjects; n++) 147 ObjectAcl::exportSubject(elements[n], pub, priv); 148} 149 150void ThresholdAclSubject::exportBlob(Writer::Counter &pub, Writer::Counter &priv) 151{ exportBlobForm(pub, priv); } 152 153void ThresholdAclSubject::exportBlob(Writer &pub, Writer &priv) 154{ exportBlobForm(pub, priv); } 155 156 157void ThresholdAclSubject::add(AclSubject *subject, unsigned beforePosition) 158{ 159 secdebug("threshacl", "adding subject %p before position %u", 160 subject, beforePosition); 161 elements.insert(elements.begin() + beforePosition, subject); 162 totalSubjects++; 163} 164 165 166#ifdef DEBUGDUMP 167 168void ThresholdAclSubject::debugDump() const 169{ 170 Debug::dump("Threshold(%u of %u)", minimumNeeded, totalSubjects); 171 for (unsigned int n = 0; n < elements.size(); n++) { 172 Debug::dump(" ["); 173 if (Version v = elements[n]->version()) 174 Debug::dump("V=%d ", v); 175 elements[n]->debugDump(); 176 Debug::dump("]"); 177 } 178} 179 180#endif //DEBUGDUMP 181