⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ieee802_1x.c

📁 最新的Host AP 新添加了许多pcmcia 的驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * hostapd / IEEE 802.1X-2004 Authenticator * Copyright (c) 2002-2008, Jouni Malinen <j@w1.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 "hostapd.h"#include "ieee802_1x.h"#include "accounting.h"#include "radius/radius.h"#include "radius/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 "hw_features.h"#include "eap_server/eap.h"#include "ieee802_11_defs.h"static void ieee802_1x_finished(struct hostapd_data *hapd,				struct sta_info *sta, int success);static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,			    u8 type, const u8 *data, size_t datalen){	u8 *buf;	struct ieee802_1x_hdr *xhdr;	size_t len;	int encrypt = 0;	len = sizeof(*xhdr) + datalen;	buf = os_zalloc(len);	if (buf == NULL) {		wpa_printf(MSG_ERROR, "malloc() failed for "			   "ieee802_1x_send(len=%lu)",			   (unsigned long) len);		return;	}	xhdr = (struct ieee802_1x_hdr *) buf;	xhdr->version = hapd->conf->eapol_version;	xhdr->type = type;	xhdr->length = host_to_be16(datalen);	if (datalen > 0 && data != NULL)		os_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);	}	os_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, sta->flags,					    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, sta->flags,					    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_tx_key_one(struct hostapd_data *hapd,				  struct sta_info *sta,				  int idx, 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 = os_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 (os_get_random(key->key_iv, sizeof(key->key_iv))) {		wpa_printf(MSG_ERROR, "Could not get random numbers");		os_free(buf);		return;	}	key->key_index = idx | (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 + MSK[0..31]" as the RC4-key and	 * MSK[32..63] is used to sign the message. */	if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) {		wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting "			   "and signing EAPOL-Key");		os_free(buf);		return;	}	os_memcpy((u8 *) (key + 1), key_data, key_len);	ekey_len = sizeof(key->key_iv) + 32;	ekey = os_malloc(ekey_len);	if (ekey == NULL) {		wpa_printf(MSG_ERROR, "Could not encrypt key");		os_free(buf);		return;	}	os_memcpy(ekey, key->key_iv, sizeof(key->key_iv));	os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32);	rc4((u8 *) (key + 1), key_len, ekey, ekey_len);	os_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 = host_to_be16(len);	hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len,		 key->key_signature);	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key to " MACSTR		   " (%s index=%d)", MAC2STR(sm->addr),		   broadcast ? "broadcast" : "unicast", idx);	ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len);	if (sta->eapol_sm)		sta->eapol_sm->dot1xAuthEapolFramesTx++;	os_free(buf);}static struct hostapd_wep_keys *ieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname){	struct hostapd_wep_keys *key;	key = os_zalloc(sizeof(*key));	if (key == NULL)		return NULL;	key->default_len = hapd->conf->default_wep_key_len;	if (key->idx >= hapd->conf->broadcast_key_idx_max ||	    key->idx < hapd->conf->broadcast_key_idx_min)		key->idx = hapd->conf->broadcast_key_idx_min;	else		key->idx++;	if (!key->key[key->idx])		key->key[key->idx] = os_malloc(key->default_len);	if (key->key[key->idx] == NULL ||	    os_get_random(key->key[key->idx], key->default_len)) {		printf("Could not generate random WEP key (dynamic VLAN).\n");		os_free(key->key[key->idx]);		key->key[key->idx] = NULL;		os_free(key);		return NULL;	}	key->len[key->idx] = key->default_len;	wpa_printf(MSG_DEBUG, "%s: Default WEP idx %d for dynamic VLAN\n",		   ifname, key->idx);	wpa_hexdump_key(MSG_DEBUG, "Default WEP key (dynamic VLAN)",			key->key[key->idx], key->len[key->idx]);	if (hostapd_set_encryption(ifname, hapd, "WEP", NULL, key->idx,				   key->key[key->idx], key->len[key->idx], 1))		printf("Could not set dynamic VLAN WEP encryption key.\n");	hostapd_set_ieee8021x(ifname, hapd, 1);	return key;}static struct hostapd_wep_keys *ieee802_1x_get_group(struct hostapd_data *hapd, struct hostapd_ssid *ssid,		     size_t vlan_id){	const char *ifname;	if (vlan_id == 0)		return &ssid->wep;	if (vlan_id <= ssid->max_dyn_vlan_keys && ssid->dyn_vlan_keys &&	    ssid->dyn_vlan_keys[vlan_id])		return ssid->dyn_vlan_keys[vlan_id];	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Creating new group "		   "state machine for VLAN ID %lu",		   (unsigned long) vlan_id);	ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);	if (ifname == NULL) {		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Unknown VLAN ID %lu - "			   "cannot create group key state machine",			   (unsigned long) vlan_id);		return NULL;	}	if (ssid->dyn_vlan_keys == NULL) {		int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]);		ssid->dyn_vlan_keys = os_zalloc(size);		if (ssid->dyn_vlan_keys == NULL)			return NULL;		ssid->max_dyn_vlan_keys = vlan_id;	}	if (ssid->max_dyn_vlan_keys < vlan_id) {		struct hostapd_wep_keys **na;		int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]);		na = os_realloc(ssid->dyn_vlan_keys, size);		if (na == NULL)			return NULL;		ssid->dyn_vlan_keys = na;		os_memset(&ssid->dyn_vlan_keys[ssid->max_dyn_vlan_keys + 1], 0,			  (vlan_id - ssid->max_dyn_vlan_keys) *			  sizeof(ssid->dyn_vlan_keys[0]));		ssid->max_dyn_vlan_keys = vlan_id;	}	ssid->dyn_vlan_keys[vlan_id] = ieee802_1x_group_alloc(hapd, ifname);	return ssid->dyn_vlan_keys[vlan_id];}void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta){	struct hostapd_wep_keys *key = NULL;	struct eapol_state_machine *sm = sta->eapol_sm;	int vlan_id;	if (sm == NULL || !sm->eap_if->eapKeyData)		return;	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR,		   MAC2STR(sta->addr));	vlan_id = sta->vlan_id;	if (vlan_id < 0 || vlan_id > MAX_VLAN_ID)		vlan_id = 0;	if (vlan_id) {		key = ieee802_1x_get_group(hapd, sta->ssid, vlan_id);		if (key && key->key[key->idx])			ieee802_1x_tx_key_one(hapd, sta, key->idx, 1,					      key->key[key->idx],					      key->len[key->idx]);	} else 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 = os_malloc(hapd->conf->individual_wep_key_len);		if (ikey == NULL ||		    os_get_random(ikey, hapd->conf->individual_wep_key_len)) {			wpa_printf(MSG_ERROR, "Could not generate random "				   "individual WEP key.");			os_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)) {			wpa_printf(MSG_ERROR, "Could not set individual WEP "				   "encryption.");		}		os_free(ikey);	}}const char *radius_mode_txt(struct hostapd_data *hapd){	if (hapd->iface->current_mode == NULL)		return "802.11";	switch (hapd->iface->current_mode->mode) {	case HOSTAPD_MODE_IEEE80211A:		return "802.11a";	case HOSTAPD_MODE_IEEE80211G:		return "802.11g";	case HOSTAPD_MODE_IEEE80211B:	default:		return "802.11b";	}}int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta){	int i;	u8 rate = 0;	for (i = 0; i < sta->supported_rates_len; i++)		if ((sta->supported_rates[i] & 0x7f) > rate)			rate = sta->supported_rates[i] & 0x7f;	return rate;}static void ieee802_1x_learn_identity(struct hostapd_data *hapd,				      struct eapol_state_machine *sm,				      const u8 *eap, size_t len){	const u8 *identity;	size_t identity_len;	if (len <= sizeof(struct eap_hdr) ||	    eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY)		return;	identity = eap_get_identity(sm->eap, &identity_len);	if (identity == NULL)		return;	/* Save station identity for future RADIUS packets */	os_free(sm->identity);	sm->identity = os_malloc(identity_len + 1);	if (sm->identity == NULL) {		sm->identity_len = 0;		return;	}	os_memcpy(sm->identity, identity, identity_len);	sm->identity_len = identity_len;	sm->identity[identity_len] = '\0';	hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,		       HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity);	sm->dot1xAuthEapolRespIdFramesRx++;}static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,					  struct sta_info *sta,					  const u8 *eap, size_t len){	struct radius_msg *msg;	char buf[128];	struct eapol_state_machine *sm = sta->eapol_sm;	if (sm == NULL)		return;	ieee802_1x_learn_identity(hapd, sm, eap, len);	wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS "		   "packet");	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,				 os_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;	}	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",		    MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);	buf[sizeof(buf) - 1] = '\0';	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,				 (u8 *) buf, os_strlen(buf))) {		printf("Could not add Called-Station-Id\n");		goto fail;	}	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,		    MAC2STR(sta->addr));	buf[sizeof(buf) - 1] = '\0';	if (!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 (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {		printf("Could not add Framed-MTU\n");		goto fail;	}	if (!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;	}	if (sta->flags & WLAN_STA_PREAUTH) {		os_strlcpy(buf, "IEEE 802.11i Pre-Authentication",			   sizeof(buf));	} else {		os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",			    radius_sta_rate(hapd, sta) / 2,			    (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",			    radius_mode_txt(hapd));		buf[sizeof(buf) - 1] = '\0';	}	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,				 (u8 *) buf, os_strlen(buf))) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -