From: Alan T. DeKok Date: Mon, 20 Feb 2023 20:24:41 +0000 (-0500) Subject: encode / decode as nested attributes X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=931bf829dadc56c3d63c4c8690c57136a0cc9d91;p=thirdparty%2Ffreeradius-server.git encode / decode as nested attributes --- diff --git a/src/protocols/tacacs/decode.c b/src/protocols/tacacs/decode.c index 851a2c0a033..6cd5a104d48 100644 --- a/src/protocols/tacacs/decode.c +++ b/src/protocols/tacacs/decode.c @@ -182,14 +182,31 @@ static int tacacs_decode_args(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr uint8_t arg_cnt, uint8_t const *argv, uint8_t const *attrs, NDEBUG_UNUSED uint8_t const *end) { uint8_t i; + bool append = false; uint8_t const *p = attrs; fr_pair_t *vp; + fr_pair_t *vendor = NULL; /* * No one? Just get out! */ if (!arg_cnt) return 0; + /* + * Try to decode as nested attributes. If we can't, everything is + * + * Argument-List = "foo=bar" + */ + if (parent) { + vendor = fr_pair_find_by_da(out, NULL, parent); + if (!vendor) { + vendor = fr_pair_afrom_da(ctx, parent); + if (!vendor) return -1; + + append = true; + } + } + /* * Then, do the dirty job of creating attributes. */ @@ -232,11 +249,11 @@ static int tacacs_decode_args(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr * * Argument-List += "name=value" */ - if (parent) { + if (vendor) { da = fr_dict_attr_by_name(NULL, parent, (char *) buffer); if (!da) goto raw; - vp = fr_pair_afrom_da(ctx, da); + vp = fr_pair_afrom_da(vendor, da); if (!vp) goto oom; /* @@ -252,25 +269,23 @@ static int tacacs_decode_args(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr if (da->type == FR_TYPE_OCTETS) { if ((arg_end > value) && (fr_pair_value_memdup(vp, value, arg_end - value, true) < 0)) { - talloc_free(vp); - return -1; + goto fail; } } else if (da->type == FR_TYPE_STRING) { if ((arg_end > value) && (fr_pair_value_bstrndup(vp, (char const *) value, arg_end - value, true) < 0)) { - talloc_free(vp); - return -1; + goto fail; } } else if (arg_end == value) { /* * Any other leaf type MUST have non-zero contents. */ + talloc_free(vp); goto raw; } else { - /* * Parse the string, and try to convert it to the * underlying data type. If it can't be @@ -285,16 +300,24 @@ static int tacacs_decode_args(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr } /* - * Else it parsed fine, append it to the output list. + * Else it parsed fine, append it to the output vendor list. */ } + fr_pair_append(&vendor->vp_group, vp); + } else { raw: vp = fr_pair_afrom_da(ctx, attr_tacacs_argument_list); if (!vp) { oom: fr_strerror_const("Out of Memory"); + fail: + if (append) { + talloc_free(vendor); + } else { + talloc_free(vp); + } return -1; } @@ -303,17 +326,24 @@ static int tacacs_decode_args(TALLOC_CTX *ctx, fr_pair_list_t *out, fr_dict_attr if ((arg_end > value) && (fr_pair_value_bstrndup(vp, (char const *) value, arg_end - value, true) < 0)) { - talloc_free(vp); - return -1; + goto fail; } - } - fr_pair_append(out, vp); + fr_pair_append(out, vp); + } next: p += argv[i]; } + if (append) { + if (fr_pair_list_num_elements(&vendor->vp_group) > 0) { + fr_pair_append(out, vendor); + } else { + talloc_free(vendor); + } + } + return 0; } diff --git a/src/protocols/tacacs/encode.c b/src/protocols/tacacs/encode.c index d038e7752d5..111cd194958 100644 --- a/src/protocols/tacacs/encode.c +++ b/src/protocols/tacacs/encode.c @@ -132,8 +132,8 @@ int fr_tacacs_code_to_packet(fr_tacacs_packet_t *pkt, uint32_t code) */ static uint8_t tacacs_encode_body_arg_cnt(fr_pair_list_t *vps, fr_dict_attr_t const *da) { - uint8_t arg_cnt = 0; - fr_pair_t *vp; + int arg_cnt = 0; + fr_pair_t *vp; for (vp = fr_pair_list_head(vps); vp; @@ -151,11 +151,14 @@ static uint8_t tacacs_encode_body_arg_cnt(fr_pair_list_t *vps, fr_dict_attr_t co continue; } + fr_assert(fr_dict_by_da(vp->da) == dict_tacacs); + /* - * @todo - if we find a Vendor, count its children + * Recurse into children. */ - - fr_assert(fr_dict_by_da(vp->da) == dict_tacacs); + if (vp->da->type == FR_TYPE_VENDOR) { + arg_cnt += tacacs_encode_body_arg_cnt(&vp->vp_group, NULL); + } if (vp->da->parent->type != FR_TYPE_VENDOR) continue; diff --git a/src/tests/unit/protocols/tacacs/typed.txt b/src/tests/unit/protocols/tacacs/typed.txt index 305722ffcf1..e57329c02ff 100644 --- a/src/tests/unit/protocols/tacacs/typed.txt +++ b/src/tests/unit/protocols/tacacs/typed.txt @@ -29,7 +29,7 @@ match c0 02 01 00 e1 66 78 e6 00 00 00 35 4b c5 ea 62 13 cc ca a6 6a 03 3c 8e 3f # Authorization - Response: (Client <- Server) # decode-proto c0 02 02 00 e1 66 78 e6 00 00 00 13 02 59 f9 90 38 81 e1 bb 9d a6 13 93 fc 86 7e 4a 14 1c 24 -match Packet.Version-Major = Plus, Packet.Version-Minor = 0, Packet.Packet-Type = Authorization, Packet.Sequence-Number = 2, Packet.Flags = None, Packet.Session-Id = 3781589222, Packet.Length = 19, Packet-Body-Type = Response, Authorization-Status = Pass-Add, Server-Message = "", Data = 0x, Test.addr = 1.2.3.4 +match Packet.Version-Major = Plus, Packet.Version-Minor = 0, Packet.Packet-Type = Authorization, Packet.Sequence-Number = 2, Packet.Flags = None, Packet.Session-Id = 3781589222, Packet.Length = 19, Packet-Body-Type = Response, Authorization-Status = Pass-Add, Server-Message = "", Data = 0x, Test = { addr = 1.2.3.4 } encode-proto - match c0 02 02 00 e1 66 78 e6 00 00 00 13 02 59 f9 90 38 81 e1 bb 9d a6 13 93 fc 86 7e 4a 14 1c 24