static fr_randctx fr_rand_pool; /* across multiple calls */
static int fr_rand_initialized = 0;
+#ifndef WITH_RADIUSV11_ONLY
static unsigned int salt_offset = 0;
static uint8_t nullvector[AUTH_VECTOR_LEN] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* for CoA decode */
+#endif
char const *fr_packet_codes[FR_MAX_PACKET_CODE] = {
"", //!< 0
}
+#ifndef WITH_RADIUSV11_ONLY
#define AUTH_PASS_LEN (AUTH_VECTOR_LEN)
/** Build an encrypted secret value to return in a reply packet
*
fr_md5_destroy(&old);
fr_md5_destroy(&context);
}
+#endif /* WITH_RADIUSV11_ONLY */
static int do_next_tlv(VALUE_PAIR const *vp, VALUE_PAIR const *next, int nest)
{
*/
if (len > (ssize_t) room) len = room;
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 does not encrypt any attributes.
+ */
+ if (packet->radiusv11) goto tag;
+#endif
+
/*
* Encrypt the various password styles
*
* 128 bytes long.
*/
switch (vp->da->flags.encrypt) {
+#ifndef WITH_RADIUSV11_ONLY
case FLAG_ENCRYPT_USER_PASSWORD:
make_passwd(ptr, &len, data, len,
secret, packet->vector);
make_secret(ptr, packet->vector, secret, data, len);
len = AUTH_VECTOR_LEN;
break;
-
+#endif /* WITH_RADIUSV11_ONLY */
default:
+#ifdef WITH_RADIUSV11
+ tag:
+#endif
if (vp->da->flags.has_tag && TAG_VALID(vp->tag)) {
if (vp->da->type == PW_TYPE_STRING) {
if (len > ((ssize_t) (room - 1))) len = room - 1;
* Message-Authenticator is hard-coded.
*/
if (vp->da->attr == PW_MESSAGE_AUTHENTICATOR) {
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 does not encode or verify Message-Authenticator.
+ */
+ if (packet->radiusv11) {
+ *pvp = (*pvp)->next;
+ return 0;
+ }
+#endif
+
if (room < 18) return -1;
ptr[0] = PW_MESSAGE_AUTHENTICATOR;
* length and initial value.
*/
if (!reply->da->vendor && (reply->da->attr == PW_MESSAGE_AUTHENTICATOR)) {
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 does not encode or verify Message-Authenticator.
+ */
+ if (packet->radiusv11) {
+ reply = reply->next;
+ continue;
+ }
+#endif
+
if (room < 18) break;
/*
return 0;
}
+#ifdef WITH_RADIUSV11_ONLY
+#define RADIUSV11_UNUSED UNUSED
+#else
+#define RADIUSV11_UNUSED
+#endif
/** Sign a previously encoded packet
*
*/
int rad_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
- char const *secret)
+ RADIUSV11_UNUSED char const *secret)
{
radius_packet_t *hdr = (radius_packet_t *)packet->data;
return -1;
}
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 uses the authenticator field for matching
+ * requests to responses, and does not otherwise verify
+ * it.
+ */
+ if (packet->radiusv11) {
+ return 0;
+ }
+#endif
+
/*
* Set up the authentication vector with zero, or with
* the original vector, prior to signing.
if ((fr_debug_lvl > 3) && fr_log_fp) rad_print_hex(packet);
#endif
+#ifndef WITH_RADIUSV11_ONLY
/*
* If there's a Message-Authenticator, update it
* now.
memcpy(packet->data + packet->offset + 2,
calc_auth_vector, AUTH_VECTOR_LEN);
}
+#endif /* WITH_RADIUSV11_ONLY */
/*
* Copy the request authenticator over to the packet.
*/
memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN);
+#ifndef WITH_RADIUSV11_ONLY
/*
* Switch over the packet code, deciding how to
* sign the packet.
break;
}
}/* switch over packet codes */
+#endif /* WITH_RADIUSV11_ONLY */
return 0;
}
return result; /* 0 is OK, !0 is !OK, just like memcmp */
}
-
+#ifndef WITH_RADIUSV11_ONLY
/** Validates the requesting client NAS
*
* Calculates the request Authenticator based on the clients private key.
if (rad_digest_cmp(packet->vector, calc_digest, AUTH_VECTOR_LEN) != 0) return 2;
return 0;
}
+#endif /* WITH_RADIUSV11_ONLY */
/** Check if a set of RADIUS formatted TLVs are OK
*
int count;
radius_packet_t *hdr;
char host_ipaddr[128];
+#ifndef WITH_RADIUSV11_ONLY
bool require_ma = false;
bool seen_ma = false;
- uint32_t num_attributes;
- decode_fail_t failure = DECODE_FAIL_NONE;
bool eap = false;
bool non_eap = false;
+#endif
+ uint32_t num_attributes;
+ decode_fail_t failure = DECODE_FAIL_NONE;
/*
* Check for packets smaller than the packet header.
goto finish;
}
+#ifndef WITH_RADIUSV11_ONLY
/*
* Sanity check the attributes for length.
*/
break;
case PW_MESSAGE_AUTHENTICATOR:
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 does not encode or verify Message-Authenticator.
+ */
+ if (packet->radiusv11) break;
+#endif
+
if (attr[1] != 2 + AUTH_VECTOR_LEN) {
FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: Message-Authenticator has invalid length %d",
inet_ntop(packet->src_ipaddr.af,
seen_ma = true;
break;
}
+#endif
/*
* FIXME: Look up the base 255 attributes in the
* Similarly, Status-Server packets MUST contain
* Message-Authenticator attributes.
*/
- if (require_ma && !seen_ma) {
+ if (require_ma &&
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 does not encode or verify Message-Authenticator.
+ */
+ !packet->radiusv11 &&
+#endif
+ !seen_ma) {
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,
goto finish;
}
+#ifndef WITH_RADIUSV11_ONLY
if (eap && non_eap) {
FR_DEBUG_STRERROR_PRINTF("Bad packet from host %s: Packet contains EAP-Message and non-EAP authentication attribute",
inet_ntop(packet->src_ipaddr.af,
failure = DECODE_FAIL_TOO_MANY_AUTH;
goto finish;
}
+#endif
/*
* Fill RADIUS header fields
/** 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, RADIUSV11_UNUSED RADIUS_PACKET *original, RADIUSV11_UNUSED char const *secret)
{
uint8_t *ptr;
int length;
int attrlen;
+#ifndef WITH_RADIUSV11_ONLY
int rcode;
+#endif
char buffer[32];
if (!packet || !packet->data) return -1;
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 uses the authenticator field for matching
+ * requests to responses, and does not otherwise verify
+ * it.
+ */
+ if (packet->radiusv11) {
+ return 0;
+ }
+#endif
+
/*
* Before we allocate memory for the attributes, do more
* sanity checking.
ptr = packet->data + RADIUS_HDR_LEN;
length = packet->data_len - RADIUS_HDR_LEN;
while (length > 0) {
+#ifndef WITH_RADIUSV11_ONLY
uint8_t msg_auth_vector[AUTH_VECTOR_LEN];
uint8_t calc_auth_vector[AUTH_VECTOR_LEN];
+#endif
attrlen = ptr[1];
+#ifndef WITH_RADIUSV11_ONLY
switch (ptr[0]) {
default: /* don't do anything. */
break;
* attribute is invalid.
*/
case PW_MESSAGE_AUTHENTICATOR:
+#ifdef WITH_RADIUSV11
+ /*
+ * Ignore Message-Authenticator for RADIUSV11 packets.
+ */
+ if (packet->radiusv11) break;
+#endif
+
memcpy(msg_auth_vector, &ptr[2], sizeof(msg_auth_vector));
memset(&ptr[2], 0, AUTH_VECTOR_LEN);
memcpy(packet->data + 4, packet->vector, AUTH_VECTOR_LEN);
break;
} /* switch over the attributes */
+#endif /* WITH_RADIUSV11_ONLY */
ptr += attrlen;
length -= attrlen;
return -1;
}
+#ifndef WITH_RADIUSV11_ONLY
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 uses the authenticator field for matching
+ * requests to responses, and does not otherwise verify
+ * it.
+ */
+ if (packet->radiusv11) return 0;
+#endif
+
/*
* Calculate and/or verify Request or Response Authenticator.
*/
packet->src_port);
return -1;
}
+#endif
return 0;
}
tlv_len = data2vp(ctx, packet, original, secret, child,
data + 2, data[1] - 2, data[1] - 2, tail);
if (tlv_len < 0) {
- dict_attr_free(&child); /* only frees unknowns */
fr_pair_list_free(&head);
return -1;
}
attrlen - (dv->type + dv->length),
attrlen - (dv->type + dv->length),
pvp);
- if (my_len < 0) {
- dict_attr_free(&da); /* only frees unknowns */
- return my_len;
- }
+ if (my_len < 0) return my_len;
return attrlen;
}
rcode = data2vp(ctx, packet, original, secret, child,
data, attrlen, attrlen, pvp);
- if (rcode < 0) {
- dict_attr_free(&child); /* only frees unknowns */
- return rcode;
- }
+ if (rcode < 0) return rcode;
return attrlen;
}
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;
}
rcode = data2vp(ctx, packet, original, secret, child,
data, attrlen, attrlen, pvp);
- if (rcode < 0) {
- dict_attr_free(&child); /* only frees unknowns */
- return rcode;
- }
+ if (rcode < 0) return rcode;
return attrlen;
}
* then decode the tag.
*/
if (da->flags.has_tag && (datalen > 1) &&
- ((data[0] < 0x20) ||
- (da->flags.encrypt == FLAG_ENCRYPT_TUNNEL_PASSWORD))) {
+ ((data[0] < 0x20)
+#ifndef WITH_RADIUSV11_ONLY
+ || (da->flags.encrypt == FLAG_ENCRYPT_TUNNEL_PASSWORD)
+#endif
+ )) {
+
/*
* Only "short" attributes can be encrypted.
*/
data = buffer;
}
+#ifndef WITH_RADIUSV11_ONLY
/*
* Decrypt the attribute.
*/
- if (secret && packet && (da->flags.encrypt != FLAG_ENCRYPT_NONE)) {
+ if (secret && packet &&
+
+#ifdef WITH_RADIUSV11
+ /*
+ * RADIUSV11 does not encrypt any attributes.
+ */
+ !packet->radiusv11 &&
+#endif
+
+ (da->flags.encrypt != FLAG_ENCRYPT_NONE)) {
VP_TRACE("data2vp: decrypting type %u\n", da->flags.encrypt);
/*
* Encrypted attributes can only exist for the
break;
} /* switch over encryption flags */
}
+#endif /* WITH_RADIUSV11_ONLY */
/*
* Double-check the length after decrypting the
/*
* This requires a whole lot more work.
*/
- rcode = data2vp_extended(ctx, packet, original, secret, child,
- start, attrlen, packetlen, pvp);
- if (rcode < 0) dict_attr_free(&child); /* only frees unknowns */
- return rcode;
+ return data2vp_extended(ctx, packet, original, secret, child,
+ start, attrlen, packetlen, pvp);
case PW_TYPE_EVS:
if (datalen < 6) goto raw; /* vid, vtype, value */
* information, decode the actual data.
*/
vp = fr_pair_afrom_da(ctx, da);
- if (!vp) {
- dict_attr_free(&da); /* only frees unknowns */
- return -1;
- }
+ if (!vp) return -1;
alloc_raw:
vp->vp_length = datalen;
fail:
#endif
default:
- dict_attr_free(&da); /* only frees unknowns */
fr_pair_list_free(&vp);
fr_strerror_printf("Internal sanity check %d", __LINE__);
return -1;
*/
rcode = data2vp(ctx, packet, original, secret, da,
data + 2, data[1] - 2, length - 2, pvp);
- if (rcode < 0) {
- dict_attr_free(&da); /* only frees unknowns */
- return rcode;
- }
+ if (rcode < 0) return rcode;
return 2 + rcode;
}
return 0;
}
-
+#ifndef WITH_RADIUSV11_ONLY
/** Encode password
*
* We assume that the passwd buffer passed is big enough.
reallen = passwd[2] ^ digest[0];
if (reallen > encrypted_len) {
fr_strerror_printf("tunnel password is too long for the attribute");
- fr_md5_destroy(&old);
- fr_md5_destroy(&context);
return -1;
}
return 0;
}
+#endif /* WITH_RADIUSV11_ONLYx */
/** Seed the random number generator
#ifdef WITH_TCP
reply->proto = packet->proto;
+#ifdef WITH_RADIUSV11
+ reply->radiusv11 = packet->radiusv11;
+ if (reply->radiusv11) {
+ memcpy(reply->vector, packet->vector, sizeof(reply->vector));
+ }
+#endif
#endif
return reply;
}