resolve merge conflicts

MFC after:	2 weeks
This commit is contained in:
Sam Leffler 2006-03-07 05:51:52 +00:00
parent ead3cc4315
commit f40bc3005e
10 changed files with 419 additions and 340 deletions

View File

@ -4,7 +4,9 @@ driver.c
driver_bsd.c
driver_madwifi.c
driver_prism54.c
l2_packet.c
l2_packet_freebsd.c
l2_packet_linux.c
l2_packet_pcap.c
prism54.h
priv_netlink.h
wireless_copy.h

View File

@ -6,12 +6,12 @@ WPA/802.1x Authenticator
For the import files and directories were pruned by:
tar -X FREEBSD-Xlist -zxf hostapd-0.3.7.tar.gz
tar -X FREEBSD-Xlist -zxf hostapd-0.4.8.tar.gz
then imported by:
cvs import -m 'Import of hostapd 0.3.7' \
src/contrib/hostapd MALINEN v0_3_7
cvs import -m 'Import of hostapd 0.4.8' \
src/contrib/hostapd MALINEN v0_4_8
To make local changes to hostapd, simply patch and commit to the
main branch (aka HEAD). Never make local changes on the vendor
@ -21,4 +21,4 @@ All local changes should be submitted to Jouni Malinen for inclusion in
the next vendor release.
sam@FreeBSD.org
4-June-2005
6-March-2006

View File

