00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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;
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;
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;
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
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
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
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
00242 struct hostapd_acl_query_data *query;
00243
00244
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
00258
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
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
00295
00296 return HOSTAPD_ACL_PENDING;
00297 #endif
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
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
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
00464 #ifdef NEED_AP_MLME
00465
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
00470 #endif
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
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
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
00517
00518 query = hapd->acl_queries;
00519 while (query) {
00520 prev = query;
00521 query = query->next;
00522 hostapd_acl_query_free(prev);
00523 }
00524 }