summaryrefslogtreecommitdiffstats
path: root/src/lib/radius.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/radius.c')
-rw-r--r--src/lib/radius.c154
1 files changed, 102 insertions, 52 deletions
diff --git a/src/lib/radius.c b/src/lib/radius.c
index b2de15b..a19c9a4 100644
--- a/src/lib/radius.c
+++ b/src/lib/radius.c
@@ -145,8 +145,9 @@ char const *fr_packet_codes[FR_MAX_PACKET_CODE] = {
"47",
"48",
"49",
- "IP-Address-Allocate",
- "IP-Address-Release", //!< 50
+ "IP-Address-Allocate", //!< 50
+ "IP-Address-Release",
+ "Protocol-Error",
};
@@ -536,7 +537,7 @@ static void make_secret(uint8_t *digest, uint8_t const *vector,
fr_md5_destroy(&context);
}
-#define MAX_PASS_LEN (128)
+#define MAX_PASS_LEN (256)
static void make_passwd(uint8_t *output, ssize_t *outlen,
uint8_t const *input, size_t inlen,
char const *secret, uint8_t const *vector)
@@ -1819,6 +1820,14 @@ int rad_vp2attr(RADIUS_PACKET const *packet, RADIUS_PACKET const *original,
return rad_vp2vsa(packet, original, secret, pvp, start, room);
}
+static const bool code2ma[FR_MAX_PACKET_CODE] = {
+ [ PW_CODE_ACCESS_REQUEST ] = true,
+ [ PW_CODE_ACCESS_ACCEPT ] = true,
+ [ PW_CODE_ACCESS_REJECT ] = true,
+ [ PW_CODE_ACCESS_CHALLENGE ] = true,
+ [ PW_CODE_STATUS_SERVER ] = true,
+ [ PW_CODE_PROTOCOL_ERROR ] = true,
+};
/** Encode a packet
*
@@ -1831,6 +1840,7 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
uint16_t total_length;
int len;
VALUE_PAIR const *reply;
+ bool seen_ma = false;
/*
* A 4K packet, aligned on 64-bits.
@@ -1883,6 +1893,12 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
id = htonl(id);
memcpy(hdr->vector, &id, sizeof(id));
memset(hdr->vector + sizeof(id), 0, sizeof(hdr->vector) - sizeof(id));
+
+ /*
+ * We don't encode Message-Authenticator
+ */
+ seen_ma = true;
+ packet->offset = -1;
} else
#endif
{
@@ -1909,6 +1925,27 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
*/
/*
+ * Always add Message-Authenticator for replies to
+ * Access-Request packets, and for all Access-Accept,
+ * Access-Reject, Access-Challenge.
+ *
+ * It must be the FIRST attribute in the packet.
+ */
+ if (!packet->tls &&
+ ((code2ma[packet->code]) || (original && code2ma[original->code]))) {
+ seen_ma = true;
+
+ packet->offset = RADIUS_HDR_LEN;
+
+ ptr[0] = PW_MESSAGE_AUTHENTICATOR;
+ ptr[1] = 18;
+ memset(ptr + 2, 0, 16);
+
+ ptr += 18;
+ total_length += 18;
+ }
+
+ /*
* Loop over the reply attributes for the packet.
*/
reply = packet->vps;
@@ -1943,18 +1980,9 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
#ifdef WITH_RADIUSV11
/*
- * Do not encode Message-Authenticator for RADIUS/1.1
- */
- if ((reply->da->vendor == 0) && (reply->da->attr == PW_MESSAGE_AUTHENTICATOR)) {
- reply = reply->next;
- continue;
- }
-
-
- /*
* Do not encode Original-Packet-Code for RADIUS/1.1
*/
- if (reply->da->vendor == ((unsigned int) PW_EXTENDED_ATTRIBUTE_1 << 24) && (reply->da->attr == 4)) {
+ if (packet->radiusv11 && reply->da->vendor == ((unsigned int) PW_EXTENDED_ATTRIBUTE_1 << 24) && (reply->da->attr == 4)) {
reply = reply->next;
continue;
}
@@ -1984,15 +2012,13 @@ int rad_encode(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
* 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.
+ * We have already encoded the Message-Authenticator, don't do it again.
*/
- if (packet->radiusv11) {
+ if (seen_ma) {
reply = reply->next;
continue;
}
-#endif
if (room < 18) break;
@@ -2152,11 +2178,7 @@ int rad_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
case PW_CODE_ACCOUNTING_REQUEST:
case PW_CODE_DISCONNECT_REQUEST:
- case PW_CODE_DISCONNECT_ACK:
- case PW_CODE_DISCONNECT_NAK:
case PW_CODE_COA_REQUEST:
- case PW_CODE_COA_ACK:
- case PW_CODE_COA_NAK:
memset(hdr->vector, 0, AUTH_VECTOR_LEN);
break;
@@ -2164,6 +2186,10 @@ int rad_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original,
case PW_CODE_ACCESS_ACCEPT:
case PW_CODE_ACCESS_REJECT:
case PW_CODE_ACCESS_CHALLENGE:
+ case PW_CODE_DISCONNECT_ACK:
+ case PW_CODE_DISCONNECT_NAK:
+ case PW_CODE_COA_ACK:
+ case PW_CODE_COA_NAK:
memcpy(hdr->vector, original->vector, AUTH_VECTOR_LEN);
break;
@@ -2510,6 +2536,8 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
char host_ipaddr[128];
#ifndef WITH_RADIUSV11_ONLY
bool require_ma = false;
+ bool limit_proxy_state = false;
+ bool seen_proxy_state = false;
bool seen_ma = false;
bool eap = false;
bool non_eap = false;
@@ -2559,15 +2587,23 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
}
/*
- * Message-Authenticator is required in Status-Server
- * packets, otherwise they can be trivially forged.
+ * If the caller requires Message-Authenticator, then set
+ * the flag.
+ *
+ * We also require Message-Authenticator if the packet
+ * code is Status-Server.
+ *
+ * If we're receiving packets from a proxy socket, then
+ * require Message-Authenticator for Access-* replies,
+ * and for Protocol-Error.
*/
- if (hdr->code == PW_CODE_STATUS_SERVER) require_ma = true;
+ require_ma = ((flags & 0x01) != 0) || (hdr->code == PW_CODE_STATUS_SERVER) || (((flags & 0x08) != 0) && code2ma[hdr->code]);
/*
- * It's also required if the caller asks for it.
+ * We only limit Proxy-State if we're not requiring
+ * Message-Authenticator.
*/
- if (flags) require_ma = true;
+ limit_proxy_state = ((flags & 0x04) != 0) && !require_ma;
/*
* Repeat the length checks. This time, instead of
@@ -2723,6 +2759,7 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
case PW_EAP_MESSAGE:
require_ma = true;
eap = true;
+ packet->eap_message = true;
break;
case PW_USER_PASSWORD:
@@ -2731,6 +2768,11 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
non_eap = true;
break;
+ case PW_PROXY_STATE:
+ seen_proxy_state = true;
+ packet->proxy_state = true;
+ break;
+
case PW_MESSAGE_AUTHENTICATOR:
#ifdef WITH_RADIUSV11
/*
@@ -2749,6 +2791,7 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
goto finish;
}
seen_ma = true;
+ packet->message_authenticator = true;
break;
}
#endif
@@ -2813,7 +2856,7 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
!packet->radiusv11 &&
#endif
!seen_ma) {
- FR_DEBUG_STRERROR_PRINTF("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. You may need to set \"require_message_authenticator = no\" in the configuration.",
inet_ntop(packet->src_ipaddr.af,
&packet->src_ipaddr.ipaddr,
host_ipaddr, sizeof(host_ipaddr)));
@@ -2822,6 +2865,18 @@ bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason)
}
#ifndef WITH_RADIUSV11_ONLY
+ /*
+ * The client is a NAS which shouldn't send Proxy-State, but it did!
+ */
+ if (limit_proxy_state && seen_proxy_state && !seen_ma) {
+ FR_DEBUG_STRERROR_PRINTF("Insecure packet from host %s: Packet does not contain required Message-Authenticator attribute, but still has one or more Proxy-State attributes",
+ inet_ntop(packet->src_ipaddr.af,
+ &packet->src_ipaddr.ipaddr,
+ host_ipaddr, sizeof(host_ipaddr)));
+ failure = DECODE_FAIL_MA_MISSING;
+ goto finish;
+ }
+
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,
@@ -3938,7 +3993,7 @@ ssize_t data2vp(TALLOC_CTX *ctx,
VALUE_PAIR *vp;
uint8_t const *data = start;
char *p;
- uint8_t buffer[256];
+ uint8_t buffer[MAX_PASS_LEN];
/*
* FIXME: Attrlen can be larger than 253 for extended attrs!
@@ -4054,7 +4109,7 @@ ssize_t data2vp(TALLOC_CTX *ctx,
attrlen, secret,
packet->vector);
}
- buffer[253] = '\0';
+ buffer[attrlen] = '\0';
/*
* MS-CHAP-MPPE-Keys are 24 octets, and
@@ -4654,22 +4709,24 @@ int rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original,
ssize_t my_len;
#ifdef WITH_RADIUSV11
- /*
- * Don't decode Message-Authenticator
- */
- if (ptr[0] == PW_MESSAGE_AUTHENTICATOR) {
- packet_length -= ptr[1];
- ptr += ptr[1];
- continue;
- }
+ if (packet->radiusv11) {
+ /*
+ * Don't decode Message-Authenticator
+ */
+ if (ptr[0] == PW_MESSAGE_AUTHENTICATOR) {
+ packet_length -= ptr[1];
+ ptr += ptr[1];
+ continue;
+ }
- /*
- * Don't decode Original-Packet-Code
- */
- if ((ptr[0] == PW_EXTENDED_ATTRIBUTE_1) && (ptr[1] >= 3) && (ptr[2] == 4)) {
- packet_length -= ptr[1];
- ptr += ptr[1];
- continue;
+ /*
+ * Don't decode Original-Packet-Code
+ */
+ if ((ptr[0] == PW_EXTENDED_ATTRIBUTE_1) && (ptr[1] >= 3) && (ptr[2] == 4)) {
+ packet_length -= ptr[1];
+ ptr += ptr[1];
+ continue;
+ }
}
#endif
@@ -4761,7 +4818,7 @@ int rad_pwencode(char *passwd, size_t *pwlen, char const *secret,
*/
len = *pwlen;
- if (len > 128) len = 128;
+ if (len > MAX_STRING_LEN) len = MAX_STRING_LEN;
if (len == 0) {
memset(passwd, 0, AUTH_PASS_LEN);
@@ -4821,13 +4878,6 @@ int rad_pwdecode(char *passwd, size_t pwlen, char const *secret,
size_t n, secretlen;
/*
- * The RFC's say that the maximum is 128.
- * The buffer we're putting it into above is 254, so
- * we don't need to do any length checking.
- */
- if (pwlen > 128) pwlen = 128;
-
- /*
* Catch idiots.
*/
if (pwlen == 0) goto done;