@ -26,6 +26,7 @@
#include "sta_info.h"
#include "eap_i.h"
#define EAP_MAX_AUTH_ROUNDS 50
extern const struct eap_method eap_method_identity;
#ifdef EAP_MD5
@ -52,6 +53,12 @@ extern const struct eap_method eap_method_ttls;
#ifdef EAP_SIM
extern const struct eap_method eap_method_sim;
#endif /* EAP_SIM */
#ifdef EAP_PAX
extern const struct eap_method eap_method_pax;
#endif /* EAP_PAX */
#ifdef EAP_PSK
extern const struct eap_method eap_method_psk;
#endif /* EAP_PSK */
static const struct eap_method *eap_methods[] =
{
@ -80,6 +87,12 @@ static const struct eap_method *eap_methods[] =
#ifdef EAP_SIM
&eap_method_sim,
#endif /* EAP_SIM */
#ifdef EAP_PAX
&eap_method_pax,
#endif /* EAP_PAX */
#ifdef EAP_PSK
&eap_method_psk,
#endif /* EAP_PSK */
};
#define NUM_EAP_METHODS (sizeof(eap_methods) / sizeof(eap_methods[0]))
@ -199,6 +212,7 @@ int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
SM_STATE(EAP, DISABLED)
{
SM_ENTRY(EAP, DISABLED);
sm->num_rounds = 0;
}
@ -234,6 +248,7 @@ SM_STATE(EAP, INITIALIZE)
sm->currentId = sm->respId;
}
}
sm->num_rounds = 0;
}
@ -290,6 +305,7 @@ SM_STATE(EAP, RECEIVED)
/* parse rxResp, respId, respMethod */
eap_sm_parseEapResp(sm, sm->eapRespData, sm->eapRespDataLen);
sm->num_rounds++;
}
@ -505,7 +521,15 @@ SM_STEP(EAP)
SM_ENTER_GLOBAL(EAP, INITIALIZE);
else if (!eapol_get_bool(sm, EAPOL_portEnabled))
SM_ENTER_GLOBAL(EAP, DISABLED);
else switch (sm->EAP_state) {
else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
wpa_printf(MSG_DEBUG, "EAP: more than %d "
"authentication rounds - abort",
EAP_MAX_AUTH_ROUNDS);
sm->num_rounds++;
SM_ENTER_GLOBAL(EAP, FAILURE);
}
} else switch (sm->EAP_state) {
case EAP_INITIALIZE:
if (sm->backend_auth) {
if (!sm->rxResp)
@ -912,6 +936,7 @@ void eap_sm_deinit(struct eap_sm *sm)
free(sm);
}
void eap_sm_notify_cached(struct eap_sm *sm)
{
if (sm == NULL)

View File

@ -32,6 +32,7 @@ struct eapol_callbacks {
size_t eapKeyDataLen);
int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
int phase2, struct eap_user *user);
const char * (*get_eap_req_id_text)(void *ctx, size_t *len);
};
struct eap_config {
@ -41,7 +42,7 @@ struct eap_config {
};
#ifdef EAP_AUTHENTICATOR
#ifdef EAP_SERVER
struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
struct eap_config *eap_conf);
@ -52,7 +53,7 @@ void eap_set_eapRespData(struct eap_sm *sm, const u8 *eapRespData,
size_t eapRespDataLen);
void eap_sm_notify_cached(struct eap_sm *sm);
#else /* EAP_AUTHENTICATOR */
#else /* EAP_SERVER */
static inline struct eap_sm * eap_sm_init(void *eapol_ctx,
struct eapol_callbacks *eapol_cb,
@ -85,6 +86,6 @@ static inline void eap_sm_notify_cached(struct eap_sm *sm)
{
}
#endif /* EAP_AUTHENTICATOR */
#endif /* EAP_SERVER */
#endif /* EAP_H */

View File

@ -68,6 +68,9 @@ static void sm_ ## machine ## _Step(struct eapol_state_machine *sm)
#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
static void eapol_sm_step_run(struct eapol_state_machine *sm);
static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx);
/* Port Timers state machine - implemented as a function that will be called
* once a second as a registered event loop timeout */
@ -76,19 +79,34 @@ static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
{
struct eapol_state_machine *state = timeout_ctx;
if (state->aWhile > 0)
if (state->aWhile > 0) {
state->aWhile--;
if (state->quietWhile > 0)
if (state->aWhile == 0) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
" - aWhile --> 0",
MAC2STR(state->addr));
}
}
if (state->quietWhile > 0) {
state->quietWhile--;
if (state->reAuthWhen > 0)
if (state->quietWhile == 0) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
" - quietWhile --> 0",
MAC2STR(state->addr));
}
}
if (state->reAuthWhen > 0) {
state->reAuthWhen--;
if (state->reAuthWhen == 0) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
" - reAuthWhen --> 0",
MAC2STR(state->addr));
}
}
if (state->hapd->conf->debug >= HOSTAPD_DEBUG_MSGDUMPS)
printf("IEEE 802.1X: " MACSTR " Port Timers TICK "
"(timers: %d %d %d)\n", MAC2STR(state->addr),
state->aWhile, state->quietWhile, state->reAuthWhen);
eapol_sm_step(state);
eapol_sm_step_run(state);
eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, state);
}
@ -359,6 +377,19 @@ SM_STATE(BE_AUTH, REQUEST)
txReq();
sm->be_auth.eapReq = FALSE;
sm->be_auth.backendOtherRequestsToSupplicant++;
/*
* Clearing eapolEap here is not specified in IEEE Std 802.1X-2004, but
* it looks like this would be logical thing to do there since the old
* EAP response would not be valid anymore after the new EAP request
* was sent out.
*
* A race condition has been reported, in which hostapd ended up
* sending out EAP-Response/Identity as a response to the first
* EAP-Request from the main EAP method. This can be avoided by
* clearing eapolEap here.
*/
sm->eapolEap = FALSE;
}
@ -705,7 +736,7 @@ eapol_sm_alloc(hostapd *hapd, struct sta_info *sta)
else
sm->portValid = TRUE;
if (hapd->conf->eap_authenticator) {
if (hapd->conf->eap_server) {
struct eap_config eap_conf;
memset(&eap_conf, 0, sizeof(eap_conf));
eap_conf.ssl_ctx = hapd->ssl_ctx;
@ -729,6 +760,7 @@ void eapol_sm_free(struct eapol_state_machine *sm)
return;
eloop_cancel_timeout(eapol_port_timers_tick, sm->hapd, sm);
eloop_cancel_timeout(eapol_sm_step_cb, sm, NULL);
if (sm->eap)
eap_sm_deinit(sm->eap);
free(sm);
@ -745,55 +777,63 @@ static int eapol_sm_sta_entry_alive(struct hostapd_data *hapd, u8 *addr)
}
void eapol_sm_step(struct eapol_state_machine *sm)
static void eapol_sm_step_run(struct eapol_state_machine *sm)
{
struct hostapd_data *hapd = sm->hapd;
u8 addr[ETH_ALEN];
int prev_auth_pae, prev_be_auth, prev_reauth_timer, prev_auth_key_tx,
prev_key_rx, prev_ctrl_dir;
/* FIX: could re-run eapol_sm_step from registered timeout (after
* 0 sec) to make sure that other possible timeouts/events are
* processed */
int max_steps = 100;
memcpy(addr, sm->sta->addr, ETH_ALEN);
restart:
do {
prev_auth_pae = sm->auth_pae.state;
prev_be_auth = sm->be_auth.state;
prev_reauth_timer = sm->reauth_timer.state;
prev_auth_key_tx = sm->auth_key_tx.state;
prev_key_rx = sm->key_rx.state;
prev_ctrl_dir = sm->ctrl_dir.state;
SM_STEP_RUN(AUTH_PAE);
if (!sm->initializing && !eapol_sm_sta_entry_alive(hapd, addr))
break;
/*
* Allow EAPOL state machines to run as long as there are state
* changes, but exit and return here through event loop if more than
* 100 steps is needed as a precaution against infinite loops inside
* eloop callback.
*/
restart:
prev_auth_pae = sm->auth_pae.state;
prev_be_auth = sm->be_auth.state;
prev_reauth_timer = sm->reauth_timer.state;
prev_auth_key_tx = sm->auth_key_tx.state;
prev_key_rx = sm->key_rx.state;
prev_ctrl_dir = sm->ctrl_dir.state;
SM_STEP_RUN(AUTH_PAE);
if (sm->initializing || eapol_sm_sta_entry_alive(hapd, addr))
SM_STEP_RUN(BE_AUTH);
if (!sm->initializing && !eapol_sm_sta_entry_alive(hapd, addr))
break;
if (sm->initializing || eapol_sm_sta_entry_alive(hapd, addr))
SM_STEP_RUN(REAUTH_TIMER);
if (!sm->initializing && !eapol_sm_sta_entry_alive(hapd, addr))
break;
if (sm->initializing || eapol_sm_sta_entry_alive(hapd, addr))
SM_STEP_RUN(AUTH_KEY_TX);
if (!sm->initializing && !eapol_sm_sta_entry_alive(hapd, addr))
break;
if (sm->initializing || eapol_sm_sta_entry_alive(hapd, addr))
SM_STEP_RUN(KEY_RX);
if (!sm->initializing && !eapol_sm_sta_entry_alive(hapd, addr))
break;
if (sm->initializing || eapol_sm_sta_entry_alive(hapd, addr))
SM_STEP_RUN(CTRL_DIR);
if (!sm->initializing && !eapol_sm_sta_entry_alive(hapd, addr))
break;
} while (prev_auth_pae != sm->auth_pae.state ||
prev_be_auth != sm->be_auth.state ||
prev_reauth_timer != sm->reauth_timer.state ||
prev_auth_key_tx != sm->auth_key_tx.state ||
prev_key_rx != sm->key_rx.state ||
prev_ctrl_dir != sm->ctrl_dir.state);
if (prev_auth_pae != sm->auth_pae.state ||
prev_be_auth != sm->be_auth.state ||
prev_reauth_timer != sm->reauth_timer.state ||
prev_auth_key_tx != sm->auth_key_tx.state ||
prev_key_rx != sm->key_rx.state ||
prev_ctrl_dir != sm->ctrl_dir.state) {
if (--max_steps > 0)
goto restart;
/* Re-run from eloop timeout */
eapol_sm_step(sm);
return;
}
if (eapol_sm_sta_entry_alive(hapd, addr) && sm->eap) {
if (eap_sm_step(sm->eap))
goto restart;
if (eap_sm_step(sm->eap)) {
if (--max_steps > 0)
goto restart;
/* Re-run from eloop timeout */
eapol_sm_step(sm);
return;
}
}
if (eapol_sm_sta_entry_alive(hapd, addr))
@ -801,15 +841,34 @@ void eapol_sm_step(struct eapol_state_machine *sm)
}
static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx)
{
struct eapol_state_machine *sm = eloop_ctx;
eapol_sm_step_run(sm);
}
void eapol_sm_step(struct eapol_state_machine *sm)
{
/*
* Run eapol_sm_step_run from a registered timeout to make sure that
* other possible timeouts/events are processed and to avoid long
* function call chains.
*/
eloop_register_timeout(0, 0, eapol_sm_step_cb, sm, NULL);
}
void eapol_sm_initialize(struct eapol_state_machine *sm)
{
sm->initializing = TRUE;
/* Initialize the state machines by asserting initialize and then
* deasserting it after one step */
sm->initialize = TRUE;
eapol_sm_step(sm);
eapol_sm_step_run(sm);
sm->initialize = FALSE;
eapol_sm_step(sm);
eapol_sm_step_run(sm);
sm->initializing = FALSE;
/* Start one second tick for port timers state machine */
@ -1183,6 +1242,14 @@ static int eapol_sm_get_eap_user(void *ctx, const u8 *identity,
}
static const char * eapol_sm_get_eap_req_id_text(void *ctx, size_t *len)
{
struct eapol_state_machine *sm = ctx;
*len = sm->hapd->conf->eap_req_id_text_len;
return sm->hapd->conf->eap_req_id_text;
}
static struct eapol_callbacks eapol_cb =
{
.get_bool = eapol_sm_get_bool,
@ -1190,4 +1257,5 @@ static struct eapol_callbacks eapol_cb =
.set_eapReqData = eapol_sm_set_eapReqData,
.set_eapKeyData = eapol_sm_set_eapKeyData,
.get_eap_user = eapol_sm_get_eap_user,
.get_eap_req_id_text = eapol_sm_get_eap_req_id_text,
};

View File

@ -1,188 +0,0 @@
/*
* hostapd - hostapd control interface library
* Copyright (c) 2004, 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 <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/un.h>
#include "hostapd_ctrl.h"
struct hostapd_ctrl {
int s;
struct sockaddr_un local;
struct sockaddr_un dest;
};
struct hostapd_ctrl * hostapd_ctrl_open(const char *ctrl_path)
{
struct hostapd_ctrl *ctrl;
static int counter = 0;
ctrl = malloc(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
memset(ctrl, 0, sizeof(*ctrl));
ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
if (ctrl->s < 0) {
free(ctrl);
return NULL;
}
ctrl->local.sun_family = AF_UNIX;
snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
"/tmp/hostapd_ctrl_%d-%d", getpid(), counter++);
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local.sun_family) +
strlen(ctrl->local.sun_path)) < 0) {
close(ctrl->s);
free(ctrl);
return NULL;
}
ctrl->dest.sun_family = AF_UNIX;
strncpy(ctrl->dest.sun_path, ctrl_path, sizeof(ctrl->dest.sun_path));
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
sizeof(ctrl->dest.sun_family) +
strlen(ctrl->dest.sun_path)) < 0) {
close(ctrl->s);
unlink(ctrl->local.sun_path);
free(ctrl);
return NULL;
}
return ctrl;
}
void hostapd_ctrl_close(struct hostapd_ctrl *ctrl)
{
unlink(ctrl->local.sun_path);
close(ctrl->s);
free(ctrl);
}
int hostapd_ctrl_request(struct hostapd_ctrl *ctrl, char *cmd, size_t cmd_len,
char *reply, size_t *reply_len,
void (*msg_cb)(char *msg, size_t len))
{
struct timeval tv;
int res;
fd_set rfds;
if (send(ctrl->s, cmd, cmd_len, 0) < 0)
return -1;
for (;;) {
tv.tv_sec = 2;
tv.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(ctrl->s, &rfds);
res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
if (FD_ISSET(ctrl->s, &rfds)) {
res = recv(ctrl->s, reply, *reply_len, 0);
if (res < 0)
return res;
if (res > 0 && reply[0] == '<') {
/* This is an unsolicited message from
* wpa_supplicant, not the reply to the
* request. Use msg_cb to report this to the
* caller. */
if (msg_cb) {
/* Make sure the message is nul
* terminated. */
if (res == *reply_len)
res = (*reply_len) - 1;
reply[res] = '\0';
msg_cb(reply, res);
}
continue;
}
*reply_len = res;
break;
} else {
return -2;
}
}
return 0;
}
static int hostapd_ctrl_attach_helper(struct hostapd_ctrl *ctrl, int attach)
{
char buf[10];
int ret;
size_t len = 10;
ret = hostapd_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
buf, &len, NULL);
if (ret < 0)
return ret;
if (len == 3 && memcmp(buf, "OK\n", 3) == 0)
return 0;
return -1;
}
int hostapd_ctrl_attach(struct hostapd_ctrl *ctrl)
{
return hostapd_ctrl_attach_helper(ctrl, 1);
}
int hostapd_ctrl_detach(struct hostapd_ctrl *ctrl)
{
return hostapd_ctrl_attach_helper(ctrl, 0);
}
int hostapd_ctrl_recv(struct hostapd_ctrl *ctrl, char *reply,
size_t *reply_len)
{
int res;
res = recv(ctrl->s, reply, *reply_len, 0);
if (res < 0)
return res;
*reply_len = res;
return 0;
}
int hostapd_ctrl_pending(struct hostapd_ctrl *ctrl)
{
struct timeval tv;
int res;
fd_set rfds;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(ctrl->s, &rfds);
res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
return FD_ISSET(ctrl->s, &rfds);
}
int hostapd_ctrl_get_fd(struct hostapd_ctrl *ctrl)
{
return ctrl->s;
}

