📄 ieee802_1x.c
字号:
/* * hostapd / IEEE 802.1X Authenticator * Copyright (c) 2002-2006, Jouni Malinen <jkmaline@cc.hut.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */#include "includes.h"#include <assert.h>#include "hostapd.h"#include "ieee802_1x.h"#include "accounting.h"#include "radius.h"#include "radius_client.h"#include "eapol_sm.h"#include "md5.h"#include "rc4.h"#include "eloop.h"#include "sta_info.h"#include "wpa.h"#include "preauth.h"#include "pmksa_cache.h"#include "driver.h"#include "eap.h"static void ieee802_1x_new_auth_session(struct hostapd_data *hapd, struct sta_info *sta);static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, u8 type, u8 *data, size_t datalen){ u8 *buf; struct ieee802_1x_hdr *xhdr; size_t len; int encrypt = 0; len = sizeof(*xhdr) + datalen; buf = wpa_zalloc(len); if (buf == NULL) { printf("malloc() failed for ieee802_1x_send(len=%lu)\n", (unsigned long) len); return; }#if 0 /* TODO: * According to IEEE 802.1aa/D4 EAPOL-Key should be sent before any * remaining EAP frames, if possible. This would allow rest of the * frames to be encrypted. This code could be used to request * encryption from the kernel driver. */ if (sta->eapol_sm && sta->eapol_sm->be_auth.state == BE_AUTH_SUCCESS && sta->eapol_sm->keyTxEnabled) encrypt = 1;#endif xhdr = (struct ieee802_1x_hdr *) buf; xhdr->version = hapd->conf->eapol_version; xhdr->type = type; xhdr->length = htons(datalen); if (datalen > 0 && data != NULL) memcpy(xhdr + 1, data, datalen); if (wpa_auth_pairwise_set(sta->wpa_sm)) encrypt = 1; if (sta->flags & WLAN_STA_PREAUTH) { rsn_preauth_send(hapd, sta, buf, len); } else { hostapd_send_eapol(hapd, sta->addr, buf, len, encrypt); } free(buf);}void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, struct sta_info *sta, int authorized){ int res; if (sta->flags & WLAN_STA_PREAUTH) return; if (authorized) { sta->flags |= WLAN_STA_AUTHORIZED; res = hostapd_sta_set_flags(hapd, sta->addr, WLAN_STA_AUTHORIZED, ~0); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "authorizing port"); } else { sta->flags &= ~WLAN_STA_AUTHORIZED; res = hostapd_sta_set_flags(hapd, sta->addr, 0, ~WLAN_STA_AUTHORIZED); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "unauthorizing port"); } if (res && errno != ENOENT) { printf("Could not set station " MACSTR " flags for kernel " "driver (errno=%d).\n", MAC2STR(sta->addr), errno); } if (authorized) accounting_sta_start(hapd, sta);}static void ieee802_1x_eap_timeout(void *eloop_ctx, void *timeout_ctx){ struct sta_info *sta = eloop_ctx; struct eapol_state_machine *sm = sta->eapol_sm; if (sm == NULL) return; hostapd_logger(sm->hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "EAP timeout"); sm->eapTimeout = TRUE; eapol_sm_step(sm);}void ieee802_1x_request_identity(struct hostapd_data *hapd, struct sta_info *sta){ u8 *buf; struct eap_hdr *eap; int tlen; u8 *pos; struct eapol_state_machine *sm = sta->eapol_sm; if (hapd->conf->eap_server) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "IEEE 802.1X: Integrated EAP server in " "use - do not generate EAP-Request/Identity\n"); return; } if (sm == NULL || !sm->eapRestart) return; ieee802_1x_new_auth_session(hapd, sta); tlen = sizeof(*eap) + 1 + hapd->conf->eap_req_id_text_len; buf = wpa_zalloc(tlen); if (buf == NULL) { printf("Could not allocate memory for identity request\n"); return; } eap = (struct eap_hdr *) buf; eap->code = EAP_CODE_REQUEST; eap->identifier = ++sm->currentId; eap->length = htons(tlen); pos = (u8 *) (eap + 1); *pos++ = EAP_TYPE_IDENTITY; if (hapd->conf->eap_req_id_text) { memcpy(pos, hapd->conf->eap_req_id_text, hapd->conf->eap_req_id_text_len); } sm->eapReq = TRUE; free(sm->last_eap_radius); sm->last_eap_radius = buf; sm->last_eap_radius_len = tlen; eloop_cancel_timeout(ieee802_1x_eap_timeout, sta, NULL); eloop_register_timeout(30, 0, ieee802_1x_eap_timeout, sta, NULL); sm->eapTimeout = FALSE; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "IEEE 802.1X: Generated EAP Request-Identity for " MACSTR " (identifier %d, timeout 30)\n", MAC2STR(sta->addr), eap->identifier); sm->eapRestart = FALSE;}void ieee802_1x_tx_canned_eap(struct hostapd_data *hapd, struct sta_info *sta, int success){ struct eap_hdr eap; struct eapol_state_machine *sm = sta->eapol_sm; memset(&eap, 0, sizeof(eap)); eap.code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE; eap.identifier = 1; if (sm && sm->last_eap_radius) { struct eap_hdr *hdr = (struct eap_hdr *) sm->last_eap_radius; eap.identifier = hdr->identifier + 1; } eap.length = htons(sizeof(eap)); HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "IEEE 802.1X: Sending canned EAP packet %s to " MACSTR " (identifier %d)\n", success ? "SUCCESS" : "FAILURE", MAC2STR(sta->addr), eap.identifier); ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAP_PACKET, (u8 *) &eap, sizeof(eap)); if (sm) sm->dot1xAuthEapolFramesTx++;}void ieee802_1x_tx_req(struct hostapd_data *hapd, struct sta_info *sta){ struct eap_hdr *eap; struct eapol_state_machine *sm = sta->eapol_sm; u8 *type; if (sm == NULL) return; if (sm->last_eap_radius == NULL) { printf("Error: TxReq called for station " MACSTR ", but there " "is no EAP request from the authentication server\n", MAC2STR(sm->addr)); return; } eap = (struct eap_hdr *) sm->last_eap_radius; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "IEEE 802.1X: Sending EAP Packet to " MACSTR " (identifier %d)\n", MAC2STR(sm->addr), eap->identifier); sm->currentId = eap->identifier; ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAP_PACKET, sm->last_eap_radius, sm->last_eap_radius_len); sm->dot1xAuthEapolFramesTx++; type = (u8 *) (eap + 1); if (sm->last_eap_radius_len > sizeof(*eap) && *type == EAP_TYPE_IDENTITY) sm->dot1xAuthEapolReqIdFramesTx++; else sm->dot1xAuthEapolReqFramesTx++;}static void ieee802_1x_tx_key_one(struct hostapd_data *hapd, struct sta_info *sta, int index, int broadcast, u8 *key_data, size_t key_len){ u8 *buf, *ekey; struct ieee802_1x_hdr *hdr; struct ieee802_1x_eapol_key *key; size_t len, ekey_len; struct eapol_state_machine *sm = sta->eapol_sm; if (sm == NULL) return; len = sizeof(*key) + key_len; buf = wpa_zalloc(sizeof(*hdr) + len); if (buf == NULL) return; hdr = (struct ieee802_1x_hdr *) buf; key = (struct ieee802_1x_eapol_key *) (hdr + 1); key->type = EAPOL_KEY_TYPE_RC4; key->key_length = htons(key_len); wpa_get_ntp_timestamp(key->replay_counter); if (hostapd_get_rand(key->key_iv, sizeof(key->key_iv))) { printf("Could not get random numbers\n"); free(buf); return; } key->key_index = index | (broadcast ? 0 : BIT(7)); if (hapd->conf->eapol_key_index_workaround) { /* According to some information, WinXP Supplicant seems to * interpret bit7 as an indication whether the key is to be * activated, so make it possible to enable workaround that * sets this bit for all keys. */ key->key_index |= BIT(7); } /* Key is encrypted using "Key-IV + sm->eapol_key_crypt" as the * RC4-key */ memcpy((u8 *) (key + 1), key_data, key_len); ekey_len = sizeof(key->key_iv) + sm->eapol_key_crypt_len; ekey = malloc(ekey_len); if (ekey == NULL) { printf("Could not encrypt key\n"); free(buf); return; } memcpy(ekey, key->key_iv, sizeof(key->key_iv)); memcpy(ekey + sizeof(key->key_iv), sm->eapol_key_crypt, sm->eapol_key_crypt_len); rc4((u8 *) (key + 1), key_len, ekey, ekey_len); free(ekey); /* This header is needed here for HMAC-MD5, but it will be regenerated * in ieee802_1x_send() */ hdr->version = hapd->conf->eapol_version; hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; hdr->length = htons(len); hmac_md5(sm->eapol_key_sign, sm->eapol_key_sign_len, buf, sizeof(*hdr) + len, key->key_signature); HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "IEEE 802.1X: Sending EAPOL-Key to " MACSTR " (%s index=%d)\n", MAC2STR(sm->addr), broadcast ? "broadcast" : "unicast", index); ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len); if (sta->eapol_sm) sta->eapol_sm->dot1xAuthEapolFramesTx++; free(buf);}void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta){ struct eapol_state_machine *sm = sta->eapol_sm; if (sm == NULL || !sm->eapol_key_sign || !sm->eapol_key_crypt) return; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR "\n", MAC2STR(sta->addr)); if (hapd->default_wep_key) ieee802_1x_tx_key_one(hapd, sta, hapd->default_wep_key_idx, 1, hapd->default_wep_key, hapd->conf->default_wep_key_len); if (hapd->conf->individual_wep_key_len > 0) { u8 *ikey; ikey = malloc(hapd->conf->individual_wep_key_len); if (ikey == NULL || hostapd_get_rand(ikey, hapd->conf->individual_wep_key_len)) { printf("Could not generate random individual WEP " "key.\n"); free(ikey); return; } wpa_hexdump_key(MSG_DEBUG, "Individual WEP key", ikey, hapd->conf->individual_wep_key_len); ieee802_1x_tx_key_one(hapd, sta, 0, 0, ikey, hapd->conf->individual_wep_key_len); /* TODO: set encryption in TX callback, i.e., only after STA * has ACKed EAPOL-Key frame */ if (hostapd_set_encryption(hapd->conf->iface, hapd, "WEP", sta->addr, 0, ikey, hapd->conf->individual_wep_key_len, 1)) { printf("Could not set individual WEP encryption.\n"); } free(ikey); }}static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd, struct sta_info *sta, u8 *eap, size_t len){ struct radius_msg *msg; char buf[128]; struct eapol_state_machine *sm = sta->eapol_sm; if (sm == NULL) return; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Encapsulating EAP message into a RADIUS packet\n"); sm->radius_identifier = radius_client_get_id(hapd->radius); msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, sm->radius_identifier); if (msg == NULL) { printf("Could not create net RADIUS packet\n"); return; } radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta)); if (sm->identity && !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, sm->identity, sm->identity_len)) { printf("Could not add User-Name\n"); goto fail; } if (hapd->conf->own_ip_addr.af == AF_INET && !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) { printf("Could not add NAS-IP-Address\n"); goto fail; }#ifdef CONFIG_IPV6 if (hapd->conf->own_ip_addr.af == AF_INET6 && !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) { printf("Could not add NAS-IPv6-Address\n"); goto fail; }#endif /* CONFIG_IPV6 */ if (hapd->conf->nas_identifier && !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, (u8 *) hapd->conf->nas_identifier, strlen(hapd->conf->nas_identifier))) { printf("Could not add NAS-Identifier\n"); goto fail; } if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) { printf("Could not add NAS-Port\n"); goto fail; } snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s", MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid); if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, (u8 *) buf, strlen(buf))) { printf("Could not add Called-Station-Id\n"); goto fail; } snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, MAC2STR(sta->addr)); if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, (u8 *) buf, strlen(buf))) { printf("Could not add Calling-Station-Id\n"); goto fail; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -