#include <freeradius-devel/udpfromto.h>
#endif
+/*
+ * Some messages get printed out only in debugging mode.
+ */
+#define FR_DEBUG_STRERROR_PRINTF if (fr_debug_lvl) fr_strerror_printf
+
#if 0
-#define VP_TRACE if (fr_debug_flag) printf
+#define VP_TRACE printf
static void VP_HEXDUMP(char const *msg, uint8_t const *data, size_t len)
{
if ((i & 0x0f) == 0x0f) printf("\n");
}
if ((len == 0x0f) || ((len & 0x0f) != 0x0f)) printf("\n");
+ fflush(stdout);
}
#else
va_list ap;
va_start(ap, fmt);
- if ((fr_debug_flag == 0) || !fr_log_fp) {
+ if ((fr_debug_lvl == 0) || !fr_log_fp) {
va_end(ap);
return;
}
if (!packet->data || !fr_log_fp) return;
- fprintf(fr_log_fp, " Code:\t\t%u\n", packet->data[0]);
+ fprintf(fr_log_fp, " Socket:\t%d\n", packet->sockfd);
+#ifdef WITH_TCP
+ fprintf(fr_log_fp, " Proto:\t%d\n", packet->proto);
+#endif
+
+ if (packet->src_ipaddr.af == AF_INET) {
+ char buffer[32];
+
+ fprintf(fr_log_fp, " Src IP:\t%s\n",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)));
+ fprintf(fr_log_fp, " port:\t%u\n", packet->src_port);
+
+ fprintf(fr_log_fp, " Dst IP:\t%s\n",
+ inet_ntop(packet->dst_ipaddr.af,
+ &packet->dst_ipaddr.ipaddr,
+ buffer, sizeof(buffer)));
+ fprintf(fr_log_fp, " port:\t%u\n", packet->dst_port);
+ }
+
+ if (packet->data[0] < FR_MAX_PACKET_CODE) {
+ fprintf(fr_log_fp, " Code:\t\t(%d) %s\n", packet->data[0], fr_packet_codes[packet->data[0]]);
+ } else {
+ fprintf(fr_log_fp, " Code:\t\t%u\n", packet->data[0]);
+ }
fprintf(fr_log_fp, " Id:\t\t%u\n", packet->data[1]);
fprintf(fr_log_fp, " Length:\t%u\n", ((packet->data[2] << 8) |
(packet->data[3])));
(struct sockaddr *)&src, &sizeof_src);
}
-
+/** Basic validation of RADIUS packet header
+ *
+ * @note fr_strerror errors are only available if fr_debug_lvl > 0. This is to reduce CPU time
+ * consumed when discarding malformed packet.
+ *
+ * @param[in] sockfd we're reading from.
+ * @param[out] src_ipaddr of the packet.
+ * @param[out] src_port of the packet.
+ * @param[out] code Pointer to where to write the packet code.
+ * @return
+ * - -1 on failure.
+ * - 1 on decode error.
+ * - >= RADIUS_HDR_LEN on success. This is the packet length as specified in the header.
+ */
ssize_t rad_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, int *code)
{
ssize_t data_len, packet_len;
struct sockaddr_storage src;
socklen_t sizeof_src = sizeof(src);
- data_len = recvfrom(sockfd, header, sizeof(header), MSG_PEEK,
- (struct sockaddr *)&src, &sizeof_src);
+ data_len = recvfrom(sockfd, header, sizeof(header), MSG_PEEK, (struct sockaddr *)&src, &sizeof_src);
if (data_len < 0) {
if ((errno == EAGAIN) || (errno == EINTR)) return 0;
return -1;
}
/*
- * Too little data is available, discard the packet.
+ * Convert AF. If unknown, discard packet.
*/
- if (data_len < 4) {
+ if (!fr_sockaddr2ipaddr(&src, sizeof_src, src_ipaddr, src_port)) {
+ FR_DEBUG_STRERROR_PRINTF("Unkown address family");
rad_recv_discard(sockfd);
return 1;
+ }
- } else { /* we got 4 bytes of data. */
- /*
- * See how long the packet says it is.
- */
- packet_len = (header[2] * 256) + header[3];
-
- /*
- * The length in the packet says it's less than
- * a RADIUS header length: discard it.
- */
- if (packet_len < RADIUS_HDR_LEN) {
- rad_recv_discard(sockfd);
+ /*
+ * Too little data is available, discard the packet.
+ */
+ if (data_len < 4) {
+ FR_DEBUG_STRERROR_PRINTF("Expected at least 4 bytes of header data, got %zu bytes", data_len);
+invalid:
+ FR_DEBUG_STRERROR_PRINTF("Invalid data from %s: %s",
+ fr_inet_ntop(src_ipaddr->af, &src_ipaddr->ipaddr),
+ fr_strerror());
+ rad_recv_discard(sockfd);
- return 1;
+ return 1;
+ }
- /*
- * Enforce RFC requirements, for sanity.
- * Anything after 4k will be discarded.
- */
- } else if (packet_len > MAX_PACKET_LEN) {
- rad_recv_discard(sockfd);
+ /*
+ * See how long the packet says it is.
+ */
+ packet_len = (header[2] * 256) + header[3];
- return 1;
- }
+ /*
+ * The length in the packet says it's less than
+ * a RADIUS header length: discard it.
+ */
+ if (packet_len < RADIUS_HDR_LEN) {
+ FR_DEBUG_STRERROR_PRINTF("Expected at least " STRINGIFY(RADIUS_HDR_LEN) " bytes of packet "
+ "data, got %zu bytes", packet_len);
+ goto invalid;
}
/*
- * Convert AF. If unknown, discard packet.
+ * Enforce RFC requirements, for sanity.
+ * Anything after 4k will be discarded.
*/
- if (!fr_sockaddr2ipaddr(&src, sizeof_src, src_ipaddr, src_port)) {
- rad_recv_discard(sockfd);
-
- return 1;
+ if (packet_len > MAX_PACKET_LEN) {
+ FR_DEBUG_STRERROR_PRINTF("Length field value too large, expected maximum of "
+ STRINGIFY(MAX_PACKET_LEN) " bytes, got %zu bytes", packet_len);
+ goto invalid;
}
*code = header[0];
memcpy(output, passwd, len);
}
+
static void make_tunnel_passwd(uint8_t *output, ssize_t *outlen,
uint8_t const *input, size_t inlen, size_t room,
char const *secret, uint8_t const *vector)
{
FR_MD5_CTX context, old;
uint8_t digest[AUTH_VECTOR_LEN];
- uint8_t passwd[MAX_STRING_LEN + AUTH_VECTOR_LEN];
- int i, n;
- int len;
+ size_t i, n;
+ size_t encrypted_len;
/*
- * Be paranoid.
+ * The password gets encoded with a 1-byte "length"
+ * field. Ensure that it doesn't overflow.
*/
if (room > 253) room = 253;
/*
- * Account for 2 bytes of the salt, and round the room
- * available down to the nearest multiple of 16. Then,
- * subtract one from that to account for the length byte,
- * and the resulting number is the upper bound on the data
- * to copy.
- *
- * We could short-cut this calculation just be forcing
- * inlen to be no more than 239. It would work for all
- * VSA's, as we don't pack multiple VSA's into one
- * attribute.
- *
- * However, this calculation is more general, if a little
- * complex. And it will work in the future for all possible
- * kinds of weird attribute packing.
+ * Limit the maximum size of the input password. 2 bytes
+ * are taken up by the salt, and one by the encoded
+ * "length" field. Note that if we have a tag, the
+ * "room" will be 252 octets, not 253 octets.
*/
- room -= 2;
- room -= (room & 0x0f);
- room--;
-
- if (inlen > room) inlen = room;
+ if (inlen > (room - 3)) inlen = room - 3;
/*
- * Length of the encrypted data is password length plus
- * one byte for the length of the password.
+ * Length of the encrypted data is the clear-text
+ * password length plus one byte which encodes the length
+ * of the password. We round up to the nearest encoding
+ * block. Note that this can result in the encoding
+ * length being more than 253 octets.
*/
- len = inlen + 1;
- if ((len & 0x0f) != 0) {
- len += 0x0f;
- len &= ~0x0f;
+ encrypted_len = inlen + 1;
+ if ((encrypted_len & 0x0f) != 0) {
+ encrypted_len += 0x0f;
+ encrypted_len &= ~0x0f;
}
- *outlen = len + 2; /* account for the salt */
/*
- * Copy the password over.
+ * We need 2 octets for the salt, followed by the actual
+ * encrypted data.
+ */
+ if (encrypted_len > (room - 2)) encrypted_len = room - 2;
+
+ *outlen = encrypted_len + 2; /* account for the salt */
+
+ /*
+ * Copy the password over, and zero-fill the remainder.
*/
- memcpy(passwd + 3, input, inlen);
- memset(passwd + 3 + inlen, 0, sizeof(passwd) - 3 - inlen);
+ memcpy(output + 3, input, inlen);
+ memset(output + 3 + inlen, 0, *outlen - 3 - inlen);
/*
- * Generate salt. The RFC's say:
+ * Generate salt. The RFCs say:
*
* The high bit of salt[0] must be set, each salt in a
* packet should be unique, and they should be random
* So, we set the high bit, add in a counter, and then
* add in some CSPRNG data. should be OK..
*/
- passwd[0] = (0x80 | ( ((salt_offset++) & 0x0f) << 3) |
+ output[0] = (0x80 | ( ((salt_offset++) & 0x0f) << 3) |
(fr_rand() & 0x07));
- passwd[1] = fr_rand();
- passwd[2] = inlen; /* length of the password string */
+ output[1] = fr_rand();
+ output[2] = inlen; /* length of the password string */
fr_md5_init(&context);
fr_md5_update(&context, (uint8_t const *) secret, strlen(secret));
old = context;
fr_md5_update(&context, vector, AUTH_VECTOR_LEN);
- fr_md5_update(&context, &passwd[0], 2);
+ fr_md5_update(&context, &output[0], 2);
+
+ for (n = 0; n < encrypted_len; n += AUTH_PASS_LEN) {
+ size_t block_len;
- for (n = 0; n < len; n += AUTH_PASS_LEN) {
if (n > 0) {
context = old;
fr_md5_update(&context,
- passwd + 2 + n - AUTH_PASS_LEN,
+ output + 2 + n - AUTH_PASS_LEN,
AUTH_PASS_LEN);
}
fr_md5_final(digest, &context);
- for (i = 0; i < AUTH_PASS_LEN; i++) {
- passwd[i + 2 + n] ^= digest[i];
+ if ((2 + n + AUTH_PASS_LEN) < room) {
+ block_len = AUTH_PASS_LEN;
+ } else {
+ block_len = room - 2 - n;
+ }
+
+ for (i = 0; i < block_len; i++) {
+ output[i + 2 + n] ^= digest[i];
}
}
- memcpy(output, passwd, len + 2);
}
-extern int const fr_attr_max_tlv;
-extern int const fr_attr_shift[];
-extern int const fr_attr_mask[];
-
static int do_next_tlv(VALUE_PAIR const *vp, VALUE_PAIR const *next, int nest)
{
unsigned int tlv1, tlv2;
ptr[1] += len;
#ifndef NDEBUG
- if ((fr_debug_flag > 3) && fr_log_fp) {
+ if ((fr_debug_lvl > 3) && fr_log_fp) {
fprintf(fr_log_fp, "\t\t%02x %02x ", ptr[0], ptr[1]);
print_hex_data(ptr + 2, len, 3);
}
}
#ifndef NDEBUG
- if ((fr_debug_flag > 3) && fr_log_fp) {
+ if ((fr_debug_lvl > 3) && fr_log_fp) {
DICT_ATTR const *da;
da = dict_attrbyvalue(svp->da->attr & ((1 << fr_attr_shift[nest ]) - 1), svp->da->vendor);
start, room);
}
- debug_pair(vp);
-
/*
* Set up the default sources for the data.
*/
- len = vp->length;
+ len = vp->vp_length;
- switch(vp->da->type) {
+ switch (vp->da->type) {
case PW_TYPE_STRING:
case PW_TYPE_OCTETS:
- case PW_TYPE_TLV:
data = vp->data.ptr;
if (!data) {
fr_strerror_printf("ERROR: Cannot encode NULL data");
make_tunnel_passwd(ptr + lvalue, &len, data, len,
room - lvalue,
secret, original->vector);
+ len += lvalue;
break;
case PW_CODE_ACCOUNTING_REQUEST:
case PW_CODE_DISCONNECT_REQUEST:
case PW_CODE_COA_REQUEST:
ptr[0] = TAG_VALID(vp->tag) ? vp->tag : TAG_NONE;
- make_tunnel_passwd(ptr + 1, &len, data, len - 1, room,
+ make_tunnel_passwd(ptr + 1, &len, data, len, room - 1,
secret, packet->vector);
+ len += lvalue;
break;
}
break;
ptr[1] += len;
#ifndef NDEBUG
- if ((fr_debug_flag > 3) && fr_log_fp) {
+ if ((fr_debug_lvl > 3) && fr_log_fp) {
int jump = 3;
fprintf(fr_log_fp, "\t\t%02x %02x ", ptr[0], ptr[1]);
ptr[7] += len;
#ifndef NDEBUG
- if ((fr_debug_flag > 3) && fr_log_fp) {
+ if ((fr_debug_lvl > 3) && fr_log_fp) {
fprintf(fr_log_fp, "\t\t%02x %02x %02x%02x%02x%02x (%u) %02x %02x %02x ",
ptr[0], ptr[1],
ptr[2], ptr[3], ptr[4], ptr[5],
VERIFY_VP(vp);
- debug_pair(vp);
-
p = vp->vp_octets;
- len = vp->length;
+ len = vp->vp_length;
while (len > 0) {
if (room <= 2) break;
memcpy(ptr + 2, p, left);
#ifndef NDEBUG
- if ((fr_debug_flag > 3) && fr_log_fp) {
+ if ((fr_debug_lvl > 3) && fr_log_fp) {
fprintf(fr_log_fp, "\t\t%02x %02x ", ptr[0], ptr[1]);
print_hex_data(ptr + 2, len, 3);
}
ptr[1] += len;
#ifndef NDEBUG
- if ((fr_debug_flag > 3) && fr_log_fp) {
+ if ((fr_debug_lvl > 3) && fr_log_fp) {
fprintf(fr_log_fp, "\t\t%02x %02x ", ptr[0], ptr[1]);
print_hex_data(ptr + 2, len, 3);
}
if (dv->length) ptr[dv->type + dv->length - 1] += len;
#ifndef NDEBUG
- if ((fr_debug_flag > 3) && fr_log_fp) {
+ if ((fr_debug_lvl > 3) && fr_log_fp) {
switch (dv->type) {
default:
break;
case 4:
- if ((fr_debug_flag > 3) && fr_log_fp)
+ if ((fr_debug_lvl > 3) && fr_log_fp)
fprintf(fr_log_fp, "\t\t%02x%02x%02x%02x ",
ptr[0], ptr[1], ptr[2], ptr[3]);
break;
case 2:
- if ((fr_debug_flag > 3) && fr_log_fp)
+ if ((fr_debug_lvl > 3) && fr_log_fp)
fprintf(fr_log_fp, "\t\t%02x%02x ",
ptr[0], ptr[1]);
break;
case 1:
- if ((fr_debug_flag > 3) && fr_log_fp)
+ if ((fr_debug_lvl > 3) && fr_log_fp)
fprintf(fr_log_fp, "\t\t%02x ", ptr[0]);
break;
}
VALUE_PAIR const *vp = *pvp;
VERIFY_VP(vp);
+
+ if (vp->da->vendor == 0) {
+ fr_strerror_printf("rad_vp2vsa called with rfc attribute");
+ return -1;
+ }
+
/*
* Double-check for WiMAX format.
*/
if (vp->da->flags.wimax) {
- return rad_vp2wimax(packet, original, secret, pvp,
- ptr, room);
+ return rad_vp2wimax(packet, original, secret, pvp, ptr, room);
}
if (vp->da->vendor > FR_MAX_VENDOR) {
if (len < 0) return len;
#ifndef NDEBUG
- if ((fr_debug_flag > 3) && fr_log_fp) {
+ if ((fr_debug_lvl > 3) && fr_log_fp) {
fprintf(fr_log_fp, "\t\t%02x %02x %02x%02x%02x%02x (%u) ",
ptr[0], ptr[1],
ptr[2], ptr[3], ptr[4], ptr[5],
* Only CUI is allowed to have zero length.
* Thank you, WiMAX!
*/
- if ((vp->length == 0) &&
+ if ((vp->vp_length == 0) &&
(vp->da->attr == PW_CHARGEABLE_USER_IDENTITY)) {
ptr[0] = PW_CHARGEABLE_USER_IDENTITY;
ptr[1] = 2;
/*
* Message-Authenticator is hard-coded.
*/
- if (vp->da->attr == PW_MESSAGE_AUTHENTICATOR) {
+ if (!vp->da->vendor && (vp->da->attr == PW_MESSAGE_AUTHENTICATOR)) {
if (room < 18) return -1;
- debug_pair(vp);
ptr[0] = PW_MESSAGE_AUTHENTICATOR;
ptr[1] = 18;
memset(ptr + 2, 0, 16);
#ifndef NDEBUG
- if ((fr_debug_flag > 3) && fr_log_fp) {
+ if ((fr_debug_lvl > 3) && fr_log_fp) {
fprintf(fr_log_fp, "\t\t50 12 ...\n");
}
#endif
/*
* EAP-Message is special.
*/
- if (vp->da->flags.concat && (vp->length > 253)) {
+ if (vp->da->flags.concat && (vp->vp_length > 253)) {
return vp2attr_concat(packet, original, secret, pvp, vp->da->attr,
ptr, room);
}
start, room);
}
- return rad_vp2vsa(packet, original, secret, pvp,
- start, room);
+ return rad_vp2vsa(packet, original, secret, pvp, start, room);
}
uint16_t total_length;
int len;
VALUE_PAIR const *reply;
- char const *what;
- char ip_src_buffer[INET6_ADDRSTRLEN];
- char ip_dst_buffer[INET6_ADDRSTRLEN];
/*
* A 4K packet, aligned on 64-bits.
*/
uint64_t data[MAX_PACKET_LEN / sizeof(uint64_t)];
- if (is_radius_code(packet->code)) {
- what = fr_packet_codes[packet->code];
- } else {
- what = "Reply";
- }
-
- DEBUG("Sending %s Id %d from %s:%u to %s:%u\n",
- what, packet->id,
- inet_ntop(packet->src_ipaddr.af,
- &packet->src_ipaddr.ipaddr,
- ip_src_buffer, sizeof(ip_src_buffer)),
- packet->src_port,
- inet_ntop(packet->dst_ipaddr.af,
- &packet->dst_ipaddr.ipaddr,
- ip_dst_buffer, sizeof(ip_dst_buffer)),
- packet->dst_port);
-
/*
* Double-check some things based on packet code.
*/
* attributes with a debug build.
*/
if (reply->da->attr == PW_RAW_ATTRIBUTE) {
- memcpy(ptr, reply->vp_octets, reply->length);
- len = reply->length;
+ memcpy(ptr, reply->vp_octets, reply->vp_length);
+ len = reply->vp_length;
reply = reply->next;
goto next;
}
* Set the Message-Authenticator to the correct
* length and initial value.
*/
- if (reply->da->attr == PW_MESSAGE_AUTHENTICATOR) {
+ if (!reply->da->vendor && (reply->da->attr == PW_MESSAGE_AUTHENTICATOR)) {
/*
* Cache the offset to the
* Message-Authenticator
packet->offset = total_length;
last_len = 16;
} else {
- last_len = reply->length;
+ last_len = reply->vp_length;
}
last_name = reply->da->name;
int rad_send(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
char const *secret)
{
- VALUE_PAIR *reply;
- char const *what;
- char ip_src_buffer[128];
- char ip_dst_buffer[128];
-
/*
* Maybe it's a fake packet. Don't send it.
*/
return 0;
}
- if (is_radius_code(packet->code)) {
- what = fr_packet_codes[packet->code];
- } else {
- what = "Reply";
- }
-
/*
* First time through, allocate room for the packet
*/
* If packet->data points to data, then we print out
* the VP list again only for debugging.
*/
- } else if (fr_debug_flag) {
- DEBUG("Sending %s Id %d from %s:%u to %s:%u\n", what,
- packet->id,
- inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr,
- ip_src_buffer, sizeof(ip_src_buffer)),
- packet->src_port,
- inet_ntop(packet->dst_ipaddr.af, &packet->dst_ipaddr.ipaddr,
- ip_dst_buffer, sizeof(ip_dst_buffer)),
- packet->dst_port);
-
- for (reply = packet->vps; reply; reply = reply->next) {
- if ((reply->da->vendor == 0) &&
- ((reply->da->attr & 0xFFFF) > 0xff)) continue;
- debug_pair(reply);
- }
}
#ifndef NDEBUG
- if ((fr_debug_flag > 3) && fr_log_fp) rad_print_hex(packet);
+ if ((fr_debug_lvl > 3) && fr_log_fp) rad_print_hex(packet);
#endif
#ifdef WITH_TCP
{
uint8_t const *end = data + length;
+ VP_TRACE("checking TLV %u/%u\n", (unsigned int) dv_type, (unsigned int) dv_length);
+
+ VP_HEXDUMP("tlv_ok", data, length);
+
if ((dv_length > 2) || (dv_type == 0) || (dv_type > 4)) {
fr_strerror_printf("rad_tlv_ok: Invalid arguments");
return -1;
break;
case 1:
- if (data[0] == 0) goto zero;
+ /*
+ * Zero is allowed, because the Colubris
+ * people are dumb and use it.
+ */
break;
default:
* "The minimum length is 20 ..."
*/
if (packet->data_len < RADIUS_HDR_LEN) {
- fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: too short (received %zu < minimum %d)",
+ FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: too short (received %zu < minimum %d)",
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
*/
if ((hdr->code == 0) ||
(hdr->code >= FR_MAX_PACKET_CODE)) {
- fr_strerror_printf("WARNING: Bad RADIUS packet from host %s: unknown packet code %d",
+ FR_DEBUG_STRERROR_PRINTF("Bad RADIUS packet from host %s: unknown packet code %d",
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
* "The minimum length is 20 ..."
*/
if (totallen < RADIUS_HDR_LEN) {
- fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: too short (length %zu < minimum %d)",
+ FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: too short (length %zu < minimum %d)",
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
* i.e. No response to the NAS.
*/
if (packet->data_len < totallen) {
- fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: received %zu octets, packet length says %zu",
+ FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: received %zu octets, packet length says %zu",
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
* attribute header.
*/
if (count < 2) {
- fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: attribute header overflows the packet",
+ FR_DEBUG_STRERROR_PRINTF("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)));
* Attribute number zero is NOT defined.
*/
if (attr[0] == 0) {
- fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: Invalid attribute 0",
+ FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: Invalid attribute 0",
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)));
* fields. Anything shorter is an invalid attribute.
*/
if (attr[1] < 2) {
- fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: attribute %u too short",
+ FR_DEBUG_STRERROR_PRINTF("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)),
* 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",
+ FR_DEBUG_STRERROR_PRINTF("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)),
case PW_MESSAGE_AUTHENTICATOR:
if (attr[1] != 2 + AUTH_VECTOR_LEN) {
- fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: Message-Authenticator has invalid length %d",
+ FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: Message-Authenticator has invalid length %d",
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
* If not, we complain, and throw the packet away.
*/
if (count != 0) {
- fr_strerror_printf("WARNING: Malformed RADIUS packet from host %s: packet attributes do NOT exactly fill the packet",
+ FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: packet attributes do NOT exactly fill the packet",
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)));
*/
if ((fr_max_attributes > 0) &&
(num_attributes > fr_max_attributes)) {
- fr_strerror_printf("WARNING: Possible DoS attack from host %s: Too many attributes in request (received %d, max %d are allowed).",
+ FR_DEBUG_STRERROR_PRINTF("Possible DoS attack from host %s: Too many attributes in request (received %d, max %d are allowed).",
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
* Message-Authenticator attributes.
*/
if (require_ma && !seen_ma) {
- fr_strerror_printf("WARNING: Insecure packet from host %s: Packet does not contain required Message-Authenticator attribute",
+ FR_DEBUG_STRERROR_PRINTF("Insecure packet from host %s: Packet does not contain required Message-Authenticator attribute",
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)));
/** Receive UDP client requests, and fill in the basics of a RADIUS_PACKET structure
*
*/
-RADIUS_PACKET *rad_recv(int fd, int flags)
+RADIUS_PACKET *rad_recv(TALLOC_CTX *ctx, int fd, int flags)
{
int sock_flags = 0;
ssize_t data_len;
/*
* Allocate the new request data structure
*/
- packet = rad_alloc(NULL, false);
+ packet = rad_alloc(ctx, false);
if (!packet) {
fr_strerror_printf("out of memory");
return NULL;
* Check for socket errors.
*/
if (data_len < 0) {
- fr_strerror_printf("Error receiving packet: %s", fr_syserror(errno));
+ FR_DEBUG_STRERROR_PRINTF("Error receiving packet: %s", fr_syserror(errno));
/* packet->data is NULL */
rad_free(&packet);
return NULL;
* packet.
*/
if (packet->data_len > MAX_PACKET_LEN) {
- fr_strerror_printf("Discarding packet: Larger than RFC limitation of 4096 bytes");
+ FR_DEBUG_STRERROR_PRINTF("Discarding packet: Larger than RFC limitation of 4096 bytes");
/* packet->data is NULL */
rad_free(&packet);
return NULL;
* packet->data == NULL
*/
if ((packet->data_len == 0) || !packet->data) {
- fr_strerror_printf("Empty packet: Socket is not ready");
+ FR_DEBUG_STRERROR_PRINTF("Empty packet: Socket is not ready");
rad_free(&packet);
return NULL;
}
*/
packet->vps = NULL;
- if (fr_debug_flag) {
- char src_ipaddr[128];
- char dst_ipaddr[128];
-
- if (is_radius_code(packet->code)) {
- DEBUG("Received %s Id %d from %s:%d to %s:%d length %d\n",
- fr_packet_codes[packet->code],
- packet->id,
- inet_ntop(packet->src_ipaddr.af,
- &packet->src_ipaddr.ipaddr,
- src_ipaddr, sizeof(src_ipaddr)),
- packet->src_port,
- inet_ntop(packet->dst_ipaddr.af,
- &packet->dst_ipaddr.ipaddr,
- dst_ipaddr, sizeof(dst_ipaddr)),
- packet->dst_port,
- (int) packet->data_len);
- } else {
- DEBUG("Received code %d Id %d from %s:%d to %s:%d length %d\n",
- packet->code,
- packet->id,
- inet_ntop(packet->src_ipaddr.af,
- &packet->src_ipaddr.ipaddr,
- src_ipaddr, sizeof(src_ipaddr)),
- packet->src_port,
- inet_ntop(packet->dst_ipaddr.af,
- &packet->dst_ipaddr.ipaddr,
- dst_ipaddr, sizeof(dst_ipaddr)),
- packet->dst_port,
- (int) packet->data_len);
- }
- }
-
#ifndef NDEBUG
- if ((fr_debug_flag > 3) && fr_log_fp) rad_print_hex(packet);
+ if ((fr_debug_lvl > 3) && fr_log_fp) rad_print_hex(packet);
#endif
return packet;
/** Verify the Request/Response Authenticator (and Message-Authenticator if present) of a packet
*
*/
-int rad_verify(RADIUS_PACKET *packet, RADIUS_PACKET *original,
- char const *secret)
+int rad_verify(RADIUS_PACKET *packet, RADIUS_PACKET *original, char const *secret)
{
- uint8_t *ptr;
- int length;
- int attrlen;
+ uint8_t *ptr;
+ int length;
+ int attrlen;
+ int rcode;
+ char buffer[32];
if (!packet || !packet->data) return -1;
case PW_CODE_COA_ACK:
case PW_CODE_COA_NAK:
if (!original) {
- fr_strerror_printf("ERROR: Cannot validate Message-Authenticator in response packet without a request packet");
+ fr_strerror_printf("Cannot validate Message-Authenticator in response "
+ "packet without a request packet");
return -1;
}
memcpy(packet->data + 4, original->vector, AUTH_VECTOR_LEN);
(uint8_t const *) secret, strlen(secret));
if (rad_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.)",
- inet_ntop(packet->src_ipaddr.af,
- &packet->src_ipaddr.ipaddr,
- buffer, sizeof(buffer)));
+ fr_strerror_printf("Received packet from %s with invalid Message-Authenticator! "
+ "(Shared secret is incorrect.)",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)));
/* Silently drop packet, according to RFC 3579 */
return -1;
} /* else the message authenticator was good */
* so can't validate the authenticators.
*/
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 Request/Response Authenticator.",
- packet->code,
- inet_ntop(packet->src_ipaddr.af,
- &packet->src_ipaddr.ipaddr,
- buffer, sizeof(buffer)),
- packet->src_port);
+ "from client %s port %d: Cannot validate Request/Response Authenticator.",
+ packet->code,
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ packet->src_port);
return -1;
}
* Calculate and/or verify Request or Response Authenticator.
*/
switch (packet->code) {
- int rcode;
- char buffer[32];
-
case PW_CODE_ACCESS_REQUEST:
case PW_CODE_STATUS_SERVER:
/*
case PW_CODE_ACCOUNTING_REQUEST:
if (calc_acctdigest(packet, secret) > 1) {
fr_strerror_printf("Received %s packet "
- "from client %s with invalid Request Authenticator! (Shared secret is incorrect.)",
- fr_packet_codes[packet->code],
- inet_ntop(packet->src_ipaddr.af,
- &packet->src_ipaddr.ipaddr,
- buffer, sizeof(buffer)));
+ "from client %s with invalid Request Authenticator! "
+ "(Shared secret is incorrect.)",
+ fr_packet_codes[packet->code],
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)));
return -1;
}
break;
rcode = calc_replydigest(packet, original, secret);
if (rcode > 1) {
fr_strerror_printf("Received %s packet "
- "from home server %s port %d with invalid Response Authenticator! (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);
+ "from home server %s port %d with invalid Response Authenticator! "
+ "(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);
return -1;
}
break;
default:
fr_strerror_printf("Received Unknown packet code %d "
- "from client %s port %d: Cannot validate Request/Response Authenticator",
- packet->code,
- inet_ntop(packet->src_ipaddr.af,
- &packet->src_ipaddr.ipaddr,
- buffer, sizeof(buffer)),
- packet->src_port);
+ "from client %s port %d: Cannot validate Request/Response Authenticator",
+ packet->code,
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)),
+ packet->src_port);
return -1;
}
if (ptr[0] != attr) break;
}
- vp = pairalloc(ctx, da);
+ vp = fr_pair_afrom_da(ctx, da);
if (!vp) return -1;
- vp->length = total;
- vp->vp_octets = p = talloc_array(vp, uint8_t, vp->length);
+ vp->vp_length = total;
+ vp->vp_octets = p = talloc_array(vp, uint8_t, vp->vp_length);
if (!p) {
- pairfree(&vp);
+ fr_pair_list_free(&vp);
return -1;
}
total = 0;
ptr = start;
- while (total < vp->length) {
+ while (total < vp->vp_length) {
memcpy(p, ptr + 2, ptr[1] - 2);
p += ptr[1] - 2;
total += ptr[1] - 2;
/** Convert TLVs to one or more VPs
*
*/
-static ssize_t data2vp_tlvs(TALLOC_CTX *ctx,
+ssize_t rad_data2vp_tlvs(TALLOC_CTX *ctx,
RADIUS_PACKET *packet, RADIUS_PACKET const *original,
char const *secret, DICT_ATTR const *da,
uint8_t const *start, size_t length,
my_vendor = da->vendor;
if (!dict_attr_child(da, &my_attr, &my_vendor)) {
- pairfree(&head);
+ fr_pair_list_free(&head);
return -1;
}
child = dict_unknown_afrom_fields(ctx, my_attr, my_vendor);
if (!child) {
- pairfree(&head);
+ fr_pair_list_free(&head);
return -1;
}
}
tlv_len = data2vp(ctx, packet, original, secret, child,
data + 2, data[1] - 2, data[1] - 2, tail);
if (tlv_len < 0) {
- pairfree(&head);
+ fr_pair_list_free(&head);
return -1;
}
- tail = &((*tail)->next);
+ if (*tail) tail = &((*tail)->next);
data += data[1];
}
ssize_t attrlen, my_len;
DICT_ATTR const *da;
+ VP_TRACE("data2vp_vsa: length %u\n", (unsigned int) length);
+
#ifndef NDEBUG
if (length <= (dv->type + dv->length)) {
fr_strerror_printf("data2vp_vsa: Failure to call rad_tlv_ok");
return -1;
}
-#ifndef NDEBUG
- if (attrlen <= (ssize_t) (dv->type + dv->length)) {
- fr_strerror_printf("data2vp_vsa: Failure to call rad_tlv_ok");
- return -1;
- }
-#endif
-
/*
* See if the VSA is known.
*/
uint32_t vendor;
DICT_VENDOR *dv;
VALUE_PAIR *head, **tail;
+ DICT_VENDOR my_dv;
if (attrlen > packetlen) return -1;
if (attrlen < 5) return -1; /* vid, value */
if (data[0] != 0) return -1; /* we require 24-bit VIDs */
+ VP_TRACE("data2vp_vsas\n");
+
memcpy(&vendor, data, 4);
vendor = ntohl(vendor);
dv = dict_vendorbyvalue(vendor);
- if (!dv) return -1;
+ if (!dv) {
+ /*
+ * RFC format is 1 octet type, 1 octet length
+ */
+ if (rad_tlv_ok(data + 4, attrlen - 4, 1, 1) < 0) {
+ VP_TRACE("data2vp_vsas: unknown tlvs not OK: %s\n", fr_strerror());
+ return -1;
+ }
+
+ /*
+ * It's a known unknown.
+ */
+ memset(&my_dv, 0, sizeof(my_dv));
+ dv = &my_dv;
+
+ /*
+ * Fill in the fields. Note that the name is empty!
+ */
+ dv->vendorpec = vendor;
+ dv->type = 1;
+ dv->length = 1;
+
+ goto create_attrs;
+ }
/*
* WiMAX craziness
* VSAs should normally be in TLV format.
*/
if (rad_tlv_ok(data + 4, attrlen - 4,
- dv->type, dv->length) < 0) return -1;
+ dv->type, dv->length) < 0) {
+ VP_TRACE("data2vp_vsas: tlvs not OK: %s\n", fr_strerror());
+ return -1;
+ }
/*
* There may be more than one VSA in the
* Vendor-Specific. If so, loop over them all.
*/
+create_attrs:
data += 4;
attrlen -= 4;
packetlen -= 4;
vsa_len = data2vp_vsa(ctx, packet, original, secret, dv,
data, attrlen, tail);
if (vsa_len < 0) {
- pairfree(&head);
+ fr_pair_list_free(&head);
fr_strerror_printf("Internal sanity check %d", __LINE__);
return -1;
}
- tail = &((*tail)->next);
+
+ /*
+ * Vendors can send zero-length VSAs.
+ */
+ if (*tail) tail = &((*tail)->next);
+
data += vsa_len;
attrlen -= vsa_len;
packetlen -= vsa_len;
ssize_t rcode;
uint32_t vendor;
DICT_ATTR const *child;
- DICT_VENDOR *dv;
VALUE_PAIR *vp;
uint8_t const *data = start;
char *p;
* Decrypt the attribute.
*/
if (secret && packet && (da->flags.encrypt != FLAG_ENCRYPT_NONE)) {
+ VP_TRACE("data2vp: decrypting type %u\n", da->flags.encrypt);
/*
* Encrypted attributes can only exist for the
* old-style format. Extended attributes CANNOT
packet->vector);
}
buffer[253] = '\0';
- datalen = strlen((char *) buffer);
+
+ /*
+ * MS-CHAP-MPPE-Keys are 24 octets, and
+ * encrypted. Since it's binary, we can't
+ * look for trailing zeros.
+ */
+ if (da->flags.length) {
+ if (datalen > da->flags.length) {
+ datalen = da->flags.length;
+ } /* else leave datalen alone */
+ } else {
+ /*
+ * Take off trailing zeros from the END.
+ * This allows passwords to have zeros in
+ * the middle of a field.
+ *
+ * However, if the password has a zero at
+ * the end, it will get mashed by this
+ * code. There's really no way around
+ * that.
+ */
+ while ((datalen > 0) && (buffer[datalen - 1] == '\0')) datalen--;
+ }
break;
/*
* Double-check the length after decrypting the
* attribute.
*/
+ VP_TRACE("data2vp: type %u\n", da->type);
switch (da->type) {
case PW_TYPE_STRING:
case PW_TYPE_OCTETS:
if (datalen != 6) goto raw;
break;
- case PW_TYPE_IP_ADDR:
+ case PW_TYPE_COMBO_IP_ADDR:
if (datalen == 4) {
child = dict_attrbytype(da->attr, da->vendor,
PW_TYPE_IPV4_ADDR);
memcpy(&vendor, data, 4);
vendor = ntohl(vendor);
- dv = dict_vendorbyvalue(vendor);
- if (!dv) {
- child = dict_unknown_afrom_fields(ctx, data[4], da->vendor | vendor);
- } else {
- child = dict_attrbyparent(da, data[4], vendor);
- if (!child) {
- child = dict_unknown_afrom_fields(ctx, data[4], da->vendor | vendor);
- }
+ vendor |= da->vendor;
+
+ child = dict_attrbyvalue(data[4], vendor);
+ if (!child) {
+ /*
+ * Create a "raw" attribute from the
+ * contents of the EVS VSA.
+ */
+ da = dict_unknown_afrom_fields(ctx, data[4], vendor);
+ data += 5;
+ datalen -= 5;
+ break;
}
- if (!child) goto raw;
rcode = data2vp(ctx, packet, original, secret, child,
data + 5, attrlen - 5, attrlen - 5, pvp);
* attribute, OR they've already been grouped
* into a contiguous memory buffer.
*/
- rcode = data2vp_tlvs(ctx, packet, original, secret, da,
- data, attrlen, pvp);
+ rcode = rad_data2vp_tlvs(ctx, packet, original, secret, da,
+ data, attrlen, pvp);
if (rcode < 0) goto raw;
return rcode;
* information, decode the actual data.
*/
alloc_cui:
- vp = pairalloc(ctx, da);
+ vp = fr_pair_afrom_da(ctx, da);
if (!vp) return -1;
- vp->length = datalen;
+ vp->vp_length = datalen;
vp->tag = tag;
switch (da->type) {
case PW_TYPE_STRING:
- p = talloc_array(vp, char, vp->length + 1);
- memcpy(p, data, vp->length);
- p[vp->length] = '\0';
+ p = talloc_array(vp, char, vp->vp_length + 1);
+ memcpy(p, data, vp->vp_length);
+ p[vp->vp_length] = '\0';
vp->vp_strvalue = p;
break;
case PW_TYPE_OCTETS:
- pairmemcpy(vp, data, vp->length);
+ fr_pair_value_memcpy(vp, data, vp->vp_length);
break;
case PW_TYPE_ABINARY:
- if (vp->length > sizeof(vp->vp_filter)) {
- vp->length = sizeof(vp->vp_filter);
+ if (vp->vp_length > sizeof(vp->vp_filter)) {
+ vp->vp_length = sizeof(vp->vp_filter);
}
- memcpy(vp->vp_filter, data, vp->length);
+ memcpy(vp->vp_filter, data, vp->vp_length);
break;
case PW_TYPE_BYTE:
break;
case PW_TYPE_ETHERNET:
- memcpy(&vp->vp_ether, data, 6);
+ memcpy(vp->vp_ether, data, 6);
break;
case PW_TYPE_IPV4_ADDR:
break;
case PW_TYPE_IFID:
- memcpy(&vp->vp_ifid, data, 8);
+ memcpy(vp->vp_ifid, data, 8);
break;
case PW_TYPE_IPV6_ADDR:
case PW_TYPE_IPV6_PREFIX:
/*
* FIXME: double-check that
- * (vp->vp_octets[1] >> 3) matches vp->length + 2
+ * (vp->vp_octets[1] >> 3) matches vp->vp_length + 2
*/
- memcpy(&vp->vp_ipv6prefix, data, vp->length);
- if (vp->length < 18) {
- memset(((uint8_t *)vp->vp_ipv6prefix) + vp->length, 0,
- 18 - vp->length);
+ memcpy(vp->vp_ipv6prefix, data, vp->vp_length);
+ if (vp->vp_length < 18) {
+ memset(((uint8_t *)vp->vp_ipv6prefix) + vp->vp_length, 0,
+ 18 - vp->vp_length);
}
break;
case PW_TYPE_IPV4_PREFIX:
/* FIXME: do the same double-check as for IPv6Prefix */
- memcpy(&vp->vp_ipv4prefix, data, vp->length);
+ memcpy(vp->vp_ipv4prefix, data, vp->vp_length);
/*
* /32 means "keep all bits". Otherwise, mask
break;
default:
- pairfree(&vp);
+ fr_pair_list_free(&vp);
fr_strerror_printf("Internal sanity check %d", __LINE__);
return -1;
}
}
da = dict_attrbyvalue(data[0], 0);
- if (!da) da = dict_unknown_afrom_fields(ctx, data[0], 0);
+ if (!da) {
+ VP_TRACE("attr2vp: unknown attribute %u\n", data[0]);
+ da = dict_unknown_afrom_fields(ctx, data[0], 0);
+ }
if (!da) return -1;
/*
* Pass the entire thing to the decoding function
*/
if (da->flags.concat) {
+ VP_TRACE("attr2vp: concat attribute\n");
return data2vp_concat(ctx, da, data, length, pvp);
}
return 2 + rcode;
}
-fr_thread_local_setup(uint8_t *, rad_vp2data_buff);
+fr_thread_local_setup(uint8_t *, rad_vp2data_buff)
/** Converts vp_data to network byte order
*
VERIFY_VP(vp);
- switch(vp->da->type) {
+ switch (vp->da->type) {
case PW_TYPE_STRING:
case PW_TYPE_OCTETS:
- case PW_TYPE_TLV:
memcpy(out, &vp->data.ptr, sizeof(*out));
break;
case PW_TYPE_IPV4_PREFIX:
case PW_TYPE_ABINARY:
case PW_TYPE_ETHERNET:
- case PW_TYPE_IP_ADDR:
- case PW_TYPE_IP_PREFIX:
+ case PW_TYPE_COMBO_IP_ADDR:
+ case PW_TYPE_COMBO_IP_PREFIX:
{
void const *p = &vp->data;
memcpy(out, &p, sizeof(*out));
case PW_TYPE_LONG_EXTENDED:
case PW_TYPE_EVS:
case PW_TYPE_VSA:
+ case PW_TYPE_TLV:
case PW_TYPE_TIMEVAL:
case PW_TYPE_MAX:
fr_strerror_printf("Cannot get data for VALUE_PAIR type %i", vp->da->type);
/* Don't add default */
}
- return vp->length;
+ return vp->vp_length;
}
/** Calculate/check digest, and decode radius attributes
my_len = rad_attr2vp(packet, packet, original, secret,
ptr, packet_length, &vp);
if (my_len < 0) {
- pairfree(&head);
+ fr_pair_list_free(&head);
return -1;
}
*tail = vp;
while (vp) {
num_attributes++;
- debug_pair(vp);
tail = &(vp->next);
vp = vp->next;
}
(num_attributes > fr_max_attributes)) {
char host_ipaddr[128];
- pairfree(&head);
- fr_strerror_printf("WARNING: Possible DoS attack from host %s: Too many attributes in request (received %d, max %d are allowed).",
+ fr_pair_list_free(&head);
+ fr_strerror_printf("Possible DoS attack from host %s: Too many attributes in request (received %d, max %d are allowed).",
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)),
if (len > 127) len = 127;
/*
- * Shift the password 3 positions right to place a salt and original
- * length, tag will be added automatically on packet send
+ * Shift the password 3 positions right to place a salt and original
+ * length, tag will be added automatically on packet send.
*/
- for (n=len ; n>=0 ; n--) passwd[n+3] = passwd[n];
+ for (n = len ; n >= 0 ; n--) passwd[n + 3] = passwd[n];
salt = passwd;
passwd += 2;
+
/*
- * save original password length as first password character;
+ * save original password length as first password character;
*/
*passwd = len;
len += 1;
FR_MD5_CTX context, old;
uint8_t digest[AUTH_VECTOR_LEN];
int secretlen;
- unsigned i, n, len, reallen;
+ size_t i, n, encrypted_len, reallen;
- len = *pwlen;
+ encrypted_len = *pwlen;
/*
* We need at least a salt.
*/
- if (len < 2) {
+ if (encrypted_len < 2) {
fr_strerror_printf("tunnel password is too short");
return -1;
}
* more data. So the 'data_len' field may be wrong,
* but that's ok...
*/
- if (len <= 3) {
+ if (encrypted_len <= 3) {
passwd[0] = 0;
*pwlen = 0;
return 0;
}
- len -= 2; /* discount the salt */
+ encrypted_len -= 2; /* discount the salt */
/*
* Use the secret to setup the decryption digest
fr_md5_update(&context, passwd, 2);
reallen = 0;
- for (n = 0; n < len; n += AUTH_PASS_LEN) {
- int base = 0;
+ for (n = 0; n < encrypted_len; n += AUTH_PASS_LEN) {
+ size_t base;
+ size_t block_len = AUTH_PASS_LEN;
+
+ /*
+ * Ensure we don't overflow the input on MD5
+ */
+ if ((n + 2 + AUTH_PASS_LEN) > *pwlen) {
+ block_len = *pwlen - n - 2;
+ }
if (n == 0) {
+ base = 1;
+
fr_md5_final(digest, &context);
context = old;
* 'data_len' field. Ensure it's sane.
*/
reallen = passwd[2] ^ digest[0];
- if (reallen >= len) {
+ if (reallen > encrypted_len) {
fr_strerror_printf("tunnel password is too long for the attribute");
return -1;
}
- fr_md5_update(&context, passwd + 2, AUTH_PASS_LEN);
+ fr_md5_update(&context, passwd + 2, block_len);
- base = 1;
} else {
+ base = 0;
+
fr_md5_final(digest, &context);
context = old;
- fr_md5_update(&context, passwd + n + 2, AUTH_PASS_LEN);
+ fr_md5_update(&context, passwd + n + 2, block_len);
}
- for (i = base; i < AUTH_PASS_LEN; i++) {
+ for (i = base; i < block_len; i++) {
passwd[n + i - 1] = passwd[n + i + 2] ^ digest[i];
}
}
- /*
- * See make_tunnel_password, above.
- */
- if (reallen > 239) reallen = 239;
-
*pwlen = reallen;
passwd[reallen] = 0;
/** Encode a CHAP password
*
* @bug FIXME: might not work with Ascend because
- * we use vp->length, and Ascend gear likes
+ * we use vp->vp_length, and Ascend gear likes
* to send an extra '\0' in the string!
*/
int rad_chap_encode(RADIUS_PACKET *packet, uint8_t *output, int id,
*ptr++ = id;
i++;
- memcpy(ptr, password->vp_strvalue, password->length);
- ptr += password->length;
- i += password->length;
+ memcpy(ptr, password->vp_strvalue, password->vp_length);
+ ptr += password->vp_length;
+ i += password->vp_length;
/*
* Use Chap-Challenge pair if present,
* Request Authenticator otherwise.
*/
- challenge = pairfind(packet->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY);
+ challenge = fr_pair_find_by_num(packet->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY);
if (challenge) {
- memcpy(ptr, challenge->vp_strvalue, challenge->length);
- i += challenge->length;
+ memcpy(ptr, challenge->vp_strvalue, challenge->vp_length);
+ i += challenge->vp_length;
} else {
memcpy(ptr, packet->vector, AUTH_VECTOR_LEN);
i += AUTH_VECTOR_LEN;
VERIFY_PACKET(radius_packet);
- pairfree(&radius_packet->vps);
+ fr_pair_list_free(&radius_packet->vps);
talloc_free(radius_packet);
*radius_packet_ptr = NULL;
out->data = NULL;
out->data_len = 0;
- out->vps = paircopy(out, in->vps);
+ out->vps = fr_pair_list_copy(out, in->vps);
out->offset = 0;
return out;