View File

@ -1,18 +0,0 @@
#ifndef HOSTAPD_CTRL_H
#define HOSTAPD_CTRL_H
struct hostapd_ctrl;
struct hostapd_ctrl * hostapd_ctrl_open(const char *ctrl_path);
void hostapd_ctrl_close(struct hostapd_ctrl *ctrl);
int hostapd_ctrl_request(struct hostapd_ctrl *ctrl, char *cmd, size_t cmd_len,
char *reply, size_t *reply_len,
void (*msg_cb)(char *msg, size_t len));
int hostapd_ctrl_attach(struct hostapd_ctrl *ctrl);
int hostapd_ctrl_detach(struct hostapd_ctrl *ctrl);
int hostapd_ctrl_recv(struct hostapd_ctrl *ctrl, char *reply,
size_t *reply_len);
int hostapd_ctrl_pending(struct hostapd_ctrl *ctrl);
int hostapd_ctrl_get_fd(struct hostapd_ctrl *ctrl);
#endif /* HOSTAPD_CTRL_H */

View File

@ -135,13 +135,13 @@ void ieee802_1x_request_identity(struct hostapd_data *hapd,
{
u8 *buf;
struct eap_hdr *eap;
int extra, tlen;
int tlen;
u8 *pos;
struct eapol_state_machine *sm = sta->eapol_sm;
if (hapd->conf->eap_authenticator) {
if (hapd->conf->eap_server) {
HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
"IEEE 802.1X: Integrated EAP Authenticator in "
"IEEE 802.1X: Integrated EAP server in "
"use - do not generate EAP-Request/Identity\n");
return;
}
@ -151,12 +151,7 @@ void ieee802_1x_request_identity(struct hostapd_data *hapd,
ieee802_1x_new_auth_session(hapd, sta);
if (hapd->conf->eap_req_id_text)
extra = strlen(hapd->conf->eap_req_id_text);
else
extra = 0;
tlen = sizeof(*eap) + 1 + extra;
tlen = sizeof(*eap) + 1 + hapd->conf->eap_req_id_text_len;
buf = malloc(tlen);
if (buf == NULL) {
@ -172,8 +167,10 @@ void ieee802_1x_request_identity(struct hostapd_data *hapd,
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, extra);
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);
@ -424,12 +421,22 @@ static void ieee802_1x_encapsulate_radius(hostapd *hapd, struct sta_info *sta,
goto fail;
}
if (!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr, 4)) {
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,
@ -665,7 +672,8 @@ static void handle_eap(hostapd *hapd, struct sta_info *sta, u8 *buf,
/* Process the EAPOL frames from the Supplicant */
void ieee802_1x_receive(hostapd *hapd, u8 *sa, u8 *buf, size_t len)
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
size_t len)
{
struct sta_info *sta;
struct ieee802_1x_hdr *hdr;
@ -800,20 +808,17 @@ void ieee802_1x_new_station(hostapd *hapd, struct sta_info *sta)
if (!hapd->conf->ieee802_1x || sta->wpa_key_mgmt == WPA_KEY_MGMT_PSK)
return;
if (sta->eapol_sm) {
sta->eapol_sm->portEnabled = TRUE;
eapol_sm_step(sta->eapol_sm);
return;
}
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "start authentication");
sta->eapol_sm = eapol_sm_alloc(hapd, sta);
if (sta->eapol_sm == NULL) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_INFO, "failed to allocate "
"state machine");
return;
HOSTAPD_LEVEL_DEBUG, "start authentication");
sta->eapol_sm = eapol_sm_alloc(hapd, sta);
if (sta->eapol_sm == NULL) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_INFO,
"failed to allocate state machine");
return;
}
}
sta->eapol_sm->portEnabled = TRUE;
@ -831,7 +836,49 @@ void ieee802_1x_new_station(hostapd *hapd, struct sta_info *sta)
sta->eapol_sm->authSuccess = TRUE;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
} else
eapol_sm_step(sta->eapol_sm);
}
void ieee802_1x_free_radius_class(struct radius_class_data *class)
{
int i;
if (class == NULL)
return;
for (i = 0; i < class->count; i++)
free(class->attr[i].data);
free(class->attr);
class->attr = NULL;
class->count = 0;
}
int ieee802_1x_copy_radius_class(struct radius_class_data *dst,
struct radius_class_data *src)
{
size_t i;
if (src->attr == NULL)
return 0;
dst->attr = malloc(src->count * sizeof(struct radius_attr_data));
if (dst->attr == NULL)
return -1;
memset(dst->attr, 0, src->count * sizeof(struct radius_attr_data));
dst->count = 0;
for (i = 0; i < src->count; i++) {
dst->attr[i].data = malloc(src->attr[i].len);
if (dst->attr[i].data == NULL)
break;
dst->count++;
memcpy(dst->attr[i].data, src->attr[i].data, src->attr[i].len);
dst->attr[i].len = src->attr[i].len;
}
return 0;
}
@ -854,7 +901,7 @@ void ieee802_1x_free_station(struct sta_info *sta)
free(sm->last_eap_supp);
free(sm->last_eap_radius);
free(sm->identity);
free(sm->radius_class);
ieee802_1x_free_radius_class(&sm->radius_class);
free(sm->eapol_key_sign);
free(sm->eapol_key_crypt);
eapol_sm_free(sm);
@ -997,31 +1044,87 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
u8 *class;
size_t class_len;
struct eapol_state_machine *sm = sta->eapol_sm;
int count, i;
struct radius_attr_data *nclass;
size_t nclass_count;
if (!hapd->conf->acct_server || hapd->radius == NULL || sm == NULL)
if (!hapd->conf->radius->acct_server || hapd->radius == NULL ||
sm == NULL)
return;
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS, &class,
&class_len) < 0 ||
class_len < 1) {
free(sm->radius_class);
sm->radius_class = NULL;
sm->radius_class_len = 0;
ieee802_1x_free_radius_class(&sm->radius_class);
count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1);
if (count <= 0)
return;
nclass = malloc(count * sizeof(struct radius_attr_data));
if (nclass == NULL)
return;
nclass_count = 0;
memset(nclass, 0, count * sizeof(struct radius_attr_data));
class = NULL;
for (i = 0; i < count; i++) {
do {
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS,
&class, &class_len,
class) < 0) {
i = count;
break;
}
} while (class_len < 1);
nclass[nclass_count].data = malloc(class_len);
if (nclass[nclass_count].data == NULL)
break;
memcpy(nclass[nclass_count].data, class, class_len);
nclass[nclass_count].len = class_len;
nclass_count++;
}
if (sm->radius_class == NULL ||
sm->radius_class_len < class_len) {
free(sm->radius_class);
sm->radius_class = malloc(class_len);
if (sm->radius_class == NULL) {
sm->radius_class_len = 0;
return;
}
}
sm->radius_class.attr = nclass;
sm->radius_class.count = nclass_count;
HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "IEEE 802.1X: Stored %lu RADIUS "
"Class attributes for " MACSTR "\n",
(unsigned long) sm->radius_class.count,
MAC2STR(sta->addr));
}
memcpy(sm->radius_class, class, class_len);
sm->radius_class_len = class_len;
/* Update sta->identity based on User-Name attribute in Access-Accept */
static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd,
struct sta_info *sta,
struct radius_msg *msg)
{
u8 *buf, *identity;
size_t len;
struct eapol_state_machine *sm = sta->eapol_sm;
if (sm == NULL)
return;
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len,
NULL) < 0)
return;
identity = malloc(len + 1);
if (identity == NULL)
return;
memcpy(identity, buf, len);
identity[len] = '\0';
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with "
"User-Name from Access-Accept '%s'",
sm->identity ? (char *) sm->identity : "N/A",
(char *) identity);
free(sm->identity);
sm->identity = identity;
sm->identity_len = len;
}
@ -1066,7 +1169,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
{
struct hostapd_data *hapd = data;
struct sta_info *sta;
u32 session_timeout, termination_action, acct_interim_interval;
u32 session_timeout = 0, termination_action, acct_interim_interval;
int session_timeout_set;
int eap_timeout;
struct eapol_state_machine *sm;
@ -1091,7 +1194,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
"Access-Reject without Message-Authenticator "
"since it does not include EAP-Message\n");
} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
req)) {
req, 1)) {
printf("Incoming RADIUS packet did not have correct "
"Message-Authenticator - dropped\n");
return RADIUS_RX_INVALID_AUTHENTICATOR;
@ -1123,7 +1226,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
&termination_action))
termination_action = RADIUS_TERMINATION_ACTION_DEFAULT;
if (hapd->conf->radius_acct_interim_interval == 0 &&
if (hapd->conf->radius->acct_interim_interval == 0 &&
msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT &&
radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
&acct_interim_interval) == 0) {
@ -1152,12 +1255,13 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
override_eapReq = 1;
ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret,
shared_secret_len);
ieee802_1x_store_radius_class(hapd, sta, msg);
ieee802_1x_update_sta_identity(hapd, sta, msg);
if (sm->keyAvailable) {
pmksa_cache_add(hapd, sta, sm->eapol_key_crypt,
session_timeout_set ?
session_timeout : -1);
}
ieee802_1x_store_radius_class(hapd, sta, msg);
break;
case RADIUS_CODE_ACCESS_REJECT:
sm->eapFail = TRUE;
@ -1199,7 +1303,7 @@ void ieee802_1x_send_resp_to_server(hostapd *hapd, struct sta_info *sta)
if (sm == NULL)
return;
if (hapd->conf->eap_authenticator) {
if (hapd->conf->eap_server) {
eap_set_eapRespData(sm->eap, sm->last_eap_supp,
sm->last_eap_supp_len);
} else {
@ -1229,9 +1333,6 @@ void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
free(sm->last_eap_radius);
sm->last_eap_radius = NULL;
sm->last_eap_radius_len = 0;
free(sm->radius_class);
sm->radius_class = NULL;
sm->radius_class_len = 0;
}
@ -1482,13 +1583,15 @@ u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len)
}
u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len)
u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
int idx)
{
if (sm == NULL || sm->radius_class == NULL)
if (sm == NULL || sm->radius_class.attr == NULL ||
idx >= sm->radius_class.count)
return NULL;
*len = sm->radius_class_len;
return sm->radius_class;
*len = sm->radius_class.attr[idx].len;
return sm->radius_class.attr[idx].data;
}
@ -1508,6 +1611,7 @@ void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
if (sm == NULL)
return;
sm->portEnabled = enabled ? TRUE : FALSE;
eapol_sm_step(sm);
}
@ -1517,6 +1621,7 @@ void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
if (sm == NULL)
return;
sm->portValid = valid ? TRUE : FALSE;
eapol_sm_step(sm);
}

