talloc_free(edited);
talloc_free(deleted);
}
+
+/** Move a map using the operators from the old pairmove API.
+ *
+ */
+int fr_pairmove_map(request_t *request, map_t const *map)
+{
+ int rcode;
+ fr_pair_t *vp, *next;
+ fr_dict_attr_t const *da;
+ fr_pair_list_t *list;
+ TALLOC_CTX *ctx;
+
+ /*
+ * Finds both the correct ctx and nested list.
+ */
+ tmpl_pair_list_and_ctx(ctx, list, request, tmpl_request(map->lhs), tmpl_list(map->lhs));
+ if (!ctx) return -1;
+
+ da = tmpl_attr_tail_da(map->lhs);
+
+ fr_assert(tmpl_is_data(map->rhs));
+
+ switch (map->op) {
+ case T_OP_CMP_FALSE: /* delete all */
+ fr_pair_delete_by_da(list, da);
+ break;
+
+ case T_OP_EQ: /* set only if not already exist */
+ vp = fr_pair_find_by_da(list, NULL, da);
+ if (vp) return 0;
+ goto add;
+
+ case T_OP_SET: /* delete all and set one */
+ fr_pair_delete_by_da(list, da);
+ FALL_THROUGH;
+
+ case T_OP_ADD_EQ: /* append one */
+ add:
+ vp = fr_pair_afrom_da(ctx, da);
+ if (!vp) return -1;
+
+ if (fr_value_box_copy(vp, &vp->data, tmpl_value(map->rhs)) < 0) {
+ talloc_free(vp);
+ return -1;
+ }
+
+ fr_pair_append(list, vp);
+ break;
+
+ case T_OP_PREPEND: /* prepend one */
+ vp = fr_pair_afrom_da(ctx, da);
+ if (!vp) return -1;
+
+ if (fr_value_box_copy(vp, &vp->data, tmpl_value(map->rhs)) < 0) {
+ talloc_free(vp);
+ return -1;
+ }
+
+ fr_pair_prepend(list, vp);
+ break;
+
+ case T_OP_SUB_EQ: /* delete if match */
+ vp = fr_pair_find_by_da(list, NULL, da);
+ if (!vp) break;
+
+ redo_sub:
+ next = fr_pair_find_by_da(list, vp, da);
+ rcode = fr_value_box_cmp_op(T_OP_CMP_EQ, &vp->data, tmpl_value(map->rhs));
+
+ if (rcode < 0) return -1;
+
+ if (rcode == 1) {
+ fr_pair_delete(list, vp);
+ }
+
+ if (!next) break;
+ vp = next;
+ goto redo_sub;
+
+ case T_OP_CMP_EQ: /* replace if not == */
+ case T_OP_LE: /* replace if not <= */
+ case T_OP_GE: /* replace if not >= */
+ vp = fr_pair_find_by_da(list, NULL, da);
+ if (!vp) goto add;
+
+ redo_filter:
+ rcode = fr_value_box_cmp_op(map->op, &vp->data, tmpl_value(map->rhs));
+ if (rcode < 0) return -1;
+
+ if (rcode == 0) {
+ if (fr_value_box_copy(vp, &vp->data, tmpl_value(map->rhs)) < 0) {
+ return -1;
+ }
+ }
+
+ vp = fr_pair_find_by_da(list, vp, da);
+ if (vp) goto redo_filter;
+ break;
+
+ default:
+ fr_assert(0);
+ break;
+ }
+
+ return 0;
+}
fr_htrie_t *tree;
fr_htrie_type_t htype;
fr_value_box_t *box;
+ map_t *reply_head;
if (!filename) {
*ptree = NULL;
entry = NULL;
while ((entry = fr_dlist_next(&users.head, entry))) {
map_t *map = NULL;
+ map_t *prev;
fr_dict_attr_t const *da;
+ reply_head = NULL;
+
/*
* Look for improper use of '=' in the
* check items. They should be using
}
/*
- * Ignore attributes which are set
- * properly.
+ * Move assignment operations to the reply list.
*/
- if (map->op != T_OP_EQ) {
- continue;
- }
+ switch (map->op) {
+ case T_OP_EQ:
+ case T_OP_SET:
+ case T_OP_ADD_EQ:
+ prev = map_list_remove(&entry->check, map);
+ map_list_insert_after(&entry->reply, reply_head, map);
+ reply_head = map;
+ map = prev;
+ break;
- /*
- * If it's a vendor attribute,
- * or it's a wire protocol,
- * ensure it has '=='.
- */
- if ((fr_dict_vendor_num_by_da(da) != 0) ||
- (da->attr < 0x100)) {
- WARN("%s[%d] Changing '%s =' to '%s =='\n\tfor comparing RADIUS attribute in check item list for key %s",
- entry->filename, entry->lineno,
- da->name, da->name,
- entry->name);
- map->op = T_OP_CMP_EQ;
- continue;
+ default:
+ break;
}
} /* end of loop over check items */
}
da = tmpl_attr_tail_da(map->lhs);
+ if (map->op == T_OP_CMP_FALSE) {
+ ERROR("%s[%d] Invalid operator '!*' for reply item %s",
+ entry->filename, entry->lineno, map->lhs->name);
+ return -1;
+ }
+
if ((htype != FR_HTRIE_TRIE) && (da == attr_next_shortest_prefix)) {
ERROR("%s[%d] Cannot use %s when key is not an IP / IP prefix",
entry->filename, entry->lineno, da->name);
* free all subsequent maps.
*/
if (da == attr_fall_through) {
- map_t *prev;
-
if (tmpl_is_data(map->rhs) && (tmpl_value_type(map->rhs) == FR_TYPE_BOOL)) {
entry->fall_through = tmpl_value(map->rhs)->vb_bool;
}
map = prev;
continue;
}
-
- /*
- * If we allow list qualifiers in
- * users_file.c, then this module also
- * needs to be updated. Ensure via an
- * assertion that they do not get out of
- * sync.
- */
- fr_assert(tmpl_list(map->lhs) == request_attr_reply);
}
}
* Find the entry for the user.
*/
while (user_pl || default_pl) {
- fr_pair_t *vp;
map_t *map = NULL;
PAIR_LIST const *pl;
- fr_pair_list_t list;
bool next_shortest_prefix;
bool match = true;
default_pl = fr_dlist_next(&default_list->head, default_pl);
}
- fr_pair_list_init(&list);
-
/*
- * Realize the map to a list of VPs
+ * Run the check items.
*/
while ((map = map_list_next(&pl->check, map))) {
- fr_pair_list_t tmp_list;
-
RDEBUG3(" %s %s %s", map->lhs->name, fr_tokens[map->op], map->rhs->name);
/*
case T_OP_EQ:
case T_OP_SET:
case T_OP_ADD_EQ:
- fr_pair_list_init(&tmp_list);
- if (map_to_vp(request->control_ctx, &tmp_list, request, map, NULL) < 0) {
- fr_pair_list_free(&list);
- RPWARN("Failed parsing check item, skipping entry");
- match = false;
- break;
- }
-
- fr_pair_list_append(&list, &tmp_list);
- break;
+ fr_assert(0);
+ return -1;
/*
* Evaluate the map, including regexes.
*/
default:
if (!files_eval_map(request, map)) {
- RDEBUG3(" failed match - %s", fr_strerror());
+ RDEBUG3(" failed match");
match = false;
}
break;
if (!match) break;
}
- if (!match) {
- fr_pair_list_free(&list);
- continue;
- }
+ if (!match) continue;
RDEBUG2("Found match \"%s\" on line %d of %s", pl->name, pl->lineno, pl->filename);
found = true;
next_shortest_prefix = false;
- /*
- * Move the control items over, too.
- */
- radius_pairmove(request, &request->control_pairs, &list);
-
/* ctx may be reply */
if (!map_list_empty(&pl->reply)) {
map = NULL;
- while ((map = map_list_next(&pl->reply, map))) {
- fr_pair_list_t tmp_list;
- fr_pair_list_init(&tmp_list);
- if (map->op == T_OP_CMP_FALSE) continue;
-
- if (map_to_vp(request->reply_ctx, &tmp_list, request, map, NULL) < 0) {
- RPWARN("Failed parsing map for reply item %s, skipping it", map->lhs->name);
- break;
- }
+ while ((map = map_list_next(&pl->reply, map))) {
/*
- * And do the same checks for prefix tries.
+ * Do Fall-Through style checks for prefix tries.
*/
- if (trie && (keylen > 0)) {
- vp = fr_pair_list_head(&tmp_list);
- if (vp->da == attr_next_shortest_prefix) {
- next_shortest_prefix = vp->vp_bool;
- fr_pair_list_free(&tmp_list);
- continue;
- }
+ if (trie && (keylen > 0) && (tmpl_attr_tail_da(map->lhs) == attr_next_shortest_prefix)) {
+ fr_assert(tmpl_is_data(map->rhs));
+
+ next_shortest_prefix = tmpl_value(map->rhs)->vb_bool;
+ continue;
}
- radius_pairmove(request, &request->reply_pairs, &tmp_list);
+ if (fr_pairmove_map(request, map) < 0) {
+ RPWARN("Failed parsing map for reply item %s, skipping it", map->lhs->name);
+ break;
+ }
}
}