From patchwork Fri Nov 16 15:12:57 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [v2,3/4] cache list of PSK entries Date: Fri, 16 Nov 2012 05:12:57 -0000 From: michael-dev@fami-braun.de X-Patchwork-Id: 199658 Message-Id: <20121116151257.13466.61822.stgit@localhost6.localdomain6> To: hostap@lists.shmoo.com Cc: projekt-wlan@fem.tu-ilmenau.de --- src/ap/hostapd.c | 2 + src/ap/ieee802_11.c | 16 ++++++---- src/ap/ieee802_11_auth.c | 75 +++++++++++++++++++++++++++++----------------- src/ap/ieee802_11_auth.h | 2 + 4 files changed, 60 insertions(+), 35 deletions(-) diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 1c968a7..1e562d4 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -16,6 +16,7 @@ #include "drivers/driver.h" #include "hostapd.h" #include "authsrv.h" +#include "ap_config.h" #include "sta_info.h" #include "accounting.h" #include "ap_list.h" @@ -29,7 +30,6 @@ #include "hw_features.h" #include "wpa_auth_glue.h" #include "ap_drv_ops.h" -#include "ap_config.h" #include "p2p_hostapd.h" #include "gas_serv.h" diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 8d5268e..5f8cca9 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -23,6 +23,7 @@ #include "wps/wps.h" #include "hostapd.h" #include "beacon.h" +#include "ap_config.h" #include "ieee802_11_auth.h" #include "sta_info.h" #include "ieee802_1x.h" @@ -30,7 +31,6 @@ #include "wmm.h" #include "ap_list.h" #include "accounting.h" -#include "ap_config.h" #include "ap_mlme.h" #include "p2p_hostapd.h" #include "ap_drv_ops.h" @@ -443,8 +443,7 @@ static void handle_auth(struct hostapd_data *hapd, const u8 *challenge = NULL; u32 session_timeout, acct_interim_interval; int vlan_id = 0; - u8 psk[PMK_LEN]; - int has_psk = 0; + struct hostapd_sta_wpa_psk_short* psk = NULL; u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; size_t resp_ies_len = 0; char *identity = NULL; @@ -514,7 +513,7 @@ static void handle_auth(struct hostapd_data *hapd, res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len, &session_timeout, &acct_interim_interval, &vlan_id, - psk, &has_psk, &identity, &radius_cui); + &psk, &identity, &radius_cui); if (res == HOSTAPD_ACL_REJECT) { printf("Station " MACSTR " not allowed to authenticate.\n", @@ -553,11 +552,11 @@ static void handle_auth(struct hostapd_data *hapd, 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); sta->psk = os_malloc(PMK_LEN); if (sta->psk) - os_memcpy(sta->psk, psk, PMK_LEN); + os_memcpy(sta->psk, psk->psk, PMK_LEN); } else { os_free(sta->psk); sta->psk = NULL; @@ -636,6 +635,11 @@ static void handle_auth(struct hostapd_data *hapd, fail: os_free(identity); 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, auth_transaction + 1, resp, resp_ies, resp_ies_len); diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c index 12b65b5..7fb2aed 100644 --- a/src/ap/ieee802_11_auth.c +++ b/src/ap/ieee802_11_auth.c @@ -36,8 +36,7 @@ struct hostapd_cached_radius_acl { u32 session_timeout; u32 acct_interim_interval; int vlan_id; - int has_psk; - u8 psk[PMK_LEN]; + struct hostapd_sta_wpa_psk_short* psk; char *identity; char *radius_cui; }; @@ -58,6 +57,12 @@ static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e) { os_free(e->identity); os_free(e->radius_cui); + struct hostapd_sta_wpa_psk_short* psk = e->psk; + while (psk) { + struct hostapd_sta_wpa_psk_short* prev = psk; + psk = psk->next; + os_free(prev); + } os_free(e); } @@ -73,11 +78,10 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache) } } - static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr, u32 *session_timeout, u32 *acct_interim_interval, int *vlan_id, - u8 *psk, int *has_psk, char **identity, + struct hostapd_sta_wpa_psk_short **psk, char **identity, char **radius_cui) { struct hostapd_cached_radius_acl *entry; @@ -99,10 +103,21 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr, entry->acct_interim_interval; if (vlan_id) *vlan_id = entry->vlan_id; - if (psk) - os_memcpy(psk, entry->psk, PMK_LEN); - if (has_psk) - *has_psk = entry->has_psk; + /* copy PSK linked list */ + { + struct hostapd_sta_wpa_psk_short ** copy_to = psk; + struct hostapd_sta_wpa_psk_short * copy_from = entry->psk; + 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; + } if (identity) { if (entry->identity) *identity = os_strdup(entry->identity); @@ -200,8 +215,7 @@ static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr, * @session_timeout: Buffer for returning session timeout (from RADIUS) * @acct_interim_interval: Buffer for returning account interval (from RADIUS) * @vlan_id: Buffer for returning VLAN ID - * @psk: Buffer for returning WPA PSK - * @has_psk: Buffer for indicating whether psk was filled + * @psk: Linked list buffer for returning WPA PSK * @identity: Buffer for returning identity (from RADIUS) * @radius_cui: Buffer for returning CUI (from RADIUS) * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING @@ -212,7 +226,7 @@ static int hostapd_radius_acl_query(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, u32 *acct_interim_interval, int *vlan_id, - u8 *psk, int *has_psk, char **identity, + struct hostapd_sta_wpa_psk_short **psk, char **identity, char **radius_cui) { if (session_timeout) @@ -221,10 +235,8 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, *acct_interim_interval = 0; if (vlan_id) *vlan_id = 0; - if (has_psk) - *has_psk = 0; if (psk) - os_memset(psk, 0, PMK_LEN); + *psk = NULL; if (identity) *identity = NULL; if (radius_cui) @@ -253,7 +265,7 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, /* Check whether ACL cache has an entry for this station */ int res = hostapd_acl_cache_get(hapd, addr, session_timeout, acct_interim_interval, - vlan_id, psk, has_psk, + vlan_id, psk, identity, radius_cui); if (res == HOSTAPD_ACL_ACCEPT || res == HOSTAPD_ACL_ACCEPT_TIMEOUT) @@ -456,6 +468,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) { int passphraselen; char *passphrase; + size_t i; u8 *buf; size_t len; @@ -477,27 +490,35 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, } cache->vlan_id = radius_msg_get_vlanid(msg); - - passphrase = radius_msg_get_tunnel_password( - 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) { + /* 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. */ char *strpassphrase = os_zalloc(passphraselen + 1); - if (strpassphrase) { + struct hostapd_sta_wpa_psk_short* 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, - cache->psk, PMK_LEN); - os_free(strpassphrase); + psk->psk, PMK_LEN); + psk->next = cache->psk; + cache->psk = psk; + psk = NULL; } + os_free(strpassphrase); + os_free(psk); os_free(passphrase); + passphrase = NULL; } if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len, NULL) == 0) { @@ -514,7 +535,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, } if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED && - !cache->has_psk) + !cache->psk) cache->accepted = HOSTAPD_ACL_REJECT; } else cache->accepted = HOSTAPD_ACL_REJECT; diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h index 0e8d1cb..a830115 100644 --- a/src/ap/ieee802_11_auth.h +++ b/src/ap/ieee802_11_auth.h @@ -19,7 +19,7 @@ enum { int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, const u8 *msg, size_t len, u32 *session_timeout, u32 *acct_interim_interval, int *vlan_id, - u8 *psk, int *has_psk, char **identity, + struct hostapd_sta_wpa_psk_short **psk, char **identity, char **radius_cui); int hostapd_acl_init(struct hostapd_data *hapd); void hostapd_acl_deinit(struct hostapd_data *hapd);