ieee802_11_auth.c

Go to the documentation of this file.
00001 
00021 #include "includes.h"
00022 
00023 #ifndef CONFIG_NATIVE_WINDOWS
00024 
00025 #include "hostapd.h"
00026 #include "config.h"
00027 #include "ieee802_11.h"
00028 #include "ieee802_11_auth.h"
00029 #include "radius/radius.h"
00030 #include "radius/radius_client.h"
00031 #include "eloop.h"
00032 #ifdef CONFIG_DRIVER_RADIUS_ACL
00033 #include "driver_i.h"
00034 #endif /* CONFIG_DRIVER_RADIUS_ACL */
00035 
00036 #define RADIUS_ACL_TIMEOUT 30
00037 
00038 
00039 struct hostapd_cached_radius_acl {
00040         time_t timestamp;
00041         macaddr addr;
00042         int accepted; /* HOSTAPD_ACL_* */
00043         struct hostapd_cached_radius_acl *next;
00044         u32 session_timeout;
00045         u32 acct_interim_interval;
00046         int vlan_id;
00047 };
00048 
00049 
00050 struct hostapd_acl_query_data {
00051         time_t timestamp;
00052         u8 radius_id;
00053         macaddr addr;
00054         u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
00055         size_t auth_msg_len;
00056         struct hostapd_acl_query_data *next;
00057 };
00058 
00059 
00060 #ifndef CONFIG_NO_RADIUS
00061 static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
00062 {
00063         struct hostapd_cached_radius_acl *prev;
00064 
00065         while (acl_cache) {
00066                 prev = acl_cache;
00067                 acl_cache = acl_cache->next;
00068                 os_free(prev);
00069         }
00070 }
00071 
00072 
00073 static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
00074                                  u32 *session_timeout,
00075                                  u32 *acct_interim_interval, int *vlan_id)
00076 {
00077         struct hostapd_cached_radius_acl *entry;
00078         time_t now;
00079 
00080         time(&now);
00081         entry = hapd->acl_cache;
00082 
00083         while (entry) {
00084                 if (os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
00085                         if (now - entry->timestamp > RADIUS_ACL_TIMEOUT)
00086                                 return -1; /* entry has expired */
00087                         if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
00088                                 if (session_timeout)
00089                                         *session_timeout =
00090                                                 entry->session_timeout;
00091                         if (acct_interim_interval)
00092                                 *acct_interim_interval =
00093                                         entry->acct_interim_interval;
00094                         if (vlan_id)
00095                                 *vlan_id = entry->vlan_id;
00096                         return entry->accepted;
00097                 }
00098 
00099                 entry = entry->next;
00100         }
00101 
00102         return -1;
00103 }
00104 #endif /* CONFIG_NO_RADIUS */
00105 
00106 
00107 static void hostapd_acl_query_free(struct hostapd_acl_query_data *query)
00108 {
00109         if (query == NULL)
00110                 return;
00111         os_free(query->auth_msg);
00112         os_free(query);
00113 }
00114 
00115 
00116 #ifndef CONFIG_NO_RADIUS
00117 static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
00118                                     struct hostapd_acl_query_data *query)
00119 {
00120         struct radius_msg *msg;
00121         char buf[128];
00122 
00123         query->radius_id = radius_client_get_id(hapd->radius);
00124         msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id);
00125         if (msg == NULL)
00126                 return -1;
00127 
00128         radius_msg_make_authenticator(msg, addr, ETH_ALEN);
00129 
00130         os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
00131         if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
00132                                  os_strlen(buf))) {
00133                 wpa_printf(MSG_DEBUG, "Could not add User-Name");
00134                 goto fail;
00135         }
00136 
00137         if (!radius_msg_add_attr_user_password(
00138                     msg, (u8 *) buf, os_strlen(buf),
00139                     hapd->conf->radius->auth_server->shared_secret,
00140                     hapd->conf->radius->auth_server->shared_secret_len)) {
00141                 wpa_printf(MSG_DEBUG, "Could not add User-Password");
00142                 goto fail;
00143         }
00144 
00145         if (hapd->conf->own_ip_addr.af == AF_INET &&
00146             !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
00147                                  (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
00148                 wpa_printf(MSG_DEBUG, "Could not add NAS-IP-Address");
00149                 goto fail;
00150         }
00151 
00152 #ifdef CONFIG_IPV6
00153         if (hapd->conf->own_ip_addr.af == AF_INET6 &&
00154             !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
00155                                  (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
00156                 wpa_printf(MSG_DEBUG, "Could not add NAS-IPv6-Address");
00157                 goto fail;
00158         }
00159 #endif /* CONFIG_IPV6 */
00160 
00161         if (hapd->conf->nas_identifier &&
00162             !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
00163                                  (u8 *) hapd->conf->nas_identifier,
00164                                  os_strlen(hapd->conf->nas_identifier))) {
00165                 wpa_printf(MSG_DEBUG, "Could not add NAS-Identifier");
00166                 goto fail;
00167         }
00168 
00169         os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
00170                     MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
00171         if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
00172                                  (u8 *) buf, os_strlen(buf))) {
00173                 wpa_printf(MSG_DEBUG, "Could not add Called-Station-Id");
00174                 goto fail;
00175         }
00176 
00177         os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
00178                     MAC2STR(addr));
00179         if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
00180                                  (u8 *) buf, os_strlen(buf))) {
00181                 wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id");
00182                 goto fail;
00183         }
00184 
00185         if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
00186                                        RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
00187                 wpa_printf(MSG_DEBUG, "Could not add NAS-Port-Type");
00188                 goto fail;
00189         }
00190 
00191         os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
00192         if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
00193                                  (u8 *) buf, os_strlen(buf))) {
00194                 wpa_printf(MSG_DEBUG, "Could not add Connect-Info");
00195                 goto fail;
00196         }
00197 
00198         radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr);
00199         return 0;
00200 
00201  fail:
00202         radius_msg_free(msg);
00203         os_free(msg);
00204         return -1;
00205 }
00206 #endif /* CONFIG_NO_RADIUS */
00207 
00208 
00221 int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
00222                             const u8 *msg, size_t len, u32 *session_timeout,
00223                             u32 *acct_interim_interval, int *vlan_id)
00224 {
00225         if (session_timeout)
00226                 *session_timeout = 0;
00227         if (acct_interim_interval)
00228                 *acct_interim_interval = 0;
00229         if (vlan_id)
00230                 *vlan_id = 0;
00231 
00232         if (hostapd_maclist_found(hapd->conf->accept_mac,
00233                                   hapd->conf->num_accept_mac, addr, vlan_id))
00234                 return HOSTAPD_ACL_ACCEPT;
00235 
00236         if (hostapd_maclist_found(hapd->conf->deny_mac,
00237                                   hapd->conf->num_deny_mac, addr, vlan_id))
00238                 return HOSTAPD_ACL_REJECT;
00239 
00240         if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED)
00241                 return HOSTAPD_ACL_ACCEPT;
00242         if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED)
00243                 return HOSTAPD_ACL_REJECT;
00244 
00245         if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) {
00246 #ifdef CONFIG_NO_RADIUS
00247                 return HOSTAPD_ACL_REJECT;
00248 #else /* CONFIG_NO_RADIUS */
00249                 struct hostapd_acl_query_data *query;
00250 
00251                 /* Check whether ACL cache has an entry for this station */
00252                 int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
00253                                                 acct_interim_interval,
00254                                                 vlan_id);
00255                 if (res == HOSTAPD_ACL_ACCEPT ||
00256                     res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
00257                         return res;
00258                 if (res == HOSTAPD_ACL_REJECT)
00259                         return HOSTAPD_ACL_REJECT;
00260 
00261                 query = hapd->acl_queries;
00262                 while (query) {
00263                         if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
00264                                 /* pending query in RADIUS retransmit queue;
00265                                  * do not generate a new one */
00266                                 return HOSTAPD_ACL_PENDING;
00267                         }
00268                         query = query->next;
00269                 }
00270 
00271                 if (!hapd->conf->radius->auth_server)
00272                         return HOSTAPD_ACL_REJECT;
00273 
00274                 /* No entry in the cache - query external RADIUS server */
00275                 query = os_zalloc(sizeof(*query));
00276                 if (query == NULL) {
00277                         wpa_printf(MSG_ERROR, "malloc for query data failed");
00278                         return HOSTAPD_ACL_REJECT;
00279                 }
00280                 time(&query->timestamp);
00281                 os_memcpy(query->addr, addr, ETH_ALEN);
00282                 if (hostapd_radius_acl_query(hapd, addr, query)) {
00283                         wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
00284                                    "for ACL query.");
00285                         hostapd_acl_query_free(query);
00286                         return HOSTAPD_ACL_REJECT;
00287                 }
00288 
00289                 query->auth_msg = os_malloc(len);
00290                 if (query->auth_msg == NULL) {
00291                         wpa_printf(MSG_ERROR, "Failed to allocate memory for "
00292                                    "auth frame.");
00293                         hostapd_acl_query_free(query);
00294                         return HOSTAPD_ACL_REJECT;
00295                 }
00296                 os_memcpy(query->auth_msg, msg, len);
00297                 query->auth_msg_len = len;
00298                 query->next = hapd->acl_queries;
00299                 hapd->acl_queries = query;
00300 
00301                 /* Queued data will be processed in hostapd_acl_recv_radius()
00302                  * when RADIUS server replies to the sent Access-Request. */
00303                 return HOSTAPD_ACL_PENDING;
00304 #endif /* CONFIG_NO_RADIUS */
00305         }
00306 
00307         return HOSTAPD_ACL_REJECT;
00308 }
00309 
00310 
00311 #ifndef CONFIG_NO_RADIUS
00312 static void hostapd_acl_expire_cache(struct hostapd_data *hapd, time_t now)
00313 {
00314         struct hostapd_cached_radius_acl *prev, *entry, *tmp;
00315 
00316         prev = NULL;
00317         entry = hapd->acl_cache;
00318 
00319         while (entry) {
00320                 if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
00321                         wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR
00322                                    " has expired.", MAC2STR(entry->addr));
00323                         if (prev)
00324                                 prev->next = entry->next;
00325                         else
00326                                 hapd->acl_cache = entry->next;
00327 #ifdef CONFIG_DRIVER_RADIUS_ACL
00328                         hostapd_set_radius_acl_expire(hapd, entry->addr);
00329 #endif /* CONFIG_DRIVER_RADIUS_ACL */
00330                         tmp = entry;
00331                         entry = entry->next;
00332                         os_free(tmp);
00333                         continue;
00334                 }
00335 
00336                 prev = entry;
00337                 entry = entry->next;
00338         }
00339 }
00340 
00341 
00342 static void hostapd_acl_expire_queries(struct hostapd_data *hapd, time_t now)
00343 {
00344         struct hostapd_acl_query_data *prev, *entry, *tmp;
00345 
00346         prev = NULL;
00347         entry = hapd->acl_queries;
00348 
00349         while (entry) {
00350                 if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
00351                         wpa_printf(MSG_DEBUG, "ACL query for " MACSTR
00352                                    " has expired.", MAC2STR(entry->addr));
00353                         if (prev)
00354                                 prev->next = entry->next;
00355                         else
00356                                 hapd->acl_queries = entry->next;
00357 
00358                         tmp = entry;
00359                         entry = entry->next;
00360                         hostapd_acl_query_free(tmp);
00361                         continue;
00362                 }
00363 
00364                 prev = entry;
00365                 entry = entry->next;
00366         }
00367 }
00368 
00369 
00376 static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
00377 {
00378         struct hostapd_data *hapd = eloop_ctx;
00379         time_t now;
00380 
00381         time(&now);
00382         hostapd_acl_expire_cache(hapd, now);
00383         hostapd_acl_expire_queries(hapd, now);
00384 
00385         eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
00386 }
00387 
00388 
00400 static RadiusRxResult
00401 hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
00402                         const u8 *shared_secret, size_t shared_secret_len,
00403                         void *data)
00404 {
00405         struct hostapd_data *hapd = data;
00406         struct hostapd_acl_query_data *query, *prev;
00407         struct hostapd_cached_radius_acl *cache;
00408 
00409         query = hapd->acl_queries;
00410         prev = NULL;
00411         while (query) {
00412                 if (query->radius_id == msg->hdr->identifier)
00413                         break;
00414                 prev = query;
00415                 query = query->next;
00416         }
00417         if (query == NULL)
00418                 return RADIUS_RX_UNKNOWN;
00419 
00420         wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS "
00421                    "message (id=%d)", query->radius_id);
00422 
00423         if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
00424                 wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have "
00425                            "correct authenticator - dropped\n");
00426                 return RADIUS_RX_INVALID_AUTHENTICATOR;
00427         }
00428 
00429         if (msg->hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
00430             msg->hdr->code != RADIUS_CODE_ACCESS_REJECT) {
00431                 wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL "
00432                            "query", msg->hdr->code);
00433                 return RADIUS_RX_UNKNOWN;
00434         }
00435 
00436         /* Insert Accept/Reject info into ACL cache */
00437         cache = os_zalloc(sizeof(*cache));
00438         if (cache == NULL) {
00439                 wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
00440                 goto done;
00441         }
00442         time(&cache->timestamp);
00443         os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
00444         if (msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
00445                 if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
00446                                               &cache->session_timeout) == 0)
00447                         cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
00448                 else
00449                         cache->accepted = HOSTAPD_ACL_ACCEPT;
00450 
00451                 if (radius_msg_get_attr_int32(
00452                             msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
00453                             &cache->acct_interim_interval) == 0 &&
00454                     cache->acct_interim_interval < 60) {
00455                         wpa_printf(MSG_DEBUG, "Ignored too small "
00456                                    "Acct-Interim-Interval %d for STA " MACSTR,
00457                                    cache->acct_interim_interval,
00458                                    MAC2STR(query->addr));
00459                         cache->acct_interim_interval = 0;
00460                 }
00461 
00462                 cache->vlan_id = radius_msg_get_vlanid(msg);
00463         } else
00464                 cache->accepted = HOSTAPD_ACL_REJECT;
00465         cache->next = hapd->acl_cache;
00466         hapd->acl_cache = cache;
00467 
00468 #ifdef CONFIG_DRIVER_RADIUS_ACL
00469         hostapd_set_radius_acl_auth(hapd, query->addr, cache->accepted,
00470                                     cache->session_timeout);
00471 #else /* CONFIG_DRIVER_RADIUS_ACL */
00472 #ifdef NEED_AP_MLME
00473         /* Re-send original authentication frame for 802.11 processing */
00474         wpa_printf(MSG_DEBUG, "Re-sending authentication frame after "
00475                    "successful RADIUS ACL query");
00476         ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len,
00477                         WLAN_FC_STYPE_AUTH, NULL);
00478 #endif /* NEED_AP_MLME */
00479 #endif /* CONFIG_DRIVER_RADIUS_ACL */
00480 
00481  done:
00482         if (prev == NULL)
00483                 hapd->acl_queries = query->next;
00484         else
00485                 prev->next = query->next;
00486 
00487         hostapd_acl_query_free(query);
00488 
00489         return RADIUS_RX_PROCESSED;
00490 }
00491 #endif /* CONFIG_NO_RADIUS */
00492 
00493 
00499 int hostapd_acl_init(struct hostapd_data *hapd)
00500 {
00501 #ifndef CONFIG_NO_RADIUS
00502         if (radius_client_register(hapd->radius, RADIUS_AUTH,
00503                                    hostapd_acl_recv_radius, hapd))
00504                 return -1;
00505 
00506         eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
00507 #endif /* CONFIG_NO_RADIUS */
00508 
00509         return 0;
00510 }
00511 
00512 
00518 void hostapd_acl_deinit(struct hostapd_data *hapd)
00519 {
00520         struct hostapd_acl_query_data *query, *prev;
00521 
00522 #ifndef CONFIG_NO_RADIUS
00523         eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL);
00524 
00525         hostapd_acl_cache_free(hapd->acl_cache);
00526 #endif /* CONFIG_NO_RADIUS */
00527 
00528         query = hapd->acl_queries;
00529         while (query) {
00530                 prev = query;
00531                 query = query->next;
00532                 hostapd_acl_query_free(prev);
00533         }
00534 }
00535 
00536 
00537 int hostapd_acl_reconfig(struct hostapd_data *hapd,
00538                          struct hostapd_config *oldconf)
00539 {
00540         if (!hapd->radius_client_reconfigured)
00541                 return 0;
00542 
00543         hostapd_acl_deinit(hapd);
00544         return hostapd_acl_init(hapd);
00545 }
00546 
00547 #endif /* CONFIG_NATIVE_WINDOWS */
00548 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on Sat Nov 21 23:16:48 2009 for hostapd by  doxygen 1.6.1