]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cdsa_utilities/lib/acl_threshold.cpp
Security-57740.1.18.tar.gz
[apple/security.git] / OSX / libsecurity_cdsa_utilities / lib / acl_threshold.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 // 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 //
42 class SublistValidationContext : public AclValidationContext {
43 public:
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
56 bool ThresholdAclSubject::validates(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]->validates(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 //
88 CssmList 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 //
102 ThresholdAclSubject *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
120 ThresholdAclSubject *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
130 ThresholdAclSubject::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 //
141 template <class Action>
142 void 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
150 void ThresholdAclSubject::exportBlob(Writer::Counter &pub, Writer::Counter &priv)
151 { exportBlobForm(pub, priv); }
152
153 void ThresholdAclSubject::exportBlob(Writer &pub, Writer &priv)
154 { exportBlobForm(pub, priv); }
155
156
157 void ThresholdAclSubject::add(AclSubject *subject, unsigned beforePosition)
158 {
159 secinfo("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
168 void 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