Remove all matching attributes from the list. Both the attribute name
and value have to match in order for the attribute to be removed from
the list.
+.IP <=
+Enforce that the integer value of the attribute is less than or equal
+to the value given here. If there is no attribute of the same name in
+the list, the attribute is added with the given value, is with "+=".
+If an attribute in the list exists, and has value less than given
+here, it's value is unchanged. If an attribute in the exists, and has
+value greater than given here, it's value is replaced with the value
+given here.
+
+This operator is valid only for attributes of integer type.
+.IP >=
+Enforce that the integer value of the attribute is greater than or
+equal to the value given here. If there is no attribute of the same
+name in the list, the attribute is added with the given value, is with
+"+=". If an attribute in the list exists, and has value greater than
+given here, it's value is unchanged. If an attribute in the exists,
+and has value less than given here, it's value is replaced with the
+value given here.
+
+This operator is valid only for attributes of integer type.
.RE
.IP Values
.br
break;
case CONF_ITEM_SECTION: {
-
CONF_SECTION *section = cf_itemtosection(ci);
cf_section_free(§ion);
}
case T_EOL:
case T_HASH:
t2 = T_OP_EQ;
+ goto do_set;
- case T_OP_EQ:
case T_OP_ADD:
case T_OP_SUB:
+ case T_OP_LE:
+ case T_OP_GE:
+ if (!this || (strcmp(this->name1, "update") != 0)) {
+ radlog(L_ERR, "%s[%d]: Invalid operator in assignment",
+ file, *lineno);
+ return -1;
+ }
+
+ case T_OP_EQ:
case T_OP_SET:
+ do_set:
t3 = getstring(&ptr, buf3, sizeof(buf3));
/*
* Delete all matching attributes from
* "to"
*/
- if (from_list[i]->operator == T_OP_SUB) {
+ if ((from_list[i]->operator == T_OP_SUB) ||
+ (from_list[i]->operator == T_OP_LE) ||
+ (from_list[i]->operator == T_OP_GE)) {
+ int rcode;
+ int old_op = from_list[i]->operator;
+
/*
* Check for equality.
*/
* If equal, delete the one in
* the "to" list.
*/
- if (radius_compare_vps(NULL, from_list[i],
- to_list[j]) == 0) {
-
- DEBUG4("::: DELETING %s FROM %d TO %d",
- from_list[i]->name, i, j);
- pairfree(&to_list[j]);
- to_list[j] = NULL;
- }
-
+ rcode = radius_compare_vps(NULL, from_list[i],
+ to_list[j]);
/*
* We may want to do more
* subtractions, so we re-set the
* operator back to it's original
* value.
*/
- from_list[i]->operator = T_OP_SUB;
+ from_list[i]->operator = old_op;
+
+ switch (old_op) {
+ case T_OP_SUB:
+ if (rcode == 0) {
+ DEBUG4("::: DELETING %s FROM %d TO %d",
+ from_list[i]->name, i, j);
+ pairfree(&to_list[j]);
+ to_list[j] = NULL;
+ }
+ break;
+
+ /*
+ * Enforce <=. If it's
+ * >, replace it.
+ */
+ case T_OP_LE:
+ if (rcode > 0) {
+ DEBUG4("::: REPLACING %s FROM %d TO %d",
+ from_list[i]->name, i, j);
+ pairfree(&to_list[j]);
+ to_list[j] = from_list[i];
+ from_list[i] = NULL;
+ }
+ break;
+
+ case T_OP_GE:
+ if (rcode < 0) {
+ DEBUG4("::: REPLACING %s FROM %d TO %d",
+ from_list[i]->name, i, j);
+ pairfree(&to_list[j]);
+ to_list[j] = from_list[i];
+ from_list[i] = NULL;
+ }
+ break;
+ }
+
continue;
}
*/
if (!found) {
if ((from_list[i]->operator == T_OP_EQ) ||
+ (from_list[i]->operator == T_OP_LE) ||
+ (from_list[i]->operator == T_OP_GE) ||
(from_list[i]->operator == T_OP_SET)) {
append:
DEBUG4("::: APPENDING %s FROM %d TO %d",
if ((vp->operator != T_OP_EQ) &&
(vp->operator != T_OP_ADD) &&
(vp->operator != T_OP_SUB) &&
+ (vp->operator != T_OP_LE) &&
+ (vp->operator != T_OP_GE) &&
(vp->operator != T_OP_SET)) {
pairfree(&head);
radlog(L_ERR|L_CONS, "%s[%d]: Invalid operator for attribute",
filename, cf_pair_lineno(cp));
return NULL;
+ }
+ /*
+ * A few more sanity checks. The enforcement of
+ * <= or >= can only happen for integer
+ * attributes.
+ */
+ if ((vp->operator == T_OP_LE) ||
+ (vp->operator == T_OP_GE)) {
+ if ((vp->type != PW_TYPE_BYTE) &&
+ (vp->type != PW_TYPE_SHORT) &&
+ (vp->type != PW_TYPE_INTEGER)) {
+ pairfree(&head);
+ radlog(L_ERR|L_CONS, "%s[%d]: Enforcment of <= or >= is possible only for integer attributes",
+ filename, cf_pair_lineno(cp));
+ return NULL;
+ }
}
*tail = vp;
if (!cf_section_name2(cs)) {
radlog(L_ERR|L_CONS,
- "%s[%d] Require variable to switch over for 'switch'.\n",
+ "%s[%d] Require variable to switch over for 'switch'.",
+ filename, lineno);
+ return NULL;
+ }
+
+ if (!cf_item_find_next(cs, NULL)) {
+ radlog(L_ERR|L_CONS,
+ "%s[%d] 'switch' statments cannot be empty.",
filename, lineno);
return NULL;
}
} else if (strcmp(modrefname, "if") == 0) {
if (!cf_section_name2(cs)) {
radlog(L_ERR|L_CONS,
- "%s[%d]: 'if' without condition.\n",
+ "%s[%d]: 'if' without condition.",
filename, lineno);
return NULL;
}
((parent->type == MOD_LOAD_BALANCE) ||
(parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
radlog(L_ERR|L_CONS,
- "%s[%d] 'elsif' cannot be used in this section section.\n",
+ "%s[%d] 'elsif' cannot be used in this section section.",
filename, lineno);
return NULL;
}
if (!cf_section_name2(cs)) {
radlog(L_ERR|L_CONS,
- "%s[%d] 'elsif' without condition.\n",
+ "%s[%d] 'elsif' without condition.",
filename, lineno);
return NULL;
}
((parent->type == MOD_LOAD_BALANCE) ||
(parent->type == MOD_REDUNDANT_LOAD_BALANCE))) {
radlog(L_ERR|L_CONS,
- "%s[%d] 'else' cannot be used in this section section.\n",
+ "%s[%d] 'else' cannot be used in this section section.",
filename, lineno);
return NULL;
}
if (cf_section_name2(cs)) {
radlog(L_ERR|L_CONS,
- "%s[%d] Cannot have conditions on 'else'.\n",
+ "%s[%d] Cannot have conditions on 'else'.",
filename, lineno);
return NULL;
}
if (cf_item_is_section(ci)) {
radlog(L_ERR|L_CONS,
"%s[%d] Subsection of module instance call "
- "not allowed\n", filename,
+ "not allowed", filename,
cf_section_lineno(cf_itemtosection(ci)));
modcallable_free(&csingle);
return NULL;
grouptype, &junk);
if (!single) {
radlog(L_ERR|L_CONS,
- "%s[%d] Failed to parse \"%s\" subsection.\n",
+ "%s[%d] Failed to parse \"%s\" subsection.",
filename, lineno,
cf_section_name1(subcs));
modcallable_free(&c);
&junk);
if (!single) {
radlog(L_ERR|L_CONS,
- "%s[%d] Failed to parse \"%s\" entry.\n",
+ "%s[%d] Failed to parse \"%s\" entry.",
filename, lineno, attr);
modcallable_free(&c);
return NULL;