static int radius_server_request(struct radius_server_data *data, struct radius_msg *msg, struct sockaddr *from, socklen_t fromlen, struct radius_client *client, const char *from_addr, int from_port, struct radius_session *force_sess) { u8 *eap = NULL; size_t eap_len; int res, state_included = 0; u8 statebuf[4]; unsigned int state; struct radius_session *sess; struct radius_msg *reply; int is_complete = 0; if (force_sess) sess = force_sess; else { res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf, sizeof(statebuf)); state_included = res >= 0; if (res == sizeof(statebuf)) { state = WPA_GET_BE32(statebuf); sess = radius_server_get_session(client, state); } else { sess = NULL; } } if (sess) { RADIUS_DEBUG("Request for session 0x%x", sess->sess_id); } else if (state_included) { RADIUS_DEBUG("State attribute included but no session found"); radius_server_reject(data, client, msg, from, fromlen, from_addr, from_port); return -1; } else { sess = radius_server_get_new_session(data, client, msg); if (sess == NULL) { RADIUS_DEBUG("Could not create a new session"); radius_server_reject(data, client, msg, from, fromlen, from_addr, from_port); return -1; } } if (sess->last_from_port == from_port && sess->last_identifier == msg->hdr->identifier && os_memcmp(sess->last_authenticator, msg->hdr->authenticator, 16) == 0) { RADIUS_DEBUG("Duplicate message from %s", from_addr); data->counters.dup_access_requests++; client->counters.dup_access_requests++; if (sess->last_reply) { res = sendto(data->auth_sock, sess->last_reply->buf, sess->last_reply->buf_used, 0, (struct sockaddr *) from, fromlen); if (res < 0) { perror("sendto[RADIUS SRV]"); } return 0; } RADIUS_DEBUG("No previous reply available for duplicate " "message"); return -1; } eap = radius_msg_get_eap(msg, &eap_len); if (eap == NULL) { RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s", from_addr); data->counters.packets_dropped++; client->counters.packets_dropped++; return -1; } RADIUS_DUMP("Received EAP data", eap, eap_len); /* FIX: if Code is Request, Success, or Failure, send Access-Reject; * RFC3579 Sect. 2.6.2. * Include EAP-Response/Nak with no preferred method if * code == request. * If code is not 1-4, discard the packet silently. * Or is this already done by the EAP state machine? */ wpabuf_free(sess->eap_if->eapRespData); sess->eap_if->eapRespData = wpabuf_alloc_ext_data(eap, eap_len); if (sess->eap_if->eapRespData == NULL) os_free(eap); eap = NULL; sess->eap_if->eapResp = TRUE; eap_server_sm_step(sess->eap); if ((sess->eap_if->eapReq || sess->eap_if->eapSuccess || sess->eap_if->eapFail) && sess->eap_if->eapReqData) { RADIUS_DUMP("EAP data from the state machine", wpabuf_head(sess->eap_if->eapReqData), wpabuf_len(sess->eap_if->eapReqData)); } else if (sess->eap_if->eapFail) { RADIUS_DEBUG("No EAP data from the state machine, but eapFail " "set"); } else if (eap_sm_method_pending(sess->eap)) { if (sess->last_msg) { radius_msg_free(sess->last_msg); os_free(sess->last_msg); } sess->last_msg = msg; sess->last_from_port = from_port; os_free(sess->last_from_addr); sess->last_from_addr = os_strdup(from_addr); sess->last_fromlen = fromlen; os_memcpy(&sess->last_from, from, fromlen); return -2; } else { RADIUS_DEBUG("No EAP data from the state machine - ignore this" " Access-Request silently (assuming it was a " "duplicate)"); data->counters.packets_dropped++; client->counters.packets_dropped++; return -1; } if (sess->eap_if->eapSuccess || sess->eap_if->eapFail) is_complete = 1; reply = radius_server_encapsulate_eap(data, client, sess, msg); if (reply) { RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port); if (wpa_debug_level <= MSG_MSGDUMP) { radius_msg_dump(reply); } switch (reply->hdr->code) { case RADIUS_CODE_ACCESS_ACCEPT: data->counters.access_accepts++; client->counters.access_accepts++; break; case RADIUS_CODE_ACCESS_REJECT: data->counters.access_rejects++; client->counters.access_rejects++; break; case RADIUS_CODE_ACCESS_CHALLENGE: data->counters.access_challenges++; client->counters.access_challenges++; break; } res = sendto(data->auth_sock, reply->buf, reply->buf_used, 0, (struct sockaddr *) from, fromlen); if (res < 0) { perror("sendto[RADIUS SRV]"); } if (sess->last_reply) { radius_msg_free(sess->last_reply); os_free(sess->last_reply); } sess->last_reply = reply; sess->last_from_port = from_port; sess->last_identifier = msg->hdr->identifier; os_memcpy(sess->last_authenticator, msg->hdr->authenticator, 16); } else { data->counters.packets_dropped++; client->counters.packets_dropped++; } if (is_complete) { RADIUS_DEBUG("Removing completed session 0x%x after timeout", sess->sess_id); eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess); eloop_register_timeout(10, 0, radius_server_session_remove_timeout, data, sess); } return 0; }
static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e) { u8 *eap; size_t len; struct eap_hdr *hdr; int eap_type = -1; char buf[64]; struct radius_msg *msg; if (e->last_recv_radius == NULL) return; msg = e->last_recv_radius; eap = radius_msg_get_eap(msg, &len); if (eap == NULL) { /* draft-aboba-radius-rfc2869bis-20.txt, Chap. 2.6.3: * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message * attribute */ wpa_printf(MSG_DEBUG, "could not extract " "EAP-Message from RADIUS message"); os_free(e->last_eap_radius); e->last_eap_radius = NULL; e->last_eap_radius_len = 0; return; } if (len < sizeof(*hdr)) { wpa_printf(MSG_DEBUG, "too short EAP packet " "received from authentication server"); os_free(eap); return; } if (len > sizeof(*hdr)) eap_type = eap[sizeof(*hdr)]; hdr = (struct eap_hdr *) eap; switch (hdr->code) { case EAP_CODE_REQUEST: os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)", eap_type >= 0 ? eap_type_text(eap_type) : "??", eap_type); break; case EAP_CODE_RESPONSE: os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)", eap_type >= 0 ? eap_type_text(eap_type) : "??", eap_type); break; case EAP_CODE_SUCCESS: os_strlcpy(buf, "EAP Success", sizeof(buf)); /* LEAP uses EAP Success within an authentication, so must not * stop here with eloop_terminate(); */ break; case EAP_CODE_FAILURE: os_strlcpy(buf, "EAP Failure", sizeof(buf)); eloop_terminate(); break; default: os_strlcpy(buf, "unknown EAP code", sizeof(buf)); wpa_hexdump(MSG_DEBUG, "Decapsulated EAP packet", eap, len); break; } wpa_printf(MSG_DEBUG, "decapsulated EAP packet (code=%d " "id=%d len=%d) from RADIUS server: %s", hdr->code, hdr->identifier, ntohs(hdr->length), buf); /* sta->eapol_sm->be_auth.idFromServer = hdr->identifier; */ os_free(e->last_eap_radius); e->last_eap_radius = eap; e->last_eap_radius_len = len; { struct ieee802_1x_hdr *dot1x; dot1x = os_malloc(sizeof(*dot1x) + len); assert(dot1x != NULL); dot1x->version = EAPOL_VERSION; dot1x->type = IEEE802_1X_TYPE_EAP_PACKET; dot1x->length = htons(len); os_memcpy((u8 *) (dot1x + 1), eap, len); eapol_sm_rx_eapol(e->wpa_s->eapol, e->wpa_s->bssid, (u8 *) dot1x, sizeof(*dot1x) + len); os_free(dot1x); } }
static int radius_server_request(struct radius_server_data *data, struct radius_msg *msg, struct sockaddr_in *from, struct radius_client *client) { u8 *eap = NULL; size_t eap_len; int res, state_included; u8 statebuf[4], resp_id; unsigned int state; struct radius_session *sess; struct radius_msg *reply; struct eap_hdr *hdr; /* TODO: Implement duplicate packet processing */ res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf, sizeof(statebuf)); state_included = res >= 0; if (res == sizeof(statebuf)) { state = (statebuf[0] << 24) | (statebuf[1] << 16) | (statebuf[2] << 8) | statebuf[3]; sess = radius_server_get_session(client, state); } else { sess = NULL; } if (sess) { RADIUS_DEBUG("Request for session 0x%x", sess->sess_id); } else if (state_included) { RADIUS_DEBUG("State attribute included but no session found"); radius_server_reject(data, client, msg, from); return -1; } else { sess = radius_server_get_new_session(data, client, msg); if (sess == NULL) { RADIUS_DEBUG("Could not create a new session"); return -1; } } eap = radius_msg_get_eap(msg, &eap_len); if (eap == NULL) { RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s", inet_ntoa(from->sin_addr)); return -1; } RADIUS_DUMP("Received EAP data", eap, eap_len); if (eap_len >= sizeof(*hdr)) { hdr = (struct eap_hdr *) eap; resp_id = hdr->identifier; } else { resp_id = 0; } eap_set_eapRespData(sess->eap, eap, eap_len); free(eap); eap = NULL; sess->eapResp = TRUE; eap_sm_step(sess->eap); if (sess->eapReqData) { RADIUS_DUMP("EAP data from the state machine", sess->eapReqData, sess->eapReqDataLen); } else if (sess->eapFail) { RADIUS_DEBUG("No EAP data from the state machine, but eapFail " "set - generate EAP-Failure"); hdr = malloc(sizeof(*hdr)); if (hdr) { memset(hdr, 0, sizeof(*hdr)); hdr->identifier = resp_id; hdr->length = htons(sizeof(*hdr)); sess->eapReqData = (u8 *) hdr; sess->eapReqDataLen = sizeof(*hdr); } } else { RADIUS_DEBUG("No EAP data from the state machine - ignore this" " Access-Request silently (assuming it was a " "duplicate)"); return -1; } reply = radius_server_encapsulate_eap(data, client, sess, msg); free(sess->eapReqData); sess->eapReqData = NULL; sess->eapReqDataLen = 0; if (reply) { RADIUS_DEBUG("Reply to %s:%d", inet_ntoa(from->sin_addr), ntohs(from->sin_port)); if (wpa_debug_level <= MSG_MSGDUMP) { radius_msg_dump(reply); } res = sendto(data->auth_sock, reply->buf, reply->buf_used, 0, (struct sockaddr *) from, sizeof(*from)); if (res < 0) { perror("sendto[RADIUS SRV]"); } radius_msg_free(reply); free(reply); } if (sess->eapSuccess || sess->eapFail) { RADIUS_DEBUG("Removing completed session 0x%x", sess->sess_id); radius_server_session_remove(data, sess); } return 0; }