+ // Store off the wildcards ahead of time.
+ for (vector<const Policy*>::const_iterator pol=applicablePolicies.begin(); pol!=applicablePolicies.end(); ++pol) {
+ pair<Policy::rules_t::const_iterator,Policy::rules_t::const_iterator> rules = (*pol)->m_rules.equal_range("*");
+ for (; rules.first!=rules.second; ++rules.first)
+ wildcardRules.push_back(rules.first->second);
+ }
+
+ // To track what to keep without removing anything from the original set until the end, we maintain
+ // a map of each Attribute object to a boolean array with true flags indicating what to delete.
+ // A single dimension array tracks attributes being removed entirely.
+ vector<bool> deletedAttributes(attributes.size(), false);
+ map< Attribute*, vector<bool> > deletedPositions;
+
+ // Loop over each attribute to filter them.
+ for (vector<Attribute*>::size_type a=0; a<attributes.size(); ++a) {
+ Attribute* attr = attributes[a];
+
+ // Clear the rule store.
+ applicableRules.clear();
+
+ // Look for rules to run in each policy.
+ for (vector<const Policy*>::const_iterator pol=applicablePolicies.begin(); pol!=applicablePolicies.end(); ++pol) {
+ pair<Policy::rules_t::const_iterator,Policy::rules_t::const_iterator> rules = (*pol)->m_rules.equal_range(attr->getId());
+ for (; rules.first!=rules.second; ++rules.first)
+ applicableRules.push_back(rules.first->second);
+ }
+
+ // If no rules found, apply wildcards.
+ const vector< pair<const MatchFunctor*,const MatchFunctor*> >& rulesToRun = applicableRules.empty() ? wildcardRules : applicableRules;
+
+ // If no rules apply, remove the attribute entirely.
+ if (rulesToRun.empty()) {
+ m_log.warn(
+ "no rule found, removing attribute (%s) from (%s)",
+ attr->getId(), issuer.get() ? issuer.get() : "unknown source"
+ );
+ deletedAttributes[a] = true;
+ continue;
+ }
+
+ // Run each permit/deny rule.
+ m_log.debug(
+ "applying filtering rule(s) for attribute (%s) from (%s)",
+ attr->getId(), issuer.get() ? issuer.get() : "unknown source"
+ );
+
+ bool kickit;
+
+ // Examine each value.
+ for (size_t count = attr->valueCount(), index = 0; index < count; ++index) {
+
+ // Assume we're kicking it out.
+ kickit=true;
+
+ for (vector< pair<const MatchFunctor*,const MatchFunctor*> >::const_iterator r=rulesToRun.begin(); r!=rulesToRun.end(); ++r) {
+ // If there's a permit rule that passes, don't kick it.
+ if (r->first && r->first->evaluatePermitValue(context, *attr, index))
+ kickit = false;
+ if (!kickit && r->second && r->second->evaluatePermitValue(context, *attr, index))
+ kickit = true;
+ }
+
+ // If we're kicking it, record that in the tracker.
+ if (kickit) {
+ m_log.warn(
+ "removed value at position (%lu) of attribute (%s) from (%s)",
+ index, attr->getId(), issuer.get() ? issuer.get() : "unknown source"
+ );
+ deletedPositions[attr].resize(index+1);
+ deletedPositions[attr][index] = true;
+ }
+ }
+ }
+
+ // Final step: go over the deletedPositions matrix and apply the actual changes. In order to delete
+ // any attributes that end up with no values, we have to do it by looping over the originals.
+ for (vector<Attribute*>::size_type a=0; a<attributes.size();) {
+ Attribute* attr = attributes[a];
+
+ if (deletedAttributes[a]) {
+ delete attr;
+ deletedAttributes.erase(deletedAttributes.begin() + a);
+ attributes.erase(attributes.begin() + a);
+ continue;
+ }
+ else if (deletedPositions.count(attr) > 0) {
+ // To do the removal, we loop over the bits backwards so that the
+ // underlying value sequence doesn't get distorted by any removals.
+ // Index has to be offset by one because size_type is unsigned.
+ const vector<bool>& row = deletedPositions[attr];
+ for (vector<bool>::size_type index = row.size(); index > 0; --index) {
+ if (row[index-1])
+ attr->removeValue(index-1);
+ }
+
+ // Check for no values.
+ if (attr->valueCount() == 0) {
+ m_log.warn(
+ "no values left, removing attribute (%s) from (%s)",
+ attr->getId(), issuer.get() ? issuer.get() : "unknown source"
+ );
+ delete attr;
+ attributes.erase(attributes.begin() + a);
+ continue;