]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
allow 'length=uint16' as a flag
authorAlan T. DeKok <aland@freeradius.org>
Thu, 31 Oct 2019 19:06:48 +0000 (15:06 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 31 Oct 2019 19:30:24 +0000 (15:30 -0400)
This is mainly for DHCPv6, but it allows us to auto-encode lengths
inside of structs too, which wasn't previously possible.

src/lib/util/dict.h
src/lib/util/dict_print.c
src/lib/util/dict_tokenize.c
src/lib/util/dict_validate.c

index 0c2052fc8211278ccb6fac05cf14e03bf50ee921..0715e479e8283040916cb36c5be87708a5507b6b 100644 (file)
@@ -99,9 +99,11 @@ enum {
 enum {
        FLAG_EXTRA_NONE = 0,                            //!< no extra meaning, should be invalid
        FLAG_KEY_FIELD,                                 //!< this is a key field for a subsequent struct
+       FLAG_LENGTH_UINT16,                             //!< string / octets type is prefixed by uint16 of length
 };
 
 #define da_is_key_field(_da) ((_da)->flags.extra && ((_da)->flags.subtype == FLAG_KEY_FIELD))
+#define da_is_length_field(_da) ((_da)->flags.extra && ((_da)->flags.subtype == FLAG_LENGTH_UINT16))
 
 extern const size_t dict_attr_sizes[FR_TYPE_MAX + 1][2];
 extern fr_dict_t *fr_dict_internal;
index 286fc9441e3fdc2f2eca6b6a9eb76afb4a2e881f..64b5fddd4c44947190f8e79f307988127ece41cc 100644 (file)
@@ -52,7 +52,7 @@ do { \
        FLAG_SET(concat);
        FLAG_SET(virtual);
 
-       if (dict && flags->subtype) {
+       if (dict && !flags->extra && flags->subtype) {
                p += snprintf(p, end - p, "%s", fr_table_str_by_value(dict->subtype_table, flags->subtype, "?"));
                if (p >= end) return -1;
        }
@@ -63,13 +63,15 @@ do { \
        }
 
        if (flags->extra) {
-               switch (type) {
-               case FR_TYPE_UINT8:
-               case FR_TYPE_UINT16:
-               case FR_TYPE_UINT32:
+               switch (flags->subtype) {
+               case FLAG_KEY_FIELD:
                        p += snprintf(p, end - p, "key,");
                        break;
 
+               case FLAG_LENGTH_UINT16:
+                       p += snprintf(p, end - p, "length=uint16,");
+                       break;
+
                default:
                        break;
                }
index e9c02a270b3545fef06decbdbc54390a1bab50fa..f3cf192f924bf04dbcbbc1ae663879788ff1728c 100644 (file)
@@ -343,6 +343,19 @@ static int dict_process_flag_field(dict_tokenize_ctx_t *ctx, char *name, fr_type
                        flags->extra = 1;
                        flags->subtype = FLAG_KEY_FIELD;
 
+               } else if (strcmp(key, "length") == 0) {
+                       if (!value || (strcmp(value, "uint16") != 0)) {
+                               fr_strerror_printf("The 'length' flag can only be used with value 'uint16'");
+                       }
+
+                       if ((type != FR_TYPE_STRING) && (type != FR_TYPE_OCTETS) && (type != FR_TYPE_UINT32)) {
+                               fr_strerror_printf("The 'length' flag can only be used for attributes of type 'string' or 'octets'");
+                               return -1;
+                       }
+
+                       flags->extra = 1;
+                       flags->subtype = FLAG_LENGTH_UINT16;
+
                } else if ((type == FR_TYPE_DATE) || (type == FR_TYPE_TIME_DELTA)) {
                        flags->length = 4;
                        flags->type_size = FR_TIME_RES_SEC;
index 00c6a1c2f5802e6f0cb9e9696383b0d67177db31..e15e08441fec12b27c41c508059219fe1ce370d4 100644 (file)
@@ -160,7 +160,12 @@ bool dict_attr_flags_valid(fr_dict_t *dict, fr_dict_attr_t const *parent,
                        break;
                }
 
+               /*
+                *      DHCPv6 has arrays of string / octets, prefixed
+                *      with a uint16 field of "length".  Also, arrays of dns_labels.
+                */
                if (dict->root->attr == FR_PROTOCOL_DHCPV6) {
+                       ALLOW_FLAG(extra);
                        ALLOW_FLAG(subtype);
                }
 
@@ -221,8 +226,8 @@ bool dict_attr_flags_valid(fr_dict_t *dict, fr_dict_attr_t const *parent,
         *      the data type.
         */
        if (flags->extra) {
-               if (flags->subtype != FLAG_KEY_FIELD) {
-                       fr_strerror_printf("The 'key' flag cannot be used with any other flags.");
+               if ((flags->subtype != FLAG_KEY_FIELD) && (flags->subtype != FLAG_LENGTH_UINT16)) {
+                       fr_strerror_printf("The 'key' and 'length' flags cannot be used with any other flags.");
                        return false;
                }
 
@@ -230,17 +235,39 @@ bool dict_attr_flags_valid(fr_dict_t *dict, fr_dict_attr_t const *parent,
                case FR_TYPE_UINT8:
                case FR_TYPE_UINT16:
                case FR_TYPE_UINT32:
-                       ALLOW_FLAG(extra);
-                       ALLOW_FLAG(subtype);
+                       if (flags->subtype != FLAG_KEY_FIELD) {
+                               fr_strerror_printf("Invalid type for extra flag.");
+                               return false;
+                       }
+
                        if (parent->type != FR_TYPE_STRUCT) {
                                fr_strerror_printf("The 'key' flag can only be used inside of a 'struct'.");
                                return false;
                        }
 
+                       ALLOW_FLAG(extra);
+                       ALLOW_FLAG(subtype);
+                       break;
+
+               case FR_TYPE_OCTETS:
+                       if (flags->length != 0) {
+                               fr_strerror_printf("Cannot use [..] and length=uint16");
+                               return false;
+                       }
+                       /* FALL-THROUGH */
+
+               case FR_TYPE_STRING:
+                       if (flags->subtype != FLAG_LENGTH_UINT16) {
+                               fr_strerror_printf("Invalid type for extra flag.");
+                               return false;
+                       }
+
+                       ALLOW_FLAG(extra);
+                       ALLOW_FLAG(array);
+                       ALLOW_FLAG(subtype);
                        break;
 
                default:
-                       fr_strerror_printf("The 'key' flag can only be used with unsigned integer data types");
                        return -1;
                }