continue;
}
+ if (vp->vp_edit) {
+ RWDEBUG("Attribute cannot be removed, as it is being used in a 'foreach' loop - %pP", vp);
+ continue;
+ }
+
if (fr_edit_list_pair_delete(current->el, list, vp) < 0) {
tmpl_dcursor_clear(&cc);
return -1;
return rcode;
}
+static bool pair_is_editable(request_t *request, fr_pair_t *vp)
+{
+ if (vp->vp_edit) {
+ RWDEBUG("Attribute cannot be removed, as it is being used in a 'foreach' loop - %s", vp->da->name);
+ return false;
+ }
+
+ if (!fr_type_is_structural(vp->vp_type)) return true;
+
+ fr_pair_list_foreach(&vp->vp_group, child) {
+ if (!pair_is_editable(request, child)) return false;
+ }
+
+ return true;
+}
+
static int edit_delete_lhs(request_t *request, edit_map_t *current, bool delete)
{
tmpl_dcursor_ctx_t cc;
fr_assert(parent != NULL);
if (!delete) {
+ if (!pair_is_editable(request, vp)) return -1;
+
if (fr_type_is_structural(vp->vp_type)) {
+
if (fr_edit_list_free_pair_children(current->el, vp) < 0) return -1;
} else {
/*
((tmpl_attr_tail_num(current->lhs.vpt) == NUM_UNSPEC) || (tmpl_attr_tail_num(current->lhs.vpt) > 0) ||
!current->map->rhs)) {
if (edit_delete_lhs(request, current,
- (tmpl_attr_tail_num(current->lhs.vpt) == NUM_UNSPEC) || !current->map->rhs) < 0) return -1;
+ (tmpl_attr_tail_num(current->lhs.vpt) == NUM_UNSPEC) || !current->map->rhs) < 0) return -1;
}
/*
fr_assert(vp != NULL);
do {
- if (fr_type_is_leaf(vp->vp_type)) fr_pair_clear_immutable(vp);
-
+ vp->vp_edit = false;
} while ((vp = fr_dcursor_next(&state->cursor)) != NULL);
tmpl_dcursor_clear(&state->cc);
* under us.
*/
do {
- if (fr_type_is_leaf(vp->vp_type)) fr_pair_set_immutable(vp);
-
+ if (vp->vp_edit) {
+ REDEBUG("Cannot do nested 'foreach' loops over the same attribute %pP", vp);
+ *p_result = RLM_MODULE_FAIL;
+ return UNLANG_ACTION_CALCULATE_RESULT;
+ }
+
+ vp->vp_edit = true;
} while ((vp = fr_dcursor_next(&state->cursor)) != NULL);
tmpl_dcursor_clear(&state->cc);
memset(&vp->data, 0xff, sizeof(vp->data));
#endif
+ /*
+ * Make sure that the pad field is initialized.
+ */
+ if (sizeof(vp->pad)) memset(vp->pad, 0, sizeof(vp->pad));
+
/*
* Hack around const issues...
- * Here again, the orkaround suffices for the compiler but
+ * Here again, the workaround suffices for the compiler but
* not for Coverity, so again we annotate.
*/
/* coverity[store_writes_const_field] */
#define vp_type data.type
#define vp_tainted data.tainted
#define vp_immutable data.immutable
+#define vp_edit data.edit
#define vp_raw da->flags.is_raw
#define ATTRIBUTE_EQ(_x, _y) ((_x && _y) && (_x->da == _y->da))
unsigned int secret : 1; //!< Same as #fr_dict_attr_flags_t secret
unsigned int immutable : 1; //!< once set, the value cannot be changed
unsigned int talloced : 1; //!< Talloced, not stack or text allocated.
+
+ unsigned int edit : 1; //!< to control foreach / edits
+
fr_value_box_safe_for_t _CONST safe_for; //!< A unique value to indicate if that value box is safe
///< for consumption by a particular module for a particular
///< purpose. e.g. LDAP, SQL, etc.