View File

@ -12,13 +12,7 @@ struct ieee802_1x_hdr {
/* followed by length octets of data */
} __attribute__ ((packed));
#if defined(IEEE802_1X_EAPOL_VERSION_2)
#define EAPOL_VERSION 2
#else
/* Enable support for older Authenticators/Supplicants using EAPOL Version 1 */
#define EAPOL_VERSION 1
#endif /* ! IEEE802_1X_EAPOL_VERSION_2 */
enum { IEEE802_1X_TYPE_EAP_PACKET = 0,
IEEE802_1X_TYPE_EAPOL_START = 1,
@ -55,7 +49,8 @@ enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,
EAPOL_KEY_TYPE_WPA = 254 };
void ieee802_1x_receive(hostapd *hapd, u8 *sa, u8 *buf, size_t len);
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
size_t len);
void ieee802_1x_new_station(hostapd *hapd, struct sta_info *sta);
void ieee802_1x_free_station(struct sta_info *sta);
@ -77,7 +72,8 @@ void ieee802_1x_deinit(hostapd *hapd);
int ieee802_1x_tx_status(hostapd *hapd, struct sta_info *sta, u8 *buf,
size_t len, int ack);
u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len);
u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
int idx);
u8 * ieee802_1x_get_key_crypt(struct eapol_state_machine *sm, size_t *len);
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
int enabled);
@ -91,4 +87,10 @@ void hostapd_get_ntp_timestamp(u8 *buf);
void ieee802_1x_finished(struct hostapd_data *hapd, struct sta_info *sta,
int success);
struct radius_class_data;
void ieee802_1x_free_radius_class(struct radius_class_data *class);
int ieee802_1x_copy_radius_class(struct radius_class_data *dst,
struct radius_class_data *src);
#endif /* IEEE802_1X_H */

