From: Alan T. DeKok Date: Tue, 19 Aug 2025 17:30:36 +0000 (-0400) Subject: move child of union to ATTRIBUTE instead of STRUCT X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9f6face10c8e8cf453ceca595c8f015473147a2a;p=thirdparty%2Ffreeradius-server.git move child of union to ATTRIBUTE instead of STRUCT --- diff --git a/src/lib/util/dict_tokenize.c b/src/lib/util/dict_tokenize.c index a826f1d837a..8bace828266 100644 --- a/src/lib/util/dict_tokenize.c +++ b/src/lib/util/dict_tokenize.c @@ -1346,8 +1346,9 @@ static int dict_read_process_attribute(dict_tokenize_ctx_t *dctx, char **argv, i ssize_t slen; unsigned int attr; - fr_dict_attr_t const *parent; + fr_dict_attr_t const *parent, *key = NULL; fr_dict_attr_t *da; + fr_value_box_t box; if ((argc < 3) || (argc > 4)) { fr_strerror_const("Invalid ATTRIBUTE syntax"); @@ -1419,10 +1420,24 @@ static int dict_read_process_attribute(dict_tokenize_ctx_t *dctx, char **argv, i return -1; } + /* + * A UNION can have child ATTRIBUTEs + */ if (parent->type == FR_TYPE_UNION) { - fr_strerror_printf("Parent attribute %s is of type 'union', and can only have STRUCT children", - parent->name); - return -1; + fr_dict_attr_ext_ref_t *ext; + + /* + * The parent is a union. Get and verify the key ref. + */ + ext = fr_dict_attr_ext(parent, FR_DICT_ATTR_EXT_KEY); + fr_assert(ext != NULL); + + /* + * Double-check names against the reference. + */ + key = ext->ref; + fr_assert(key); + fr_assert(fr_dict_attr_is_key_field(key)); } da = dict_attr_alloc_null(dctx->dict->pool, dctx->dict->proto); @@ -1444,6 +1459,20 @@ static int dict_read_process_attribute(dict_tokenize_ctx_t *dctx, char **argv, i return -1; } + /* + * Check the attribute number against the allowed values. + */ + if (key) { + fr_value_box_init(&box, FR_TYPE_UINT32, NULL, false); + box.vb_uint32 = attr; + + if (fr_value_box_cast_in_place(da, &box, key->type, NULL) < 0) { + fr_strerror_printf_push("Invalid attribute number as key field %s has data type %s", + key->name, fr_type_to_str(key->type)); + goto error; + } + } + if (dict_read_process_common(dctx, &da, parent, argv[0], argv[2], (argc > 3) ? argv[3] : NULL, base_flags) < 0) { goto error; @@ -1518,6 +1547,14 @@ static int dict_read_process_attribute(dict_tokenize_ctx_t *dctx, char **argv, i } } + /* + * Add the VALUE to the key attribute, and ensure that + * the VALUE also contains a pointer to the child struct. + */ + if (key && (dict_attr_enum_add_name(fr_dict_attr_unconst(key), da->name, &box, false, true, da) < 0)) { + goto error; + } + /* * Adding an attribute of type 'struct' is an implicit * BEGIN-STRUCT. @@ -2613,9 +2650,9 @@ static int dict_read_process_struct(dict_tokenize_ctx_t *dctx, char **argv, int if (dict_dctx_push(dctx, da, NEST_NONE) < 0) return -1; /* - * Add the VALUE to the key attribute, and ensure that - * the VALUE also contains a pointer to the child struct. - */ + * Add the VALUE to the key attribute, and ensure that + * the VALUE also contains a pointer to the child struct. + */ if (dict_attr_enum_add_name(fr_dict_attr_unconst(key), name, &box, false, true, da) < 0) { fr_value_box_clear(&box); return -1; diff --git a/src/tests/unit/protocols/radius/dictionary.test b/src/tests/unit/protocols/radius/dictionary.test index 40fcd4286cb..512aa2fd7d4 100644 --- a/src/tests/unit/protocols/radius/dictionary.test +++ b/src/tests/unit/protocols/radius/dictionary.test @@ -45,7 +45,7 @@ MEMBER Key-Field uint8 key MEMBER Data union key=Key-Field BEGIN Test-Struct2.Data -STRUCT Sub-Struct 1 +ATTRIBUTE Sub-Struct 1 struct MEMBER Nested-Sub1 uint8 MEMBER Nested-Sub2 uint8 END Test-Struct2.Data