/** * radius_client_get_id - Get an identifier for a new RADIUS message * @radius: RADIUS client context from radius_client_init() * Returns: Allocated identifier * * This function is used to fetch a unique (among pending requests) identifier * for a new RADIUS message. */ u8 radius_client_get_id(struct radius_client_data *radius) { struct radius_msg_list *entry, *prev, *_remove; u8 id = radius->next_radius_identifier++; /* remove entries with matching id from retransmit list to avoid * using new reply from the RADIUS server with an old request */ entry = radius->msgs; prev = NULL; while (entry) { if (radius_msg_get_hdr(entry->msg)->identifier == id) { hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_DEBUG, "Removing pending RADIUS message, " "since its id (%d) is reused", id); if (prev) prev->next = entry->next; else radius->msgs = entry->next; _remove = entry; } else { _remove = NULL; prev = entry; } entry = entry->next; if (_remove) radius_client_msg_free(_remove); } return id; }
/* Process the RADIUS frames from Authentication Server */ static RadiusRxResult ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, const u8 *shared_secret, size_t shared_secret_len, void *data) { struct eapol_test_data *e = data; struct radius_hdr *hdr = radius_msg_get_hdr(msg); /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be * present when packet contains an EAP-Message attribute */ if (hdr->code == RADIUS_CODE_ACCESS_REJECT && radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL, 0) < 0 && radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) { wpa_printf(MSG_DEBUG, "Allowing RADIUS " "Access-Reject without Message-Authenticator " "since it does not include EAP-Message\n"); } else if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 1)) { printf("Incoming RADIUS packet did not have correct " "Message-Authenticator - dropped\n"); return RADIUS_RX_UNKNOWN; } if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && hdr->code != RADIUS_CODE_ACCESS_REJECT && hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) { printf("Unknown RADIUS message code\n"); return RADIUS_RX_UNKNOWN; } e->radius_identifier = -1; wpa_printf(MSG_DEBUG, "RADIUS packet matching with station"); radius_msg_free(e->last_recv_radius); e->last_recv_radius = msg; switch (hdr->code) { case RADIUS_CODE_ACCESS_ACCEPT: e->radius_access_accept_received = 1; ieee802_1x_get_keys(e, msg, req, shared_secret, shared_secret_len); break; case RADIUS_CODE_ACCESS_REJECT: e->radius_access_reject_received = 1; break; } ieee802_1x_decapsulate_radius(e); if ((hdr->code == RADIUS_CODE_ACCESS_ACCEPT && e->eapol_test_num_reauths < 0) || hdr->code == RADIUS_CODE_ACCESS_REJECT) { if (!e->ctrl_iface) eloop_terminate(); } return RADIUS_RX_QUEUED; }
static int radius_server_reject(struct radius_server_data *data, struct radius_client *client, struct radius_msg *request, struct sockaddr *from, socklen_t fromlen, const char *from_addr, int from_port) { struct radius_msg *msg; int ret = 0; struct eap_hdr eapfail; struct wpabuf *buf; struct radius_hdr *hdr = radius_msg_get_hdr(request); RADIUS_DEBUG("Reject invalid request from %s:%d", from_addr, from_port); msg = radius_msg_new(RADIUS_CODE_ACCESS_REJECT, hdr->identifier); if (msg == NULL) { return -1; } os_memset(&eapfail, 0, sizeof(eapfail)); eapfail.code = EAP_CODE_FAILURE; eapfail.identifier = 0; eapfail.length = host_to_be16(sizeof(eapfail)); if (!radius_msg_add_eap(msg, (u8 *) &eapfail, sizeof(eapfail))) { RADIUS_DEBUG("Failed to add EAP-Message attribute"); } if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) { RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)"); radius_msg_free(msg); return -1; } if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret, client->shared_secret_len, hdr->authenticator) < 0) { RADIUS_DEBUG("Failed to add Message-Authenticator attribute"); } if (wpa_debug_level <= MSG_MSGDUMP) { radius_msg_dump(msg); } data->counters.access_rejects++; client->counters.access_rejects++; buf = radius_msg_get_buf(msg); if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0, (struct sockaddr *) from, sizeof(*from)) < 0) { wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", strerror(errno)); ret = -1; } radius_msg_free(msg); return ret; }
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; if (entry->msg_type == RADIUS_ACCT || entry->msg_type == RADIUS_ACCT_INTERIM) { s = radius->acct_sock; if (entry->attempts == 0) conf->acct_server->requests++; else { conf->acct_server->timeouts++; conf->acct_server->retransmissions++; } } else { s = radius->auth_sock; if (entry->attempts == 0) conf->auth_server->requests++; else { conf->auth_server->timeouts++; conf->auth_server->retransmissions++; } } /* 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_time(&entry->last_attempt); buf = radius_msg_get_buf(entry->msg); if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) radius_client_handle_send_error(radius, s, entry->msg_type); 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) { printf("Removing un-ACKed RADIUS message due to too many " "failed retransmit attempts\n"); return 1; } return 0; }
/* Process the RADIUS frames from Authentication Server */ static RadiusRxResult receive_auth(struct radius_msg *msg, struct radius_msg *req, const u8 *shared_secret, size_t shared_secret_len, void *data) { /* struct radius_ctx *ctx = data; */ printf("Received RADIUS Authentication message; code=%d\n", radius_msg_get_hdr(msg)->code); /* We're done for this example, so request eloop to terminate. */ eloop_terminate(); return RADIUS_RX_PROCESSED; }
/** * accounting_receive - Process the RADIUS frames from Accounting Server * @msg: RADIUS response message * @req: RADIUS request message * @shared_secret: RADIUS shared secret * @shared_secret_len: Length of shared_secret in octets * @data: Context data (struct hostapd_data *) * Returns: Processing status */ static RadiusRxResult accounting_receive(struct radius_msg *msg, struct radius_msg *req, const u8 *shared_secret, size_t shared_secret_len, void *data) { if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_RESPONSE) { wpa_printf(MSG_INFO, "Unknown RADIUS message code"); return RADIUS_RX_UNKNOWN; } if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) { wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Authenticator - dropped"); return RADIUS_RX_INVALID_AUTHENTICATOR; } return RADIUS_RX_PROCESSED; }
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; 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 (s < 0) { wpa_printf(MSG_INFO, "RADIUS: No valid socket for retransmission"); return 1; } /* 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_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 ieee802_1x_encapsulate_radius(struct eapol_test_data *e, const u8 *eap, size_t len) { struct radius_msg *msg; char buf[128]; const struct eap_hdr *hdr; const u8 *pos; wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS " "packet"); e->radius_identifier = radius_client_get_id(e->radius); msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, e->radius_identifier); if (msg == NULL) { printf("Could not create net RADIUS packet\n"); return; } radius_msg_make_authenticator(msg, (u8 *) e, sizeof(*e)); hdr = (const struct eap_hdr *) eap; pos = (const u8 *) (hdr + 1); if (len > sizeof(*hdr) && hdr->code == EAP_CODE_RESPONSE && pos[0] == EAP_TYPE_IDENTITY) { pos++; os_free(e->eap_identity); e->eap_identity_len = len - sizeof(*hdr) - 1; e->eap_identity = os_malloc(e->eap_identity_len); if (e->eap_identity) { os_memcpy(e->eap_identity, pos, e->eap_identity_len); wpa_hexdump(MSG_DEBUG, "Learned identity from " "EAP-Response-Identity", e->eap_identity, e->eap_identity_len); } } if (e->eap_identity && !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, e->eap_identity, e->eap_identity_len)) { printf("Could not add User-Name\n"); goto fail; } if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_IP_ADDRESS) && !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, (u8 *) &e->own_ip_addr, 4)) { printf("Could not add NAS-IP-Address\n"); goto fail; } os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, MAC2STR(e->wpa_s->own_addr)); if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CALLING_STATION_ID) && !radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, (u8 *) buf, os_strlen(buf))) { printf("Could not add Calling-Station-Id\n"); goto fail; } /* TODO: should probably check MTU from driver config; 2304 is max for * IEEE 802.11, but use 1400 to avoid problems with too large packets */ if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_FRAMED_MTU) && !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { printf("Could not add Framed-MTU\n"); goto fail; } if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_PORT_TYPE) && !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { printf("Could not add NAS-Port-Type\n"); goto fail; } os_snprintf(buf, sizeof(buf), "%s", e->connect_info); if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CONNECT_INFO) && !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, (u8 *) buf, os_strlen(buf))) { printf("Could not add Connect-Info\n"); goto fail; } if (add_extra_attrs(msg, e->extra_attrs) < 0) goto fail; if (eap && !radius_msg_add_eap(msg, eap, len)) { printf("Could not add EAP-Message\n"); goto fail; } /* State attribute must be copied if and only if this packet is * Access-Request reply to the previous Access-Challenge */ if (e->last_recv_radius && radius_msg_get_hdr(e->last_recv_radius)->code == RADIUS_CODE_ACCESS_CHALLENGE) { int res = radius_msg_copy_attr(msg, e->last_recv_radius, RADIUS_ATTR_STATE); if (res < 0) { printf("Could not copy State attribute from previous " "Access-Challenge\n"); goto fail; } if (res > 0) { wpa_printf(MSG_DEBUG, " Copied RADIUS State " "Attribute"); } } radius_client_send(e->radius, msg, RADIUS_AUTH, e->wpa_s->own_addr); return; fail: radius_msg_free(msg); }
/** * hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages * @msg: RADIUS response message * @req: RADIUS request message * @shared_secret: RADIUS shared secret * @shared_secret_len: Length of shared_secret in octets * @data: Context data (struct hostapd_data *) * Returns: RADIUS_RX_PROCESSED if RADIUS message was a reply to ACL query (and * was processed here) or RADIUS_RX_UNKNOWN if not. */ static RadiusRxResult hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, const u8 *shared_secret, size_t shared_secret_len, void *data) { struct hostapd_data *hapd = data; struct hostapd_acl_query_data *query, *prev; struct hostapd_cached_radius_acl *cache; struct radius_hdr *hdr = radius_msg_get_hdr(msg); query = hapd->acl_queries; prev = NULL; while (query) { if (query->radius_id == hdr->identifier) break; prev = query; query = query->next; } if (query == NULL) return RADIUS_RX_UNKNOWN; wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS " "message (id=%d)", query->radius_id); if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) { wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have " "correct authenticator - dropped\n"); return RADIUS_RX_INVALID_AUTHENTICATOR; } if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && hdr->code != RADIUS_CODE_ACCESS_REJECT) { wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL " "query", hdr->code); return RADIUS_RX_UNKNOWN; } /* Insert Accept/Reject info into ACL cache */ cache = os_zalloc(sizeof(*cache)); if (cache == NULL) { wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry"); goto done; } time(&cache->timestamp); os_memcpy(cache->addr, query->addr, sizeof(cache->addr)); if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) { if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, &cache->session_timeout) == 0) cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT; else cache->accepted = HOSTAPD_ACL_ACCEPT; if (radius_msg_get_attr_int32( msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, &cache->acct_interim_interval) == 0 && cache->acct_interim_interval < 60) { wpa_printf(MSG_DEBUG, "Ignored too small " "Acct-Interim-Interval %d for STA " MACSTR, cache->acct_interim_interval, MAC2STR(query->addr)); cache->acct_interim_interval = 0; } cache->vlan_id = radius_msg_get_vlanid(msg); } else cache->accepted = HOSTAPD_ACL_REJECT; cache->next = hapd->acl_cache; hapd->acl_cache = cache; #ifdef CONFIG_DRIVER_RADIUS_ACL hapd->drv.set_radius_acl_auth(hapd, query->addr, cache->accepted, cache->session_timeout); #else /* CONFIG_DRIVER_RADIUS_ACL */ #ifdef NEED_AP_MLME /* Re-send original authentication frame for 802.11 processing */ wpa_printf(MSG_DEBUG, "Re-sending authentication frame after " "successful RADIUS ACL query"); ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL); #endif /* NEED_AP_MLME */ #endif /* CONFIG_DRIVER_RADIUS_ACL */ done: if (prev == NULL) hapd->acl_queries = query->next; else prev->next = query->next; hostapd_acl_query_free(query); return RADIUS_RX_PROCESSED; }
static struct radius_msg * radius_das_disconnect(struct radius_das_data *das, struct radius_msg *msg, const char *abuf, int from_port) { struct radius_hdr *hdr; struct radius_msg *reply; u8 allowed[] = { RADIUS_ATTR_USER_NAME, RADIUS_ATTR_NAS_IP_ADDRESS, RADIUS_ATTR_CALLING_STATION_ID, RADIUS_ATTR_NAS_IDENTIFIER, RADIUS_ATTR_ACCT_SESSION_ID, RADIUS_ATTR_ACCT_MULTI_SESSION_ID, RADIUS_ATTR_EVENT_TIMESTAMP, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, #ifdef CONFIG_IPV6 RADIUS_ATTR_NAS_IPV6_ADDRESS, #endif /* CONFIG_IPV6 */ 0 }; int error = 405; u8 attr; enum radius_das_res res; struct radius_das_attrs attrs; u8 *buf; size_t len; char tmp[100]; u8 sta_addr[ETH_ALEN]; hdr = radius_msg_get_hdr(msg); attr = radius_msg_find_unlisted_attr(msg, allowed); if (attr) { wpa_printf(MSG_INFO, "DAS: Unsupported attribute %u in " "Disconnect-Request from %s:%d", attr, abuf, from_port); error = 401; goto fail; } os_memset(&attrs, 0, sizeof(attrs)); if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, &buf, &len, NULL) == 0) { if (len != 4) { wpa_printf(MSG_INFO, "DAS: Invalid NAS-IP-Address from %s:%d", abuf, from_port); error = 407; goto fail; } attrs.nas_ip_addr = buf; } #ifdef CONFIG_IPV6 if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, &buf, &len, NULL) == 0) { if (len != 16) { wpa_printf(MSG_INFO, "DAS: Invalid NAS-IPv6-Address from %s:%d", abuf, from_port); error = 407; goto fail; } attrs.nas_ipv6_addr = buf; } #endif /* CONFIG_IPV6 */ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IDENTIFIER, &buf, &len, NULL) == 0) { attrs.nas_identifier = buf; attrs.nas_identifier_len = len; } if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID, &buf, &len, NULL) == 0) { if (len >= sizeof(tmp)) len = sizeof(tmp) - 1; os_memcpy(tmp, buf, len); tmp[len] = '\0'; if (hwaddr_aton2(tmp, sta_addr) < 0) { wpa_printf(MSG_INFO, "DAS: Invalid Calling-Station-Id " "'%s' from %s:%d", tmp, abuf, from_port); error = 407; goto fail; } attrs.sta_addr = sta_addr; } if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len, NULL) == 0) { attrs.user_name = buf; attrs.user_name_len = len; } if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_SESSION_ID, &buf, &len, NULL) == 0) { attrs.acct_session_id = buf; attrs.acct_session_id_len = len; } if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID, &buf, &len, NULL) == 0) { attrs.acct_multi_session_id = buf; attrs.acct_multi_session_id_len = len; } if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, &buf, &len, NULL) == 0) { attrs.cui = buf; attrs.cui_len = len; } res = das->disconnect(das->ctx, &attrs); switch (res) { case RADIUS_DAS_NAS_MISMATCH: wpa_printf(MSG_INFO, "DAS: NAS mismatch from %s:%d", abuf, from_port); error = 403; break; case RADIUS_DAS_SESSION_NOT_FOUND: wpa_printf(MSG_INFO, "DAS: Session not found for request from " "%s:%d", abuf, from_port); error = 503; break; case RADIUS_DAS_MULTI_SESSION_MATCH: wpa_printf(MSG_INFO, "DAS: Multiple sessions match for request from %s:%d", abuf, from_port); error = 508; break; case RADIUS_DAS_SUCCESS: error = 0; break; } fail: reply = radius_msg_new(error ? RADIUS_CODE_DISCONNECT_NAK : RADIUS_CODE_DISCONNECT_ACK, hdr->identifier); if (reply == NULL) return NULL; if (error) { if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, error)) { radius_msg_free(reply); return NULL; } } return reply; }
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 ((unsigned int) abs((int) (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 */ if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, 405)) { radius_msg_free(reply); reply = NULL; break; } 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 struct radius_msg * radius_server_encapsulate_eap(struct radius_server_data *data, struct radius_client *client, struct radius_session *sess, struct radius_msg *request) { struct radius_msg *msg; int code; unsigned int sess_id; struct radius_hdr *hdr = radius_msg_get_hdr(request); if (sess->eap_if->eapFail) { sess->eap_if->eapFail = FALSE; code = RADIUS_CODE_ACCESS_REJECT; } else if (sess->eap_if->eapSuccess) { sess->eap_if->eapSuccess = FALSE; code = RADIUS_CODE_ACCESS_ACCEPT; } else { sess->eap_if->eapReq = FALSE; code = RADIUS_CODE_ACCESS_CHALLENGE; } msg = radius_msg_new(code, hdr->identifier); if (msg == NULL) { RADIUS_DEBUG("Failed to allocate reply message"); return NULL; } sess_id = htonl(sess->sess_id); if (code == RADIUS_CODE_ACCESS_CHALLENGE && !radius_msg_add_attr(msg, RADIUS_ATTR_STATE, (u8 *) &sess_id, sizeof(sess_id))) { RADIUS_DEBUG("Failed to add State attribute"); } if (sess->eap_if->eapReqData && !radius_msg_add_eap(msg, wpabuf_head(sess->eap_if->eapReqData), wpabuf_len(sess->eap_if->eapReqData))) { RADIUS_DEBUG("Failed to add EAP-Message attribute"); } if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) { int len; #ifdef CONFIG_RADIUS_TEST if (data->dump_msk_file) { FILE *f; char buf[2 * 64 + 1]; f = fopen(data->dump_msk_file, "a"); if (f) { len = sess->eap_if->eapKeyDataLen; if (len > 64) len = 64; len = wpa_snprintf_hex( buf, sizeof(buf), sess->eap_if->eapKeyData, len); buf[len] = '\0'; fprintf(f, "%s\n", buf); fclose(f); } } #endif /* CONFIG_RADIUS_TEST */ if (sess->eap_if->eapKeyDataLen > 64) { len = 32; } else { len = sess->eap_if->eapKeyDataLen / 2; } if (!radius_msg_add_mppe_keys(msg, hdr->authenticator, (u8 *) client->shared_secret, client->shared_secret_len, sess->eap_if->eapKeyData + len, len, sess->eap_if->eapKeyData, len)) { RADIUS_DEBUG("Failed to add MPPE key attributes"); } } if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) { RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)"); radius_msg_free(msg); return NULL; } if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret, client->shared_secret_len, hdr->authenticator) < 0) { RADIUS_DEBUG("Failed to add Message-Authenticator attribute"); } return msg; }
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; }
static void radius_server_receive_auth(int sock, void *eloop_ctx, void *sock_ctx) { struct radius_server_data *data = eloop_ctx; u8 *buf = NULL; union { struct sockaddr_storage ss; struct sockaddr_in sin; #ifdef CONFIG_IPV6 struct sockaddr_in6 sin6; #endif /* CONFIG_IPV6 */ } from; socklen_t fromlen; int len; struct radius_client *client = NULL; struct radius_msg *msg = NULL; char abuf[50]; int from_port = 0; buf = os_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.ss, &fromlen); if (len < 0) { wpa_printf(MSG_INFO, "recvfrom[radius_server]: %s", strerror(errno)); goto fail; } #ifdef CONFIG_IPV6 if (data->ipv6) { if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf, sizeof(abuf)) == NULL) abuf[0] = '\0'; from_port = ntohs(from.sin6.sin6_port); RADIUS_DEBUG("Received %d bytes from %s:%d", len, abuf, from_port); client = radius_server_get_client(data, (struct in_addr *) &from.sin6.sin6_addr, 1); } #endif /* CONFIG_IPV6 */ if (!data->ipv6) { os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf)); from_port = ntohs(from.sin.sin_port); RADIUS_DEBUG("Received %d bytes from %s:%d", len, abuf, from_port); client = radius_server_get_client(data, &from.sin.sin_addr, 0); } RADIUS_DUMP("Received data", buf, len); if (client == NULL) { RADIUS_DEBUG("Unknown client %s - packet ignored", abuf); data->counters.invalid_requests++; goto fail; } msg = radius_msg_parse(buf, len); if (msg == NULL) { RADIUS_DEBUG("Parsing incoming RADIUS frame failed"); data->counters.malformed_access_requests++; client->counters.malformed_access_requests++; goto fail; } os_free(buf); buf = NULL; if (wpa_debug_level <= MSG_MSGDUMP) { radius_msg_dump(msg); } if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCESS_REQUEST) { RADIUS_DEBUG("Unexpected RADIUS code %d", radius_msg_get_hdr(msg)->code); data->counters.unknown_types++; client->counters.unknown_types++; goto fail; } data->counters.access_requests++; client->counters.access_requests++; if (radius_msg_verify_msg_auth(msg, (u8 *) client->shared_secret, client->shared_secret_len, NULL)) { RADIUS_DEBUG("Invalid Message-Authenticator from %s", abuf); data->counters.bad_authenticators++; client->counters.bad_authenticators++; goto fail; } if (radius_server_request(data, msg, (struct sockaddr *) &from, fromlen, client, abuf, from_port, NULL) == -2) return; /* msg was stored with the session */ fail: radius_msg_free(msg); os_free(buf); }
/** * hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages * @msg: RADIUS response message * @req: RADIUS request message * @shared_secret: RADIUS shared secret * @shared_secret_len: Length of shared_secret in octets * @data: Context data (struct hostapd_data *) * Returns: RADIUS_RX_PROCESSED if RADIUS message was a reply to ACL query (and * was processed here) or RADIUS_RX_UNKNOWN if not. */ static RadiusRxResult hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, const u8 *shared_secret, size_t shared_secret_len, void *data) { struct hostapd_data *hapd = data; struct hostapd_acl_query_data *query, *prev; struct hostapd_cached_radius_acl *cache; struct radius_hdr *hdr = radius_msg_get_hdr(msg); query = hapd->acl_queries; prev = NULL; while (query) { if (query->radius_id == hdr->identifier) break; prev = query; query = query->next; } if (query == NULL) return RADIUS_RX_UNKNOWN; wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS " "message (id=%d)", query->radius_id); if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) { wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have " "correct authenticator - dropped\n"); return RADIUS_RX_INVALID_AUTHENTICATOR; } if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && hdr->code != RADIUS_CODE_ACCESS_REJECT) { wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL " "query", hdr->code); return RADIUS_RX_UNKNOWN; } /* Insert Accept/Reject info into ACL cache */ cache = os_zalloc(sizeof(*cache)); if (cache == NULL) { wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry"); goto done; } os_get_reltime(&cache->timestamp); os_memcpy(cache->addr, query->addr, sizeof(cache->addr)); if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) { u8 *buf; size_t len; if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, &cache->session_timeout) == 0) cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT; else cache->accepted = HOSTAPD_ACL_ACCEPT; if (radius_msg_get_attr_int32( msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, &cache->acct_interim_interval) == 0 && cache->acct_interim_interval < 60) { wpa_printf(MSG_DEBUG, "Ignored too small " "Acct-Interim-Interval %d for STA " MACSTR, cache->acct_interim_interval, MAC2STR(query->addr)); cache->acct_interim_interval = 0; } if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED) cache->vlan_id.notempty = !!radius_msg_get_vlanid( msg, &cache->vlan_id.untagged, MAX_NUM_TAGGED_VLAN, cache->vlan_id.tagged); decode_tunnel_passwords(hapd, shared_secret, shared_secret_len, msg, req, cache); if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len, NULL) == 0) { cache->identity = os_zalloc(len + 1); if (cache->identity) os_memcpy(cache->identity, buf, len); } if (radius_msg_get_attr_ptr( msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, &buf, &len, NULL) == 0) { cache->radius_cui = os_zalloc(len + 1); if (cache->radius_cui) os_memcpy(cache->radius_cui, buf, len); } if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED && !cache->psk) cache->accepted = HOSTAPD_ACL_REJECT; if (cache->vlan_id.notempty && !hostapd_vlan_valid(hapd->conf->vlan, &cache->vlan_id)) { hostapd_logger(hapd, query->addr, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO, "Invalid VLAN %d%s received from RADIUS server", cache->vlan_id.untagged, cache->vlan_id.tagged[0] ? "+" : ""); os_memset(&cache->vlan_id, 0, sizeof(cache->vlan_id)); } if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED && !cache->vlan_id.notempty) cache->accepted = HOSTAPD_ACL_REJECT; } else cache->accepted = HOSTAPD_ACL_REJECT; cache->next = hapd->acl_cache; hapd->acl_cache = cache; #ifdef CONFIG_DRIVER_RADIUS_ACL hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted, cache->session_timeout); #else /* CONFIG_DRIVER_RADIUS_ACL */ #ifdef NEED_AP_MLME /* Re-send original authentication frame for 802.11 processing */ wpa_printf(MSG_DEBUG, "Re-sending authentication frame after " "successful RADIUS ACL query"); ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL); #endif /* NEED_AP_MLME */ #endif /* CONFIG_DRIVER_RADIUS_ACL */ done: if (prev == NULL) hapd->acl_queries = query->next; else prev->next = query->next; hostapd_acl_query_free(query); return RADIUS_RX_PROCESSED; }