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) { struct wpabuf *eap = NULL; 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 == radius_msg_get_hdr(msg)->identifier && os_memcmp(sess->last_authenticator, radius_msg_get_hdr(msg)->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) { struct wpabuf *buf; buf = radius_msg_get_buf(sess->last_reply); res = sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0, (struct sockaddr *) from, fromlen); if (res < 0) { wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", strerror(errno)); } return 0; } RADIUS_DEBUG("No previous reply available for duplicate " "message"); return -1; } eap = radius_msg_get_eap(msg); 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", wpabuf_head(eap), wpabuf_len(eap)); /* 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 = eap; 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)) { radius_msg_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) { struct wpabuf *buf; struct radius_hdr *hdr; RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port); if (wpa_debug_level <= MSG_MSGDUMP) { radius_msg_dump(reply); } switch (radius_msg_get_hdr(reply)->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; } buf = radius_msg_get_buf(reply); res = sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0, (struct sockaddr *) from, fromlen); if (res < 0) { wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", strerror(errno)); } radius_msg_free(sess->last_reply); sess->last_reply = reply; sess->last_from_port = from_port; hdr = radius_msg_get_hdr(msg); sess->last_identifier = hdr->identifier; os_memcpy(sess->last_authenticator, 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; }
/** * radius_client_send - Send a RADIUS request * @radius: RADIUS client context from radius_client_init() * @msg: RADIUS message to be sent * @msg_type: Message type (RADIUS_AUTH, RADIUS_ACCT, RADIUS_ACCT_INTERIM) * @addr: MAC address of the device related to this message or %NULL * Returns: 0 on success, -1 on failure * * This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or * accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference * between accounting and interim accounting messages is that the interim * message will not be retransmitted. Instead, a callback is used to indicate * that the transmission failed for the specific station @addr so that a new * interim accounting update message can be generated with up-to-date session * data instead of trying to resend old information. * * The message is added on the retransmission queue and will be retransmitted * automatically until a response is received or maximum number of retries * (RADIUS_CLIENT_MAX_RETRIES) is reached. No such retries are used with * RADIUS_ACCT_INTERIM, i.e., such a pending message is removed from the queue * automatically on transmission failure. * * The related device MAC address can be used to identify pending messages that * can be removed with radius_client_flush_auth(). */ int radius_client_send(struct radius_client_data *radius, struct radius_msg *msg, RadiusType msg_type, const u8 *addr) { struct hostapd_radius_servers *conf = radius->conf; const u8 *shared_secret; size_t shared_secret_len; char *name; int s, res; struct wpabuf *buf; if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) { if (conf->acct_server && radius->acct_sock < 0) radius_client_init_acct(radius); if (conf->acct_server == NULL || radius->acct_sock < 0 || conf->acct_server->shared_secret == NULL) { hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO, "No accounting server configured"); return -1; } shared_secret = conf->acct_server->shared_secret; shared_secret_len = conf->acct_server->shared_secret_len; radius_msg_finish_acct(msg, shared_secret, shared_secret_len); name = "accounting"; s = radius->acct_sock; conf->acct_server->requests++; } else { if (conf->auth_server && radius->auth_sock < 0) radius_client_init_auth(radius); if (conf->auth_server == NULL || radius->auth_sock < 0 || conf->auth_server->shared_secret == NULL) { hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO, "No authentication server configured"); return -1; } shared_secret = conf->auth_server->shared_secret; shared_secret_len = conf->auth_server->shared_secret_len; radius_msg_finish(msg, shared_secret, shared_secret_len); name = "authentication"; s = radius->auth_sock; conf->auth_server->requests++; } hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s " "server", name); if (conf->msg_dumps) radius_msg_dump(msg); buf = radius_msg_get_buf(msg); res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0); if (res < 0) radius_client_handle_send_error(radius, s, msg_type); radius_client_list_add(radius, msg, msg_type, shared_secret, shared_secret_len, addr); return 0; }
static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) { struct radius_client_data *radius = eloop_ctx; struct hostapd_radius_servers *conf = radius->conf; RadiusType msg_type = (RadiusType) sock_ctx; int len, roundtrip; unsigned char buf[3000]; struct radius_msg *msg; struct radius_hdr *hdr; struct radius_rx_handler *handlers; size_t num_handlers, i; struct radius_msg_list *req, *prev_req; struct os_reltime now; struct hostapd_radius_server *rconf; int invalid_authenticator = 0; if (msg_type == RADIUS_ACCT) { handlers = radius->acct_handlers; num_handlers = radius->num_acct_handlers; rconf = conf->acct_server; } else { handlers = radius->auth_handlers; num_handlers = radius->num_auth_handlers; rconf = conf->auth_server; } len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT); if (len < 0) { wpa_printf(MSG_INFO, "recv[RADIUS]: %s", strerror(errno)); return; } hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS " "server", len); if (len == sizeof(buf)) { wpa_printf(MSG_INFO, "RADIUS: Possibly too long UDP frame for our buffer - dropping it"); return; } msg = radius_msg_parse(buf, len); if (msg == NULL) { wpa_printf(MSG_INFO, "RADIUS: Parsing incoming frame failed"); rconf->malformed_responses++; return; } hdr = radius_msg_get_hdr(msg); hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_DEBUG, "Received RADIUS message"); if (conf->msg_dumps) radius_msg_dump(msg); switch (hdr->code) { case RADIUS_CODE_ACCESS_ACCEPT: rconf->access_accepts++; break; case RADIUS_CODE_ACCESS_REJECT: rconf->access_rejects++; break; case RADIUS_CODE_ACCESS_CHALLENGE: rconf->access_challenges++; break; case RADIUS_CODE_ACCOUNTING_RESPONSE: rconf->responses++; break; } prev_req = NULL; req = radius->msgs; while (req) { /* TODO: also match by src addr:port of the packet when using * alternative RADIUS servers (?) */ if ((req->msg_type == msg_type || (req->msg_type == RADIUS_ACCT_INTERIM && msg_type == RADIUS_ACCT)) && radius_msg_get_hdr(req->msg)->identifier == hdr->identifier) break; prev_req = req; req = req->next; } if (req == NULL) { hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_DEBUG, "No matching RADIUS request found (type=%d " "id=%d) - dropping packet", msg_type, hdr->identifier); goto fail; } os_get_reltime(&now); roundtrip = (now.sec - req->last_attempt.sec) * 100 + (now.usec - req->last_attempt.usec) / 10000; hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_DEBUG, "Received RADIUS packet matched with a pending " "request, round trip time %d.%02d sec", roundtrip / 100, roundtrip % 100); rconf->round_trip_time = roundtrip; /* Remove ACKed RADIUS packet from retransmit list */ if (prev_req) prev_req->next = req->next; else radius->msgs = req->next; radius->num_msgs--; for (i = 0; i < num_handlers; i++) { RadiusRxResult res; res = handlers[i].handler(msg, req->msg, req->shared_secret, req->shared_secret_len, handlers[i].data); switch (res) { case RADIUS_RX_PROCESSED: radius_msg_free(msg); /* continue */ case RADIUS_RX_QUEUED: radius_client_msg_free(req); return; case RADIUS_RX_INVALID_AUTHENTICATOR: invalid_authenticator++; /* continue */ case RADIUS_RX_UNKNOWN: /* continue with next handler */ break; } } if (invalid_authenticator) rconf->bad_authenticators++; else rconf->unknown_types++; hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found " "(type=%d code=%d id=%d)%s - dropping packet", msg_type, hdr->code, hdr->identifier, invalid_authenticator ? " [INVALID AUTHENTICATOR]" : ""); radius_client_msg_free(req); fail: radius_msg_free(msg); }
static int radius_client_retransmit(struct radius_client_data *radius, struct radius_msg_list *entry, os_time_t now) { struct hostapd_radius_servers *conf = radius->conf; int s; struct wpabuf *buf; size_t prev_num_msgs; u8 *acct_delay_time; size_t acct_delay_time_len; if (entry->msg_type == RADIUS_ACCT || entry->msg_type == RADIUS_ACCT_INTERIM) { if (radius->acct_sock < 0) radius_client_init_acct(radius); if (radius->acct_sock < 0 && conf->num_acct_servers > 1) { prev_num_msgs = radius->num_msgs; radius_client_acct_failover(radius); if (prev_num_msgs != radius->num_msgs) return 0; } s = radius->acct_sock; if (entry->attempts == 0) conf->acct_server->requests++; else { conf->acct_server->timeouts++; conf->acct_server->retransmissions++; } } else { if (radius->auth_sock < 0) radius_client_init_auth(radius); if (radius->auth_sock < 0 && conf->num_auth_servers > 1) { prev_num_msgs = radius->num_msgs; radius_client_auth_failover(radius); if (prev_num_msgs != radius->num_msgs) return 0; } s = radius->auth_sock; if (entry->attempts == 0) conf->auth_server->requests++; else { conf->auth_server->timeouts++; conf->auth_server->retransmissions++; } } if (entry->msg_type == RADIUS_ACCT_INTERIM) { wpa_printf(MSG_DEBUG, "RADIUS: Failed to transmit interim accounting update to " MACSTR " - drop message and request a new update", MAC2STR(entry->addr)); if (radius->interim_error_cb) radius->interim_error_cb(entry->addr, radius->interim_error_cb_ctx); return 1; } if (s < 0) { wpa_printf(MSG_INFO, "RADIUS: No valid socket for retransmission"); return 1; } if (entry->msg_type == RADIUS_ACCT && radius_msg_get_attr_ptr(entry->msg, RADIUS_ATTR_ACCT_DELAY_TIME, &acct_delay_time, &acct_delay_time_len, NULL) == 0 && acct_delay_time_len == 4) { struct radius_hdr *hdr; u32 delay_time; /* * Need to assign a new identifier since attribute contents * changes. */ hdr = radius_msg_get_hdr(entry->msg); hdr->identifier = radius_client_get_id(radius); /* Update Acct-Delay-Time to show wait time in queue */ delay_time = now - entry->first_try; WPA_PUT_BE32(acct_delay_time, delay_time); wpa_printf(MSG_DEBUG, "RADIUS: Updated Acct-Delay-Time to %u for retransmission", delay_time); radius_msg_finish_acct(entry->msg, entry->shared_secret, entry->shared_secret_len); if (radius->conf->msg_dumps) radius_msg_dump(entry->msg); } /* retransmit; remove entry if too many attempts */ entry->attempts++; hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)", radius_msg_get_hdr(entry->msg)->identifier); os_get_reltime(&entry->last_attempt); buf = radius_msg_get_buf(entry->msg); if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) { if (radius_client_handle_send_error(radius, s, entry->msg_type) > 0) return 0; } entry->next_try = now + entry->next_wait; entry->next_wait *= 2; if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT) entry->next_wait = RADIUS_CLIENT_MAX_WAIT; if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) { wpa_printf(MSG_INFO, "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts"); return 1; } return 0; }
static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx) { struct radius_das_data *das = eloop_ctx; u8 buf[1500]; union { struct sockaddr_storage ss; struct sockaddr_in sin; #ifdef CONFIG_IPV6 struct sockaddr_in6 sin6; #endif /* CONFIG_IPV6 */ } from; char abuf[50]; int from_port = 0; socklen_t fromlen; int len; struct radius_msg *msg, *reply = NULL; struct radius_hdr *hdr; struct wpabuf *rbuf; u32 val; int res; struct os_time now; fromlen = sizeof(from); len = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from.ss, &fromlen); if (len < 0) { wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno)); return; } os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf)); from_port = ntohs(from.sin.sin_port); wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d", len, abuf, from_port); if (das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) { wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client"); return; } msg = radius_msg_parse(buf, len); if (msg == NULL) { wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet " "from %s:%d failed", abuf, from_port); return; } if (wpa_debug_level <= MSG_MSGDUMP) radius_msg_dump(msg); if (radius_msg_verify_das_req(msg, das->shared_secret, das->shared_secret_len)) { wpa_printf(MSG_DEBUG, "DAS: Invalid authenticator in packet " "from %s:%d - drop", abuf, from_port); goto fail; } os_get_time(&now); res = radius_msg_get_attr(msg, RADIUS_ATTR_EVENT_TIMESTAMP, (u8 *) &val, 4); if (res == 4) { u32 timestamp = ntohl(val); if (abs(now.sec - timestamp) > das->time_window) { wpa_printf(MSG_DEBUG, "DAS: Unacceptable " "Event-Timestamp (%u; local time %u) in " "packet from %s:%d - drop", timestamp, (unsigned int) now.sec, abuf, from_port); goto fail; } } else if (das->require_event_timestamp) { wpa_printf(MSG_DEBUG, "DAS: Missing Event-Timestamp in packet " "from %s:%d - drop", abuf, from_port); goto fail; } hdr = radius_msg_get_hdr(msg); switch (hdr->code) { case RADIUS_CODE_DISCONNECT_REQUEST: reply = radius_das_disconnect(das, msg, abuf, from_port); break; case RADIUS_CODE_COA_REQUEST: /* TODO */ reply = radius_msg_new(RADIUS_CODE_COA_NAK, hdr->identifier); if (reply == NULL) break; /* Unsupported Service */ radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, 405); break; default: wpa_printf(MSG_DEBUG, "DAS: Unexpected RADIUS code %u in " "packet from %s:%d", hdr->code, abuf, from_port); } if (reply) { wpa_printf(MSG_DEBUG, "DAS: Reply to %s:%d", abuf, from_port); if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_EVENT_TIMESTAMP, now.sec)) { wpa_printf(MSG_DEBUG, "DAS: Failed to add " "Event-Timestamp attribute"); } if (radius_msg_finish_das_resp(reply, das->shared_secret, das->shared_secret_len, hdr) < 0) { wpa_printf(MSG_DEBUG, "DAS: Failed to add " "Message-Authenticator attribute"); } if (wpa_debug_level <= MSG_MSGDUMP) radius_msg_dump(reply); rbuf = radius_msg_get_buf(reply); res = sendto(das->sock, wpabuf_head(rbuf), wpabuf_len(rbuf), 0, (struct sockaddr *) &from.ss, fromlen); if (res < 0) { wpa_printf(MSG_ERROR, "DAS: sendto(to %s:%d): %s", abuf, from_port, strerror(errno)); } } fail: radius_msg_free(msg); radius_msg_free(reply); }
static void radius_server_receive_auth(int sock, void *eloop_ctx, void *sock_ctx) { struct radius_server_data *data = eloop_ctx; u8 *buf = NULL; struct sockaddr_in from; socklen_t fromlen; int len; struct radius_client *client; struct radius_msg *msg = NULL; buf = malloc(RADIUS_MAX_MSG_LEN); if (buf == NULL) { goto fail; } fromlen = sizeof(from); len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0, (struct sockaddr *) &from, &fromlen); if (len < 0) { perror("recvfrom[radius_server]"); goto fail; } RADIUS_DEBUG("Received %d bytes from %s:%d", len, inet_ntoa(from.sin_addr), ntohs(from.sin_port)); RADIUS_DUMP("Received data", buf, len); client = radius_server_get_client(data, &from.sin_addr); if (client == NULL) { RADIUS_DEBUG("Unknown client %s - packet ignored", inet_ntoa(from.sin_addr)); goto fail; } msg = radius_msg_parse(buf, len); if (msg == NULL) { RADIUS_DEBUG("Parsing incoming RADIUS frame failed"); goto fail; } free(buf); buf = NULL; if (wpa_debug_level <= MSG_MSGDUMP) { radius_msg_dump(msg); } if (msg->hdr->code != RADIUS_CODE_ACCESS_REQUEST) { RADIUS_DEBUG("Unexpected RADIUS code %d", msg->hdr->code); goto fail; } if (radius_msg_verify_msg_auth(msg, (u8 *) client->shared_secret, client->shared_secret_len, NULL)) { RADIUS_DEBUG("Invalid Message-Authenticator from %s", inet_ntoa(from.sin_addr)); goto fail; } radius_server_request(data, msg, &from, client); fail: if (msg) { radius_msg_free(msg); free(msg); } free(buf); }
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; }
static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) { struct wpa_supplicant *wpa_s = (struct wpa_supplicant *) eloop_ctx; RadiusType msg_type = (RadiusType) sock_ctx; int len, i; unsigned char buf[3000]; struct radius_msg *msg; struct radius_rx_handler *handlers; size_t num_handlers; struct radius_msg_list *req, *prev_req; len = recv(sock, buf, sizeof(buf), 0); if (len < 0) { perror("recv[RADIUS]"); return; } HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Received %d bytes from RADIUS server\n", len); if (len == sizeof(buf)) { printf("Possibly too long UDP frame for our buffer - " "dropping it\n"); return; } msg = radius_msg_parse(buf, len); if (msg == NULL) { printf("Parsing incoming RADIUS frame failed\n"); return; } HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Received RADIUS message\n"); if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MSGDUMPS)) radius_msg_dump(msg); if (msg_type == RADIUS_ACCT) { handlers = wpa_s->radius->acct_handlers; num_handlers = wpa_s->radius->num_acct_handlers; } else { handlers = wpa_s->radius->auth_handlers; num_handlers = wpa_s->radius->num_auth_handlers; } prev_req = NULL; req = wpa_s->radius->msgs; while (req) { /* TODO: also match by src addr:port of the packet when using * alternative RADIUS servers (?) */ if ((req->msg_type == msg_type || (req->msg_type == RADIUS_ACCT_INTERIM && msg_type == RADIUS_ACCT)) && req->msg->hdr->identifier == msg->hdr->identifier) break; prev_req = req; req = req->next; } if (req == NULL) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "No matching RADIUS request found (type=%d " "id=%d) - dropping packet\n", msg_type, msg->hdr->identifier); goto fail; } /* Remove ACKed RADIUS packet from retransmit list */ if (prev_req) prev_req->next = req->next; else wpa_s->radius->msgs = req->next; wpa_s->radius->num_msgs--; for (i = 0; i < num_handlers; i++) { RadiusRxResult res; res = handlers[i].handler(wpa_s, msg, req->msg, req->shared_secret, req->shared_secret_len, handlers[i].data); switch (res) { case RADIUS_RX_PROCESSED: radius_msg_free(msg); free(msg); /* continue */ case RADIUS_RX_QUEUED: radius_client_msg_free(req); return; case RADIUS_RX_UNKNOWN: /* continue with next handler */ break; } } printf("No RADIUS RX handler found (type=%d code=%d id=%d) - dropping " "packet\n", msg_type, msg->hdr->code, msg->hdr->identifier); radius_client_msg_free(req); fail: radius_msg_free(msg); free(msg); }