static int fr_rand_initialized = 0;
static unsigned int salt_offset = 0;
-
-#define MAX_PACKET_CODE (52)
-static const char *packet_codes[] = {
+const char *fr_packet_codes[FR_MAX_PACKET_CODE] = {
"",
"Access-Request",
"Access-Accept",
return;
}
+static void print_hex(RADIUS_PACKET *packet)
+{
+ int i;
+
+ if (!packet->data) return;
+
+ printf(" Code:\t\t%u\n", packet->data[0]);
+ printf(" Id:\t\t%u\n", packet->data[1]);
+ printf(" Length:\t%u\n", ((packet->data[2] << 8) |
+ (packet->data[3])));
+ printf(" Vector:\t");
+ for (i = 4; i < 20; i++) {
+ printf("%02x", packet->data[i]);
+ }
+ printf("\n");
+
+ if (packet->data_len > 20) {
+ int total;
+ const uint8_t *ptr;
+ printf(" Data:");
+
+ total = packet->data_len - 20;
+ ptr = packet->data + 20;
+
+ while (total > 0) {
+ int attrlen;
+
+ printf("\t\t");
+ if (total < 2) { /* too short */
+ printf("%02x\n", *ptr);
+ break;
+ }
+
+ if (ptr[1] > total) { /* too long */
+ for (i = 0; i < total; i++) {
+ printf("%02x ", ptr[i]);
+ }
+ break;
+ }
+
+ printf("%02x %02x ", ptr[0], ptr[1]);
+ attrlen = ptr[1] - 2;
+ ptr += 2;
+ total -= 2;
+
+ for (i = 0; i < attrlen; i++) {
+ if ((i > 0) && ((i & 0x0f) == 0x00))
+ printf("\t\t\t");
+ printf("%02x ", ptr[i]);
+ if ((i & 0x0f) == 0x0f) printf("\n");
+ }
+
+ if ((attrlen & 0x0f) != 0x00) printf("\n");
+
+ ptr += attrlen;
+ total -= attrlen;
+ }
+ }
+ fflush(stdout);
+}
+
+
/*
* Wrapper for sendto which handles sendfromto, IPv6, and all
* possible combinations.
* And if they don't specify a source IP address, don't
* use udpfromto.
*/
- if ((dst_ipaddr->af == AF_INET) ||
+ if ((dst_ipaddr->af == AF_INET) &&
(src_ipaddr->af != AF_UNSPEC)) {
return sendfromto(sockfd, data, data_len, flags,
(struct sockaddr *)&src, sizeof_src,
}
#define MAX_PASS_LEN (128)
-static void make_passwd(uint8_t *output, int *outlen,
- const uint8_t *input, int inlen,
+static void make_passwd(uint8_t *output, size_t *outlen,
+ const uint8_t *input, size_t inlen,
const char *secret, const uint8_t *vector)
{
FR_MD5_CTX context, old;
* If the length is zero, round it up.
*/
len = inlen;
+
+ if (len > MAX_PASS_LEN) len = MAX_PASS_LEN;
+
+ memcpy(passwd, input, len);
+ memset(passwd + len, 0, sizeof(passwd) - len);
+
if (len == 0) {
len = AUTH_PASS_LEN;
}
- else if (len > MAX_PASS_LEN) len = MAX_PASS_LEN;
else if ((len & 0x0f) != 0) {
len += 0x0f;
}
*outlen = len;
- memcpy(passwd, input, len);
- memset(passwd + len, 0, sizeof(passwd) - len);
-
fr_MD5Init(&context);
fr_MD5Update(&context, (const uint8_t *) secret, strlen(secret));
old = context;
memcpy(output, passwd, len);
}
-static void make_tunnel_passwd(uint8_t *output, int *outlen,
- const uint8_t *input, int inlen, int room,
+static void make_tunnel_passwd(uint8_t *output, size_t *outlen,
+ const uint8_t *input, size_t inlen, size_t room,
const char *secret, const uint8_t *vector)
{
FR_MD5_CTX context, old;
}
fr_MD5Final(digest, &context);
+
for (i = 0; i < AUTH_PASS_LEN; i++) {
passwd[i + 2 + n] ^= digest[i];
}
memcpy(output, passwd, len + 2);
}
+/*
+ * Returns the end of the data.
+ */
static int vp2data(const RADIUS_PACKET *packet, const RADIUS_PACKET *original,
- const char *secret, const VALUE_PAIR *vp, uint8_t *ptr,
- int offset, int room)
+ const char *secret, const VALUE_PAIR *vp, uint8_t *start,
+ size_t room)
{
uint32_t lvalue;
size_t len;
const uint8_t *data;
+ uint8_t *ptr = start;
uint8_t array[4];
/*
len = 1; /* just in case */
array[0] = vp->vp_integer & 0xff;
data = array;
- offset = 0;
break;
case PW_TYPE_SHORT:
array[0] = (vp->vp_integer >> 8) & 0xff;
array[1] = vp->vp_integer & 0xff;
data = array;
- offset = 0;
break;
case PW_TYPE_INTEGER:
len = 4; /* just in case */
lvalue = htonl(vp->vp_integer);
memcpy(array, &lvalue, sizeof(lvalue));
-
- /*
- * Perhaps discard the first octet.
- */
- data = &array[offset];
- len -= offset;
+ data = array;
break;
case PW_TYPE_IPADDR:
fr_strerror_printf("ERROR: Cannot encode NULL TLV");
return -1;
}
+ if (vp->length > room) return 0; /* can't chop TLVs to fit */
break;
default: /* unknown type: ignore it */
}
/*
- * Bound the data to 255 bytes.
+ * Bound the data to the calling size
*/
- if (len + offset > room) {
- len = room - offset;
- }
+ if (len > room) len = room;
/*
* Encrypt the various password styles
*/
switch (vp->flags.encrypt) {
case FLAG_ENCRYPT_USER_PASSWORD:
- make_passwd(ptr + offset, &len,
- data, len,
+ make_passwd(ptr, &len, data, len,
secret, packet->vector);
break;
case FLAG_ENCRYPT_TUNNEL_PASSWORD:
+ lvalue = 0;
+ if (vp->flags.has_tag) lvalue = 1;
+
/*
- * Check if 255 - offset - total_length is less
- * than 18. If so, we can't fit the data into
- * the available space, and we discard the
- * attribute.
+ * Check if there's enough room. If there isn't,
+ * we discard the attribute.
*
* This is ONLY a problem if we have multiple VSA's
* in one Vendor-Specific, though.
*/
- if ((room - offset) < 18) return 0;
+ if (room < (18 + lvalue)) return 0;
switch (packet->code) {
case PW_AUTHENTICATION_ACK:
fr_strerror_printf("ERROR: No request packet, cannot encrypt %s attribute in the vp.", vp->name);
return -1;
}
- make_tunnel_passwd(ptr + offset, &len,
- data, len, room - offset,
+
+ if (lvalue) ptr[0] = vp->flags.tag;
+ make_tunnel_passwd(ptr + lvalue, &len, data, len,
+ room - lvalue,
secret, original->vector);
break;
case PW_ACCOUNTING_REQUEST:
case PW_DISCONNECT_REQUEST:
case PW_COA_REQUEST:
- make_tunnel_passwd(ptr + offset, &len,
- data, len, room - offset,
+ ptr[0] = vp->flags.tag;
+ make_tunnel_passwd(ptr + 1, &len, data, len - 1, room,
secret, packet->vector);
break;
}
* always fits.
*/
case FLAG_ENCRYPT_ASCEND_SECRET:
- make_secret(ptr + offset, packet->vector,
- secret, data);
+ make_secret(ptr, packet->vector, secret, data);
len = AUTH_VECTOR_LEN;
break;
default:
- /*
- * Just copy the data over
- */
- memcpy(ptr + offset, data, len);
+ if (vp->flags.has_tag && TAG_VALID(vp->flags.tag)) {
+ if (vp->type == PW_TYPE_STRING) {
+ if (len > (room - 1)) len = room - 1;
+ ptr[0] = vp->flags.tag;
+ ptr++;
+ } else if (vp->type == PW_TYPE_INTEGER) {
+ array[0] = vp->flags.tag;
+ } /* else it can't be any other type */
+ }
+ memcpy(ptr, data, len);
break;
} /* switch over encryption flags */
- return len;
+ return len + (ptr - start);;
}
-static VALUE_PAIR *rad_vp2tlv(VALUE_PAIR *vps)
+static int rad_vp2rfc(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const char *secret, const VALUE_PAIR *vp,
+ unsigned int attribute, uint8_t *ptr, size_t room)
{
- int maxattr = 0;
- int length, attribute;
- uint8_t *ptr;
- VALUE_PAIR *vp, *tlv;
+ int len;
- attribute = vps->attribute & 0xffff00ff;
- maxattr = vps->attribute & 0x0ff;
+ if (room < 2) return 0;
- tlv = paircreate(attribute, PW_TYPE_TLV);
- if (!tlv) return NULL;
+ ptr[0] = attribute & 0xff; /* NOT vp->attribute */
+ ptr[1] = 2;
- tlv->length = 0;
- for (vp = vps; vp != NULL; vp = vp->next) {
- /*
- * Group the attributes ONLY until we see a
- * non-TLV attribute.
- */
- if (!vp->flags.is_tlv ||
- vp->flags.encoded ||
- (vp->flags.encrypt != FLAG_ENCRYPT_NONE) ||
- ((vp->attribute & 0xffff00ff) != attribute) ||
- ((vp->attribute & 0x0000ff00) <= maxattr)) {
- break;
- }
+ if (room > (255 - ptr[1])) room = 255 - ptr[1];
+ len = vp2data(packet, original, secret, vp, ptr + 2, room);
+ if (len < 0) return len;
- maxattr = vp->attribute & 0xff00;
- tlv->length += vp->length + 2;
- }
+ ptr[1] += len;
- if (!tlv->length) {
- pairfree(&tlv);
- return NULL;
- }
+ return ptr[1];
+}
- tlv->vp_tlv = malloc(tlv->length);
- if (!tlv->vp_tlv) {
- pairfree(&tlv);
- return NULL;
- }
+extern int fr_wimax_max_tlv;
+extern int fr_wimax_shift[];
+extern int fr_wimax_mask[];
- ptr = tlv->vp_tlv;
- maxattr = vps->attribute & 0x0ff;
- for (vp = vps; vp != NULL; vp = vp->next) {
- if (!vp->flags.is_tlv ||
- vp->flags.encoded ||
- (vp->flags.encrypt != FLAG_ENCRYPT_NONE) ||
- ((vp->attribute & 0xffff00ff) != attribute) ||
- ((vp->attribute & 0x0000ff00) <= maxattr)) {
- break;
- }
+static int tlv2data(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const char *secret, const VALUE_PAIR *vp,
+ uint8_t *ptr, size_t room, int nest)
+{
+ int len;
- maxattr = vp->attribute & 0xff00;
- length = vp2data(NULL, NULL, NULL, vp, ptr + 2, 0,
- tlv->vp_tlv + tlv->length - ptr);
- if (length < 0) {
- vp->length = ptr - vp->vp_tlv;
- return tlv; /* should be a more serious error... */
- }
+ if (nest > fr_wimax_max_tlv) return -1;
- /*
- * Pack the attribute.
- */
- ptr[0] = (vp->attribute & 0xff00) >> 8;
- ptr[1] = (length & 0xff) + 2;
+ if (room < 2) return 0;
+ room -= 2;
- ptr += vp->length + 2;
- vp->flags.encoded = 1;
+ ptr[0] = (vp->attribute >> fr_wimax_shift[nest]) & fr_wimax_mask[nest];
+ ptr[1] = 2;
+
+ /*
+ * No more nested TLVs: pack the data.
+ */
+ if ((nest == fr_wimax_max_tlv) ||
+ ((vp->attribute >> fr_wimax_shift[nest + 1]) == 0)) {
+ len = vp2data(packet, original, secret, vp, ptr + 2, room);
+ } else {
+ len = tlv2data(packet, original, secret, vp, ptr + 2, room,
+ nest + 1);
}
+ if (len <= 0) return len;
+
+ ptr[1] += len;
- return tlv;
+ return ptr[1];
}
-/*
- * Pack data without any encryption.
- * start == start of RADIUS attribute
- * ptr == continuation byte (i.e. one after length)
- */
-static int rad_vp2continuation(const VALUE_PAIR *vp, uint8_t *start,
- uint8_t *ptr)
+static int wimax2data(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const char *secret, const VALUE_PAIR *vp,
+ uint8_t *start, size_t room, uint8_t *ptr)
{
- size_t left, piece;
- size_t hsize = (ptr - start);
- uint8_t *this = start;
- const uint8_t *data;
- uint8_t header[16];
-
+ int len;
+
/*
- * If it's too long and marked as encrypted, ignore it.
+ * Offsets to Vendor-Specific length, and to length of
+ * WiMAX attribute.
*/
- if (vp->flags.encrypt != FLAG_ENCRYPT_NONE) {
- return 0;
- }
-
- memcpy(header, start, hsize);
+#define VS_OFF (1)
+#define WM_OFF (7)
- left = vp->length;
-
- switch (vp->type) {
- case PW_TYPE_TLV:
- data = vp->vp_tlv;
- break;
+ if (room < 1) return 0;
+ room--;
- case PW_TYPE_OCTETS:
- case PW_TYPE_STRING:
- data = vp->vp_octets;
- break;
+ /*
+ * Account for continuation bytes. The caller has
+ * already accounting for the continuation byte in the
+ * Vendor-Specific "length" field.
+ */
+ start[WM_OFF]++;
+ *(ptr++) = 0;
- /*
- * This is invalid.
- */
- default:
+ /*
+ * Chop everything to fit in one attribute.
+ */
+ if (room > (255 - 9)) room = (255 - 9);
+
+ /*
+ * The attribute contains TLVs that we have NOT decoded
+ * properly, OR it contains TLV that the user has encoded
+ * manually. If it has no data, OR it's too long,
+ * discard it. We're not going to walk through its
+ * contents trying to figure out how to chop it across
+ * multiple continuations.
+ */
+ if (vp->flags.has_tlv && (!vp->vp_tlv || (vp->length > room))) {
return 0;
}
-
- while (left > 0) {
- memcpy(this, header, hsize);
- ptr = this + hsize;
-
- /*
- * 254 to account for
- * continuation flag.
- */
- if (left > (254 - hsize)) {
- piece = 254 - hsize;
- *(ptr++) = 0x80;
- } else {
- piece = left;
- *(ptr++) = 0x00;
- }
-
- memcpy(ptr, data, piece);
- this[1] = hsize + piece + 1;
- /*
- *
- */
- this[hsize - 1] = hsize - 6 + 1 + piece;
- data += piece;
- ptr += piece;
- left -= piece;
- this = ptr;
- }
-
- return (ptr - start);
+ /*
+ * The attribute is a top-level integer, ipaddr, etc.
+ * Encode it.
+ */
+ if (!vp->flags.is_tlv) {
+ len = vp2data(packet, original, secret, vp, ptr, room);
+ } else {
+ len = tlv2data(packet, original, secret, vp, ptr, room, 1);
+ }
+
+ if (len <= 0) return len;
+
+ start[VS_OFF] += len;
+ start[WM_OFF] += len;
+
+ return start[VS_OFF];
}
+static int rad_vp2extended(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const char *secret, const VALUE_PAIR *vp,
+ unsigned int attribute, uint8_t *ptr, size_t room)
+{
+ int len = 2;
+
+ if (room < 3) return 0;
+
+ ptr[0] = attribute & 0xff; /* NOT vp->attribute */
+ ptr[1] = 3;
+
+ if (vp->flags.extended) {
+ ptr[2] = (attribute & 0xff00) >> 8;
+ len++;
+
+ } else if (vp->flags.extended_flags) {
+ if (room < 4) return 0;
+
+ ptr[1] = 4;
+ ptr[2] = (attribute & 0xff00) >> 8;
+ ptr[3] = 0;
+
+ len += 2;
+ }
+
+ /*
+ * For now, no extended attribute can be longer than the
+ * encapsulating attribute. Once we add support for the
+ * "M" bit, this restriction will be relaxed.
+ */
+ if (room > (255 - ptr[1])) room = 255 - ptr[1];
+
+ if (!vp->flags.is_tlv) {
+ len = vp2data(packet, original, secret, vp, ptr + ptr[1], room);
+ } else {
+ len = tlv2data(packet, original, secret, vp, ptr + ptr[1], room, 2);
+ }
+
+ if (len < 0) return len;
+
+ ptr[1] += len;
+
+ return ptr[1];
+}
+
/*
* Parse a data structure into a RADIUS attribute.
*/
int rad_vp2attr(const RADIUS_PACKET *packet, const RADIUS_PACKET *original,
- const char *secret, const VALUE_PAIR *vp, uint8_t *start)
+ const char *secret, const VALUE_PAIR *vp, uint8_t *start,
+ size_t room)
{
- int vendorcode;
- int offset, len, total_length;
- uint32_t lvalue;
- uint8_t *ptr, *length_ptr, *vsa_length_ptr, *tlv_length_ptr;
+ int len;
+ uint32_t lvalue;
+ uint8_t *ptr;
+ DICT_VENDOR *dv;
- ptr = start;
- vendorcode = total_length = 0;
- length_ptr = vsa_length_ptr = tlv_length_ptr = NULL;
+ /*
+ * RFC format attributes take the fast path.
+ */
+ if (vp->vendor == 0) {
+ return rad_vp2rfc(packet, original, secret, vp,
+ vp->attribute, start, room);
+ }
+
+ if (vp->vendor == VENDORPEC_EXTENDED) {
+ return rad_vp2extended(packet, original, secret, vp,
+ vp->attribute, start, room);
+ }
/*
- * For interoperability, always put vendor attributes
- * into their own VSA.
+ * Not enough room for:
+ * attr, len, vendor-id, vsa, vsalen
*/
- if ((vendorcode = VENDOR(vp->attribute)) == 0) {
- *(ptr++) = vp->attribute & 0xFF;
- length_ptr = ptr;
- *(ptr++) = 2;
- total_length += 2;
+ if (room < 8) return 0;
- } else {
- int vsa_tlen = 1;
- int vsa_llen = 1;
- int vsa_offset = 0;
- DICT_VENDOR *dv = dict_vendorbyvalue(vendorcode);
+ /*
+ * Build the Vendor-Specific header
+ */
+ ptr = start;
+ *ptr++ = PW_VENDOR_SPECIFIC;
+ *ptr++ = 6;
+ room -= 6;
+ lvalue = htonl(vp->vendor);
+ memcpy(ptr, &lvalue, 4);
+ ptr += 4;
- /*
- * This must be an RFC-format attribute. If it
- * wasn't, then the "decode" function would have
- * made a Vendor-Specific attribute (i.e. type
- * 26), and we would have "vendorcode == 0" here.
- */
- if (dv) {
- vsa_tlen = dv->type;
- vsa_llen = dv->length;
- if (dv->flags) vsa_offset = 1;
- }
+ /*
+ * Unknown vendors, and type=1,length=1,no-continuation
+ * are RFC format attributes.
+ */
+ dv = dict_vendorbyvalue(vp->vendor);
+ if (!dv ||
+ ((dv->type == 1) && (dv->length = 1) && !dv->flags)) {
+ len = rad_vp2rfc(packet, original, secret, vp,
+ vp->attribute, ptr, room);
+ if (len <= 0) return len;
- /*
- * Build a VSA header.
- */
- *ptr++ = PW_VENDOR_SPECIFIC;
- vsa_length_ptr = ptr;
- *ptr++ = 6;
- lvalue = htonl(vendorcode);
- memcpy(ptr, &lvalue, 4);
- ptr += 4;
- total_length += 6;
+ start[1] += len;
+ return start[1];
+ }
- switch (vsa_tlen) {
+ if (room < (dv->type + dv->length + dv->flags)) return 0;
+ room -= (dv->type + dv->length + dv->flags);
+ start[1] += (dv->type + dv->length + dv->flags);
+
+ switch (dv->type) {
case 1:
ptr[0] = (vp->attribute & 0xFF);
break;
case 4:
ptr[0] = 0;
- ptr[1] = 0;
+ ptr[1] = ((vp->attribute >> 16) & 0xFF);
ptr[2] = ((vp->attribute >> 8) & 0xFF);
ptr[3] = (vp->attribute & 0xFF);
break;
default:
return 0; /* silently discard it */
- }
- ptr += vsa_tlen;
+ }
+ ptr += dv->type;
- switch (vsa_llen) {
- case 0:
- length_ptr = vsa_length_ptr;
- vsa_length_ptr = NULL;
- break;
- case 1:
- ptr[0] = 0;
- length_ptr = ptr;
- break;
- case 2:
- ptr[0] = 0;
- ptr[1] = 0;
- length_ptr = ptr + 1;
- break;
+ switch (dv->length) {
+ case 0:
+ break;
+ case 1:
+ ptr[0] = dv->type + 1;
+ break;
+ case 2:
+ ptr[0] = 0;
+ ptr[1] = dv->type + 2;
+ break;
- default:
- return 0; /* silently discard it */
- }
- ptr += vsa_llen;
+ default:
+ return 0; /* silently discard it */
+ }
+ ptr += dv->length;
- /*
- * Allow for some continuation.
- */
- if (vsa_offset) {
- /*
- * Allow TLV's to be encoded, if someone
- * manages to somehow encode the sub-tlv's.
- *
- * FIXME: Keep track of room in the packet!
- */
- if (vp->length > (254 - (ptr - start))) {
- return rad_vp2continuation(vp, start, ptr);
- }
+ /*
+ * WiMAX attributes take their own path through the
+ * system.
+ */
+ if (dv->flags) return wimax2data(packet, original, secret, vp,
+ start, room, ptr);
- ptr[0] = 0x00;
- ptr++;
+ len = vp2data(packet, original, secret, vp, ptr, room);
+ if (len <= 0) return len;
- /*
- * sub-TLV's can only be in one format.
- */
- if (vp->flags.is_tlv) {
- *(ptr++) = (vp->attribute & 0xff00) >> 8;
- tlv_length_ptr = ptr;
- *(ptr++) = 2;
- vsa_offset += 2;
- }
- }
+ if (dv->length != 0) ptr[-1] += len;
- total_length += vsa_tlen + vsa_llen + vsa_offset;
- if (vsa_length_ptr) *vsa_length_ptr += vsa_tlen + vsa_llen + vsa_offset;
- *length_ptr += vsa_tlen + vsa_llen + vsa_offset;
- }
+ start[1] += len;
- offset = 0;
- if (vp->flags.has_tag) {
- if (TAG_VALID(vp->flags.tag)) {
- ptr[0] = vp->flags.tag & 0xff;
- offset = 1;
+ return start[1];
+}
- } else if (vp->flags.encrypt == FLAG_ENCRYPT_TUNNEL_PASSWORD) {
- /*
- * Tunnel passwords REQUIRE a tag, even
- * if don't have a valid tag.
- */
- ptr[0] = 0;
- offset = 1;
- } /* else don't write a tag */
- } /* else the attribute doesn't have a tag */
+/*
+ * Swap 123a -> 0321
+ */
+#define REORDER(x) ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | ((x & 0xff000000 >> 24))
- len = vp2data(packet, original, secret, vp, ptr, offset,
- 255 - total_length);
- if (len < 0) return -1;
+
+/*
+ * Encode a WiMAX sub-TLV. It must NOT be called for WiMAX
+ * attributes that are of type integer, string, etc.
+ */
+static int rad_encode_wimax(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const char *secret, VALUE_PAIR *reply,
+ uint8_t *start, size_t room)
+{
+ int len, redo;
+ uint32_t lvalue;
+ uint8_t *ptr = start, *vsa = start;
+ uint32_t maxattr;
+ VALUE_PAIR *vp = reply;
/*
- * Account for the tag (if any).
+ * Swap the order of the WiMAX hacks, to make later
+ * comparisons easier.
*/
- len += offset;
+ maxattr = REORDER(vp->attribute);
/*
- * RFC 2865 section 5 says that zero-length attributes
- * MUST NOT be sent.
- *
- * ... and the WiMAX forum ignores this... because of
- * one vendor. Don't they have anything better to do
- * with their time?
+ * Build the Vendor-Specific header
*/
- if ((len == 0) &&
- (vp->attribute != PW_CHARGEABLE_USER_IDENTITY)) return 0;
+ ptr = start;
+ redo = 0;
+
+redo_vsa:
+ vsa = ptr;
+
+ if (room < 9) return 0;
+ *ptr++ = PW_VENDOR_SPECIFIC;
+ *ptr++ = 9;
+ room -= 9;
+ lvalue = htonl(vp->vendor);
+ memcpy(ptr, &lvalue, 4);
+ ptr += 4;
+ *(ptr++) = vp->attribute & 0xff;
+ *(ptr++) = 3;
+ *(ptr++) = 0; /* continuation */
+ room -= 9;
+
+redo_tlv:
+ len = tlv2data(packet, original, secret, vp, ptr, room, 1);
+ if (len < 0) return len;
/*
- * Update the various lengths.
+ * Not enough room. Do a continuation.
*/
- *length_ptr += len;
- if (vsa_length_ptr) *vsa_length_ptr += len;
- if (tlv_length_ptr) *tlv_length_ptr += len;
+ if ((len == 0) || ((vsa[VS_OFF] + len) > 255)) {
+ if (redo) return (start - vsa);
+
+ vsa[8] = 0x80;
+ redo = 1;
+ goto redo_vsa;
+ }
+ redo = 0;
+
ptr += len;
- total_length += len;
+ vsa[VS_OFF] += len;
+ vsa[WM_OFF] += len;
+
+ vp->flags.encoded = 1;
+ vp = vp->next;
+
+ /*
+ * Look at the NEXT tlv. Ensure that we encode
+ * attributes into a common VSA *only* if they are for
+ * the same WiMAX VSA, AND if the TLVs are in numerically
+ * increasing order.
+ */
+ if (vp && vp->flags.is_tlv && (reply->vendor == vp->vendor) &&
+ ((reply->attribute & 0xff) == (vp->attribute & 0xff))) {
+ uint32_t attr;
+
+ attr = REORDER(vp->attribute);
+ if (attr >= maxattr) {
+ maxattr = attr;
+ goto redo_tlv;
+ }
+ }
- return total_length; /* of attribute */
+ return ptr - start;
}
char ip_buffer[128];
/*
- * For simplicity in the following logic, we allow
- * the attributes to "overflow" the 4k maximum
- * RADIUS packet size, by one attribute.
- *
- * It's uint32_t, for alignment purposes.
+ * A 4K packet, aligned on 64-bits.
*/
- uint32_t data[(MAX_PACKET_LEN + 256) / 4];
+ uint64_t data[MAX_PACKET_LEN / sizeof(uint64_t)];
- if ((packet->code > 0) && (packet->code < MAX_PACKET_CODE)) {
- what = packet_codes[packet->code];
+ if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) {
+ what = fr_packet_codes[packet->code];
} else {
what = "Reply";
}
*/
for (reply = packet->vps; reply; reply = reply->next) {
/*
- * Ignore non-wire attributes
+ * Ignore non-wire attributes, but allow extended
+ * attributes.
*/
- if ((VENDOR(reply->attribute) == 0) &&
- ((reply->attribute & 0xFFFF) > 0xff)) {
+ if ((reply->vendor == 0) &&
+ ((reply->attribute & 0xFFFF) >= 256) &&
+ !reply->flags.extended && !reply->flags.extended_flags) {
#ifndef NDEBUG
/*
* Permit the admin to send BADLY formatted
debug_pair(reply);
/*
- * Print them in order, even if they were encoded
- * already.
+ * Skip attributes that are encoded.
*/
- len = 0;
- if (reply->flags.encoded) goto next;
-
- if (reply->flags.is_tlv) {
- VALUE_PAIR *tlv = rad_vp2tlv(reply);
- if (tlv) {
- tlv->next = reply->next;
- reply->next = tlv;
- }
+ if (reply->flags.encoded) continue;
- /*
- * The encoded flag MUST be set in reply!
- */
- reply = reply->next;
- }
+ if ((reply->vendor == VENDORPEC_WIMAX) && reply->flags.is_tlv) {
+ len = rad_encode_wimax(packet, original, secret,
+ reply, ptr,
+ ((uint8_t *) data) + sizeof(data) - ptr);
+ } else {
- len = rad_vp2attr(packet, original, secret, reply, ptr);
+ len = rad_vp2attr(packet, original, secret, reply, ptr,
+ ((uint8_t *) data) + sizeof(data) - ptr);
+ }
if (len < 0) return -1;
/*
- * Check that the packet is no more than 4k in
- * size, AFTER writing the attribute past the 4k
- * boundary, but BEFORE deciding to increase the
- * size of the packet. Note that the 'data'
- * buffer, above, is one attribute longer than
- * necessary, in order to permit this overflow.
+ * Failed to encode the attribute, likely because
+ * the packet is full.
*/
- if ((total_length + len) > MAX_PACKET_LEN) {
+ if ((len == 0) &&
+ (total_length > (sizeof(data) - 2 - reply->length))) {
+ DEBUG("WARNING: Attributes are too long for packet. Discarding data past %d bytes", total_length);
break;
}
return 0;
}
- if ((packet->code > 0) && (packet->code < MAX_PACKET_CODE)) {
- what = packet_codes[packet->code];
+ if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) {
+ what = fr_packet_codes[packet->code];
} else {
what = "Reply";
}
packet->dst_port);
for (reply = packet->vps; reply; reply = reply->next) {
- if ((VENDOR(reply->attribute) == 0) &&
+ if ((reply->vendor == 0) &&
((reply->attribute & 0xFFFF) > 0xff)) continue;
debug_pair(reply);
}
&packet->dst_ipaddr, packet->dst_port);
}
+/*
+ * Do a comparison of two authentication digests by comparing
+ * the FULL digest. Otehrwise, the server can be subject to
+ * timing attacks that allow attackers find a valid message
+ * authenticator.
+ *
+ * http://www.cs.rice.edu/~dwallach/pub/crosby-timing2009.pdf
+ */
+static int digest_cmp(const uint8_t *a, const uint8_t *b, size_t length)
+{
+ int result = 0;
+ size_t i;
+
+ for (i = 0; i < length; i++) {
+ result |= a[i] ^ b[i];
+ }
+
+ return result; /* 0 is OK, !0 is !OK, just like memcmp */
+}
+
/*
* Validates the requesting client NAS. Calculates the
/*
* Return 0 if OK, 2 if not OK.
*/
- if (memcmp(digest, packet->vector, AUTH_VECTOR_LEN) != 0) return 2;
+ if (digest_cmp(digest, packet->vector, AUTH_VECTOR_LEN) != 0) return 2;
return 0;
}
/*
* Return 0 if OK, 2 if not OK.
*/
- if (memcmp(packet->vector, calc_digest, AUTH_VECTOR_LEN) != 0) return 2;
+ if (digest_cmp(packet->vector, calc_digest, AUTH_VECTOR_LEN) != 0) return 2;
return 0;
}
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
- packet->data_len, AUTH_HDR_LEN);
+ (int) packet->data_len, AUTH_HDR_LEN);
return 0;
}
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
- packet->data_len, MAX_PACKET_LEN);
+ (int) packet->data_len, MAX_PACKET_LEN);
return 0;
}
* Code of 16 or greate is not understood.
*/
if ((hdr->code == 0) ||
- (hdr->code >= MAX_PACKET_CODE)) {
+ (hdr->code >= FR_MAX_PACKET_CODE)) {
fr_strerror_printf("WARNING: Bad RADIUS packet from host %s: unknown packet code%d ",
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
- packet->data_len, totallen);
+ (int) packet->data_len, totallen);
return 0;
}
while (count > 0) {
/*
+ * We need at least 2 bytes to check the
+ * attribute header.
+ */
+ if (count < 2) {
+ fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: attribute header overflows the packet",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)));
+ return 0;
+ }
+
+ /*
* Attribute number zero is NOT defined.
*/
if (attr[0] == 0) {
* fields. Anything shorter is an invalid attribute.
*/
if (attr[1] < 2) {
- fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: attribute %d too short",
+ fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: attribute %u too short",
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
}
/*
+ * If there are fewer bytes in the packet than in the
+ * attribute, it's a bad packet.
+ */
+ if (count < attr[1]) {
+ fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: attribute %u data overflows the packet",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)),
+ attr[0]);
+ return 0;
+ }
+
+ /*
* Sanity check the attributes for length.
*/
switch (attr[0]) {
*/
RADIUS_PACKET *rad_recv(int fd, int flags)
{
+ int sock_flags = 0;
RADIUS_PACKET *packet;
/*
}
memset(packet, 0, sizeof(*packet));
- packet->data_len = rad_recvfrom(fd, &packet->data, 0,
+ if (flags & 0x02) {
+ sock_flags = MSG_PEEK;
+ flags &= ~0x02;
+ }
+
+ packet->data_len = rad_recvfrom(fd, &packet->data, sock_flags,
&packet->src_ipaddr, &packet->src_port,
&packet->dst_ipaddr, &packet->dst_port);
if (fr_debug_flag) {
char host_ipaddr[128];
- if ((packet->code > 0) && (packet->code < MAX_PACKET_CODE)) {
+ if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) {
DEBUG("rad_recv: %s packet from host %s port %d",
- packet_codes[packet->code],
+ fr_packet_codes[packet->code],
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
packet->src_port,
packet->code);
}
- DEBUG(", id=%d, length=%d\n", packet->id, packet->data_len);
+ DEBUG(", id=%d, length=%d\n",
+ packet->id, (int) packet->data_len);
}
return packet;
fr_hmac_md5(packet->data, packet->data_len,
(const uint8_t *) secret, strlen(secret),
calc_auth_vector);
- if (memcmp(calc_auth_vector, msg_auth_vector,
+ if (digest_cmp(calc_auth_vector, msg_auth_vector,
sizeof(calc_auth_vector)) != 0) {
char buffer[32];
fr_strerror_printf("Received packet from %s with invalid Message-Authenticator! (Shared secret is incorrect.)",
* It looks like a RADIUS packet, but we can't validate
* the signature.
*/
- if ((packet->code == 0) || (packet->code >= MAX_PACKET_CODE)) {
+ if ((packet->code == 0) || (packet->code >= FR_MAX_PACKET_CODE)) {
char buffer[32];
fr_strerror_printf("Received Unknown packet code %d "
"from client %s port %d: Cannot validate signature.",
case PW_ACCOUNTING_REQUEST:
if (calc_acctdigest(packet, secret) > 1) {
fr_strerror_printf("Received %s packet "
- "from %s with invalid signature! (Shared secret is incorrect.)",
- packet_codes[packet->code],
+ "from client %s with invalid signature! (Shared secret is incorrect.)",
+ fr_packet_codes[packet->code],
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
buffer, sizeof(buffer)));
rcode = calc_replydigest(packet, original, secret);
if (rcode > 1) {
fr_strerror_printf("Received %s packet "
- "from client %s port %d with invalid signature (err=%d)! (Shared secret is incorrect.)",
- packet_codes[packet->code],
+ "from home server %s port %d with invalid signature! (Shared secret is incorrect.)",
+ fr_packet_codes[packet->code],
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
buffer, sizeof(buffer)),
- packet->src_port,
- rcode);
+ packet->src_port);
return -1;
}
break;
static VALUE_PAIR *data2vp(const RADIUS_PACKET *packet,
const RADIUS_PACKET *original,
- const char *secret, int attribute, int length,
+ const char *secret, size_t length,
const uint8_t *data, VALUE_PAIR *vp)
{
int offset = 0;
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) {
vp->flags.tag = data[0];
if ((vp->type == PW_TYPE_STRING) ||
- (vp->type == PW_TYPE_OCTETS)) offset = 1;
+ (vp->type == PW_TYPE_OCTETS)) {
+ if (length == 0) goto raw;
+ offset = 1;
+ }
}
}
*/
{
DICT_VALUE *dval;
- dval = dict_valbyattr(vp->attribute,
+ dval = dict_valbyattr(vp->attribute, vp->vendor,
vp->vp_integer);
if (dval) {
strlcpy(vp->vp_strvalue,
default:
raw:
- vp->type = PW_TYPE_OCTETS;
- vp->length = length;
- memcpy(vp->vp_octets, data, length);
-
-
/*
- * Ensure there's no encryption or tag stuff,
- * we just pass the attribute as-is.
+ * Change the name to show the user that the
+ * attribute is not of the correct format.
*/
- memset(&vp->flags, 0, sizeof(vp->flags));
+ {
+ int attr = vp->attribute;
+ int vendor = vp->vendor;
+ VALUE_PAIR *vp2;
+
+ vp2 = pairalloc(NULL);
+ if (!vp2) {
+ pairfree(&vp);
+ return NULL;
+ }
+ pairfree(&vp);
+ vp = vp2;
+
+ /*
+ * This sets "vp->flags" appropriately,
+ * and vp->type.
+ */
+ if (!paircreate_raw(attr, vendor, PW_TYPE_OCTETS, vp)) {
+ return NULL;
+ }
+
+ vp->length = length;
+ memcpy(vp->vp_octets, data, length);
+ }
+ break;
}
return vp;
* Sane clients should put the fragments next to each other, in
* which case this is O(N), in the number of fragments.
*/
-static uint8_t *rad_coalesce(int attribute, size_t length, uint8_t *data,
+static uint8_t *rad_coalesce(unsigned int attribute, int vendor,
+ size_t length, uint8_t *data,
size_t packet_length, size_t *ptlv_length)
{
for (ptr = data + length;
ptr != (data + packet_length);
ptr += ptr[1]) {
+ /* FIXME: Check that there are 6 bytes of data here... */
if ((ptr[0] != PW_VENDOR_SPECIFIC) ||
(ptr[1] < (2 + 4 + 3)) || /* WiMAX VSA with continuation */
- (ptr[2] != 0) || (ptr[3] != 0)) { /* our requirement */
+ (ptr[2] != 0) || (ptr[3] != 0) || /* our requirement */
+ (ptr[4] != ((vendor >> 8) & 0xff)) ||
+ (ptr[5] != (vendor & 0xff))) {
continue;
}
return tlv_data;
}
+
+/*
+ * Walk over Evil WIMAX TLVs, creating attributes.
+ */
+static VALUE_PAIR *tlv2wimax(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const char *secret,
+ int attribute, int vendor,
+ uint8_t *ptr, size_t len, int nest)
+{
+ VALUE_PAIR *head = NULL;
+ VALUE_PAIR **tail = &head;
+ VALUE_PAIR *vp;
+ uint8_t *y; /* why do I need to do this? */
+
+ if (nest > fr_wimax_max_tlv) return NULL;
+
+ /*
+ * Sanity check the attribute.
+ */
+ for (y = ptr; y < (ptr + len); y += y[1]) {
+ if ((y[0] == 0) || ((y + 2) > (ptr + len)) ||
+ (y[1] < 2) || ((y + y[1]) > (ptr + len))) {
+ return NULL;
+ }
+
+ /*
+ * Attribute number is too large for us to
+ * represent it in our horrible internal
+ * representation.
+ */
+ if ((ptr[0] & ~fr_wimax_mask[nest]) != 0) {
+ return NULL;
+ }
+ }
+
+ for (y = ptr; y < (ptr + len); y += y[1]) {
+ DICT_ATTR *da;
+
+ da = dict_attrbyvalue(attribute | (ptr[0] << fr_wimax_shift[nest]), vendor);
+ if (da && (da->type == PW_TYPE_TLV)) {
+ vp = tlv2wimax(packet, original, secret,
+ attribute | (ptr[0] << fr_wimax_shift[nest]),
+ vendor, ptr + 2, ptr[1] - 2,
+ nest + 1);
+ if (!vp) goto error;
+ } else {
+ vp = paircreate(attribute | (ptr[0] << fr_wimax_shift[nest]), vendor,
+ PW_TYPE_OCTETS);
+ if (!vp) {
+ error:
+ pairfree(&head);
+ return NULL;
+ }
+
+ if (!data2vp(packet, original, secret,
+ y[1] - 2, y + 2, vp)) {
+ goto error;
+ }
+ }
+
+ *tail = vp;
+ while (*tail) tail = &((*tail)->next);
+ }
+
+ return head;
+}
+
/*
* Start at the *data* portion of a continued attribute. search
* through the rest of the attributes to find a matching one, and
static VALUE_PAIR *rad_continuation2vp(const RADIUS_PACKET *packet,
const RADIUS_PACKET *original,
const char *secret, int attribute,
- int length,
+ int vendor,
+ int length, /* CANNOT be zero */
uint8_t *data, size_t packet_length,
int flag, DICT_ATTR *da)
{
uint8_t *ptr;
uint8_t *tlv_data;
VALUE_PAIR *vp, *head, **tail;
+ DICT_ATTR *tlv_da;
/*
* Ensure we have data that hasn't been split across
* multiple attributes.
*/
if (flag) {
- tlv_data = rad_coalesce(attribute, length,
+ tlv_data = rad_coalesce(attribute, vendor, length,
data, packet_length, &tlv_length);
if (!tlv_data) return NULL;
} else {
* Note that we don't check "flag" here. The calling
* code ensures that
*/
- if (da->type != PW_TYPE_TLV) {
+ if (!da || (da->type != PW_TYPE_TLV)) {
not_well_formed:
if (tlv_data == data) { /* true if we had 'goto' */
tlv_data = malloc(tlv_length);
memcpy(tlv_data, data, tlv_length);
}
- vp = paircreate(attribute, PW_TYPE_OCTETS);
+ vp = paircreate(attribute, vendor, PW_TYPE_OCTETS);
if (!vp) return NULL;
vp->type = PW_TYPE_TLV;
(ptr[1] > left)) {
goto not_well_formed;
}
+
left -= ptr[1];
}
for (ptr = tlv_data;
ptr != (tlv_data + tlv_length);
ptr += ptr[1]) {
- vp = paircreate(attribute | (ptr[0] << 8), PW_TYPE_OCTETS);
- if (!vp) {
- pairfree(&head);
- goto not_well_formed;
- }
- if (!data2vp(packet, original, secret,
- ptr[0], ptr[1] - 2, ptr + 2, vp)) {
- pairfree(&head);
- goto not_well_formed;
+ tlv_da = dict_attrbyvalue(attribute | (ptr[0] << fr_wimax_shift[1]), vendor);
+ if (tlv_da && (tlv_da->type == PW_TYPE_TLV)) {
+ vp = tlv2wimax(packet, original, secret,
+ attribute | (ptr[0] << 8),
+ vendor, ptr + 2, ptr[1] - 2, 2);
+
+ if (!vp) goto error;
+ } else {
+ vp = paircreate(attribute | (ptr[0] << fr_wimax_shift[1]), vendor,
+ PW_TYPE_OCTETS);
+ if (!vp) {
+ error:
+ pairfree(&head);
+ goto not_well_formed;
+ }
+
+ if (!data2vp(packet, original, secret,
+ ptr[1] - 2, ptr + 2, vp)) {
+ goto error;
+ }
}
*tail = vp;
- tail = &(vp->next);
+
+ while (*tail) tail = &((*tail)->next);
}
/*
/*
+ * Extended attribute TLV to VP.
+ */
+static VALUE_PAIR *tlv2vp(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const char *secret, int attribute,
+ int length, const uint8_t *data)
+{
+ VALUE_PAIR *vp;
+
+ if ((length < 2) || (data[1] < 2)) return NULL;
+
+ /*
+ * For now, only one TLV is allowed.
+ */
+ if (data[1] != length) return NULL;
+
+ attribute |= (data[0] << fr_wimax_shift[2]);
+
+ vp = paircreate(attribute, VENDORPEC_EXTENDED, PW_TYPE_OCTETS);
+ if (!vp) return NULL;
+
+ return data2vp(packet, original, secret, length - 2, data + 2, vp);
+}
+
+/*
* Parse a RADIUS attribute into a data structure.
*/
-VALUE_PAIR *rad_attr2vp(const RADIUS_PACKET *packet, const RADIUS_PACKET *original,
- const char *secret, int attribute, int length,
- const uint8_t *data)
+VALUE_PAIR *rad_attr2vp(const RADIUS_PACKET *packet,
+ const RADIUS_PACKET *original,
+ const char *secret, int attribute, int vendor,
+ int length, const uint8_t *data)
{
VALUE_PAIR *vp;
- vp = paircreate(attribute, PW_TYPE_OCTETS);
+ /*
+ * Hard-coded values are bad...
+ */
+ if ((vendor == 0) && (attribute >= 241) && (attribute <= 246)) {
+ DICT_ATTR *da;
+
+ da = dict_attrbyvalue(attribute, VENDORPEC_EXTENDED);
+ if (da && (da->flags.extended || da->flags.extended_flags)) {
+
+ if (length == 0) return NULL;
+
+ attribute |= (data[0] << fr_wimax_shift[1]);
+ vendor = VENDORPEC_EXTENDED;
+
+ data++;
+ length--;
+
+ /*
+ * There may be a flag octet.
+ */
+ if (da->flags.extended_flags) {
+ if (length == 0) return NULL;
+
+ /*
+ * If there's a flag, we can't
+ * handle it.
+ */
+ if (data[0] != 0) return NULL;
+ data++;
+ length--;
+ }
+
+ /*
+ * Now look up the extended attribute, to
+ * see if it's a TLV carrying more data.
+ *
+ */
+ da = dict_attrbyvalue(attribute, VENDORPEC_EXTENDED);
+ if (da && da->flags.has_tlv) {
+ return tlv2vp(packet, original, secret,
+ attribute, length, data);
+ }
+ }
+ }
+ vp = paircreate(attribute, vendor, PW_TYPE_OCTETS);
if (!vp) return NULL;
- return data2vp(packet, original, secret, attribute, length, data, vp);
+ return data2vp(packet, original, secret, length, data, vp);
}
if (myvendor == 0) goto create_pair;
/*
- * This is an implementation issue.
- * We currently pack vendor into the upper
- * 16 bits of a 32-bit attribute number,
- * so we can't handle vendor numbers larger
- * than 16 bits.
+ * Allow vendors up to 2^24. Past that,
+ * get confused.
*/
- if (myvendor > 65535) goto create_pair;
+ if (myvendor > FR_MAX_VENDOR) goto create_pair;
vsa_tlen = vsa_llen = 1;
vsa_offset = 0;
switch (vsa_llen) {
case 0:
- attribute = (myvendor << 16) | myattr;
+ attribute = myattr;
ptr += 4 + vsa_tlen;
attrlen -= (4 + vsa_tlen);
packet_length -= 4 + vsa_tlen;
default: /* can't hit this. */
return -1;
}
- attribute |= (vendorcode << 16);
vsa_ptr = ptr;
ptr += vsa_tlen;
ptr += vsa_llen + vsa_offset;
vendorlen -= vsa_tlen + vsa_llen + vsa_offset + attrlen;
- if (vendorlen == 0) vendorcode = 0;
packet_length -= (vsa_tlen + vsa_llen + vsa_offset);
/*
+ * Ignore VSAs that have no data.
+ */
+ if (attrlen == 0) goto next;
+
+ /*
* WiMAX attributes of type 0 are ignored. They
* are a secret flag to us that the attribute has
* already been dealt with.
*/
- if (attribute == 0x60b50000) goto next;
+ if ((vendorcode == VENDORPEC_WIMAX) && (attribute == 0)) {
+ goto next;
+ }
if (vsa_offset) {
DICT_ATTR *da;
- da = dict_attrbyvalue(attribute);
+ da = dict_attrbyvalue(attribute, vendorcode);
/*
* If it's NOT continued, AND we know
* Go do a lot of work to find the stuff.
*/
pair = rad_continuation2vp(packet, original, secret,
- attribute, attrlen, ptr,
+ attribute, vendorcode,
+ attrlen, ptr,
packet_length,
((vsa_ptr[2] & 0x80) != 0),
da);
(attribute != PW_CHARGEABLE_USER_IDENTITY)) goto next;
pair = rad_attr2vp(packet, original, secret,
- attribute, attrlen, ptr);
+ attribute, vendorcode, attrlen, ptr);
if (!pair) {
pairfree(&packet->vps);
fr_strerror_printf("out of memory");
}
next:
+ if (vendorlen == 0) vendorcode = 0;
ptr += attrlen;
packet_length -= attrlen;
}
* Use Chap-Challenge pair if present,
* Request-Authenticator otherwise.
*/
- challenge = pairfind(packet->vps, PW_CHAP_CHALLENGE);
+ challenge = pairfind(packet->vps, PW_CHAP_CHALLENGE, 0);
if (challenge) {
memcpy(ptr, challenge->vp_strvalue, challenge->length);
i += challenge->length;
return rp;
}
+RADIUS_PACKET *rad_alloc_reply(RADIUS_PACKET *packet)
+{
+ RADIUS_PACKET *reply;
+
+ if (!packet) return NULL;
+
+ reply = rad_alloc(0);
+ if (!reply) return NULL;
+
+ /*
+ * Initialize the fields from the request.
+ */
+ reply->sockfd = packet->sockfd;
+ reply->dst_ipaddr = packet->src_ipaddr;
+ reply->src_ipaddr = packet->dst_ipaddr;
+ reply->dst_port = packet->src_port;
+ reply->src_port = packet->dst_port;
+ reply->id = packet->id;
+ reply->code = 0; /* UNKNOWN code */
+ memcpy(reply->vector, packet->vector,
+ sizeof(reply->vector));
+ reply->vps = NULL;
+ reply->data = NULL;
+ reply->data_len = 0;
+
+ return reply;
+}
+
+
/*
* Free a RADIUS_PACKET
*/