]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
let's actually add code for this
authorAlan T. DeKok <aland@freeradius.org>
Fri, 7 May 2021 14:21:42 +0000 (10:21 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Fri, 7 May 2021 14:21:42 +0000 (10:21 -0400)
src/protocols/radius/attrs.h
src/protocols/radius/base.c
src/protocols/radius/encode.c

index 83ba9ac68a6cbe9add1fa94f19369436701c5744..df049bd2f08140e8b315e8ddd1b252c60bf60c94 100644 (file)
@@ -40,3 +40,4 @@ extern fr_dict_attr_t const *attr_eap_message;
 extern fr_dict_attr_t const *attr_message_authenticator;
 extern fr_dict_attr_t const *attr_state;
 extern fr_dict_attr_t const *attr_vendor_specific;
+extern fr_dict_attr_t const *attr_nas_filter_rule;
index 41185c6244122de8c4f9978d0277b9e40e1bd3ff..39a2965fd4a4eed195a211ae7ca2b2650c480f81 100644 (file)
@@ -60,6 +60,7 @@ fr_dict_attr_t const *attr_eap_message;
 fr_dict_attr_t const *attr_message_authenticator;
 fr_dict_attr_t const *attr_state;
 fr_dict_attr_t const *attr_vendor_specific;
+fr_dict_attr_t const *attr_nas_filter_rule;
 
 extern fr_dict_attr_autoload_t libfreeradius_radius_dict_attr[];
 fr_dict_attr_autoload_t libfreeradius_radius_dict_attr[] = {
@@ -72,6 +73,7 @@ fr_dict_attr_autoload_t libfreeradius_radius_dict_attr[] = {
        { .out = &attr_message_authenticator, .name = "Message-Authenticator", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
        { .out = &attr_state, .name = "State", .type = FR_TYPE_OCTETS, .dict = &dict_radius },
        { .out = &attr_vendor_specific, .name = "Vendor-Specific", .type = FR_TYPE_VSA, .dict = &dict_radius },
+       { .out = &attr_nas_filter_rule, .name = "NAS-Filter-Rule", .type = FR_TYPE_STRING, .dict = &dict_radius },
        { NULL }
 };
 
index e215bb33d42a82941c7e948563c2c01a10db2c82..0ba34c186d9e703ab1e3712ec6cba5404d9a8308 100644 (file)
@@ -1227,6 +1227,111 @@ static ssize_t encode_vsa(fr_dbuff_t *dbuff,
        return fr_dbuff_set(dbuff, &work_dbuff);
 }
 
+/** Encode NAS-Filter-Rule
+ *
+ *  Concatenating the string attributes together, separated by a 0x00 byte,
+ */
+static ssize_t encode_nas_filter_rule(fr_dbuff_t *dbuff,
+                                     fr_da_stack_t *da_stack, UNUSED unsigned int depth,
+                                     fr_dcursor_t *cursor, UNUSED void *encode_ctx)
+{
+       fr_dbuff_t              work_dbuff = FR_DBUFF_NO_ADVANCE(dbuff);
+       fr_dbuff_marker_t       hdr, frag_hdr;
+       fr_pair_t               *vp = fr_dcursor_current(cursor);
+       size_t                  attr_len = 2;
+
+       FR_PROTO_STACK_PRINT(da_stack, depth);
+
+       fr_dbuff_marker(&hdr, &work_dbuff);
+       fr_dbuff_marker(&frag_hdr, &work_dbuff);
+       fr_dbuff_advance(&hdr, 1);
+       FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t)vp->da->attr, 0x00);
+
+       fr_assert(vp->da == attr_nas_filter_rule);
+
+       while (vp) {
+               size_t data_len = vp->vp_length;
+               size_t frag_len;
+               char const *p = vp->vp_strvalue;
+
+               /*
+                *      Keep encoding this attribute until it's done.
+                */
+               while (data_len > 0) {
+                       frag_len = data_len;
+
+                       /*
+                        *      This fragment doesn't overflow the
+                        *      attribute.  Copy it over, update the
+                        *      length, but leave the marker at the
+                        *      current header.
+                        */
+                       if ((attr_len + frag_len) <= UINT8_MAX) {
+                               FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, p, frag_len);
+                               attr_len += frag_len;
+
+                               fr_dbuff_set(&frag_hdr, &hdr);
+                               fr_dbuff_in(&frag_hdr, (uint8_t) attr_len); /* there's no fr_dbuff_in_no_advance() */
+                               break;
+                       }
+
+                       /*
+                        *      This fragment overflows the attribute.
+                        *      Copy the fragment in, and create a new
+                        *      attribute header.
+                        */
+                       frag_len = UINT8_MAX - attr_len;
+                       FR_DBUFF_IN_MEMCPY_RETURN(&work_dbuff, p, frag_len);
+                       fr_dbuff_in(&hdr, (uint8_t) UINT8_MAX);
+
+                       fr_dbuff_marker(&hdr, &work_dbuff);
+                       fr_dbuff_advance(&hdr, 1);
+                       FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t)vp->da->attr, 0x02);
+                       attr_len = 2;
+
+                       p += frag_len;
+                       data_len -= frag_len;
+               }
+
+               /*
+                *      If we have nothing more to do here, then stop.
+                */
+               vp = fr_dcursor_next(cursor);
+               if (!vp || (vp->da != attr_nas_filter_rule)) {
+                       break;
+               }
+
+               /*
+                *      We have to add a zero byte.  If it doesn't
+                *      overflow the current attribute, then just add
+                *      it in.
+                */
+               if (attr_len < UINT8_MAX) {
+                       attr_len++;
+                       FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, 0x00);
+
+                       fr_dbuff_set(&frag_hdr, &hdr);
+                       fr_dbuff_in(&frag_hdr, (uint8_t) attr_len); /* there's no fr_dbuff_in_no_advance() */
+                       continue;
+               }
+
+               /*
+                *      The zero byte causes the current attribute to
+                *      overflow.  Create a new header with the zero
+                *      byte already populated, and keep going.
+                */
+               fr_dbuff_marker(&hdr, &work_dbuff);
+               fr_dbuff_advance(&hdr, 1);
+               FR_DBUFF_IN_BYTES_RETURN(&work_dbuff, (uint8_t)vp->da->attr, 0x00, 0x00);
+               attr_len = 3;
+       }
+
+       vp = fr_dcursor_current(cursor);
+       fr_proto_da_stack_build(da_stack, vp ? vp->da : NULL);
+               
+       return fr_dbuff_set(dbuff, &work_dbuff);
+}
+
 /** Encode an RFC standard attribute 1..255
  *
  *  This function is not the same as encode_attribute(), because this
@@ -1300,6 +1405,14 @@ static ssize_t encode_rfc(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned i
                return fr_dbuff_set(dbuff, &work_dbuff);
        }
 
+       /*
+        *      NAS-Filter-Rule has a stupid format in order to save
+        *      one byte per attribute.
+        */
+       if (vp->da == attr_nas_filter_rule) {
+               return encode_nas_filter_rule(dbuff, da_stack, depth, cursor, encode_ctx);
+       }
+
        /*
         *      Once we've checked for various top-level magic, RFC attributes are just TLVs.
         */