]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
encode / decode as nested attributes
authorAlan T. DeKok <aland@freeradius.org>
Mon, 20 Feb 2023 20:24:41 +0000 (15:24 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 20 Feb 2023 20:46:23 +0000 (15:46 -0500)
src/protocols/tacacs/decode.c
src/protocols/tacacs/encode.c
src/tests/unit/protocols/tacacs/typed.txt

index 851a2c0a03399b47ef54ec077acf8dea0755a756..6cd5a104d48c47df65325bad07ef8400adbda9f5 100644 (file)
@@ -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;
 }
 
index d038e7752d5f24e8b354640f460327498faa69a9..111cd194958650ed8f2196d2b27f0f5b6d4f2368 100644 (file)
@@ -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;
 
index 305722ffcf1928eed8da0396126f66c7a002cacb..e57329c02ff476b061852008433f9af458b5593b 100644 (file)
@@ -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