📄 ieee802_1x.c
字号:
/* * Host AP (software wireless LAN access point) user space daemon for * Host AP kernel driver / IEEE 802.1X Authenticator * Copyright (c) 2002-2005, 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 <stdlib.h>#include <stdio.h>#include <unistd.h>#include <netinet/in.h>#include <string.h>#include <sys/ioctl.h>#include <signal.h>#include <assert.h>#include <time.h>#include <sys/time.h>#include <sys/socket.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 "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(hostapd *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 = malloc(len); if (buf == NULL) { printf("malloc() failed for ieee802_1x_send(len=%lu)\n", (unsigned long) len); return; } memset(buf, 0, len);#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 = EAPOL_VERSION; xhdr->type = type; xhdr->length = htons(datalen); if (datalen > 0 && data != NULL) memcpy(xhdr + 1, data, datalen); if (sta->wpa_sm && sta->wpa_sm->pairwise_set) 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(hostapd *hapd, struct sta_info *sta, int authorized){ if (sta->flags & WLAN_STA_PREAUTH) return; if (authorized) { sta->flags |= WLAN_STA_AUTHORIZED; hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "authorizing port"); } else { sta->flags &= ~WLAN_STA_AUTHORIZED; hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_DEBUG, "unauthorizing port"); } hostapd_set_sta_authorized(hapd, sta->addr, authorized); 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->auth_pae.eapRestart) return; ieee802_1x_new_auth_session(hapd, sta); tlen = sizeof(*eap) + 1 + hapd->conf->eap_req_id_text_len; buf = malloc(tlen); if (buf == NULL) { printf("Could not allocate memory for identity request\n"); return; } memset(buf, 0, tlen); 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->be_auth.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->auth_pae.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++;}void hostapd_get_ntp_timestamp(u8 *buf){ struct timeval now; u32 sec, usec; /* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */ gettimeofday(&now, NULL); sec = htonl(now.tv_sec + 2208988800U); /* Epoch to 1900 */ /* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */ usec = now.tv_usec; usec = htonl(4295 * usec - (usec >> 5) - (usec >> 9)); memcpy(buf, (u8 *) &sec, 4); memcpy(buf + 4, (u8 *) &usec, 4);}static void ieee802_1x_tx_key_one(hostapd *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 = malloc(sizeof(*hdr) + len); if (buf == NULL) return; memset(buf, 0, sizeof(*hdr) + len); 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); hostapd_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 = 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; } if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MINIMAL)) hostapd_hexdump("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, "WEP", sta->addr, 0, ikey, hapd->conf-> individual_wep_key_len)) { printf("Could not set individual WEP encryption.\n"); } free(ikey); }}static void ieee802_1x_encapsulate_radius(hostapd *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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -