Cache a list of PSK entries for RADIUS-based PSK delivery
Signed-hostap: Michael Braun <michael-dev@fami-braun.de>
This commit is contained in:
parent
14e919478e
commit
2ad3e6c858
4 changed files with 105 additions and 47 deletions
|
@ -96,6 +96,11 @@ struct hostapd_vlan {
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PMK_LEN 32
|
#define PMK_LEN 32
|
||||||
|
struct hostapd_sta_wpa_psk_short {
|
||||||
|
struct hostapd_sta_wpa_psk_short *next;
|
||||||
|
u8 psk[PMK_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
struct hostapd_wpa_psk {
|
struct hostapd_wpa_psk {
|
||||||
struct hostapd_wpa_psk *next;
|
struct hostapd_wpa_psk *next;
|
||||||
int group;
|
int group;
|
||||||
|
|
|
@ -461,8 +461,7 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
const u8 *challenge = NULL;
|
const u8 *challenge = NULL;
|
||||||
u32 session_timeout, acct_interim_interval;
|
u32 session_timeout, acct_interim_interval;
|
||||||
int vlan_id = 0;
|
int vlan_id = 0;
|
||||||
u8 psk[PMK_LEN];
|
struct hostapd_sta_wpa_psk_short *psk = NULL;
|
||||||
int has_psk = 0;
|
|
||||||
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
|
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
|
||||||
size_t resp_ies_len = 0;
|
size_t resp_ies_len = 0;
|
||||||
char *identity = NULL;
|
char *identity = NULL;
|
||||||
|
@ -532,7 +531,7 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
|
res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
|
||||||
&session_timeout,
|
&session_timeout,
|
||||||
&acct_interim_interval, &vlan_id,
|
&acct_interim_interval, &vlan_id,
|
||||||
psk, &has_psk, &identity, &radius_cui);
|
&psk, &identity, &radius_cui);
|
||||||
|
|
||||||
if (res == HOSTAPD_ACL_REJECT) {
|
if (res == HOSTAPD_ACL_REJECT) {
|
||||||
printf("Station " MACSTR " not allowed to authenticate.\n",
|
printf("Station " MACSTR " not allowed to authenticate.\n",
|
||||||
|
@ -571,11 +570,11 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
|
HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_psk && hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
|
if (psk && hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
|
||||||
os_free(sta->psk);
|
os_free(sta->psk);
|
||||||
sta->psk = os_malloc(PMK_LEN);
|
sta->psk = os_malloc(PMK_LEN);
|
||||||
if (sta->psk)
|
if (sta->psk)
|
||||||
os_memcpy(sta->psk, psk, PMK_LEN);
|
os_memcpy(sta->psk, psk->psk, PMK_LEN);
|
||||||
} else {
|
} else {
|
||||||
os_free(sta->psk);
|
os_free(sta->psk);
|
||||||
sta->psk = NULL;
|
sta->psk = NULL;
|
||||||
|
@ -654,6 +653,11 @@ static void handle_auth(struct hostapd_data *hapd,
|
||||||
fail:
|
fail:
|
||||||
os_free(identity);
|
os_free(identity);
|
||||||
os_free(radius_cui);
|
os_free(radius_cui);
|
||||||
|
while (psk) {
|
||||||
|
struct hostapd_sta_wpa_psk_short *prev = psk;
|
||||||
|
psk = psk->next;
|
||||||
|
os_free(prev);
|
||||||
|
}
|
||||||
|
|
||||||
send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
|
send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
|
||||||
auth_transaction + 1, resp, resp_ies, resp_ies_len);
|
auth_transaction + 1, resp, resp_ies, resp_ies_len);
|
||||||
|
|
|
@ -36,8 +36,7 @@ struct hostapd_cached_radius_acl {
|
||||||
u32 session_timeout;
|
u32 session_timeout;
|
||||||
u32 acct_interim_interval;
|
u32 acct_interim_interval;
|
||||||
int vlan_id;
|
int vlan_id;
|
||||||
int has_psk;
|
struct hostapd_sta_wpa_psk_short *psk;
|
||||||
u8 psk[PMK_LEN];
|
|
||||||
char *identity;
|
char *identity;
|
||||||
char *radius_cui;
|
char *radius_cui;
|
||||||
};
|
};
|
||||||
|
@ -56,8 +55,14 @@ struct hostapd_acl_query_data {
|
||||||
#ifndef CONFIG_NO_RADIUS
|
#ifndef CONFIG_NO_RADIUS
|
||||||
static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
|
static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
|
||||||
{
|
{
|
||||||
|
struct hostapd_sta_wpa_psk_short *psk = e->psk;
|
||||||
os_free(e->identity);
|
os_free(e->identity);
|
||||||
os_free(e->radius_cui);
|
os_free(e->radius_cui);
|
||||||
|
while (psk) {
|
||||||
|
struct hostapd_sta_wpa_psk_short *prev = psk;
|
||||||
|
psk = psk->next;
|
||||||
|
os_free(prev);
|
||||||
|
}
|
||||||
os_free(e);
|
os_free(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,11 +79,34 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
|
||||||
|
struct hostapd_sta_wpa_psk_short *src)
|
||||||
|
{
|
||||||
|
struct hostapd_sta_wpa_psk_short **copy_to;
|
||||||
|
struct hostapd_sta_wpa_psk_short *copy_from;
|
||||||
|
|
||||||
|
/* Copy PSK linked list */
|
||||||
|
copy_to = psk;
|
||||||
|
copy_from = src;
|
||||||
|
while (copy_from && copy_to) {
|
||||||
|
*copy_to = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
|
||||||
|
if (*copy_to == NULL)
|
||||||
|
break;
|
||||||
|
os_memcpy(*copy_to, copy_from,
|
||||||
|
sizeof(struct hostapd_sta_wpa_psk_short));
|
||||||
|
copy_from = copy_from->next;
|
||||||
|
copy_to = &((*copy_to)->next);
|
||||||
|
}
|
||||||
|
if (copy_to)
|
||||||
|
*copy_to = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
|
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
|
||||||
u32 *session_timeout,
|
u32 *session_timeout,
|
||||||
u32 *acct_interim_interval, int *vlan_id,
|
u32 *acct_interim_interval, int *vlan_id,
|
||||||
u8 *psk, int *has_psk, char **identity,
|
struct hostapd_sta_wpa_psk_short **psk,
|
||||||
char **radius_cui)
|
char **identity, char **radius_cui)
|
||||||
{
|
{
|
||||||
struct hostapd_cached_radius_acl *entry;
|
struct hostapd_cached_radius_acl *entry;
|
||||||
struct os_time now;
|
struct os_time now;
|
||||||
|
@ -99,10 +127,7 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
|
||||||
entry->acct_interim_interval;
|
entry->acct_interim_interval;
|
||||||
if (vlan_id)
|
if (vlan_id)
|
||||||
*vlan_id = entry->vlan_id;
|
*vlan_id = entry->vlan_id;
|
||||||
if (psk)
|
copy_psk_list(psk, entry->psk);
|
||||||
os_memcpy(psk, entry->psk, PMK_LEN);
|
|
||||||
if (has_psk)
|
|
||||||
*has_psk = entry->has_psk;
|
|
||||||
if (identity) {
|
if (identity) {
|
||||||
if (entry->identity)
|
if (entry->identity)
|
||||||
*identity = os_strdup(entry->identity);
|
*identity = os_strdup(entry->identity);
|
||||||
|
@ -200,8 +225,7 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
|
||||||
* @session_timeout: Buffer for returning session timeout (from RADIUS)
|
* @session_timeout: Buffer for returning session timeout (from RADIUS)
|
||||||
* @acct_interim_interval: Buffer for returning account interval (from RADIUS)
|
* @acct_interim_interval: Buffer for returning account interval (from RADIUS)
|
||||||
* @vlan_id: Buffer for returning VLAN ID
|
* @vlan_id: Buffer for returning VLAN ID
|
||||||
* @psk: Buffer for returning WPA PSK
|
* @psk: Linked list buffer for returning WPA PSK
|
||||||
* @has_psk: Buffer for indicating whether psk was filled
|
|
||||||
* @identity: Buffer for returning identity (from RADIUS)
|
* @identity: Buffer for returning identity (from RADIUS)
|
||||||
* @radius_cui: Buffer for returning CUI (from RADIUS)
|
* @radius_cui: Buffer for returning CUI (from RADIUS)
|
||||||
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
|
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
|
||||||
|
@ -212,8 +236,8 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
|
||||||
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||||
const u8 *msg, size_t len, u32 *session_timeout,
|
const u8 *msg, size_t len, u32 *session_timeout,
|
||||||
u32 *acct_interim_interval, int *vlan_id,
|
u32 *acct_interim_interval, int *vlan_id,
|
||||||
u8 *psk, int *has_psk, char **identity,
|
struct hostapd_sta_wpa_psk_short **psk,
|
||||||
char **radius_cui)
|
char **identity, char **radius_cui)
|
||||||
{
|
{
|
||||||
if (session_timeout)
|
if (session_timeout)
|
||||||
*session_timeout = 0;
|
*session_timeout = 0;
|
||||||
|
@ -221,10 +245,8 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||||
*acct_interim_interval = 0;
|
*acct_interim_interval = 0;
|
||||||
if (vlan_id)
|
if (vlan_id)
|
||||||
*vlan_id = 0;
|
*vlan_id = 0;
|
||||||
if (has_psk)
|
|
||||||
*has_psk = 0;
|
|
||||||
if (psk)
|
if (psk)
|
||||||
os_memset(psk, 0, PMK_LEN);
|
*psk = NULL;
|
||||||
if (identity)
|
if (identity)
|
||||||
*identity = NULL;
|
*identity = NULL;
|
||||||
if (radius_cui)
|
if (radius_cui)
|
||||||
|
@ -253,7 +275,7 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||||
/* Check whether ACL cache has an entry for this station */
|
/* Check whether ACL cache has an entry for this station */
|
||||||
int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
|
int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
|
||||||
acct_interim_interval,
|
acct_interim_interval,
|
||||||
vlan_id, psk, has_psk,
|
vlan_id, psk,
|
||||||
identity, radius_cui);
|
identity, radius_cui);
|
||||||
if (res == HOSTAPD_ACL_ACCEPT ||
|
if (res == HOSTAPD_ACL_ACCEPT ||
|
||||||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
|
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
|
||||||
|
@ -396,6 +418,54 @@ static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void decode_tunnel_passwords(struct hostapd_data *hapd,
|
||||||
|
struct radius_msg *msg,
|
||||||
|
struct radius_msg *req,
|
||||||
|
struct hostapd_cached_radius_acl *cache)
|
||||||
|
{
|
||||||
|
int passphraselen;
|
||||||
|
char *passphrase, *strpassphrase;
|
||||||
|
size_t i;
|
||||||
|
struct hostapd_sta_wpa_psk_short *psk;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decode all tunnel passwords as PSK and save them into a linked list.
|
||||||
|
*/
|
||||||
|
for (i = 0; ; i++) {
|
||||||
|
passphrase = radius_msg_get_tunnel_password(
|
||||||
|
msg, &passphraselen,
|
||||||
|
hapd->conf->radius->auth_server->shared_secret,
|
||||||
|
hapd->conf->radius->auth_server->shared_secret_len,
|
||||||
|
req, i);
|
||||||
|
/*
|
||||||
|
* Passphrase is NULL iff there is no i-th Tunnel-Password
|
||||||
|
* attribute in msg.
|
||||||
|
*/
|
||||||
|
if (passphrase == NULL)
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
* passphrase does not contain the NULL termination.
|
||||||
|
* Add it here as pbkdf2_sha1() requires it.
|
||||||
|
*/
|
||||||
|
strpassphrase = os_zalloc(passphraselen + 1);
|
||||||
|
psk = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
|
||||||
|
if (strpassphrase && psk) {
|
||||||
|
os_memcpy(strpassphrase, passphrase, passphraselen);
|
||||||
|
pbkdf2_sha1(strpassphrase,
|
||||||
|
hapd->conf->ssid.ssid,
|
||||||
|
hapd->conf->ssid.ssid_len, 4096,
|
||||||
|
psk->psk, PMK_LEN);
|
||||||
|
psk->next = cache->psk;
|
||||||
|
cache->psk = psk;
|
||||||
|
psk = NULL;
|
||||||
|
}
|
||||||
|
os_free(strpassphrase);
|
||||||
|
os_free(psk);
|
||||||
|
os_free(passphrase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages
|
* hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages
|
||||||
* @msg: RADIUS response message
|
* @msg: RADIUS response message
|
||||||
|
@ -454,8 +524,6 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
|
||||||
cache->timestamp = t.sec;
|
cache->timestamp = t.sec;
|
||||||
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
|
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
|
||||||
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
|
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
|
||||||
int passphraselen;
|
|
||||||
char *passphrase;
|
|
||||||
u8 *buf;
|
u8 *buf;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
|
@ -478,27 +546,8 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
|
||||||
|
|
||||||
cache->vlan_id = radius_msg_get_vlanid(msg);
|
cache->vlan_id = radius_msg_get_vlanid(msg);
|
||||||
|
|
||||||
passphrase = radius_msg_get_tunnel_password(
|
decode_tunnel_passwords(hapd, msg, req, cache);
|
||||||
msg, &passphraselen,
|
|
||||||
hapd->conf->radius->auth_server->shared_secret,
|
|
||||||
hapd->conf->radius->auth_server->shared_secret_len,
|
|
||||||
req, 0);
|
|
||||||
cache->has_psk = passphrase != NULL;
|
|
||||||
if (passphrase != NULL) {
|
|
||||||
/* passphrase does not contain the NULL termination.
|
|
||||||
* Add it here as pbkdf2_sha1 requires it. */
|
|
||||||
char *strpassphrase = os_zalloc(passphraselen + 1);
|
|
||||||
if (strpassphrase) {
|
|
||||||
os_memcpy(strpassphrase, passphrase,
|
|
||||||
passphraselen);
|
|
||||||
pbkdf2_sha1(strpassphrase,
|
|
||||||
hapd->conf->ssid.ssid,
|
|
||||||
hapd->conf->ssid.ssid_len, 4096,
|
|
||||||
cache->psk, PMK_LEN);
|
|
||||||
os_free(strpassphrase);
|
|
||||||
}
|
|
||||||
os_free(passphrase);
|
|
||||||
}
|
|
||||||
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
|
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
|
||||||
&buf, &len, NULL) == 0) {
|
&buf, &len, NULL) == 0) {
|
||||||
cache->identity = os_zalloc(len + 1);
|
cache->identity = os_zalloc(len + 1);
|
||||||
|
@ -514,7 +563,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
|
if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
|
||||||
!cache->has_psk)
|
!cache->psk)
|
||||||
cache->accepted = HOSTAPD_ACL_REJECT;
|
cache->accepted = HOSTAPD_ACL_REJECT;
|
||||||
} else
|
} else
|
||||||
cache->accepted = HOSTAPD_ACL_REJECT;
|
cache->accepted = HOSTAPD_ACL_REJECT;
|
||||||
|
|
|
@ -19,8 +19,8 @@ enum {
|
||||||
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
|
||||||
const u8 *msg, size_t len, u32 *session_timeout,
|
const u8 *msg, size_t len, u32 *session_timeout,
|
||||||
u32 *acct_interim_interval, int *vlan_id,
|
u32 *acct_interim_interval, int *vlan_id,
|
||||||
u8 *psk, int *has_psk, char **identity,
|
struct hostapd_sta_wpa_psk_short **psk,
|
||||||
char **radius_cui);
|
char **identity, char **radius_cui);
|
||||||
int hostapd_acl_init(struct hostapd_data *hapd);
|
int hostapd_acl_init(struct hostapd_data *hapd);
|
||||||
void hostapd_acl_deinit(struct hostapd_data *hapd);
|
void hostapd_acl_deinit(struct hostapd_data *hapd);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue