The recommendation for decades has been to use =*ANY or !*ANY.
We now make it official.
Without that check, the "no &" code will expect the RHS to be
an attribute reference, and will fail.
Update the documentation to match.
=== =*
-e.g: `Attribute =* Value`
+e.g: `Attribute =* ANY`
As a check item, it matches if the request contains the named
-attribute, no matter what the value is.
+attribute. The right-hand side must be the word `ANY`.
Not allowed as a reply item.
=== !*
-e.g: `Attribute !* Value`
+e.g: `Attribute !* ANY`
As a check item, it matches if the request does not contain
-the named attribute, no matter what the value is.
+the named attribute. The right-hand side must be the word `ANY`.
Not allowed as a reply item.
output A/V Pairs. If the attribute exists, it is overwritten.
| == | Equal, value must match exactly.
| =* | Always Equal, allow all values for the specified attribute.
+ The right-hand side must be the word `ANY`.
| !* | Never Equal, disallow all values for the specified attribute.
+ The right-hand side must be the word `ANY`.
(This is redundant, as any A/V Pair not explicitly permitted
will be dropped).
| != | Not Equal, value must not match.
[cols="10%,90%"]
|=====
| Operator | Description
-| =* | Matches if the attribute exists, no matter what the value is.
-| !* | Matches if the attribute does not exist, no matter what the value is.
+| =* | Matches if the attribute exists. The right-hand side must be the word `ANY`.
+| !* | Matches if the attribute does not exist. The right-hand side must be the word `ANY`.
|=====
Due to limitations of the `users` file format, a value must be specified for these additional comparison operators. The best practice is to use a meaningless special value `ANY`, such as `Framed-IP-Address !* ANY`.
# output A/V Pairs. If the attribute exists, it is overwritten.
# | == | Equal, value must match exactly.
# | =* | Always Equal, allow all values for the specified attribute.
+# The right-hand side must be the word `ANY`.
# | !* | Never Equal, disallow all values for the specified attribute.
+# The right-hand side must be the word `ANY`.
# (This is redundant, as any A/V Pair not explicitly permitted
# will be dropped).
# | != | Not Equal, value must not match.
break;
default:
- if (!p_rules) p_rules = &value_parse_rules_bareword_quoted;
+ if ((map->op == T_OP_CMP_TRUE) || (map->op == T_OP_CMP_FALSE)) {
+ /*
+ * These operators require a hard-coded string on the RHS.
+ */
+ if (fr_sbuff_adv_past_str_literal(&our_in, "ANY") <= 0) {
+ fr_strerror_printf("Invalid value for %s", fr_tokens[map->op]);
+ goto error;
+ }
- /*
- * Use the RHS termination rules ONLY for bare
- * words. For quoted strings we already know how
- * to terminate the input string.
- */
- slen = tmpl_afrom_substr(map, &map->rhs, &our_in, token, p_rules, rhs_rules);
+ (void) tmpl_afrom_value_box(map, &map->rhs, fr_box_strvalue("ANY"), false);
+
+ } else {
+ if (!p_rules) p_rules = &value_parse_rules_bareword_quoted;
+
+ /*
+ * Use the RHS termination rules ONLY for bare
+ * words. For quoted strings we already know how
+ * to terminate the input string.
+ */
+ slen = tmpl_afrom_substr(map, &map->rhs, &our_in, token, p_rules, rhs_rules);
+ }
break;
}
if (!map->rhs) goto error_adj;
* Ignore any extra data after the string.
*/
+ } else if ((map->op == T_OP_CMP_TRUE) || (map->op == T_OP_CMP_FALSE)) {
+ /*
+ * These operators require a hard-coded string on the RHS.
+ */
+ if (strcmp(rhs, "ANY") != 0) {
+ fr_strerror_printf("Invalid value for %s", fr_tokens[map->op]);
+ goto error;
+ }
+
+ if (tmpl_afrom_value_box(map, &map->rhs, fr_box_strvalue("ANY"), false) < 0) goto error;
+
} else if (rhs[0] == '&') {
/*
* No enums here.