/* radius.c */
int rad_send(RADIUS_PACKET *, RADIUS_PACKET const *, char const *secret);
bool rad_packet_ok(RADIUS_PACKET *packet, int flags, decode_fail_t *reason);
+
+/*
+ * 1 == require_ma
+ * 2 == msg_peek
+ * 3 == limit_proxy_state
+ */
RADIUS_PACKET *rad_recv(TALLOC_CTX *ctx, int fd, int flags);
ssize_t rad_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, int *code);
void rad_recv_discard(int sockfd);
radius_packet_t *hdr;
char host_ipaddr[128];
bool require_ma = false;
+ bool limit_proxy_state = false;
+ bool seen_proxy_state = false;
bool seen_ma = false;
uint32_t num_attributes;
decode_fail_t failure = DECODE_FAIL_NONE;
/*
* Message-Authenticator is required in Status-Server
* packets, otherwise they can be trivially forged.
- */
- if (hdr->code == PW_CODE_STATUS_SERVER) require_ma = true;
-
- /*
+ *
* 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;
+ require_ma = ((flags & 0x01) != 0) || (hdr->code == PW_CODE_STATUS_SERVER);
+ limit_proxy_state = ((flags & 0x04) != 0) & !require_ma;
/*
* Repeat the length checks. This time, instead of
non_eap = true;
break;
+ case PW_PROXY_STATE:
+ seen_proxy_state = true;
+ break;
+
case PW_MESSAGE_AUTHENTICATOR:
if (attr[1] != 2 + AUTH_VECTOR_LEN) {
FR_DEBUG_STRERROR_PRINTF("Malformed RADIUS packet from host %s: Message-Authenticator has invalid length %d",
goto finish;
}
+ /*
+ * 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,
* Now that we've sanity checked everything, receive the
* packet.
*/
- packet = rad_recv(ctx, listener->fd, client->require_ma);
+ packet = rad_recv(ctx, listener->fd, client->require_ma | (((int) client->limit_proxy_state) << 2));
if (!packet) {
FR_STATS_INC(auth, total_malformed_requests);
if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror());