static void ieee802_1x_get_keys(struct eapol_test_data *e, struct radius_msg *msg, struct radius_msg *req, const u8 *shared_secret, size_t shared_secret_len) { struct radius_ms_mppe_keys *keys; u8 *buf; size_t len; keys = radius_msg_get_ms_keys(msg, req, shared_secret, shared_secret_len); if (keys && keys->send == NULL && keys->recv == NULL) { os_free(keys); keys = radius_msg_get_cisco_keys(msg, req, shared_secret, shared_secret_len); } if (keys) { if (keys->send) { wpa_hexdump(MSG_DEBUG, "MS-MPPE-Send-Key (sign)", keys->send, keys->send_len); } if (keys->recv) { wpa_hexdump(MSG_DEBUG, "MS-MPPE-Recv-Key (crypt)", keys->recv, keys->recv_len); e->authenticator_pmk_len = keys->recv_len > PMK_LEN ? PMK_LEN : keys->recv_len; os_memcpy(e->authenticator_pmk, keys->recv, e->authenticator_pmk_len); if (e->authenticator_pmk_len == 16 && keys->send && keys->send_len == 16) { /* MS-CHAP-v2 derives 16 octet keys */ wpa_printf(MSG_DEBUG, "Use MS-MPPE-Send-Key " "to extend PMK to 32 octets"); os_memcpy(e->authenticator_pmk + e->authenticator_pmk_len, keys->send, keys->send_len); e->authenticator_pmk_len += keys->send_len; } } os_free(keys->send); os_free(keys->recv); os_free(keys); } if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_EAP_KEY_NAME, &buf, &len, NULL) == 0) { os_memcpy(e->authenticator_eap_key_name, buf, len); e->authenticator_eap_key_name_len = len; } else { e->authenticator_eap_key_name_len = 0; } }
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; }
/** * 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; } cache->vlan_id = radius_msg_get_vlanid(msg); 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; } 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; }
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; }