{ NULL }
};
-/** RADIUS on-the-wire format attribute sizes
- *
- * Holds the min/max sizes of all supported RADIUS attribute values as they
- * would be found in a RADIUS packet.
- *
- * These sizes may be different than the sizes of INTERNAL formats, PRESENTATION
- * formats and generic NETWORK formats.
- */
-size_t const fr_radius_attr_sizes[FR_TYPE_MAX + 1][2] = {
- [FR_TYPE_NULL] = {~0, 0}, //!< Ensure array starts at 0 (umm?)
-
- [FR_TYPE_STRING] = {0, ~0},
- [FR_TYPE_OCTETS] = {0, ~0},
-
- [FR_TYPE_IPV4_ADDR] = {4, 4},
- [FR_TYPE_IPV4_PREFIX] = {6, 6},
- [FR_TYPE_IPV6_ADDR] = {16, 16},
- [FR_TYPE_IPV6_PREFIX] = {2, 18},
- [FR_TYPE_COMBO_IP_PREFIX] = {6, 18},
- [FR_TYPE_COMBO_IP_ADDR] = {4, 16},
- [FR_TYPE_IFID] = {8, 8},
- [FR_TYPE_ETHERNET] = {6, 6},
-
- [FR_TYPE_BOOL] = {1, 1},
- [FR_TYPE_UINT8] = {1, 1},
- [FR_TYPE_UINT16] = {2, 2},
- [FR_TYPE_UINT32] = {4, 4},
- [FR_TYPE_UINT64] = {8, 8},
-
- [FR_TYPE_INT8] = {1, 1},
- [FR_TYPE_INT16] = {2, 2},
- [FR_TYPE_INT32] = {4, 4},
- [FR_TYPE_INT64] = {8, 8},
-
- [FR_TYPE_DATE] = {2, 8},
- [FR_TYPE_TIME_DELTA] = {2, 8},
-
- [FR_TYPE_TLV] = {2, ~0},
- [FR_TYPE_STRUCT] = {1, ~0},
-
- [FR_TYPE_VSA] = {4, ~0},
-
- [FR_TYPE_MAX] = {~0, 0} //!< Ensure array covers all types.
-};
-
/*
* Some messages get printed out only in debugging mode.
*/
fr_pair_t *vp = NULL;
uint8_t const *p = data;
uint8_t buffer[256];
- size_t min = 0, max = 0;
- int extra;
+ size_t extra;
if (attr_len > 128 * 1024) {
fr_strerror_printf("%s: packet is too large to be RADIUS", __FUNCTION__);
switch (parent->type) {
case FR_TYPE_LEAF:
- min = fr_radius_attr_sizes[parent->type][0];
- max = fr_radius_attr_sizes[parent->type][1];
-
- if (data_len < min) {
- FR_PROTO_TRACE("Data len %zu too short, need at least %zu", data_len, min);
- goto raw;
- }
- if (data_len > max) {
- FR_PROTO_TRACE("Data len %zu too long, must be less than or equal to %zu", data_len, max);
- goto raw;
- }
break;
case FR_TYPE_VSA:
case FR_TYPE_TLV:
if (!flag_extended(&parent->flags)) {
- /*
- * We presume that the TLVs all fit into one
- * attribute, OR they've already been grouped
- * into a contiguous memory buffer.
- */
- ret = fr_radius_decode_tlv(ctx, out, parent, p, attr_len, packet_ctx);
- if (ret < 0) goto raw;
- return attr_len;
+ /*
+ * We presume that the TLVs all fit into one
+ * attribute, OR they've already been grouped
+ * into a contiguous memory buffer.
+ */
+ ret = fr_radius_decode_tlv(ctx, out, parent, p, attr_len, packet_ctx);
+ if (ret < 0) goto raw;
+ return attr_len;
}
/*
* Extended attributes
*/
- min = 1 + extra;
+ extra++;
/*
* Not enough data, just create a raw attribute.
*/
- if (data_len <= min) goto raw;
+ if (data_len <= extra) goto raw;
/*
* Look up the extended type. It's almost always
*/
if (!extra || ((p[1] & 0x80) == 0)) {
ret = fr_radius_decode_pair_value(ctx, out, child,
- p + min, attr_len - min,
+ p + extra, attr_len - extra,
packet_ctx);
if (ret < 0) goto invalid_extended;
return attr_len;
/*
* "long" extended. Decode the value.
*/
- if (extra) {
+ if (extra > 1) {
ret = decode_extended(ctx, out, child, data, attr_len, packet_ctx);
if (ret >= 0) return ret; /* which may be LONGER than attr_len */
}
ret = fr_radius_decode_pair_value(ctx, out, child,
- p + min, attr_len - min,
+ p + extra, attr_len - extra,
packet_ctx);
if (ret < 0) return -1;
}
* RFC does not require non-masked bits to be zero.
*/
case FR_TYPE_IPV4_PREFIX:
- if (data_len != min) goto raw;
+ if (data_len != 6) goto raw;
if (p[0] != 0) goto raw;
if ((p[1] & 0x3f) > 32) goto raw;
*/
case FR_TYPE_IPV6_PREFIX:
{
+ if (data_len > 18) goto raw;
+ if (data_len < 2) goto raw;
if (p[0] != 0) goto raw; /* First byte is always 0 */
if (p[1] > 128) goto raw;
/*
* Convert prefix bits to bytes to check that
* we have sufficient data.
+ *
+ * If Prefix has more data than Prefix-Length
+ * indicates, we just ignore the rest.
*/
if (fr_bytes_from_bits(p[1]) > (data_len - 2)) goto raw;
default:
decode:
- if (fr_value_box_from_network(vp, &vp->data, vp->da->type, vp->da,
- &FR_DBUFF_TMP(p, data_len), data_len, true) < 0) {
+ ret = fr_value_box_from_network(vp, &vp->data, vp->da->type, vp->da,
+ &FR_DBUFF_TMP(p, data_len), data_len, true);
+ if (ret < 0) {
/*
* Paranoid loop prevention
*/