Print, parse, and encode, decode "long" attributes
authorAlan T. DeKok <aland@freeradius.org>
Mon, 23 May 2011 14:06:50 +0000 (16:06 +0200)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 23 May 2011 14:06:50 +0000 (16:06 +0200)
src/include/radius.h
src/lib/print.c
src/lib/radius.c
src/lib/valuepair.c

index 9d59592..34bcb6d 100644 (file)
@@ -25,6 +25,8 @@
 #define PW_TYPE_EXTENDED_FLAGS         16
 #define PW_TYPE_EVS                    17
 
+#define PW_FLAG_LONG                   (1 << 8)
+
 #define        PW_AUTHENTICATION_REQUEST       1
 #define        PW_AUTHENTICATION_ACK           2
 #define        PW_AUTHENTICATION_REJECT        3
index 7ae05f7..b0f1d37 100644 (file)
@@ -215,6 +215,8 @@ int vp_prints_value(char * out, size_t outlen, const VALUE_PAIR *vp, int delimit
        out[0] = '\0';
        if (!vp) return 0;
 
+       if ((vp->type & PW_FLAG_LONG) != 0) goto do_tlv;
+
        switch (vp->type) {
                case PW_TYPE_STRING:
                        if ((delimitst == 1) && vp->flags.has_tag) {
@@ -337,6 +339,7 @@ int vp_prints_value(char * out, size_t outlen, const VALUE_PAIR *vp, int delimit
                        break;
 
                case PW_TYPE_TLV:
+       do_tlv:
                        if (outlen <= (2 * (vp->length + 1))) return 0;
 
                        strcpy(buf, "0x");
@@ -466,7 +469,7 @@ const char *vp_print_name(char *buffer, size_t bufsize,
                bufsize -= len;
        }
 
-       len = vp_print_attr_oid(p, bufsize , attr, dv_type);
+       vp_print_attr_oid(p, bufsize , attr, dv_type);
 
        return buffer;
 }
index c559e02..8f2140e 100644 (file)
@@ -833,6 +833,12 @@ static ssize_t vp2data_any(const RADIUS_PACKET *packet,
        data = vp->vp_octets;
        len = vp->length;
 
+       /*
+        *      Short-circuit it for long attributes.  They can't be
+        *      encrypted, tagged, etc.
+        */
+       if ((vp->type & PW_FLAG_LONG) != 0) goto do_tlv;
+
        switch(vp->type) {
        case PW_TYPE_STRING:
        case PW_TYPE_OCTETS:
@@ -888,6 +894,7 @@ static ssize_t vp2data_any(const RADIUS_PACKET *packet,
        }
 
        case PW_TYPE_TLV:
+       do_tlv:
                data = vp->vp_tlv;
                if (!data) {
                        fr_strerror_printf("ERROR: Cannot encode NULL TLV");
@@ -2740,12 +2747,13 @@ static ssize_t data2vp_raw(UNUSED const RADIUS_PACKET *packet,
        vp->length = length;
 
        /*
-        *      If the data is too large, mark it as a "TLV".
+        *      If it's short, put it into the array.  If it's too
+        *      long, flag it as such, and put it somewhere else;
         */
        if (length <= sizeof(vp->vp_octets)) {
                memcpy(vp->vp_octets, data, length);
        } else {
-               vp->type = PW_TYPE_TLV;
+               vp->type |= PW_FLAG_LONG;
                vp->vp_tlv = malloc(length);
                if (!vp->vp_tlv) {
                        pairfree(&vp);
index 8d8ed53..e7258ca 100644 (file)
@@ -1108,34 +1108,36 @@ VALUE_PAIR *pairparsevalue(VALUE_PAIR *vp, const char *value)
                        /* raw octets: 0x01020304... */
                case PW_TYPE_OCTETS:
                        if (strncasecmp(value, "0x", 2) == 0) {
+                               size_t size;
                                uint8_t *us;
+
                                cp = value + 2;
                                us = vp->vp_octets;
                                vp->length = 0;
 
-
                                /*
-                                *      There is only one character,
-                                *      die.
+                                *      Invalid.
                                 */
-                               if ((strlen(cp) & 0x01) != 0) {
+                               size = strlen(cp);
+                               if ((size  & 0x01) != 0) {
                                        fr_strerror_printf("Hex string is not an even length string.");
                                        return NULL;
                                }
 
-
-                               while (*cp &&
-                                      (vp->length < MAX_STRING_LEN)) {
-                                       unsigned int tmp;
-
-                                       if (sscanf(cp, "%02x", &tmp) != 1) {
-                                               fr_strerror_printf("Non-hex characters at %c%c", cp[0], cp[1]);
+                               vp->length = size >> 1;
+                               if (size > 2*sizeof(vp->vp_octets)) {
+                                       vp->type |= PW_FLAG_LONG;
+                                       us = vp->vp_tlv = malloc(vp->length);
+                                       if (!us) {
+                                               fr_strerror_printf("Out of memory.");
                                                return NULL;
                                        }
+                               }
 
-                                       cp += 2;
-                                       *(us++) = tmp;
-                                       vp->length++;
+                               if (fr_hex2bin(cp, us,
+                                              vp->length) != vp->length) {
+                                       fr_strerror_printf("Invalid hex data");
+                                       return NULL;
                                }
                        }
                        break;
@@ -1306,6 +1308,7 @@ static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
        unsigned int    dv_type = 1;
        size_t          size;
        const char      *p = attribute;
+       void            *data;
        char            *q;
        VALUE_PAIR      *vp;
        DICT_VENDOR     *dv;
@@ -1499,6 +1502,7 @@ static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
        if (!value) return vp;
 
        size = strlen(value + 2);
+       data = vp->vp_octets;
 
        /*
         *      We may be reading something like Attr-5.  i.e.
@@ -1515,7 +1519,14 @@ static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
        case PW_TYPE_ABINARY:
                vp->length = size >> 1;
                if (vp->length > sizeof(vp->vp_octets)) {
-                       vp->length = sizeof(vp->vp_octets);
+                       vp->vp_tlv = malloc(vp->length);
+                       if (!vp->vp_tlv) {
+                               fr_strerror_printf("Out of memory");
+                               free(vp);
+                               return NULL;
+                       }
+                       data = vp->vp_tlv;
+                       vp->type |= PW_FLAG_LONG;
                }
                break;
 
@@ -1523,12 +1534,19 @@ static VALUE_PAIR *pairmake_any(const char *attribute, const char *value,
                vp->length = size >> 1;
                memset(&vp->vp_strvalue, 0, sizeof(vp->vp_strvalue));
                if (vp->length >= sizeof(vp->vp_strvalue)) {
-                       vp->length = sizeof(vp->vp_strvalue) - 1;
+                       vp->vp_tlv = malloc(vp->length);
+                       if (!vp->vp_tlv) {
+                               fr_strerror_printf("Out of memory");
+                               free(vp);
+                               return NULL;
+                       }
+                       data = vp->vp_tlv;
+                       vp->type |= PW_FLAG_LONG;
                }
                break;
        }
 
-       if (fr_hex2bin(value + 2, vp->vp_octets, size) != vp->length) {
+       if (fr_hex2bin(value + 2, data, size) != vp->length) {
                fr_strerror_printf("Invalid hex string");
                free(vp);
                return NULL;