RADIUS DAS: Add support for Disconnect-Request
Calling-Station-Id, Acct-Session-Id, and User-Name attributes in a Disconnect-Request message can now be used to indicate which station is to be disconnected. Signed-hostap: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
fc2a924a8c
commit
8047a95809
3 changed files with 150 additions and 4 deletions
|
@ -511,6 +511,75 @@ static int mac_in_conf(struct hostapd_config *conf, const void *a)
|
|||
}
|
||||
|
||||
|
||||
#ifndef CONFIG_NO_RADIUS
|
||||
|
||||
static int hostapd_das_nas_mismatch(struct hostapd_data *hapd,
|
||||
struct radius_das_attrs *attr)
|
||||
{
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
|
||||
struct radius_das_attrs *attr)
|
||||
{
|
||||
struct sta_info *sta = NULL;
|
||||
char buf[128];
|
||||
|
||||
if (attr->sta_addr)
|
||||
sta = ap_get_sta(hapd, attr->sta_addr);
|
||||
|
||||
if (sta == NULL && attr->acct_session_id &&
|
||||
attr->acct_session_id_len == 17) {
|
||||
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||
os_snprintf(buf, sizeof(buf), "%08X-%08X",
|
||||
sta->acct_session_id_hi,
|
||||
sta->acct_session_id_lo);
|
||||
if (os_memcmp(attr->acct_session_id, buf, 17) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sta == NULL && attr->user_name) {
|
||||
for (sta = hapd->sta_list; sta; sta = sta->next) {
|
||||
u8 *identity;
|
||||
size_t identity_len;
|
||||
identity = ieee802_1x_get_identity(sta->eapol_sm,
|
||||
&identity_len);
|
||||
if (identity &&
|
||||
identity_len == attr->user_name_len &&
|
||||
os_memcmp(identity, attr->user_name, identity_len)
|
||||
== 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sta;
|
||||
}
|
||||
|
||||
|
||||
static enum radius_das_res
|
||||
hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
|
||||
{
|
||||
struct hostapd_data *hapd = ctx;
|
||||
struct sta_info *sta;
|
||||
|
||||
if (hostapd_das_nas_mismatch(hapd, attr))
|
||||
return RADIUS_DAS_NAS_MISMATCH;
|
||||
|
||||
sta = hostapd_das_find_sta(hapd, attr);
|
||||
if (sta == NULL)
|
||||
return RADIUS_DAS_SESSION_NOT_FOUND;
|
||||
|
||||
hostapd_drv_sta_deauth(hapd, sta->addr,
|
||||
WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
ap_sta_deauthenticate(hapd, sta, WLAN_REASON_PREV_AUTH_NOT_VALID);
|
||||
|
||||
return RADIUS_DAS_SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NO_RADIUS */
|
||||
|
||||
|
||||
/**
|
||||
|
@ -642,6 +711,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
|
|||
das_conf.time_window = hapd->conf->radius_das_time_window;
|
||||
das_conf.require_event_timestamp =
|
||||
hapd->conf->radius_das_require_event_timestamp;
|
||||
das_conf.ctx = hapd;
|
||||
das_conf.disconnect = hostapd_das_disconnect;
|
||||
hapd->radius_das = radius_das_init(&das_conf);
|
||||
if (hapd->radius_das == NULL) {
|
||||
wpa_printf(MSG_ERROR, "RADIUS DAS initialization "
|
||||
|
|
|
@ -26,6 +26,9 @@ struct radius_das_data {
|
|||
struct hostapd_ip_addr client_addr;
|
||||
unsigned int time_window;
|
||||
int require_event_timestamp;
|
||||
void *ctx;
|
||||
enum radius_das_res (*disconnect)(void *ctx,
|
||||
struct radius_das_attrs *attr);
|
||||
};
|
||||
|
||||
|
||||
|
@ -47,6 +50,12 @@ static struct radius_msg * radius_das_disconnect(struct radius_das_data *das,
|
|||
};
|
||||
int error = 405;
|
||||
u8 attr;
|
||||
enum radius_das_res res;
|
||||
struct radius_das_attrs attrs;
|
||||
u8 *buf;
|
||||
size_t len;
|
||||
char tmp[100];
|
||||
u8 sta_addr[ETH_ALEN];
|
||||
|
||||
hdr = radius_msg_get_hdr(msg);
|
||||
|
||||
|
@ -59,16 +68,63 @@ static struct radius_msg * radius_das_disconnect(struct radius_das_data *das,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
/* TODO */
|
||||
os_memset(&attrs, 0, sizeof(attrs));
|
||||
|
||||
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID,
|
||||
&buf, &len, NULL) == 0) {
|
||||
if (len >= sizeof(tmp))
|
||||
len = sizeof(tmp) - 1;
|
||||
os_memcpy(tmp, buf, len);
|
||||
tmp[len] = '\0';
|
||||
if (hwaddr_aton2(tmp, sta_addr) < 0) {
|
||||
wpa_printf(MSG_INFO, "DAS: Invalid Calling-Station-Id "
|
||||
"'%s' from %s:%d", tmp, abuf, from_port);
|
||||
error = 407;
|
||||
goto fail;
|
||||
}
|
||||
attrs.sta_addr = sta_addr;
|
||||
}
|
||||
|
||||
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
|
||||
&buf, &len, NULL) == 0) {
|
||||
attrs.user_name = buf;
|
||||
attrs.user_name_len = len;
|
||||
}
|
||||
|
||||
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
|
||||
&buf, &len, NULL) == 0) {
|
||||
attrs.acct_session_id = buf;
|
||||
attrs.acct_session_id_len = len;
|
||||
}
|
||||
|
||||
res = das->disconnect(das->ctx, &attrs);
|
||||
switch (res) {
|
||||
case RADIUS_DAS_NAS_MISMATCH:
|
||||
wpa_printf(MSG_INFO, "DAS: NAS mismatch from %s:%d",
|
||||
abuf, from_port);
|
||||
error = 403;
|
||||
break;
|
||||
case RADIUS_DAS_SESSION_NOT_FOUND:
|
||||
wpa_printf(MSG_INFO, "DAS: Session not found for request from "
|
||||
"%s:%d", abuf, from_port);
|
||||
error = 503;
|
||||
break;
|
||||
case RADIUS_DAS_SUCCESS:
|
||||
error = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
fail:
|
||||
reply = radius_msg_new(RADIUS_CODE_DISCONNECT_NAK, hdr->identifier);
|
||||
reply = radius_msg_new(error ? RADIUS_CODE_DISCONNECT_NAK :
|
||||
RADIUS_CODE_DISCONNECT_ACK, hdr->identifier);
|
||||
if (reply == NULL)
|
||||
return NULL;
|
||||
|
||||
radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, error);
|
||||
if (error) {
|
||||
radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE,
|
||||
error);
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
|
@ -240,6 +296,8 @@ radius_das_init(struct radius_das_conf *conf)
|
|||
|
||||
das->time_window = conf->time_window;
|
||||
das->require_event_timestamp = conf->require_event_timestamp;
|
||||
das->ctx = conf->ctx;
|
||||
das->disconnect = conf->disconnect;
|
||||
|
||||
os_memcpy(&das->client_addr, conf->client_addr,
|
||||
sizeof(das->client_addr));
|
||||
|
|
|
@ -11,6 +11,20 @@
|
|||
|
||||
struct radius_das_data;
|
||||
|
||||
enum radius_das_res {
|
||||
RADIUS_DAS_SUCCESS,
|
||||
RADIUS_DAS_NAS_MISMATCH,
|
||||
RADIUS_DAS_SESSION_NOT_FOUND
|
||||
};
|
||||
|
||||
struct radius_das_attrs {
|
||||
const u8 *sta_addr;
|
||||
const u8 *user_name;
|
||||
size_t user_name_len;
|
||||
const u8 *acct_session_id;
|
||||
size_t acct_session_id_len;
|
||||
};
|
||||
|
||||
struct radius_das_conf {
|
||||
int port;
|
||||
const u8 *shared_secret;
|
||||
|
@ -18,6 +32,9 @@ struct radius_das_conf {
|
|||
const struct hostapd_ip_addr *client_addr;
|
||||
unsigned int time_window;
|
||||
int require_event_timestamp;
|
||||
void *ctx;
|
||||
enum radius_das_res (*disconnect)(void *ctx,
|
||||
struct radius_das_attrs *attr);
|
||||
};
|
||||
|
||||
struct radius_das_data *
|
||||
|
|
Loading…
Reference in a new issue