#include <security_cdsa_utilities/acl_threshold.h>
#include <algorithm>
#include <security_utilities/endian.h>
class SublistValidationContext : public AclValidationContext {
public:
SublistValidationContext(const AclValidationContext &ctx, const TypedList &list)
: AclValidationContext(ctx), sampleList(list) { }
uint32 count() const { return sampleList.length() - 1; }
const TypedList &sample(uint32 n) const
{ return TypedList::overlay(sampleList[n+1].list()); }
void matched(const TypedList *) const { }
const TypedList &sampleList;
};
bool ThresholdAclSubject::validate(const AclValidationContext &baseCtx,
const TypedList &sample) const
{
#ifdef STRICTCOUNTING
uint32 subSampleCount = sample.length() - 1; if (subSampleCount < minimumNeeded) CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
if (subSampleCount > totalSubjects) CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
#endif //STRICTCOUNTING
SublistValidationContext ctx(baseCtx, sample);
uint32 matched = 0;
for (uint32 n = 0; n < totalSubjects; n++) {
if ((matched += elements[n]->validate(ctx)) >= minimumNeeded)
return true;
#ifdef STRICTCOUNTING
else if (matched + subSampleCount - n <= minimumNeeded)
return false; #endif //STRICTCOUNTING
}
return false;
}
CssmList ThresholdAclSubject::toList(Allocator &alloc) const
{
TypedList result(alloc, CSSM_ACL_SUBJECT_TYPE_THRESHOLD,
new(alloc) ListElement(minimumNeeded),
new(alloc) ListElement(totalSubjects));
for (uint32 n = 0; n < totalSubjects; n++)
result += new(alloc) ListElement(elements[n]->toList(alloc));
return result;
}
ThresholdAclSubject *ThresholdAclSubject::Maker::make(const TypedList &list) const
{
if (list.length() < 4) CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE);
uint32 minimumNeeded = getWord(list[1], 1);
uint32 totalSubjects = getWord(list[2], minimumNeeded);
if (list.length() != 3 + totalSubjects)
CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE);
AclSubjectVector elements(totalSubjects);
const ListElement *subSubject = &list[3];
for (uint32 n = 0; n < totalSubjects; n++, subSubject = subSubject->next())
elements[n] = ObjectAcl::make(subSubject->typedList());
return new ThresholdAclSubject(totalSubjects, minimumNeeded, elements);
}
ThresholdAclSubject *ThresholdAclSubject::Maker::make(Version, Reader &pub, Reader &priv) const
{
Endian<uint32> totalSubjects; pub(totalSubjects);
Endian<uint32> minimumNeeded; pub(minimumNeeded);
AclSubjectVector subSubjects(totalSubjects);
for (uint32 n = 0; n < totalSubjects; n++)
subSubjects[n] = ObjectAcl::importSubject(pub, priv);
return new ThresholdAclSubject(totalSubjects, minimumNeeded, subSubjects);
}
ThresholdAclSubject::ThresholdAclSubject(uint32 n, uint32 k,
const AclSubjectVector &subSubjects)
: SimpleAclSubject(CSSM_ACL_SUBJECT_TYPE_THRESHOLD),
minimumNeeded(k), totalSubjects(n), elements(subSubjects)
{
}
template <class Action>
void ThresholdAclSubject::exportBlobForm(Action &pub, Action &priv)
{
pub(h2n(totalSubjects));
pub(h2n(minimumNeeded));
for (uint32 n = 0; n < totalSubjects; n++)
ObjectAcl::exportSubject(elements[n], pub, priv);
}
void ThresholdAclSubject::exportBlob(Writer::Counter &pub, Writer::Counter &priv)
{ exportBlobForm(pub, priv); }
void ThresholdAclSubject::exportBlob(Writer &pub, Writer &priv)
{ exportBlobForm(pub, priv); }
void ThresholdAclSubject::add(AclSubject *subject, unsigned beforePosition)
{
secdebug("threshacl", "adding subject %p before position %u",
subject, beforePosition);
elements.insert(elements.begin() + beforePosition, subject);
totalSubjects++;
}
#ifdef DEBUGDUMP
void ThresholdAclSubject::debugDump() const
{
Debug::dump("Threshold(%u of %u)", minimumNeeded, totalSubjects);
for (unsigned int n = 0; n < elements.size(); n++) {
Debug::dump(" [");
if (Version v = elements[n]->version())
Debug::dump("V=%d ", v);
elements[n]->debugDump();
Debug::dump("]");
}
}
#endif //DEBUGDUMP