Allow 'octet' attributes to have a fixed length.
authorAlan T. DeKok <aland@freeradius.org>
Thu, 15 Jul 2010 09:48:56 +0000 (11:48 +0200)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 15 Jul 2010 09:48:56 +0000 (11:48 +0200)
This is currently only for a few old attributes (ARAP-*), but the
same framework is leveraged for other attributes, too.  e.g. int, ipaddr

share/dictionary.rfc2869
src/include/libradius.h
src/lib/dict.c
src/lib/radius.c

index 94f86f9..f27a81d 100644 (file)
@@ -10,8 +10,8 @@ ATTRIBUTE     Acct-Output-Gigawords                   53      integer
 
 ATTRIBUTE      Event-Timestamp                         55      date
 
-ATTRIBUTE      ARAP-Password                           70      octets  # 16 octets of data
-ATTRIBUTE      ARAP-Features                           71      octets  # 14 octets of data
+ATTRIBUTE      ARAP-Password                           70      octets[16]
+ATTRIBUTE      ARAP-Features                           71      octets[14]
 ATTRIBUTE      ARAP-Zone-Access                        72      integer
 ATTRIBUTE      ARAP-Security                           73      integer
 ATTRIBUTE      ARAP-Security-Data                      74      string
@@ -22,7 +22,7 @@ ATTRIBUTE     Configuration-Token                     78      string
 ATTRIBUTE      EAP-Message                             79      octets
 ATTRIBUTE      Message-Authenticator                   80      octets
 
-ATTRIBUTE      ARAP-Challenge-Response                 84      octets  # 8 octets of data
+ATTRIBUTE      ARAP-Challenge-Response                 84      octets[8]
 ATTRIBUTE      Acct-Interim-Interval                   85      integer
 # 86: RFC 2867
 ATTRIBUTE      NAS-Port-Id                             87      string
index 3111e8c..c8f7ce9 100644 (file)
@@ -107,6 +107,7 @@ typedef struct attr_flags {
 
        int8_t                  tag;          /* tag for tunneled attributes */
        uint8_t                 encrypt;      /* encryption method */
+       uint8_t                 length;
 } ATTR_FLAGS;
 
 /*
index 6a05e82..6c14414 100644 (file)
@@ -869,6 +869,7 @@ static int process_attribute(const char* fn, const int line,
        int             vendor = 0;
        int             value;
        int             type;
+       int             length = 0;
        ATTR_FLAGS      flags;
 
        if ((argc < 3) || (argc > 4)) {
@@ -885,14 +886,37 @@ static int process_attribute(const char* fn, const int line,
                return -1;
        }
 
-       /*
-        *      find the type of the attribute.
-        */
-       type = fr_str2int(type_table, argv[2], -1);
-       if (type < 0) {
-               fr_strerror_printf("dict_init: %s[%d]: invalid type \"%s\"",
-                       fn, line, argv[2]);
-               return -1;
+       if (strncmp(argv[2], "octets[", 7) != 0) {
+               /*
+                *      find the type of the attribute.
+                */
+               type = fr_str2int(type_table, argv[2], -1);
+               if (type < 0) {
+                       fr_strerror_printf("dict_init: %s[%d]: invalid type \"%s\"",
+                                          fn, line, argv[2]);
+                       return -1;
+               }
+       } else {
+               char *p;
+               type = PW_TYPE_OCTETS;
+               
+               p = strchr(argv[2] + 7, ']');
+               if (!p) {
+                       fr_strerror_printf("dict_init: %s[%d]: Invalid format for octets", fn, line);
+                       return -1;
+               }
+
+               *p = 0;
+
+               if (!sscanf_i(argv[1], &length)) {
+                       fr_strerror_printf("dict_init: %s[%d]: invalid length", fn, line);
+                       return -1;
+               }
+
+               if ((length == 0) || (length > 253)) {
+                       fr_strerror_printf("dict_init: %s[%d]: invalid length", fn, line);
+                       return -1;
+               }
        }
 
        /*
@@ -900,9 +924,52 @@ static int process_attribute(const char* fn, const int line,
         *      is non-empty.
         */
        memset(&flags, 0, sizeof(flags));
-       if (argc == 4) {
+       if (argc < 4) {
+               /*
+                *      Force "length" for data types of fixed length;
+                */
+               switch (type) {
+               case PW_TYPE_BYTE:
+                       length = 1;
+                       break;
+
+               case PW_TYPE_SHORT:
+                       length = 2;
+                       break;
+
+               case PW_TYPE_DATE:
+               case PW_TYPE_IPADDR:
+               case PW_TYPE_INTEGER:
+               case PW_TYPE_SIGNED:
+                       length = 4;
+                       break;
+
+               case PW_TYPE_ETHERNET:
+                       length = 6;
+                       break;
+
+               case PW_TYPE_IFID:
+                       length = 8;
+                       break;
+
+               case PW_TYPE_IPV6ADDR:
+                       length = 16;
+                       break;
+
+               default:
+                       break;
+               }
+
+               flags.length = length;
+
+       } else {                /* argc == 4: we have options */
                char *key, *next, *last;
 
+               if (length != 0) {
+                       fr_strerror_printf("dict_init: %s[%d]: length cannot be used with options", fn, line);
+                       return -1;
+               }
+
                key = argv[3];
                do {
                        next = strchr(key, ',');
index acd1174..84e88ef 100644 (file)
@@ -2209,6 +2209,15 @@ static VALUE_PAIR *data2vp(const RADIUS_PACKET *packet,
        vp->next = NULL;
 
        /*
+        *      It's supposed to be a fixed length, but we found
+        *      a different length instead.  Make it type "octets",
+        *      and do no more processing on it.
+        */
+       if ((vp->flags.length > 0) && (vp->flags.length != length)) {
+               goto raw;
+       }
+
+       /*
         *      Handle tags.
         */
        if (vp->flags.has_tag) {