* encrypting passwords to RADIUS.
*/
static void make_secret(uint8_t *digest, uint8_t const *vector,
- char const *secret, uint8_t const *value)
+ char const *secret, uint8_t const *value, size_t length)
{
FR_MD5_CTX context;
- int i;
+ size_t i;
fr_md5_init(&context);
fr_md5_update(&context, vector, AUTH_VECTOR_LEN);
fr_md5_update(&context, (uint8_t const *) secret, strlen(secret));
fr_md5_final(digest, &context);
- for ( i = 0; i < AUTH_VECTOR_LEN; i++ ) {
+ for ( i = 0; i < length; i++ ) {
digest[i] ^= value[i];
}
}
* always fits.
*/
case FLAG_ENCRYPT_ASCEND_SECRET:
- if (len != 16) return 0;
- make_secret(ptr, packet->vector, secret, data);
+ if (len > AUTH_VECTOR_LEN) len = AUTH_VECTOR_LEN;
+ make_secret(ptr, packet->vector, secret, data, len);
len = AUTH_VECTOR_LEN;
break;
* don't care about walking off of the end of it.
*/
while (ptr < end) {
+ if (ptr[1] < 2) return -1;
+ if ((ptr + ptr[1]) > end) return -1;
+
total += ptr[1] - 2;
ptr += ptr[1];
+ if (ptr == end) break;
+
/*
* Attributes MUST be consecutive.
*/
if (ptr[0] != attr) break;
}
+ end = ptr;
+
vp = fr_pair_afrom_da(ctx, da);
if (!vp) return -1;
total = 0;
ptr = start;
- while (total < vp->vp_length) {
+ while (ptr < end) {
memcpy(p, ptr + 2, ptr[1] - 2);
p += ptr[1] - 2;
total += ptr[1] - 2;
}
*pvp = vp;
+
return ptr - start;
}
VALUE_PAIR **pvp)
{
ssize_t rcode;
- size_t fraglen;
+ size_t ext_len;
+ bool more;
uint8_t *head, *tail;
- uint8_t const *frag, *end;
- uint8_t const *attr;
- int fragments;
- bool last_frag;
+ uint8_t const *attr, *end;
+ DICT_ATTR const *child;
- if (attrlen < 3) return -1;
+ /*
+ * data = Ext-Attr Flag ...
+ */
+
+ /*
+ * Not enough room for Ext-Attr + Flag + data, it's a bad
+ * attribute.
+ */
+ if (attrlen < 3) {
+ raw:
+ /*
+ * It's not an Extended attribute, it's unknown...
+ */
+ child = dict_unknown_afrom_fields(ctx, (da->vendor/ FR_MAX_VENDOR) & 0xff, 0);
+ if (!child) {
+ fr_strerror_printf("Internal sanity check %d", __LINE__);
+ return -1;
+ }
+
+ rcode = data2vp(ctx, packet, original, secret, child,
+ data, attrlen, attrlen, pvp);
+ if (rcode < 0) return rcode;
+ return attrlen;
+ }
+
+ /*
+ * No continued data, just decode the attribute in place.
+ */
+ if ((data[1] & 0x80) == 0) {
+ rcode = data2vp(ctx, packet, original, secret, da,
+ data + 2, attrlen - 2, attrlen - 2,
+ pvp);
+
+ if ((rcode < 0) || (((size_t) rcode + 2) != attrlen)) goto raw; /* didn't decode all of the data */
+ return attrlen;
+ }
+
+ /*
+ * It's continued, but there are no subsequent fragments,
+ * it's bad.
+ */
+ if (attrlen >= packetlen) goto raw;
/*
* Calculate the length of all of the fragments. For
* now, they MUST be contiguous in the packet, and they
- * MUST be all of the same TYPE and EXTENDED-TYPE
+ * MUST be all of the same Type and Ext-Type
+ *
+ * We skip the first fragment, which doesn't have a
+ * RADIUS attribute header.
*/
- attr = data - 2;
- fraglen = attrlen - 2;
- frag = data + attrlen;
+ ext_len = attrlen - 2;
+ attr = data + attrlen;
end = data + packetlen;
- fragments = 1;
- last_frag = false;
-
- while (frag < end) {
- if (last_frag ||
- (frag[0] != attr[0]) ||
- (frag[1] < 4) || /* too short for long-extended */
- (frag[2] != attr[2]) ||
- ((frag + frag[1]) > end)) { /* overflow */
- end = frag;
- break;
- }
- last_frag = ((frag[3] & 0x80) == 0);
+ while (attr < end) {
+ /*
+ * Not enough room for Attr + length + Ext-Attr
+ * continuation, it's bad.
+ */
+ if ((end - attr) < 4) goto raw;
+
+ if (attr[1] < 4) goto raw;
+
+ /*
+ * If the attribute overflows the packet, it's
+ * bad.
+ */
+ if ((attr + attr[1]) > end) goto raw;
+
+ if (attr[0] != ((da->vendor / FR_MAX_VENDOR) & 0xff)) goto raw; /* not the same Extended-Attribute-X */
+
+ if (attr[2] != data[0]) goto raw; /* Not the same Ext-Attr */
- fraglen += frag[1] - 4;
- frag += frag[1];
- fragments++;
+ /*
+ * Check the continuation flag.
+ */
+ more = ((attr[2] & 0x80) != 0);
+
+ /*
+ * Or, there's no more data, in which case we
+ * shorten "end" to finish at this attribute.
+ */
+ if (!more) end = attr + attr[1];
+
+ /*
+ * There's more data, but we're at the end of the
+ * packet. The attribute is malformed!
+ */
+ if (more && ((attr + attr[1]) == end)) goto raw;
+
+ /*
+ * Add in the length of the data we need to
+ * concatenate together.
+ */
+ ext_len += attr[1] - 4;
+
+ /*
+ * Go to the next attribute, and stop if there's
+ * no more.
+ */
+ attr += attr[1];
+ if (!more) break;
}
- head = tail = malloc(fraglen);
- if (!head) return -1;
+ if (!ext_len) goto raw;
- VP_TRACE("Fragments %d, total length %d\n", fragments, (int) fraglen);
+ head = tail = malloc(ext_len);
+ if (!head) goto raw;
/*
- * And again, but faster and looser.
- *
- * We copy the first fragment, followed by the rest of
- * the fragments.
+ * Copy the data over, this time trusting the attribute
+ * contents.
*/
- frag = attr;
+ attr = data;
+ memcpy(tail, attr + 2, attrlen - 2);
+ tail += attrlen - 2;
+ attr += attrlen;
- while (fragments > 0) {
- memcpy(tail, frag + 4, frag[1] - 4);
- tail += frag[1] - 4;
- frag += frag[1];
- fragments--;
+ while (attr < end) {
+ memcpy(tail, attr + 4, attr[1] - 4);
+ tail += attr[1] - 4;
+ attr += attr[1]; /* skip VID+WiMax header */
}
- VP_HEXDUMP("long-extended fragments", head, fraglen);
+ VP_HEXDUMP("long-extended fragments", head, ext_len);
rcode = data2vp(ctx, packet, original, secret, da,
- head, fraglen, fraglen, pvp);
+ head, ext_len, ext_len, pvp);
free(head);
- if (rcode < 0) return rcode;
+ if (rcode < 0) goto raw;
return end - data;
}
-/** Convert a Vendor-Specific WIMAX to vps
+/** Convert a Vendor-Specific WIMAX to VPs
*
* @note Called ONLY for Vendor-Specific
*/
VALUE_PAIR **pvp)
{
ssize_t rcode;
- size_t fraglen;
- bool last_frag;
+ size_t wimax_len;
+ bool more;
uint8_t *head, *tail;
- uint8_t const *frag, *end;
+ uint8_t const *attr, *end;
DICT_ATTR const *child;
- if (attrlen < 8) return -1;
+ /*
+ * data = VID VID VID VID WiMAX-Attr WimAX-Len Continuation ...
+ */
- if (((size_t) (data[5] + 4)) != attrlen) return -1;
+ /*
+ * Not enough room for WiMAX Vendor + Wimax attr + length
+ * + continuation, it's a bad attribute.
+ */
+ if (attrlen < 8) {
+ raw:
+ /*
+ * It's not a Vendor-Specific, it's unknown...
+ */
+ child = dict_unknown_afrom_fields(ctx, PW_VENDOR_SPECIFIC, 0);
+ if (!child) {
+ fr_strerror_printf("Internal sanity check %d", __LINE__);
+ return -1;
+ }
+
+ rcode = data2vp(ctx, packet, original, secret, child,
+ data, attrlen, attrlen, pvp);
+ if (rcode < 0) return rcode;
+ return attrlen;
+ }
+
+ if (data[5] < 3) goto raw; /* WiMAX-Length is too small */
child = dict_attrbyvalue(data[4], vendor);
- if (!child) return -1;
+ if (!child) goto raw;
+ /*
+ * No continued data, just decode the attribute in place.
+ */
if ((data[6] & 0x80) == 0) {
+ if ((data[5] + 4) != attrlen) goto raw; /* WiMAX attribute doesn't fill Vendor-Specific */
+
rcode = data2vp(ctx, packet, original, secret, child,
data + 7, data[5] - 3, data[5] - 3,
pvp);
- if (rcode < 0) return -1;
- return 7 + rcode;
+
+ if ((rcode < 0) || (((size_t) rcode + 7) != attrlen)) goto raw; /* didn't decode all of the data */
+ return attrlen;
}
/*
* MUST be all of the same VSA, WiMAX, and WiMAX-attr.
*
* The first fragment doesn't have a RADIUS attribute
- * header, so it needs to be treated a little special.
+ * header.
*/
- fraglen = data[5] - 3;
- frag = data + attrlen;
+ wimax_len = 0;
+ attr = data + 4;
end = data + packetlen;
- last_frag = false;
-
- while (frag < end) {
- if (last_frag ||
- (frag[0] != PW_VENDOR_SPECIFIC) ||
- (frag[1] < 9) || /* too short for wimax */
- ((frag + frag[1]) > end) || /* overflow */
- (memcmp(frag + 2, data, 4) != 0) || /* not wimax */
- (frag[6] != data[4]) || /* not the same wimax attr */
- ((frag[7] + 6) != frag[1])) { /* doesn't fill the attr */
- end = frag;
- break;
- }
- last_frag = ((frag[8] & 0x80) == 0);
+ while (attr < end) {
+ /*
+ * Not enough room for Attribute + length +
+ * continuation, it's bad.
+ */
+ if ((end - attr) < 3) goto raw;
- fraglen += frag[7] - 3;
- frag += frag[1];
- }
+ /*
+ * Must have non-zero data in the attribute.
+ */
+ if (attr[1] <= 3) goto raw;
- head = tail = malloc(fraglen);
- if (!head) return -1;
+ /*
+ * If the WiMAX attribute overflows the packet,
+ * it's bad.
+ */
+ if ((attr + attr[1]) > end) goto raw;
+
+ /*
+ * Check the continuation flag.
+ */
+ more = ((attr[2] & 0x80) != 0);
+
+ /*
+ * Or, there's no more data, in which case we
+ * shorten "end" to finish at this attribute.
+ */
+ if (!more) end = attr + attr[1];
+
+ /*
+ * There's more data, but we're at the end of the
+ * packet. The attribute is malformed!
+ */
+ if (more && ((attr + attr[1]) == end)) goto raw;
+
+ /*
+ * Add in the length of the data we need to
+ * concatenate together.
+ */
+ wimax_len += attr[1] - 3;
+
+ /*
+ * Go to the next attribute, and stop if there's
+ * no more.
+ */
+ attr += attr[1];
+ if (!more) break;
+
+ /*
+ * data = VID VID VID VID WiMAX-Attr WimAX-Len Continuation ...
+ *
+ * attr = Vendor-Specific VSA-Length VID VID VID VID WiMAX-Attr WimAX-Len Continuation ...
+ *
+ */
+
+ /*
+ * No room for Vendor-Specific + length +
+ * Vendor(4) + attr + length + continuation + data
+ */
+ if ((end - attr) < 9) goto raw;
+
+ if (attr[0] != PW_VENDOR_SPECIFIC) goto raw;
+ if (attr[1] < 9) goto raw;
+ if ((attr + attr[1]) > end) goto raw;
+ if (memcmp(data, attr + 2, 4) != 0) goto raw; /* not WiMAX Vendor ID */
+
+ if (attr[1] != (attr[7] + 6)) goto raw; /* WiMAX attr doesn't exactly fill the VSA */
+
+ if (data[4] != attr[6]) goto raw; /* different WiMAX attribute */
+
+ /*
+ * Skip over the Vendor-Specific header, and
+ * continue with the WiMAX attributes.
+ */
+ attr += 6;
+ }
/*
- * And again, but faster and looser.
- *
- * We copy the first fragment, followed by the rest of
- * the fragments.
+ * No data in the WiMAX attribute, make a "raw" one.
*/
- frag = data;
+ if (!wimax_len) goto raw;
- memcpy(tail, frag + 4 + 3, frag[4 + 1] - 3);
- tail += frag[4 + 1] - 3;
- frag += attrlen; /* should be frag[1] - 7 */
+ head = tail = malloc(wimax_len);
+ if (!head) return -1;
/*
- * frag now points to RADIUS attributes
+ * Copy the data over, this time trusting the attribute
+ * contents.
*/
- do {
- memcpy(tail, frag + 2 + 4 + 3, frag[2 + 4 + 1] - 3);
- tail += frag[2 + 4 + 1] - 3;
- frag += frag[1];
- } while (frag < end);
+ attr = data;
+ while (attr < end) {
+ memcpy(tail, attr + 4 + 3, attr[4 + 1] - 3);
+ tail += attr[4 + 1] - 3;
+ attr += 4 + attr[4 + 1]; /* skip VID+WiMax header */
+ attr += 2; /* skip Vendor-Specific header */
+ }
- VP_HEXDUMP("wimax fragments", head, fraglen);
+ VP_HEXDUMP("wimax fragments", head, wimax_len);
rcode = data2vp(ctx, packet, original, secret, child,
- head, fraglen, fraglen, pvp);
+ head, wimax_len, wimax_len, pvp);
free(head);
- if (rcode < 0) return rcode;
+ if (rcode < 0) goto raw;
return end - data;
}
goto raw;
} else {
uint8_t my_digest[AUTH_VECTOR_LEN];
+ size_t secret_len;
+
+ secret_len = datalen;
+ if (secret_len > AUTH_VECTOR_LEN) secret_len = AUTH_VECTOR_LEN;
+
make_secret(my_digest,
original->vector,
- secret, data);
+ secret, data, secret_len);
memcpy(buffer, my_digest,
AUTH_VECTOR_LEN );
buffer[AUTH_VECTOR_LEN] = '\0';
}
/*
- * If there no more fragments, then the contents
- * have to be a well-known data type.
- *
- */
- if ((data[1] & 0x80) == 0) {
- rcode = data2vp(ctx, packet, original, secret, child,
- data + 2, attrlen - 2, attrlen - 2,
- pvp);
- if (rcode < 0) goto raw;
- return 2 + rcode;
- }
-
- /*
* This requires a whole lot more work.
*/
return data2vp_extended(ctx, packet, original, secret, child,
break;
case PW_TYPE_SIGNED: /* overloaded with vp_integer */
- memcpy(&vp->vp_integer, buffer, 4);
+ memcpy(&vp->vp_integer, data, 4);
vp->vp_integer = ntohl(vp->vp_integer);
break;