View File

@ -36,6 +36,8 @@
#include "eloop.h"
#include "sta_info.h"
#include "l2_packet.h"
#include "accounting.h"
#include "hostap_common.h"
static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx);
@ -103,7 +105,7 @@ static const u8 RSN_KEY_DATA_PMKID[] = { 0x00, 0x0f, 0xac, 4 };
* Authenticated Key Management Suite Count (2 octets, little endian)
* (default: 1)
* Authenticated Key Management Suite List (4 * n octets)
* (default: unspec 802.1x)
* (default: unspec 802.1X)
* WPA Capabilities (2 octets, little endian) (default: 0)
*/
@ -125,7 +127,7 @@ struct wpa_ie_hdr {
* Authenticated Key Management Suite Count (2 octets, little endian)
* (default: 1)
* Authenticated Key Management Suite List (4 * n octets)
* (default: unspec 802.1x)
* (default: unspec 802.1X)
* RSN Capabilities (2 octets, little endian) (default: 0)
* PMKID Count (2 octets) (default: 0)
* PMKID List (16 * n octets)
@ -398,8 +400,8 @@ static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
#ifdef CONFIG_RSN_PREAUTH
static void rsn_preauth_receive(void *ctx, unsigned char *src_addr,
unsigned char *buf, size_t len)
static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
const u8 *buf, size_t len)
{
struct rsn_preauth_interface *piface = ctx;
struct hostapd_data *hapd = piface->hapd;
@ -482,13 +484,12 @@ static int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname)
}
piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH,
rsn_preauth_receive, piface);
rsn_preauth_receive, piface, 1);
if (piface->l2 == NULL) {
printf("Failed to open register layer 2 access to "
"ETH_P_PREAUTH\n");
goto fail2;
}
l2_packet_set_rx_l2_hdr(piface->l2, 1);
piface->next = hapd->preauth_iface;
hapd->preauth_iface = piface;
@ -553,6 +554,16 @@ static int rsn_preauth_iface_init(struct hostapd_data *hapd)
}
static void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
wpa_printf(MSG_DEBUG, "RSN: Removing pre-authentication STA entry for "
MACSTR, MAC2STR(sta->addr));
ap_free_sta(hapd, sta);
}
void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
int success)
{
@ -567,7 +578,11 @@ void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
pmksa_cache_add(hapd, sta, key, dot11RSNAConfigPMKLifetime);
}
ap_free_sta(hapd, sta);
/*
* Finish STA entry removal from timeout in order to avoid freeing
* STA data before the caller has finished processing.
*/
eloop_register_timeout(0, 0, rsn_preauth_finished_cb, hapd, sta);
}
@ -600,8 +615,8 @@ void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
ethhdr->h_proto = htons(ETH_P_PREAUTH);
memcpy(ethhdr + 1, buf, len);
if (l2_packet_send(piface->l2, (u8 *) ethhdr, sizeof(*ethhdr) + len) <
0) {
if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr,
sizeof(*ethhdr) + len) < 0) {
printf("Failed to send preauth packet using l2_packet_send\n");
}
free(ethhdr);
@ -618,6 +633,10 @@ static inline void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
{
}
static void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx)
{
}
void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
int success)
{
@ -809,6 +828,16 @@ static void rsn_pmkid(const u8 *pmk, const u8 *aa, const u8 *spa, u8 *pmkid)
static void pmksa_cache_set_expiration(struct hostapd_data *hapd);
static void _pmksa_cache_free_entry(struct rsn_pmksa_cache *entry)
{
if (entry == NULL)
return;
free(entry->identity);
ieee802_1x_free_radius_class(&entry->radius_class);
free(entry);
}
static void pmksa_cache_free_entry(struct hostapd_data *hapd,
struct rsn_pmksa_cache *entry)
{
@ -848,7 +877,7 @@ static void pmksa_cache_free_entry(struct hostapd_data *hapd,
prev = pos;
pos = pos->next;
}
free(entry);
_pmksa_cache_free_entry(entry);
}
@ -884,6 +913,54 @@ static void pmksa_cache_set_expiration(struct hostapd_data *hapd)
}
static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache *entry,
struct eapol_state_machine *eapol)
{
if (eapol == NULL)
return;
if (eapol->identity) {
entry->identity = malloc(eapol->identity_len);
if (entry->identity) {
entry->identity_len = eapol->identity_len;
memcpy(entry->identity, eapol->identity,
eapol->identity_len);
}
}
ieee802_1x_copy_radius_class(&entry->radius_class,
&eapol->radius_class);
}
static void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache *entry,
struct eapol_state_machine *eapol)
{
if (entry == NULL || eapol == NULL)
return;
if (entry->identity) {
free(eapol->identity);
eapol->identity = malloc(entry->identity_len);
if (eapol->identity) {
eapol->identity_len = entry->identity_len;
memcpy(eapol->identity, entry->identity,
entry->identity_len);
}
wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA",
eapol->identity, eapol->identity_len);
}
ieee802_1x_free_radius_class(&eapol->radius_class);
ieee802_1x_copy_radius_class(&eapol->radius_class,
&entry->radius_class);
if (eapol->radius_class.attr) {
wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from "
"PMKSA", (unsigned long) eapol->radius_class.count);
}
}
void pmksa_cache_add(struct hostapd_data *hapd, struct sta_info *sta, u8 *pmk,
int session_timeout)
{
@ -905,6 +982,7 @@ void pmksa_cache_add(struct hostapd_data *hapd, struct sta_info *sta, u8 *pmk,
entry->expiration += dot11RSNAConfigPMKLifetime;
entry->akmp = WPA_KEY_MGMT_IEEE8021X;
memcpy(entry->spa, sta->addr, ETH_ALEN);
pmksa_cache_from_eapol_data(entry, sta->eapol_sm);
/* Replace an old entry for the same STA (if found) with the new entry
*/
@ -961,7 +1039,7 @@ static void pmksa_cache_free(struct hostapd_data *hapd)
while (entry) {
prev = entry;
entry = entry->next;
free(prev);
_pmksa_cache_free_entry(prev);
}
eloop_cancel_timeout(pmksa_cache_expire, hapd, NULL);
for (i = 0; i < PMKID_HASH_SIZE; i++)
@ -1001,7 +1079,7 @@ struct wpa_ie_data {
};
static int wpa_parse_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
struct wpa_ie_data *data)
{
struct wpa_ie_hdr *hdr;
@ -1080,7 +1158,7 @@ static int wpa_parse_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
}
static int wpa_parse_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
static int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
struct wpa_ie_data *data)
{
struct rsn_ie_hdr *hdr;
@ -1174,7 +1252,7 @@ static int wpa_parse_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
int wpa_validate_wpa_ie(struct hostapd_data *hapd, struct sta_info *sta,
u8 *wpa_ie, size_t wpa_ie_len, int version)
const u8 *wpa_ie, size_t wpa_ie_len, int version)
{
struct wpa_ie_data data;
int ciphers, key_mgmt, res, i;
@ -1374,6 +1452,7 @@ void wpa_free_station(struct sta_info *sta)
eloop_cancel_timeout(wpa_send_eapol_timeout, sm->hapd, sta);
eloop_cancel_timeout(wpa_sm_call_step, sm->hapd, sta->wpa_sm);
eloop_cancel_timeout(rsn_preauth_finished_cb, sm->hapd, sta);
free(sm->last_rx_eapol_key);
free(sm);
sta->wpa_sm = NULL;
@ -2090,6 +2169,7 @@ SM_STATE(WPA_PTK, INITPMK)
if (sm->sta->pmksa) {
wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache");
memcpy(sm->PMK, sm->sta->pmksa->pmk, WPA_PMK_LEN);
pmksa_cache_to_eapol_data(sm->sta->pmksa, sm->sta->eapol_sm);
} else if ((key = ieee802_1x_get_key_crypt(sm->sta->eapol_sm, &len))) {
wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine "
"(len=%lu)", (unsigned long) len);
@ -2296,6 +2376,8 @@ SM_STATE(WPA_PTK, PTKINITDONE)
HOSTAPD_LEVEL_INFO, "pairwise key handshake completed "
"(%s)",
sm->sta->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
if (sm->sta->wpa_key_mgmt == WPA_KEY_MGMT_PSK)
accounting_sta_start(sm->hapd, sm->sta);
}