// &control := ...
}
+ if (fr_pair_immutable(vp)) {
+ RWDEBUG("Cannot modify immutable value for %s", current->lhs.vpt->name);
+ return -1;
+ }
+
/*
* We found an existing attribute, with a modification operator.
*/
if (!fr_type_is_leaf(dst->type)) return invalid_type(dst->type);
if (!fr_type_is_leaf(src->type)) return invalid_type(src->type);
+ if (dst->immutable) {
+ fr_strerror_printf("Cannot modify immutable value");
+ return -1;
+ }
+
/*
* These operators are included here for testing and completeness. But see comments in
* fr_edit_list_apply_pair_assignment() for what the caller should be doing.
if (!fr_type_is_numeric(src->type)) return invalid_type(src->type);
+ if (dst->immutable) {
+ fr_strerror_printf("Cannot modify immutable value");
+ return -1;
+ }
+
if (op == T_OP_INCRM) {
/*
* Add 1 or subtract 1 means RHS is always 1.
case FR_EDIT_CLEAR:
if (!fr_type_is_structural(vp->vp_type)) return 0;
+ if (fr_pair_immutable(vp)) {
+ fr_strerror_printf("Cannot modify immutable value for %s", vp->da->name);
+ return -1;
+ }
+
fr_pair_list_free(&vp->vp_group);
return 0;
*/
int fr_edit_list_pair_delete(fr_edit_list_t *el, fr_pair_list_t *list, fr_pair_t *vp)
{
+ if (fr_pair_immutable(vp)) {
+ fr_strerror_printf("Cannot modify immutable value for %s", vp->da->name);
+ return -1;
+ }
+
if (!el) {
fr_pair_delete(list, vp);
return 0;
* Delete all VPs with a matching da.
*/
fr_pair_list_foreach(list, vp) {
+ if (fr_pair_immutable(vp)) continue;
+
if (vp->da != da) continue;
(void) fr_pair_remove(list, vp);
{
if (!fr_type_is_leaf(vp->vp_type)) return -1;
+ if (vp->data.immutable) {
+ fr_strerror_printf("Cannot modify immutable value for %s", vp->da->name);
+ return -1;
+ }
+
if (el && (edit_record(el, FR_EDIT_VALUE, vp, NULL, NULL) < 0)) return -1;
if (!fr_type_is_fixed_size(vp->vp_type)) fr_value_box_clear(&vp->data);
{
if (to_replace->da != vp->da) return -1;
+ if (fr_pair_immutable(to_replace)) {
+ fr_strerror_printf("Cannot modify immutable value for %s", vp->da->name);
+ return -1;
+ }
+
if (!el) {
if (fr_pair_insert_after(list, to_replace, vp) < 0) return -1;
fr_pair_delete(list, to_replace);
fr_pair_list_foreach(list, vp) {
if (da == vp->da) {
+ if (fr_pair_immutable(vp)) continue;
+
cnt++;
fr_pair_delete(list, vp);
}
return true;
}
+/**
+ *
+ * @param[in] vp the pair to check
+ * @return
+ * - true the pair is immutable, or has an immutable child
+ * - false the pair is not immutable, or has no immutable children.
+ */
+bool fr_pair_immutable(fr_pair_t const *vp)
+{
+ if (fr_type_is_leaf(vp->vp_type)) return vp->data.immutable;
+
+ fr_pair_list_foreach(&vp->vp_group, child) {
+ if (fr_type_is_leaf(child->vp_type)) {
+ if (child->data.immutable) return true;
+
+ continue;
+ }
+
+ if (fr_pair_immutable(child)) return true;
+ }
+
+ return false;
+}
+
/** Steal a list of pairs to a new context
*
*/
bool fr_pair_validate_relaxed(fr_pair_t const *failed[2], fr_pair_list_t *filter,
fr_pair_list_t *list) CC_HINT(nonnull(2,3));
+bool fr_pair_immutable(fr_pair_t const *vp) CC_HINT(nonnull);
+
+
/* Lists */
int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from);
/** Type and flags should appear together for packing efficiency
*/
fr_type_t _CONST type; //!< Type of this value-box, at the start, see pair.h
+
unsigned int tainted : 1; //!< i.e. did it come from an untrusted source
unsigned int secret : 1; //!< Same as #fr_dict_attr_flags_t secret
+ unsigned int immutable : 1; //!< once set, the value cannot be changed
+
uint16_t _CONST safe; //!< more detailed safety
fr_value_box_entry_t entry; //!< Doubly linked list entry.
.enumv = enumv,
.tainted = tainted,
.secret = enumv && enumv->flags.secret,
+ /* don't set the immutable flag. The caller has to do it once he's finished editing the values */
}, sizeof(*vb));
fr_value_box_list_entry_init(vb);
box->secret = secret;
}
+static inline CC_HINT(nonnull, always_inline)
+void fr_value_box_set_immutable(fr_value_box_t *box)
+{
+ box->immutable = true;
+}
+
/** @name Assign and manipulate binary-unsafe C strings
*