📄 ieee802_1x.c
字号:
data++;
len--;
/* TODO: IEEE 802.1aa/D4: should use auth_pae.initialEAPMsg to check
* which EAP packet is accepted as response; currently, hostapd only
* supports EAP Response-Identity, so this can be hardcoded */
if (type == EAP_TYPE_IDENTITY)
{
char *buf, *pos;
int i;
buf = malloc(4 * len + 1);
if (buf)
{
pos = buf;
for (i = 0; i < len; i++)
{
if (data[i] >= 32 && data[i] < 127)
*pos++ = data[i];
else
{
snprintf(pos, 5, "{%02x}", data[i]);
pos += 4;
}
}
*pos = '\0';
free(buf);
}
sta->eapol_sm->auth_pae.rxInitialRsp = TRUE;
/* Save station identity for future RADIUS packets */
if (sta->identity)
free(sta->identity);
sta->identity = (u8 *) malloc(len);
if (sta->identity)
{
memcpy(sta->identity, data, len);
sta->identity_len = len;
}
}
else
{
if (type != EAP_TYPE_NAK)
sta->eapol_sm->be_auth.backendNonNakResponsesFromSupplicant++;
sta->eapol_sm->be_auth.rxResp = TRUE;
}
}
/* Process incoming EAP packet from Supplicant */
static void handle_eap(struct sta_info *sta, u8 *buf, size_t len)
{
struct eap_hdr *eap;
u16 eap_len;
//fprintf(stderr, " handle_eap\n");
if (len < sizeof(*eap))
{
DBGPRINT(RT_DEBUG_ERROR," too short EAP packet\n");
return;
}
eap = (struct eap_hdr *) buf;
eap_len = ntohs(eap->length);
DBGPRINT(RT_DEBUG_INFO," Receive EAP: code=%d identifier=%d length=%d from Supplicant ra%d\n",
eap->code, eap->identifier, eap_len,sta->ApIdx);
if (eap_len < sizeof(*eap))
{
DBGPRINT(RT_DEBUG_ERROR,"Invalid EAP length\n");
return;
}
else if (eap_len > len)
{
DBGPRINT(RT_DEBUG_ERROR,"Too short frame to contain this EAP packet\n");
return;
}
else if (eap_len < len)
{
DBGPRINT(RT_DEBUG_WARN,"Ignoring %d extra bytes after EAP packet\n", len - eap_len);
}
eap_len -= LENGTH_8021X_HDR;
switch (eap->code)
{
case EAP_CODE_REQUEST:
return;
case EAP_CODE_RESPONSE:
handle_eap_response( sta, eap, (u8 *) (eap + 1), eap_len);
break;
case EAP_CODE_SUCCESS:
return;
case EAP_CODE_FAILURE:
return;
default:
return;
}
}
/* called from Recv_Eapol(). Process the EAPOL frames from the Supplicant */
void ieee802_1x_receive(rtapd *rtapd, u8 *sa, u8 *apidx, u8 *buf, size_t len, u16 ethertype)
{
struct sta_info *sta;
struct ieee802_1x_hdr *hdr;
char SNAP_802_1H[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
char RalinkDiscardIe[] = {0x01, 0xFE, 0x00, 0x06, 0x52, 0x61, 0x6c, 0x69, 0x6e, 0x6b};
u16 datalen;
int bStop = 0;
int i;
//fprintf(stderr, " ieee802_1x_receive\n");
DBGPRINT(RT_DEBUG_INFO,"IEEE802_1X_RECEIVE : from Supplicant\n");
if (len == 10 && RTMPCompareMemory(buf, RalinkDiscardIe, 10) == 0)
bStop = 1;
sta = Ap_get_sta(rtapd, sa, apidx, ethertype, bStop);
if (!sta)
{
return;
}
if (RTMPCompareMemory(buf, SNAP_802_1H, 6) == 0)
buf += LENGTH_802_1_H;
hdr = (struct ieee802_1x_hdr *) buf;
datalen = ntohs(hdr->length);
if (len - sizeof(*hdr) < datalen)
{
DBGPRINT(RT_DEBUG_ERROR,"Frame too short for this IEEE 802.1X packet\n");
return;
}
if (!sta->eapol_sm)
{
sta->eapol_sm = eapol_sm_alloc(rtapd, sta);
if (!sta->eapol_sm)
return;
}
if (((ethertype == ETH_P_PAE) && (hdr->version != EAPOL_VERSION)) || ((ethertype == ETH_P_PRE_AUTH) && (hdr->version != EAPOL_VERSION_2)))
{
DBGPRINT(RT_DEBUG_ERROR,"Key descripter does not match with WPA rule\n");
return;
}
switch (hdr->type)
{
case IEEE802_1X_TYPE_EAP_PACKET:
DBGPRINT(RT_DEBUG_TRACE,"Handle EAP_PACKET from ixp%d\n",sta->ApIdx);
handle_eap(sta, (buf + LENGTH_8021X_HDR), datalen);
break;
case IEEE802_1X_TYPE_EAPOL_START:
DBGPRINT(RT_DEBUG_TRACE,"Handle EAPOL_START from ixp%d\n",sta->ApIdx);
//eapol_sm_initialize(sta->eapol_sm);/*add by caoyue*/
eapol_sm_reinit_port_timer(sta->eapol_sm);
sta->eapol_sm->auth_pae.eapStart = TRUE;
DBGPRINT(RT_DEBUG_TRACE," ieee802_1x_receive IEEE802_1X_TYPE_EAPOL_START call eapol_sm_step\n");
eapol_sm_step(sta->eapol_sm);
break;
case IEEE802_1X_TYPE_EAPOL_LOGOFF:
sta->eapol_sm->auth_pae.eapLogoff = TRUE;
DBGPRINT(RT_DEBUG_TRACE," ieee802_1x_receive IEEE802_1X_TYPE_EAPOL_START call eapol_sm_step\n");
eapol_sm_step(sta->eapol_sm);
break;
case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT:
/* TODO: */
DBGPRINT(RT_DEBUG_TRACE,"Handle EAPOL_ALERT from ra%d\n",sta->ApIdx);
break;
default:
DBGPRINT(RT_DEBUG_TRACE,"Handle Unknown EAP message(Type:%d) from ra%d\n",hdr->type,sta->ApIdx);
break;
}
DBGPRINT(RT_DEBUG_TRACE," ieee802_1x_receive call eapol_sm_step\n");
//fprintf(stderr, " ieee802_1x_receive call eapol_sm_step\n");
eapol_sm_step(sta->eapol_sm);
//fprintf(stderr, " ieee802_1x_receive call eapol_sm_step over\n");
}
void ieee802_1x_new_station(rtapd *rtapd, struct sta_info *sta)
{
if (sta->eapol_sm)
{
sta->eapol_sm->portEnabled = TRUE;
DBGPRINT(RT_DEBUG_TRACE," ieee802_1x_new_station call eapol_sm_step\n");
eapol_sm_step(sta->eapol_sm);
return;
}
sta->eapol_sm = eapol_sm_alloc(rtapd, sta);
if (sta->eapol_sm)
sta->eapol_sm->portEnabled = TRUE;
}
void ieee802_1x_free_station(struct sta_info *sta)
{
if (sta->last_recv_radius)
{
Radius_msg_free(sta->last_recv_radius);
free(sta->last_recv_radius);
sta->last_recv_radius = NULL;
}
free(sta->last_eap_supp);
sta->last_eap_supp = NULL;
free(sta->last_eap_radius);
sta->last_eap_radius = NULL;
free(sta->identity);
sta->identity = NULL;
free(sta->eapol_key_sign);
sta->eapol_key_sign = NULL;
free(sta->eapol_key_crypt);
sta->eapol_key_crypt = NULL;
eapol_sm_free(sta->eapol_sm);
sta->eapol_sm = NULL;
}
static void ieee802_1x_decapsulate_radius(struct sta_info *sta)
{
char *eap;
size_t len;
struct eap_hdr *hdr;
int eap_type = -1;
struct radius_msg *msg;
if (sta->last_recv_radius == NULL)
return;
msg = sta->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 */
free(sta->last_eap_radius);
sta->last_eap_radius = NULL;
sta->last_eap_radius_len = 0;
return;
}
if (len < sizeof(*hdr))
{
free(eap);
return;
}
if (len > sizeof(*hdr))
eap_type = eap[sizeof(*hdr)];
hdr = (struct eap_hdr *) eap;
sta->eapol_sm->be_auth.idFromServer = hdr->identifier;
if (sta->last_eap_radius)
free(sta->last_eap_radius);
sta->last_eap_radius = eap;
sta->last_eap_radius_len = len;
}
#if 0
static void ieee802_1x_get_keys(rtapd *rtapd, struct sta_info *sta,
struct radius_msg *msg, struct radius_msg *req,
u8 *shared_secret, size_t shared_secret_len)
{
struct radius_ms_mppe_keys *keys;
NDIS_802_11_KEY WepKey;
memset(&WepKey, 0,sizeof(NDIS_802_11_KEY));
keys = Radius_msg_get_ms_keys(msg, req, shared_secret, shared_secret_len);
if(keys && keys->recv_len != 0)
{
DBGPRINT(RT_DEBUG_INFO, "IEEE802_1x_Get_Keys, PMK_len = %d\n",keys->recv_len );
DBGPRINT(RT_DEBUG_TRACE, "PMK = %x %x %x %x %x %x %x ...%x \n",\
keys->recv[0],keys->recv[1],keys->recv[2],keys->recv[3],\
keys->recv[4],keys->recv[5],keys->recv[6],keys->recv[15]);
DBGPRINT(RT_DEBUG_INFO, "PMK[16] = %x %x %x %x %x %x %x %x \n",\
keys->recv[16],keys->recv[17],keys->recv[18],keys->recv[19],\
keys->recv[20],keys->recv[21],keys->recv[22],keys->recv[23]);
WepKey.KeyLength = keys->recv_len;
memcpy(WepKey.KeyMaterial, keys->recv, (keys->recv_len== 32?32:1));
memcpy(WepKey.addr, sta->addr, 6);
// WPA2(pre-auth)
if (sta->ethertype == ETH_P_PRE_AUTH)
{
if (RT_ioctl(rtapd, RTPRIV_IOCTL_ADD_PMKID_CACHE, (u8*)&WepKey, sizeof(NDIS_802_11_KEY), 0))
{
DBGPRINT(RT_DEBUG_ERROR,"ieee802_1x_get_keys:RTPRIV_IOCTL_ADD_PMKID_CACHE\n");
return;
}
}
else
{
if (RT_ioctl(rtapd, RTPRIV_IOCTL_ADD_WPA_KEY, (u8*)&WepKey, sizeof(NDIS_802_11_KEY), sta->ApIdx))
{
DBGPRINT(RT_DEBUG_ERROR,"ieee802_1x_get_keys:RTPRIV_IOCTL_ADD_WPA_KEY\n");
return;
}
}
if (keys->send && keys->recv)
{
free(sta->eapol_key_sign);
free(sta->eapol_key_crypt);
sta->eapol_key_sign = keys->send;
sta->eapol_key_sign_len = keys->send_len;
sta->eapol_key_crypt = keys->recv;
sta->eapol_key_crypt_len = keys->recv_len;
sta->eapol_sm->keyAvailable = TRUE;
}
else
{
free(keys->send);
free(keys->recv);
}
free(keys);
}
}
#endif
/* Process the RADIUS frames from Authentication Server */
static RadiusRxResult
ieee802_1x_receive_auth(rtapd *rtapd, struct radius_msg *msg, struct radius_msg *req,
u8 *shared_secret, size_t shared_secret_len, void *data)
{
struct sta_info *sta;
u32 session_timeout = 88, termination_action;
int session_timeout_set, free_flag = 0;
DBGPRINT(RT_DEBUG_TRACE,"Receive IEEE802_1X Response Packet From Radius Server. \n");
sta = Ap_get_sta_radius_identifier(rtapd, msg->hdr->identifier);
//fprintf(stderr, "Radius Rcv id=%d ,sta=%d\n",msg->hdr->identifier,sta);
if (sta == NULL)
{
return RADIUS_RX_UNKNOWN;
}
/* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be
* present when packet contains an EAP-Message attribute */
if (msg->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)
{
}
else if (Radius_msg_verify(msg, shared_secret, shared_secret_len, req))
{
DBGPRINT(RT_DEBUG_ERROR,"Incoming RADIUS packet did not have correct Message-Authenticator - dropped\n");
return RADIUS_RX_UNKNOWN;
}
if (msg->hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
msg->hdr->code != RADIUS_CODE_ACCESS_REJECT &&
msg->hdr->code != RADIUS_CODE_ACCESS_CHALLENGE)
{
DBGPRINT(RT_DEBUG_WARN,"Unknown RADIUS message code\n");
return RADIUS_RX_UNKNOWN;
}
sta->radius_identifier = -1;
if (sta->last_recv_radius)
{
Radius_msg_free(sta->last_recv_radius);
free(sta->last_recv_radius);
}
sta->last_recv_radius = msg;
session_timeout_set = !Radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, &session_timeout);
if (Radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION, &termination_action))
termination_action = RADIUS_TERMINATION_ACTION_DEFAULT;
switch (msg->hdr->code)
{
case RADIUS_CODE_ACCESS_ACCEPT:
/* draft-congdon-radius-8021x-22.txt, Ch. 3.17 */
if (session_timeout_set && termination_action == RADIUS_TERMINATION_ACTION_RADIUS_REQUEST)
{
sta->eapol_sm->reauth_timer.reAuthPeriod = session_timeout;
}
else if (session_timeout_set && (rtapd->conf->session_timeout_set == 1)) // 1 1
{
Ap_sta_session_timeout(rtapd, sta, ((session_timeout<rtapd->conf->session_timeout_interval) ? session_timeout : rtapd->conf->session_timeout_interval));
}
else if (session_timeout_set ) // 1 0
{
Ap_sta_session_timeout(rtapd, sta, session_timeout);
}
else if (rtapd->conf->session_timeout_set == 1) // 0 1
{
Ap_sta_session_timeout(rtapd, sta, rtapd->conf->session_timeout_interval);
}
else // 0 0
free_flag = 1;
sta->eapol_sm->be_auth.aSuccess = TRUE;
// ieee802_1x_get_keys(rtapd, sta, msg, req, shared_secret, shared_secret_len);
break;
case RADIUS_CODE_ACCESS_REJECT:
DBGPRINT(RT_DEBUG_ERROR,"AS send RADIUS_CODE_ACCESS_REJECT\n");
sta->eapol_sm->be_auth.aFail = TRUE;
break;
case RADIUS_CODE_ACCESS_CHALLENGE:
if (session_timeout_set)
{
/* RFC 2869, Ch. 2.3.2
* draft-congdon-radius-8021x-22.txt, Ch. 3.17 */
sta->eapol_sm->be_auth.suppTimeout = session_timeout;
}
sta->eapol_sm->be_auth.aReq = TRUE;
break;
}
ieee802_1x_decapsulate_radius(sta);
DBGPRINT(RT_DEBUG_TRACE," ieee802_1x_receive_auth call eapol_sm_step\n");
eapol_sm_step(sta->eapol_sm);
if (free_flag == 1)
Ap_free_sta(rtapd, sta);
return RADIUS_RX_QUEUED;
}
/* Handler for EAPOL Backend Authentication state machine sendRespToServer.
* Forward the EAP Response from Supplicant to Authentication Server. */
void ieee802_1x_send_resp_to_server(rtapd *rtapd, struct sta_info *sta)
{
ieee802_1x_encapsulate_radius(rtapd, sta, sta->last_eap_supp, sta->last_eap_supp_len);
}
int ieee802_1x_init(rtapd *rtapd)
{
if (Radius_client_register(rtapd, RADIUS_AUTH, ieee802_1x_receive_auth, NULL))
return -1;
return 0;
}
void ieee802_1x_new_auth_session(rtapd *rtapd, struct sta_info *sta)
{
if (!sta->last_recv_radius)
return;
Radius_msg_free(sta->last_recv_radius);
free(sta->last_recv_radius);
sta->last_recv_radius = NULL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -