* 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,
ptr[0] = attribute & 0xff; /* NOT vp->attribute */
ptr[1] = 2;
- len = vp2data(packet, original, secret, vp, ptr + 2, room - 2);
+ if (room > (255 - ptr[1])) room = 255 - ptr[1];
+ len = vp2data(packet, original, secret, vp, ptr + 2, room);
if (len < 0) return len;
ptr[1] += len;
}
+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.
*/
* RFC format attributes take the fast path.
*/
if (vp->vendor == 0) {
- len = rad_vp2rfc(packet, original, secret, vp,
- vp->attribute, start, room);
- if (len < 0) return -1;
-
- /*
- * 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?
- */
- if ((len == 0) &&
- (vp->attribute != PW_CHARGEABLE_USER_IDENTITY)) return 0;
-
- return len;
+ 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 (reply = packet->vps; reply; reply = reply->next) {
/*
- * Ignore non-wire attributes
+ * Ignore non-wire attributes, but allow extended
+ * attributes.
*/
if ((reply->vendor == 0) &&
- ((reply->attribute & 0xFFFF) > 0xff)) {
+ ((reply->attribute & 0xFFFF) >= 256) &&
+ !reply->flags.extended && !reply->flags.extended_flags) {
#ifndef NDEBUG
/*
* Permit the admin to send BADLY formatted
*/
if (reply->flags.encoded) continue;
- if (reply->flags.is_tlv) {
+ if ((reply->vendor == VENDORPEC_WIMAX) && reply->flags.is_tlv) {
len = rad_encode_wimax(packet, original, secret,
reply, ptr,
((uint8_t *) data) + sizeof(data) - ptr);
if (len < 0) return -1;
+ /*
+ * Failed to encode the attribute, likely because
+ * the packet is full.
+ */
+ 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;
+ }
+
next:
ptr += len;
total_length += len;
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]) {
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.)",
+ "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,
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.)",
+ "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;
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) {
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;
/*
+ * 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,
{
VALUE_PAIR *vp;
+ /*
+ * 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;