]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Cache a list of PSK entries for RADIUS-based PSK delivery
authorMichael Braun <michael-dev@fami-braun.de>
Sun, 25 Nov 2012 15:41:13 +0000 (17:41 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 25 Nov 2012 15:57:16 +0000 (17:57 +0200)
Signed-hostap: Michael Braun <michael-dev@fami-braun.de>

src/ap/ap_config.h
src/ap/ieee802_11.c
src/ap/ieee802_11_auth.c
src/ap/ieee802_11_auth.h

index 010d2164510eaf5887db5ff41dec4a6863bef9dd..71313c02379a203aeecc7dfd7b9e8cba5003b5e8 100644 (file)
@@ -96,6 +96,11 @@ struct hostapd_vlan {
 };
 
 #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 *next;
        int group;
index 366cbb664331096c1a0ac0f66459003c54db08ad..3bc7059db506e3e506003fbe2c6a1cb19c9e2487 100644 (file)
@@ -461,8 +461,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;
@@ -532,7 +531,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",
@@ -571,11 +570,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;
@@ -654,6 +653,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);
index 12b65b59316812c7495d3db635fbe2480e43d09f..0a406c7483b3a21a43ebf92b53c7d078e8ffb7eb 100644 (file)
@@ -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;
 };
@@ -56,8 +55,14 @@ struct hostapd_acl_query_data {
 #ifndef CONFIG_NO_RADIUS
 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->radius_cui);
+       while (psk) {
+               struct hostapd_sta_wpa_psk_short *prev = psk;
+               psk = psk->next;
+               os_free(prev);
+       }
        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,
                                 u32 *session_timeout,
                                 u32 *acct_interim_interval, int *vlan_id,
-                                u8 *psk, int *has_psk, char **identity,
-                                char **radius_cui)
+                                struct hostapd_sta_wpa_psk_short **psk,
+                                char **identity, char **radius_cui)
 {
        struct hostapd_cached_radius_acl *entry;
        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;
                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_list(psk, entry->psk);
                if (identity) {
                        if (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)
  * @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,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,
                            const u8 *msg, size_t len, u32 *session_timeout,
                            u32 *acct_interim_interval, int *vlan_id,
-                           u8 *psk, int *has_psk, char **identity,
-                           char **radius_cui)
+                           struct hostapd_sta_wpa_psk_short **psk,
+                           char **identity, char **radius_cui)
 {
        if (session_timeout)
                *session_timeout = 0;
@@ -221,10 +245,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 +275,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)
@@ -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
  * @msg: RADIUS response message
@@ -454,8 +524,6 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
        cache->timestamp = t.sec;
        os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
        if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
-               int passphraselen;
-               char *passphrase;
                u8 *buf;
                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);
 
-               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) {
-                       /* 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);
-               }
+               decode_tunnel_passwords(hapd, msg, req, cache);
+
                if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
                                            &buf, &len, NULL) == 0) {
                        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 &&
-                   !cache->has_psk)
+                   !cache->psk)
                        cache->accepted = HOSTAPD_ACL_REJECT;
        } else
                cache->accepted = HOSTAPD_ACL_REJECT;
index 0e8d1cb1b9176da5e04c9a12b4c2f10dfa02e547..7bbc09ae4e339960eb53495a2668cdadeb12b1cb 100644 (file)
@@ -19,8 +19,8 @@ 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,
-                           char **radius_cui);
+                           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);