From: Alan T. DeKok Date: Mon, 28 Jul 2025 19:44:37 +0000 (-0400) Subject: add FR_TYPE_ATTR X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a8f66dee56e38f5796b3fcf4605a93764320e585;p=thirdparty%2Ffreeradius-server.git add FR_TYPE_ATTR no tests. will do soon. --- diff --git a/src/bin/unit_test_attribute.c b/src/bin/unit_test_attribute.c index c9a7790205..8ede049f2b 100644 --- a/src/bin/unit_test_attribute.c +++ b/src/bin/unit_test_attribute.c @@ -1045,13 +1045,14 @@ static int dictionary_load_common(command_result_t *result, command_file_ctx_t * RETURN_OK(0); } -static size_t parse_typed_value(command_result_t *result, fr_value_box_t *box, char const **out, char const *in, size_t inlen) +static size_t parse_typed_value(command_result_t *result, command_file_ctx_t *cc, fr_value_box_t *box, char const **out, char const *in, size_t inlen) { fr_type_t type; size_t match_len; ssize_t slen; char const *p; fr_sbuff_t sbuff; + fr_dict_attr_t const *enumv = NULL; /* * Parse data types @@ -1074,7 +1075,7 @@ static size_t parse_typed_value(command_result_t *result, fr_value_box_t *box, c if (*p == '"'){ p++; sbuff = FR_SBUFF_IN(p, strlen(p)); - slen = fr_value_box_from_substr(box, box, FR_TYPE_STRING, NULL, + slen = fr_value_box_from_substr(box, box, FR_TYPE_STRING, enumv, &sbuff, &value_parse_rules_double_quoted); if (slen < 0) { @@ -1096,7 +1097,23 @@ static size_t parse_typed_value(command_result_t *result, fr_value_box_t *box, c } else { sbuff = FR_SBUFF_IN(p, strlen(p)); - slen = fr_value_box_from_substr(box, box, type, NULL, + /* + * We have no other way to pass the dict to the value-box parse function. + */ + if (type == FR_TYPE_ATTR) { + fr_dict_t const *dict = dictionary_current(cc); + + if (!dict) { + fr_strerror_const("proto-dictionary must be defined"); + RETURN_PARSE_ERROR(0); + } + + enumv = fr_dict_root(dict); + } + + fprintf(stderr, "PARSE TYPE %s %p\n", fr_type_to_str(type), enumv); + + slen = fr_value_box_from_substr(box, box, type, enumv, &sbuff, &value_parse_rules_bareword_unquoted); if (slen < 0) { @@ -1239,7 +1256,7 @@ static size_t command_calc(command_result_t *result, command_file_ctx_t *cc, p = in; end = in + inlen; - match_len = parse_typed_value(result, a, &value, p, end - p); + match_len = parse_typed_value(result, cc, a, &value, p, end - p); if (match_len == 0) return 0; /* errors have already been updated */ p += match_len; @@ -1262,7 +1279,7 @@ static size_t command_calc(command_result_t *result, command_file_ctx_t *cc, } fr_skip_whitespace(p); - match_len = parse_typed_value(result, b, &value, p, end - p); + match_len = parse_typed_value(result, cc, b, &value, p, end - p); if (match_len == 0) return 0; p += match_len; @@ -1338,7 +1355,7 @@ static size_t command_calc_nary(command_result_t *result, command_file_ctx_t *cc a = talloc_zero(group, fr_value_box_t); - match_len = parse_typed_value(result, a, &value, p, end - p); + match_len = parse_typed_value(result, cc, a, &value, p, end - p); if (match_len == 0) return 0; /* errors have already been updated */ fr_value_box_list_insert_tail(&group->vb_group, a); @@ -1386,7 +1403,7 @@ static size_t command_cast(command_result_t *result, command_file_ctx_t *cc, p = in; end = in + inlen; - match_len = parse_typed_value(result, a, &value, p, end - p); + match_len = parse_typed_value(result, cc, a, &value, p, end - p); if (match_len == 0) return 0; /* errors have already been updated */ p += match_len; @@ -2816,7 +2833,7 @@ static size_t command_value_box_normalise(command_result_t *result, command_file ssize_t slen; fr_type_t type; - match_len = parse_typed_value(result, box, &value, in, strlen(in)); + match_len = parse_typed_value(result, cc, box, &value, in, strlen(in)); if (match_len == 0) { talloc_free(box); return 0; /* errors have already been updated */ @@ -2844,7 +2861,7 @@ static size_t command_value_box_normalise(command_result_t *result, command_file * box as last time. */ box2 = talloc_zero(NULL, fr_value_box_t); - if (fr_value_box_from_str(box2, box2, type, NULL, + if (fr_value_box_from_str(box2, box2, type, box->enumv, data, slen, &fr_value_unescape_double) < 0) { talloc_free(box2); diff --git a/src/lib/json/json.c b/src/lib/json/json.c index 079588c1d7..595008430e 100644 --- a/src/lib/json/json.c +++ b/src/lib/json/json.c @@ -443,6 +443,7 @@ fr_slen_t fr_json_str_from_value(fr_sbuff_t *out, fr_value_box_t *vb, bool inclu fr_strerror_const("Structural boxes not yet supported"); return -1; + case FR_TYPE_ATTR: case FR_TYPE_INTERNAL: fr_strerror_printf("Box type %s cannot be converted to string", fr_type_to_str(vb->type)); return -1; diff --git a/src/lib/unlang/xlat_builtin.c b/src/lib/unlang/xlat_builtin.c index f9b869e969..98ba109544 100644 --- a/src/lib/unlang/xlat_builtin.c +++ b/src/lib/unlang/xlat_builtin.c @@ -366,6 +366,7 @@ static int CC_HINT(nonnull(2,3)) filename_xlat_escape(UNUSED request_t *request, case FR_TYPE_IPV4_PREFIX: case FR_TYPE_IPV6_ADDR: case FR_TYPE_IPV6_PREFIX: + case FR_TYPE_ATTR: /* * Printing prefixes etc. does NOT result in the escape function being called! So * instead, we cast the results to a string, and then escape the string. diff --git a/src/lib/util/htrie.h b/src/lib/util/htrie.h index 0ed68ef27d..191ae18226 100644 --- a/src/lib/util/htrie.h +++ b/src/lib/util/htrie.h @@ -164,6 +164,7 @@ static inline fr_htrie_type_t fr_htrie_hint(fr_type_t type) case FR_TYPE_FLOAT64: return FR_HTRIE_RB; + case FR_TYPE_ATTR: case FR_TYPE_NON_LEAF: break; } diff --git a/src/lib/util/pair.h b/src/lib/util/pair.h index eccaaa407a..9b5db0ee74 100644 --- a/src/lib/util/pair.h +++ b/src/lib/util/pair.h @@ -131,6 +131,8 @@ struct value_pair_s { #define vp_float32 data.vb_float32 #define vp_float64 data.vb_float64 +#define vp_attr data.vb_attr + #define vp_date data.vb_date #define vp_time_delta data.vb_time_delta diff --git a/src/lib/util/types.c b/src/lib/util/types.c index 105000b6b5..55ed550bb7 100644 --- a/src/lib/util/types.c +++ b/src/lib/util/types.c @@ -70,6 +70,8 @@ fr_table_num_ordered_t const fr_type_table[] = { { L("vendor"), FR_TYPE_VENDOR }, { L("group"), FR_TYPE_GROUP }, + { L("attribute"), FR_TYPE_ATTR }, + /* * Alternative names */ @@ -119,6 +121,7 @@ static char const *fr_type_to_c_type[] = { [FR_TYPE_TIME_DELTA] = "fr_time_delta_t", [FR_TYPE_SIZE] = "size_t", [FR_TYPE_VALUE_BOX] = "fr_value_box_t", + [FR_TYPE_ATTR] = "fr_dict_attr_t *", [FR_TYPE_VOID] = "void *", [FR_TYPE_VALUE_BOX_CURSOR] = "fr_dcursor_t *", @@ -162,6 +165,7 @@ static size_t const fr_type_to_c_size[] = { [FR_TYPE_TIME_DELTA] = sizeof(fr_time_delta_t), [FR_TYPE_SIZE] = sizeof(size_t), [FR_TYPE_VALUE_BOX] = sizeof(fr_value_box_t), + [FR_TYPE_ATTR] = sizeof(fr_dict_attr_t *), [FR_TYPE_VOID] = sizeof(void *), [FR_TYPE_VALUE_BOX_CURSOR] = sizeof(void *), diff --git a/src/lib/util/types.h b/src/lib/util/types.h index 0c9dadd2d2..00d91f6a36 100644 --- a/src/lib/util/types.h +++ b/src/lib/util/types.h @@ -80,6 +80,7 @@ typedef enum { FR_TYPE_GROUP, //!< A grouping of other attributes FR_TYPE_VALUE_BOX, //!< A boxed value. + FR_TYPE_ATTR, //!< A contains an attribute reference FR_TYPE_VOID, //!< User data. Should be a talloced chunk ///< assigned to the ptr value of the union. @@ -256,6 +257,7 @@ typedef enum { #define FR_TYPE_LEAF_DEF(_beg, _mid, _end) \ _beg(FR_TYPE_ETHERNET) \ _mid(FR_TYPE_IFID) \ + _mid(FR_TYPE_ATTR) \ FR_TYPE_IP_DEF(_mid, _mid, _mid) \ FR_TYPE_VARIABLE_SIZE_DEF(_mid, _mid, _mid) \ FR_TYPE_NUMERIC_DEF(_mid, _mid, _end) diff --git a/src/lib/util/value.c b/src/lib/util/value.c index 44d5334fd5..5edffdb0a5 100644 --- a/src/lib/util/value.c +++ b/src/lib/util/value.c @@ -829,6 +829,9 @@ int8_t fr_value_box_cmp(fr_value_box_t const *a, fr_value_box_t const *b) case FR_TYPE_NULL: /* NULLs are not comparable */ return -2; + case FR_TYPE_ATTR: + return CMP(a->vb_attr, b->vb_attr); + /* * These should be handled at some point */ @@ -1631,6 +1634,48 @@ ssize_t fr_value_box_to_network(fr_dbuff_t *dbuff, fr_value_box_t const *value) } break; + case FR_TYPE_ATTR: + { + fr_value_box_t tmp, base; + + /* + * For now, we only encode at depth 1. The protocol-specific encoders need to do + * something special for attributes at other depths. + */ + if (value->vb_attr->depth != 1) { + fr_strerror_printf("Unsupported depth '%u' for attribute %s", + value->vb_attr->depth, value->vb_attr->name); + return 0; + } + + switch (value->vb_attr->flags.length) { + case 1: + fr_value_box_init(&base, FR_TYPE_UINT8, NULL, false); + base.vb_uint8 = value->vb_attr->attr; + break; + + case 2: + fr_value_box_init(&base, FR_TYPE_UINT16, NULL, false); + base.vb_uint16 = value->vb_attr->attr; + break; + + case 4: + fr_value_box_init(&base, FR_TYPE_UINT32, NULL, false); + base.vb_uint32 = value->vb_attr->attr; + break; + + default: + fr_strerror_printf("Unsupported length '%d' for attribute %s", + value->vb_attr->flags.length, value->vb_attr->name); + return 0; + } + + fr_value_box_hton(&tmp, &base); + + FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, fr_value_box_raw(&tmp, tmp.type), min); + } + break; + /* * Dates and deltas are stored internally as * 64-bit nanoseconds. We have to convert to the @@ -2026,6 +2071,10 @@ ssize_t fr_value_box_from_network(TALLOC_CTX *ctx, FR_DBUFF_OUT_RETURN(&dst->vb_float64, &work_dbuff); break; + case FR_TYPE_ATTR: + fr_strerror_const("Unsupported ntoh from FR_TYPE_ATTR"); + return 0; + /* * Dates and deltas are stored internally as * 64-bit nanoseconds. We have to convert from @@ -3708,6 +3757,41 @@ int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, } break; /* use generic string/octets stuff below */ + case FR_TYPE_ATTR: + if (src->vb_attr->depth != 1) { + fr_strerror_printf("Unsupported depth '%d' for attribute %s", + src->vb_attr->depth, src->vb_attr->name); + return 0; + + } + + /* + * Convert it to an integer of the correct lenght. Then, cast it in place. + */ + switch (src->vb_attr->flags.length) { + case 1: + fr_value_box_init(dst, FR_TYPE_UINT8, NULL, false); + dst->vb_uint8 = src->vb_attr->attr; + break; + + case 2: + fr_value_box_init(dst, FR_TYPE_UINT16, NULL, false); + dst->vb_uint16 = src->vb_attr->attr; + break; + + case 4: + fr_value_box_init(dst, FR_TYPE_UINT32, NULL, false); + dst->vb_uint32 = src->vb_attr->attr; + break; + + default: + fr_strerror_printf("Unsupported length '%d' for attribute %s", + src->vb_attr->flags.length, src->vb_attr->name); + return 0; + } + + return fr_value_box_cast_in_place(ctx, dst, dst_type, dst_enumv); + /* * Invalid types for casting (were caught earlier) */ @@ -5378,6 +5462,33 @@ parse: fr_strerror_const("Unexpected value for data type NULL"); return -1; + case FR_TYPE_ATTR: + if (!dst_enumv) { + fr_strerror_const("No dictionary passed for data type 'attr'"); + return -1; + } + + if (!dst_enumv->flags.is_root) { + fr_strerror_const("Can only start from dictioanry root for data type 'attr'"); + return -1; + } + + if (!fr_sbuff_next_if_char(&our_in, '@')) { + fr_strerror_const("Expected '@...' for attribute reference"); + return -1; + } + + fr_value_box_init(dst, dst_type, dst_enumv, false); + + slen = fr_dict_attr_by_name_substr(NULL, &dst->vb_attr, dst_enumv, &our_in, rules->terminals); + if (slen <= 0) { + fr_strerror_printf("Failed to find the named attribute in %s", dst_enumv->name); + return -2; + } + fr_assert(dst->vb_attr != NULL); + + FR_SBUFF_SET_RETURN(in, &our_in); + /* * Dealt with below */ @@ -5650,6 +5761,18 @@ ssize_t fr_value_box_print(fr_sbuff_t *out, fr_value_box_t const *data, fr_sbuff FR_SBUFF_IN_CHAR_RETURN(&our_out, '}'); break; + case FR_TYPE_ATTR: + if (data->vb_attr->depth != 1) { + fr_strerror_printf("Unsupported depth '%u' for attribute %s", + data->vb_attr->depth, data->vb_attr->name); + return 0; + } + + FR_SBUFF_IN_CHAR_RETURN(&our_out, '@'); + FR_SBUFF_IN_ESCAPE_RETURN(&our_out, data->vb_attr->name, + strlen(data->vb_attr->name), e_rules); + break; + case FR_TYPE_NULL: FR_SBUFF_IN_STRCPY_LITERAL_RETURN(&our_out, "NULL"); break; diff --git a/src/lib/util/value.h b/src/lib/util/value.h index fa0b25ae2c..cab2b355f5 100644 --- a/src/lib/util/value.h +++ b/src/lib/util/value.h @@ -112,8 +112,9 @@ typedef union { }; struct { - void * _CONST cursor; //!< cursors - char const * _CONST name; //!< name of the current cursor + void * _CONST cursor; //!< cursors + char const * _CONST name; //!< name of the current cursor + fr_dict_attr_t const * _CONST da; //!< dictionary reference }; /* @@ -258,6 +259,7 @@ typedef enum { #define vb_octets datum.octets #define vb_void datum.ptr #define vb_group datum.children +#define vb_attr datum.da #define vb_ip datum.ip diff --git a/src/modules/rlm_lua/lua.c b/src/modules/rlm_lua/lua.c index dcb60f682a..91b7ad88ff 100644 --- a/src/modules/rlm_lua/lua.c +++ b/src/modules/rlm_lua/lua.c @@ -193,6 +193,7 @@ static int fr_lua_marshall(request_t *request, lua_State *L, fr_pair_t const *vp lua_pushinteger(L, (lua_Integer)vp->vp_size); break; + case FR_TYPE_ATTR: case FR_TYPE_NON_LEAF: REDEBUG("Cannot convert %s to Lua type", fr_type_to_str(vp->vp_type)); return -1; diff --git a/src/modules/rlm_mruby/mruby.c b/src/modules/rlm_mruby/mruby.c index 80c39121fd..86aa512371 100644 --- a/src/modules/rlm_mruby/mruby.c +++ b/src/modules/rlm_mruby/mruby.c @@ -261,10 +261,12 @@ static mrb_value mruby_pair_value_to_ruby(mrb_state *mrb, request_t *request, fr return value; } - default: - fr_assert(0); + case FR_TYPE_ATTR: + case FR_TYPE_NON_LEAF: + REDEBUG("Cannot convert %s to ruby type", fr_type_to_str(vp->vp_type)); break; } + return mrb_nil_value(); } diff --git a/src/modules/rlm_perl/rlm_perl.c b/src/modules/rlm_perl/rlm_perl.c index d9248469ad..f9e6ea7bb6 100644 --- a/src/modules/rlm_perl/rlm_perl.c +++ b/src/modules/rlm_perl/rlm_perl.c @@ -576,6 +576,11 @@ static int perl_value_marshal(fr_pair_t *vp, SV **value) PERLINT(32) PERLINT(64) + + case FR_TYPE_SIZE: + *value = sv_2mortal(newSVuv(vp->vp_size)); + break; + case FR_TYPE_BOOL: *value = sv_2mortal(newSVuv(vp->vp_bool)); break; @@ -614,8 +619,9 @@ static int perl_value_marshal(fr_pair_t *vp, SV **value) break; /* Only leaf nodes should be able to call this */ - default: - fr_assert(0); + case FR_TYPE_ATTR: + case FR_TYPE_NON_LEAF: + croak("Cannot convert %s to Perl type", fr_type_to_str(vp->vp_type)); return -1; } diff --git a/src/modules/rlm_python/rlm_python.c b/src/modules/rlm_python/rlm_python.c index a34634062a..94f4f476a5 100644 --- a/src/modules/rlm_python/rlm_python.c +++ b/src/modules/rlm_python/rlm_python.c @@ -878,6 +878,7 @@ static PyObject *py_freeradius_pair_getvalue(PyObject *self, UNUSED void *closur case FR_TYPE_COMBO_IP_ADDR: case FR_TYPE_COMBO_IP_PREFIX: case FR_TYPE_ETHERNET: + case FR_TYPE_ATTR: { ssize_t slen; char buffer[1024]; @@ -1040,6 +1041,7 @@ static int py_freeradius_pair_setvalue(PyObject *self, PyObject *value, UNUSED v case FR_TYPE_COMBO_IP_ADDR: case FR_TYPE_COMBO_IP_PREFIX: case FR_TYPE_ETHERNET: + case FR_TYPE_ATTR: { char const *val; ssize_t len;