Package: libfreeradius-client2
Version: 1.1.6-7
Severity: normal
Tags: patch
Cc: freeradius-de...@lists.freeradius.org

I have noticed that the attribute list is empty for radius packets like:


Radius Protocol
    Code: Access-Accept (2)
    Packet identifier: 0xe4 (228)
    Length: 137
    Authenticator: c43ca3c2765cfab8545e6e4a7f83ba9a
    [This is a response to a request in frame 142]
    [Time from request: 0.004763000 seconds]
    Attribute Value Pairs
        AVP: l=11 t=Vendor-Specific(26) v=Reserved(0)
            VSA: l=5 t=Unknown-Attribute(27): 363030
                Unknown-Attribute: 363030
        AVP: l=12 t=Vendor-Specific(26) v=Wireless Broadband Alliance Ltd 
(previous was 'Wi-Fi Alliance')(14122)
            VSA: l=6 t=WISPr-Bandwidth-Max-Down(8): 124008
                WISPr-Bandwidth-Max-Down: 124008
        AVP: l=12 t=Vendor-Specific(26) v=Wireless Broadband Alliance Ltd 
(previous was 'Wi-Fi Alliance')(14122)
            VSA: l=6 t=WISPr-Bandwidth-Max-Up(7): 124007
                WISPr-Bandwidth-Max-Up: 124007
        AVP: l=6 t=Framed-Protocol(7): PPP(1)
            Framed-Protocol: PPP (1)
        AVP: l=6 t=Service-Type(6): Framed(2)
            Service-Type: Framed (2)
        AVP: l=46 t=Class(25): 
8fdc089a00000137000102000a010a2d00000000d5a02756...
            Class: 8fdc089a00000137000102000a010a2d00000000d5a02756...
        AVP: l=12 t=Vendor-Specific(26) v=Microsoft(311)
            VSA: l=6 t=MS-Link-Utilization-Threshold(14): 50
                MS-Link-Utilization-Threshold: 50
        AVP: l=12 t=Vendor-Specific(26) v=Microsoft(311)
            VSA: l=6 t=MS-Link-Drop-Time-Limit(15): 120
                MS-Link-Drop-Time-Limit: 120


The problem is that the vendor microsoft in my version was unknown.
The recursive attribute parser uses NULL as information for the caller that
its part of the parsing failed. But NULL is also returned when the last
attribute was from an unknown vendor. Instead it should only be skipped as
it is documented inside the function.

A proof of concept patch is attached which uses a special parameter which
is used to inform the caller about an error. The returned value is only
used as handler for the list.

--- System information. ---
Architecture: amd64
Kernel:       Linux 4.0.0-2-amd64

Debian Release: stretch/sid
  500 unstable        httpredir.debian.org 
From: Sven Eckelmann <s...@open-mesh.com>
Date: Wed, 22 Jul 2015 12:24:47 +0200
Subject: [PATCH] radiusclient-ng: Don't drop attribute list when last attribute is from unknown vendor

The recursive attribute parser uses NULL as information for the caller that
its part of the parsing failed. But NULL is also returned when the last
attribute was from an unknown vendor. Instead it should only be skipped as
it is documented inside the function.

Introduce an extra parameter which is only used to store the error state
and leave the return value for the list item.
---
 lib/avpair.c | 44 +++++++++++++++++++++++++++++---------------
 1 file changed, 29 insertions(+), 15 deletions(-)

diff --git a/lib/avpair.c b/lib/avpair.c
index 979c0d9..7b215d2 100644
--- a/lib/avpair.c
+++ b/lib/avpair.c
@@ -154,6 +154,10 @@ VALUE_PAIR *rc_avpair_new (rc_handle *rh, int attrid, void *pval, int len, int v
 	return vp;
 }
 
+static VALUE_PAIR *
+rc_avpair_gen_rec(rc_handle *rh, VALUE_PAIR *pair, unsigned char *ptr,
+    int length, int vendorpec, int *recursive_error);
+
 /*
  *
  * Function: rc_avpair_gen
@@ -168,6 +172,15 @@ VALUE_PAIR *
 rc_avpair_gen(rc_handle *rh, VALUE_PAIR *pair, unsigned char *ptr,
     int length, int vendorpec)
 {
+	int recursive_error = 0;
+
+	return rc_avpair_gen_rec(rh, pair,ptr, length, vendorpec, &recursive_error);
+}
+
+static VALUE_PAIR *
+rc_avpair_gen_rec(rc_handle *rh, VALUE_PAIR *pair, unsigned char *ptr,
+    int length, int vendorpec, int *recursive_error)
+{
 	int attribute, attrlen, x_len;
 	unsigned char *x_ptr;
 	UINT4 lvalue;
@@ -178,22 +191,22 @@ rc_avpair_gen(rc_handle *rh, VALUE_PAIR *pair, unsigned char *ptr,
 	char hex[3];
 
 	if (length < 2) {
-		rc_log(LOG_ERR, "rc_avpair_gen: received attribute with "
+		rc_log(LOG_ERR, "rc_avpair_gen_rec: received attribute with "
 		    "invalid length");
 		goto shithappens;
 	}
 	attrlen = ptr[1];
 	if (length < attrlen || attrlen < 2) {
-		rc_log(LOG_ERR, "rc_avpair_gen: received attribute with "
+		rc_log(LOG_ERR, "rc_avpair_gen_rec: received attribute with "
 		    "invalid length");
 		goto shithappens;
 	}
 
 	/* Advance to the next attribute and process recursively */
 	if (length != attrlen) {
-		pair = rc_avpair_gen(rh, pair, ptr + attrlen, length - attrlen,
-		    vendorpec);
-		if (pair == NULL)
+		pair = rc_avpair_gen_rec(rh, pair, ptr + attrlen, length - attrlen,
+		    vendorpec, recursive_error);
+		if (*recursive_error)
 			return NULL;
 	}
 
