$search
00001 /* 00002 * hostapd / IEEE 802.11 authentication (ACL) 00003 * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 * 00014 * Access control list for IEEE 802.11 authentication can uses statically 00015 * configured ACL from configuration files or an external RADIUS server. 00016 * Results from external RADIUS queries are cached to allow faster 00017 * authentication frame processing. 00018 */ 00019 00020 #include "utils/includes.h" 00021 00022 #include "utils/common.h" 00023 #include "utils/eloop.h" 00024 #include "radius/radius.h" 00025 #include "radius/radius_client.h" 00026 #include "hostapd.h" 00027 #include "ap_config.h" 00028 #include "ieee802_11.h" 00029 #include "ieee802_11_auth.h" 00030 00031 #define RADIUS_ACL_TIMEOUT 30 00032 00033 00034 struct hostapd_cached_radius_acl { 00035 time_t timestamp; 00036 macaddr addr; 00037 int accepted; /* HOSTAPD_ACL_* */ 00038 struct hostapd_cached_radius_acl *next; 00039 u32 session_timeout; 00040 u32 acct_interim_interval; 00041 int vlan_id; 00042 }; 00043 00044 00045 struct hostapd_acl_query_data { 00046 time_t timestamp; 00047 u8 radius_id; 00048 macaddr addr; 00049 u8 *auth_msg; /* IEEE 802.11 authentication frame from station */ 00050 size_t auth_msg_len; 00051 struct hostapd_acl_query_data *next; 00052 }; 00053 00054 00055 #ifndef CONFIG_NO_RADIUS 00056 static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache) 00057 { 00058 struct hostapd_cached_radius_acl *prev; 00059 00060 while (acl_cache) { 00061 prev = acl_cache; 00062 acl_cache = acl_cache->next; 00063 os_free(prev); 00064 } 00065 } 00066 00067 00068 static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr, 00069 u32 *session_timeout, 00070 u32 *acct_interim_interval, int *vlan_id) 00071 { 00072 struct hostapd_cached_radius_acl *entry; 00073 time_t now; 00074 00075 time(&now); 00076 entry = hapd->acl_cache; 00077 00078 while (entry) { 00079 if (os_memcmp(entry->addr, addr, ETH_ALEN) == 0) { 00080 if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) 00081 return -1; /* entry has expired */ 00082 if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT) 00083 if (session_timeout) 00084 *session_timeout = 00085 entry->session_timeout; 00086 if (acct_interim_interval) 00087 *acct_interim_interval = 00088 entry->acct_interim_interval; 00089 if (vlan_id) 00090 *vlan_id = entry->vlan_id; 00091 return entry->accepted; 00092 } 00093 00094 entry = entry->next; 00095 } 00096 00097 return -1; 00098 } 00099 #endif /* CONFIG_NO_RADIUS */ 00100 00101 00102 static void hostapd_acl_query_free(struct hostapd_acl_query_data *query) 00103 { 00104 if (query == NULL) 00105 return; 00106 os_free(query->auth_msg); 00107 os_free(query); 00108 } 00109 00110 00111 #ifndef CONFIG_NO_RADIUS 00112 static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr, 00113 struct hostapd_acl_query_data *query) 00114 { 00115 struct radius_msg *msg; 00116 char buf[128]; 00117 00118 query->radius_id = radius_client_get_id(hapd->radius); 00119 msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id); 00120 if (msg == NULL) 00121 return -1; 00122 00123 radius_msg_make_authenticator(msg, addr, ETH_ALEN); 00124 00125 os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr)); 00126 if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf, 00127 os_strlen(buf))) { 00128 wpa_printf(MSG_DEBUG, "Could not add User-Name"); 00129 goto fail; 00130 } 00131 00132 if (!radius_msg_add_attr_user_password( 00133 msg, (u8 *) buf, os_strlen(buf), 00134 hapd->conf->radius->auth_server->shared_secret, 00135 hapd->conf->radius->auth_server->shared_secret_len)) { 00136 wpa_printf(MSG_DEBUG, "Could not add User-Password"); 00137 goto fail; 00138 } 00139 00140 if (hapd->conf->own_ip_addr.af == AF_INET && 00141 !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, 00142 (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) { 00143 wpa_printf(MSG_DEBUG, "Could not add NAS-IP-Address"); 00144 goto fail; 00145 } 00146 00147 #ifdef CONFIG_IPV6 00148 if (hapd->conf->own_ip_addr.af == AF_INET6 && 00149 !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, 00150 (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) { 00151 wpa_printf(MSG_DEBUG, "Could not add NAS-IPv6-Address"); 00152 goto fail; 00153 } 00154 #endif /* CONFIG_IPV6 */ 00155 00156 if (hapd->conf->nas_identifier && 00157 !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, 00158 (u8 *) hapd->conf->nas_identifier, 00159 os_strlen(hapd->conf->nas_identifier))) { 00160 wpa_printf(MSG_DEBUG, "Could not add NAS-Identifier"); 00161 goto fail; 00162 } 00163 00164 os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s", 00165 MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid); 00166 if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, 00167 (u8 *) buf, os_strlen(buf))) { 00168 wpa_printf(MSG_DEBUG, "Could not add Called-Station-Id"); 00169 goto fail; 00170 } 00171 00172 os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, 00173 MAC2STR(addr)); 00174 if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, 00175 (u8 *) buf, os_strlen(buf))) { 00176 wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id"); 00177 goto fail; 00178 } 00179 00180 if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, 00181 RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { 00182 wpa_printf(MSG_DEBUG, "Could not add NAS-Port-Type"); 00183 goto fail; 00184 } 00185 00186 os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b"); 00187 if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, 00188 (u8 *) buf, os_strlen(buf))) { 00189 wpa_printf(MSG_DEBUG, "Could not add Connect-Info"); 00190 goto fail; 00191 } 00192 00193 radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr); 00194 return 0; 00195 00196 fail: 00197 radius_msg_free(msg); 00198 return -1; 00199 } 00200 #endif /* CONFIG_NO_RADIUS */ 00201 00202 00214 int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, 00215 const u8 *msg, size_t len, u32 *session_timeout, 00216 u32 *acct_interim_interval, int *vlan_id) 00217 { 00218 if (session_timeout) 00219 *session_timeout = 0; 00220 if (acct_interim_interval) 00221 *acct_interim_interval = 0; 00222 if (vlan_id) 00223 *vlan_id = 0; 00224 00225 if (hostapd_maclist_found(hapd->conf->accept_mac, 00226 hapd->conf->num_accept_mac, addr, vlan_id)) 00227 return HOSTAPD_ACL_ACCEPT; 00228 00229 if (hostapd_maclist_found(hapd->conf->deny_mac, 00230 hapd->conf->num_deny_mac, addr, vlan_id)) 00231 return HOSTAPD_ACL_REJECT; 00232 00233 if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED) 00234 return HOSTAPD_ACL_ACCEPT; 00235 if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED) 00236 return HOSTAPD_ACL_REJECT; 00237 00238 if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) { 00239 #ifdef CONFIG_NO_RADIUS 00240 return HOSTAPD_ACL_REJECT; 00241 #else /* CONFIG_NO_RADIUS */ 00242 struct hostapd_acl_query_data *query; 00243 00244 /* Check whether ACL cache has an entry for this station */ 00245 int res = hostapd_acl_cache_get(hapd, addr, session_timeout, 00246 acct_interim_interval, 00247 vlan_id); 00248 if (res == HOSTAPD_ACL_ACCEPT || 00249 res == HOSTAPD_ACL_ACCEPT_TIMEOUT) 00250 return res; 00251 if (res == HOSTAPD_ACL_REJECT) 00252 return HOSTAPD_ACL_REJECT; 00253 00254 query = hapd->acl_queries; 00255 while (query) { 00256 if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) { 00257 /* pending query in RADIUS retransmit queue; 00258 * do not generate a new one */ 00259 return HOSTAPD_ACL_PENDING; 00260 } 00261 query = query->next; 00262 } 00263 00264 if (!hapd->conf->radius->auth_server) 00265 return HOSTAPD_ACL_REJECT; 00266 00267 /* No entry in the cache - query external RADIUS server */ 00268 query = os_zalloc(sizeof(*query)); 00269 if (query == NULL) { 00270 wpa_printf(MSG_ERROR, "malloc for query data failed"); 00271 return HOSTAPD_ACL_REJECT; 00272 } 00273 time(&query->timestamp); 00274 os_memcpy(query->addr, addr, ETH_ALEN); 00275 if (hostapd_radius_acl_query(hapd, addr, query)) { 00276 wpa_printf(MSG_DEBUG, "Failed to send Access-Request " 00277 "for ACL query."); 00278 hostapd_acl_query_free(query); 00279 return HOSTAPD_ACL_REJECT; 00280 } 00281 00282 query->auth_msg = os_malloc(len); 00283 if (query->auth_msg == NULL) { 00284 wpa_printf(MSG_ERROR, "Failed to allocate memory for " 00285 "auth frame."); 00286 hostapd_acl_query_free(query); 00287 return HOSTAPD_ACL_REJECT; 00288 } 00289 os_memcpy(query->auth_msg, msg, len); 00290 query->auth_msg_len = len; 00291 query->next = hapd->acl_queries; 00292 hapd->acl_queries = query; 00293 00294 /* Queued data will be processed in hostapd_acl_recv_radius() 00295 * when RADIUS server replies to the sent Access-Request. */ 00296 return HOSTAPD_ACL_PENDING; 00297 #endif /* CONFIG_NO_RADIUS */ 00298 } 00299 00300 return HOSTAPD_ACL_REJECT; 00301 } 00302 00303 00304 #ifndef CONFIG_NO_RADIUS 00305 static void hostapd_acl_expire_cache(struct hostapd_data *hapd, time_t now) 00306 { 00307 struct hostapd_cached_radius_acl *prev, *entry, *tmp; 00308 00309 prev = NULL; 00310 entry = hapd->acl_cache; 00311 00312 while (entry) { 00313 if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) { 00314 wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR 00315 " has expired.", MAC2STR(entry->addr)); 00316 if (prev) 00317 prev->next = entry->next; 00318 else 00319 hapd->acl_cache = entry->next; 00320 #ifdef CONFIG_DRIVER_RADIUS_ACL 00321 hapd->drv.set_radius_acl_expire(hapd, entry->addr); 00322 #endif /* CONFIG_DRIVER_RADIUS_ACL */ 00323 tmp = entry; 00324 entry = entry->next; 00325 os_free(tmp); 00326 continue; 00327 } 00328 00329 prev = entry; 00330 entry = entry->next; 00331 } 00332 } 00333 00334 00335 static void hostapd_acl_expire_queries(struct hostapd_data *hapd, time_t now) 00336 { 00337 struct hostapd_acl_query_data *prev, *entry, *tmp; 00338 00339 prev = NULL; 00340 entry = hapd->acl_queries; 00341 00342 while (entry) { 00343 if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) { 00344 wpa_printf(MSG_DEBUG, "ACL query for " MACSTR 00345 " has expired.", MAC2STR(entry->addr)); 00346 if (prev) 00347 prev->next = entry->next; 00348 else 00349 hapd->acl_queries = entry->next; 00350 00351 tmp = entry; 00352 entry = entry->next; 00353 hostapd_acl_query_free(tmp); 00354 continue; 00355 } 00356 00357 prev = entry; 00358 entry = entry->next; 00359 } 00360 } 00361 00362 00368 static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx) 00369 { 00370 struct hostapd_data *hapd = eloop_ctx; 00371 time_t now; 00372 00373 time(&now); 00374 hostapd_acl_expire_cache(hapd, now); 00375 hostapd_acl_expire_queries(hapd, now); 00376 00377 eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL); 00378 } 00379 00380 00391 static RadiusRxResult 00392 hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, 00393 const u8 *shared_secret, size_t shared_secret_len, 00394 void *data) 00395 { 00396 struct hostapd_data *hapd = data; 00397 struct hostapd_acl_query_data *query, *prev; 00398 struct hostapd_cached_radius_acl *cache; 00399 struct radius_hdr *hdr = radius_msg_get_hdr(msg); 00400 00401 query = hapd->acl_queries; 00402 prev = NULL; 00403 while (query) { 00404 if (query->radius_id == hdr->identifier) 00405 break; 00406 prev = query; 00407 query = query->next; 00408 } 00409 if (query == NULL) 00410 return RADIUS_RX_UNKNOWN; 00411 00412 wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS " 00413 "message (id=%d)", query->radius_id); 00414 00415 if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) { 00416 wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have " 00417 "correct authenticator - dropped\n"); 00418 return RADIUS_RX_INVALID_AUTHENTICATOR; 00419 } 00420 00421 if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && 00422 hdr->code != RADIUS_CODE_ACCESS_REJECT) { 00423 wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL " 00424 "query", hdr->code); 00425 return RADIUS_RX_UNKNOWN; 00426 } 00427 00428 /* Insert Accept/Reject info into ACL cache */ 00429 cache = os_zalloc(sizeof(*cache)); 00430 if (cache == NULL) { 00431 wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry"); 00432 goto done; 00433 } 00434 time(&cache->timestamp); 00435 os_memcpy(cache->addr, query->addr, sizeof(cache->addr)); 00436 if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) { 00437 if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, 00438 &cache->session_timeout) == 0) 00439 cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT; 00440 else 00441 cache->accepted = HOSTAPD_ACL_ACCEPT; 00442 00443 if (radius_msg_get_attr_int32( 00444 msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, 00445 &cache->acct_interim_interval) == 0 && 00446 cache->acct_interim_interval < 60) { 00447 wpa_printf(MSG_DEBUG, "Ignored too small " 00448 "Acct-Interim-Interval %d for STA " MACSTR, 00449 cache->acct_interim_interval, 00450 MAC2STR(query->addr)); 00451 cache->acct_interim_interval = 0; 00452 } 00453 00454 cache->vlan_id = radius_msg_get_vlanid(msg); 00455 } else 00456 cache->accepted = HOSTAPD_ACL_REJECT; 00457 cache->next = hapd->acl_cache; 00458 hapd->acl_cache = cache; 00459 00460 #ifdef CONFIG_DRIVER_RADIUS_ACL 00461 hapd->drv.set_radius_acl_auth(hapd, query->addr, cache->accepted, 00462 cache->session_timeout); 00463 #else /* CONFIG_DRIVER_RADIUS_ACL */ 00464 #ifdef NEED_AP_MLME 00465 /* Re-send original authentication frame for 802.11 processing */ 00466 wpa_printf(MSG_DEBUG, "Re-sending authentication frame after " 00467 "successful RADIUS ACL query"); 00468 ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL); 00469 #endif /* NEED_AP_MLME */ 00470 #endif /* CONFIG_DRIVER_RADIUS_ACL */ 00471 00472 done: 00473 if (prev == NULL) 00474 hapd->acl_queries = query->next; 00475 else 00476 prev->next = query->next; 00477 00478 hostapd_acl_query_free(query); 00479 00480 return RADIUS_RX_PROCESSED; 00481 } 00482 #endif /* CONFIG_NO_RADIUS */ 00483 00484 00490 int hostapd_acl_init(struct hostapd_data *hapd) 00491 { 00492 #ifndef CONFIG_NO_RADIUS 00493 if (radius_client_register(hapd->radius, RADIUS_AUTH, 00494 hostapd_acl_recv_radius, hapd)) 00495 return -1; 00496 00497 eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL); 00498 #endif /* CONFIG_NO_RADIUS */ 00499 00500 return 0; 00501 } 00502 00503 00508 void hostapd_acl_deinit(struct hostapd_data *hapd) 00509 { 00510 struct hostapd_acl_query_data *query, *prev; 00511 00512 #ifndef CONFIG_NO_RADIUS 00513 eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL); 00514 00515 hostapd_acl_cache_free(hapd->acl_cache); 00516 #endif /* CONFIG_NO_RADIUS */ 00517 00518 query = hapd->acl_queries; 00519 while (query) { 00520 prev = query; 00521 query = query->next; 00522 hostapd_acl_query_free(prev); 00523 } 00524 }