uint8_t *code;
ssize_t data_len;
- packet = rad_alloc(NULL, 0);
+ packet = rad_alloc(NULL, false);
if (!packet) {
fr_strerror_printf("Failed allocating packet");
return NULL;
static int fr_dhcp_attr2vp(RADIUS_PACKET *packet, VALUE_PAIR *vp, uint8_t const *p, size_t alen);
-static int decode_tlv(RADIUS_PACKET *packet, VALUE_PAIR *tlv, uint8_t const *data, size_t data_len)
+static int fr_dhcp_decode_suboption(RADIUS_PACKET *packet, VALUE_PAIR *tlv, uint8_t const *data, size_t data_len)
{
- uint8_t const *p;
+ uint8_t const *p, *q;
VALUE_PAIR *head, *vp;
vp_cursor_t cursor;
* Take a pass at parsing it.
*/
p = data;
- while (p < (data + data_len)) {
- if ((p + 2) > (data + data_len)) goto make_tlv;
+ q = data + data_len;
+ while (p < q) {
+ /*
+ * The RFC 3046 is very specific about not allowing termination
+ * with a 255 sub-option. But vendors are stupid, so allow it
+ * and the 0 padding sub-option.
+ * This requirement really should be a SHOULD anyway...
+ */
+ if (*p == 0) {
+ p++;
+ continue;
+ }
+ if (*p == 255) {
+ q--;
+ break;
+ }
- if ((p + p[1] + 2) > (data + data_len)) goto make_tlv;
- p += 2 + p[1];
+ /*
+ * Check if reading length would take us past the end of the buffer
+ */
+ if (++p >= q) goto malformed;
+ p += p[0];
+
+ /*
+ * Check if length > the length of the buffer we have left
+ */
+ if (p >= q) goto malformed;
+ p++;
}
/*
fr_cursor_init(&cursor, &head);
p = data;
- while (p < (data + data_len)) {
+ while (p < q) {
vp = paircreate(packet, tlv->da->attr | (p[0] << 8), DHCP_MAGIC_VENDOR);
if (!vp) {
pairfree(&head);
- goto make_tlv;
+ goto malformed;
}
if (fr_dhcp_attr2vp(packet, vp, p + 2, p[1]) < 0) {
pairfree(&head);
- goto make_tlv;
+ goto malformed;
}
fr_cursor_insert(&cursor, vp);
case PW_TYPE_OCTETS:
case PW_TYPE_TLV:
(void) talloc_steal(tlv, head->data.ptr);
+
default:
break;
}
return 0;
-make_tlv:
+malformed:
tlv->vp_tlv = talloc_array(tlv, uint8_t, data_len);
if (!tlv->vp_tlv) {
fr_strerror_printf("No memory");
vp->vp_integer = ntohl(vp->vp_integer);
break;
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
if (alen != 4) goto raw;
/*
* Keep value in Network Order!
if (pair2unknown(vp) < 0) return -1;
case PW_TYPE_OCTETS:
- if (alen > 253) return -1;
+ if (alen > 255) return -1;
pairmemcpy(vp, p, alen);
break;
+ /*
+ * For option 82 et al...
+ */
case PW_TYPE_TLV:
- return decode_tlv(packet, vp, p, alen);
+ return fr_dhcp_decode_suboption(packet, vp, p, alen);
default:
fr_strerror_printf("Internal sanity check %d %d", vp->da->type, __LINE__);
p = next;
- if (*p == 0) break;
- if (*p == 255) break; /* end of options signifier */
+ if (*p == 0) { /* 0x00 - Padding option */
+ next++;
+ continue;
+ }
+ if (*p == 255) break; /* 0xff - End of options signifier */
+
if ((p + 2) > (data + len)) break;
next = p + 2 + p[1];
- if (p[1] >= 253) {
- fr_strerror_printf("Attribute too long %u %u",
- p[0], p[1]);
- continue;
- }
-
da = dict_attrbyvalue(p[0], DHCP_MAGIC_VENDOR);
if (!da) {
- fr_strerror_printf("Attribute not in our dictionary: %u",
- p[0]);
+ fr_strerror_printf("Attribute not in our dictionary: %u", p[0]);
continue;
}
alen = 2;
break;
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
case PW_TYPE_INTEGER:
case PW_TYPE_DATE: /* ignore any trailing data */
num_entries = alen >> 2;
for (i = 0; i < num_entries; i++) {
vp = pairmake(packet, NULL, da->name, NULL, T_OP_ADD);
if (!vp) {
- fr_strerror_printf("Cannot build attribute %s",
- fr_strerror());
+ fr_strerror_printf("Cannot build attribute %s", fr_strerror());
pairfree(head);
return -1;
}
- /*
- * Hack for ease of use.
- */
- if ((da->vendor == DHCP_MAGIC_VENDOR) &&
- (da->attr == 61) && !da->flags.array &&
- (alen == 7) && (*p == 1) && (num_entries == 1)) {
- pairmemcpy(vp, p + 1, 6);
-
- } else if (fr_dhcp_attr2vp(packet, vp, p, alen) < 0) {
+ if (fr_dhcp_attr2vp(packet, vp, p, alen) < 0) {
pairfree(&vp);
pairfree(head);
return -1;
vp->length = 4;
break;
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
memcpy(&vp->vp_ipaddr, p, 4);
vp->length = 4;
break;
memcpy(p, &lvalue, 4);
break;
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
memcpy(p, &vp->vp_ipaddr, 4);
break;
*/
/* DHCP-Boot-Filename */
- if ((vp = pairfind(packet->vps, 269, DHCP_MAGIC_VENDOR, TAG_ANY))) {
+ vp = pairfind(packet->vps, 269, DHCP_MAGIC_VENDOR, TAG_ANY);
+ if (vp) {
if (vp->length > DHCP_FILE_LEN) {
memcpy(p, vp->vp_strvalue, DHCP_FILE_LEN);
} else {
vp->vp_integer = ntohl(vp->vp_integer);
break;
- case PW_TYPE_IPADDR:
+ case PW_TYPE_IPV4_ADDR:
memcpy(&vp->vp_ipaddr, p, 4);
break;
* Each call to fr_dhcp_encode_option will encode one complete DHCP option,
* and sub options.
*/
- while (fr_cursor_current(&cursor)) {
+ while ((vp = fr_cursor_current(&cursor))) {
len = fr_dhcp_encode_option(p, packet->data_len - (p - packet->data), packet, &cursor);
if (len < 0) break;
if (len > 0) debug_pair(vp);