@@ -205,7 +218,7 @@ rc_avpair_gen(rc_handle *rh, VALUE_PAIR *pair, unsigned char *ptr,
 	/* VSA */
 	if (attribute == PW_VENDOR_SPECIFIC) {
 		if (attrlen < 4) {
-			rc_log(LOG_ERR, "rc_avpair_gen: received VSA "
+			rc_log(LOG_ERR, "rc_avpair_gen_rec: received VSA "
 			    "attribute with invalid length");
 			goto shithappens;
 		}
@@ -213,13 +226,13 @@ rc_avpair_gen(rc_handle *rh, VALUE_PAIR *pair, unsigned char *ptr,
 		vendorpec = ntohl(lvalue);
 		if (rc_dict_getvend(rh, vendorpec) == NULL) {
 			/* Warn and skip over the unknown VSA */
-			rc_log(LOG_WARNING, "rc_avpair_gen: received VSA "
+			rc_log(LOG_WARNING, "rc_avpair_gen_rec: received VSA "
 			    "attribute with unknown Vendor-Id %d", vendorpec);
 			return pair;
 		}
 		/* Process recursively */
-		return rc_avpair_gen(rh, pair, ptr + 4, attrlen - 4,
-		    vendorpec);
+		return rc_avpair_gen_rec(rh, pair, ptr + 4, attrlen - 4,
+		    vendorpec, recursive_error);
 	}
 
 	/* Normal */
@@ -232,11 +245,11 @@ rc_avpair_gen(rc_handle *rh, VALUE_PAIR *pair, unsigned char *ptr,
 			strcat(buffer, hex);
 		}
 		if (vendorpec == 0) {
-			rc_log(LOG_WARNING, "rc_avpair_gen: received "
+			rc_log(LOG_WARNING, "rc_avpair_gen_rec: received "
 			    "unknown attribute %d of length %d: 0x%s",
 			    attribute, attrlen + 2, buffer);
 		} else {
-			rc_log(LOG_WARNING, "rc_avpair_gen: received "
+			rc_log(LOG_WARNING, "rc_avpair_gen_rec: received "
 			    "unknown VSA attribute %d, vendor %d of "
 			    "length %d: 0x%s", attribute & 0xffff,
 			    VENDOR(attribute), attrlen + 2, buffer);
@@ -246,7 +259,7 @@ rc_avpair_gen(rc_handle *rh, VALUE_PAIR *pair, unsigned char *ptr,
 
 	rpair = malloc(sizeof(*rpair));
 	if (rpair == NULL) {
-		rc_log(LOG_CRIT, "rc_avpair_gen: out of memory");
+		rc_log(LOG_CRIT, "rc_avpair_gen_rec: out of memory");
 		goto shithappens;
 	}
 	memset(rpair, '\0', sizeof(*rpair));
@@ -267,13 +280,13 @@ rc_avpair_gen(rc_handle *rh, VALUE_PAIR *pair, unsigned char *ptr,
 
 	case PW_TYPE_INTEGER:
 		if (attrlen != 4) {
-			rc_log(LOG_ERR, "rc_avpair_gen: received INT "
+			rc_log(LOG_ERR, "rc_avpair_gen_rec: received INT "
 			    "attribute with invalid length");
 			goto shithappens;
 		}
 	case PW_TYPE_IPADDR:
 		if (attrlen != 4) {
-			rc_log(LOG_ERR, "rc_avpair_gen: received IPADDR"
+			rc_log(LOG_ERR, "rc_avpair_gen_rec: received IPADDR"
 			    " attribute with invalid length");
 			goto shithappens;
 		}
@@ -282,7 +295,7 @@ rc_avpair_gen(rc_handle *rh, VALUE_PAIR *pair, unsigned char *ptr,
 		break;
 
 	default:
-		rc_log(LOG_WARNING, "rc_avpair_gen: %s has unknown type",
+		rc_log(LOG_WARNING, "rc_avpair_gen_rec: %s has unknown type",
 		    attr->name);
 		goto shithappens;
 	}
@@ -294,6 +307,7 @@ shithappens:
 		free(pair);
 		pair = rpair;
 	}
+	recursive_error = 1;
 	return NULL;
 }
 

Reply via email to