1 /* 2 * hostapd / IEEE 802.11 authentication (ACL) 3 * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 * 8 * Access control list for IEEE 802.11 authentication can uses statically 9 * configured ACL from configuration files or an external RADIUS server. 10 * Results from external RADIUS queries are cached to allow faster 11 * authentication frame processing. 12 */ 13 14 #include "utils/includes.h" 15 16 #include "utils/common.h" 17 #include "utils/eloop.h" 18 #include "radius/radius.h" 19 #include "radius/radius_client.h" 20 #include "hostapd.h" 21 #include "ap_config.h" 22 #include "ap_drv_ops.h" 23 #include "ieee802_11.h" 24 #include "ieee802_1x.h" 25 #include "ieee802_11_auth.h" 26 27 #define RADIUS_ACL_TIMEOUT 30 28 29 30 struct hostapd_cached_radius_acl { 31 struct os_reltime timestamp; 32 macaddr addr; 33 int accepted; /* HOSTAPD_ACL_* */ 34 struct hostapd_cached_radius_acl *next; 35 struct radius_sta info; 36 }; 37 38 39 struct hostapd_acl_query_data { 40 struct os_reltime timestamp; 41 u8 radius_id; 42 macaddr addr; 43 u8 *auth_msg; /* IEEE 802.11 authentication frame from station */ 44 size_t auth_msg_len; 45 struct hostapd_acl_query_data *next; 46 }; 47 48 49 #ifndef CONFIG_NO_RADIUS 50 static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e) 51 { 52 os_free(e->info.identity); 53 os_free(e->info.radius_cui); 54 hostapd_free_psk_list(e->info.psk); 55 os_free(e); 56 } 57 58 59 static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache) 60 { 61 struct hostapd_cached_radius_acl *prev; 62 63 while (acl_cache) { 64 prev = acl_cache; 65 acl_cache = acl_cache->next; 66 hostapd_acl_cache_free_entry(prev); 67 } 68 } 69 70 71 static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr, 72 struct radius_sta *out) 73 { 74 struct hostapd_cached_radius_acl *entry; 75 struct os_reltime now; 76 77 os_get_reltime(&now); 78 79 for (entry = hapd->acl_cache; entry; entry = entry->next) { 80 if (os_memcmp(entry->addr, addr, ETH_ALEN) != 0) 81 continue; 82 83 if (os_reltime_expired(&now, &entry->timestamp, 84 RADIUS_ACL_TIMEOUT)) 85 return -1; /* entry has expired */ 86 *out = entry->info; 87 88 return entry->accepted; 89 } 90 91 return -1; 92 } 93 #endif /* CONFIG_NO_RADIUS */ 94 95 96 static void hostapd_acl_query_free(struct hostapd_acl_query_data *query) 97 { 98 if (query == NULL) 99 return; 100 os_free(query->auth_msg); 101 os_free(query); 102 } 103 104 105 #ifndef CONFIG_NO_RADIUS 106 static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr, 107 struct hostapd_acl_query_data *query) 108 { 109 struct radius_msg *msg; 110 char buf[128]; 111 112 query->radius_id = radius_client_get_id(hapd->radius); 113 msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id); 114 if (msg == NULL) 115 return -1; 116 117 if (radius_msg_make_authenticator(msg) < 0) { 118 wpa_printf(MSG_INFO, "Could not make Request Authenticator"); 119 goto fail; 120 } 121 122 os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr)); 123 if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf, 124 os_strlen(buf))) { 125 wpa_printf(MSG_DEBUG, "Could not add User-Name"); 126 goto fail; 127 } 128 129 if (!radius_msg_add_attr_user_password( 130 msg, (u8 *) buf, os_strlen(buf), 131 hapd->conf->radius->auth_server->shared_secret, 132 hapd->conf->radius->auth_server->shared_secret_len)) { 133 wpa_printf(MSG_DEBUG, "Could not add User-Password"); 134 goto fail; 135 } 136 137 if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, 138 NULL, msg) < 0) 139 goto fail; 140 141 os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, 142 MAC2STR(addr)); 143 if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, 144 (u8 *) buf, os_strlen(buf))) { 145 wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id"); 146 goto fail; 147 } 148 149 os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b"); 150 if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, 151 (u8 *) buf, os_strlen(buf))) { 152 wpa_printf(MSG_DEBUG, "Could not add Connect-Info"); 153 goto fail; 154 } 155 156 if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0) 157 goto fail; 158 return 0; 159 160 fail: 161 radius_msg_free(msg); 162 return -1; 163 } 164 #endif /* CONFIG_NO_RADIUS */ 165 166 167 /** 168 * hostapd_check_acl - Check a specified STA against accept/deny ACLs 169 * @hapd: hostapd BSS data 170 * @addr: MAC address of the STA 171 * @vlan_id: Buffer for returning VLAN ID 172 * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING 173 */ 174 int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr, 175 struct vlan_description *vlan_id) 176 { 177 if (hostapd_maclist_found(hapd->conf->accept_mac, 178 hapd->conf->num_accept_mac, addr, vlan_id)) 179 return HOSTAPD_ACL_ACCEPT; 180 181 if (hostapd_maclist_found(hapd->conf->deny_mac, 182 hapd->conf->num_deny_mac, addr, vlan_id)) 183 return HOSTAPD_ACL_REJECT; 184 185 if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED) 186 return HOSTAPD_ACL_ACCEPT; 187 if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED) 188 return HOSTAPD_ACL_REJECT; 189 190 return HOSTAPD_ACL_PENDING; 191 } 192 193 194 /** 195 * hostapd_allowed_address - Check whether a specified STA can be authenticated 196 * @hapd: hostapd BSS data 197 * @addr: MAC address of the STA 198 * @msg: Authentication message 199 * @len: Length of msg in octets 200 * @out.session_timeout: Buffer for returning session timeout (from RADIUS) 201 * @out.acct_interim_interval: Buffer for returning account interval (from 202 * RADIUS) 203 * @out.vlan_id: Buffer for returning VLAN ID 204 * @out.psk: Linked list buffer for returning WPA PSK 205 * @out.identity: Buffer for returning identity (from RADIUS) 206 * @out.radius_cui: Buffer for returning CUI (from RADIUS) 207 * @is_probe_req: Whether this query for a Probe Request frame 208 * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING 209 * 210 * The caller is responsible for properly cloning the returned out->identity and 211 * out->radius_cui and out->psk values. 212 */ 213 int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, 214 const u8 *msg, size_t len, struct radius_sta *out, 215 int is_probe_req) 216 { 217 int res; 218 219 os_memset(out, 0, sizeof(*out)); 220 221 res = hostapd_check_acl(hapd, addr, &out->vlan_id); 222 if (res != HOSTAPD_ACL_PENDING) 223 return res; 224 225 if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) { 226 #ifdef CONFIG_NO_RADIUS 227 return HOSTAPD_ACL_REJECT; 228 #else /* CONFIG_NO_RADIUS */ 229 struct hostapd_acl_query_data *query; 230 231 if (is_probe_req) { 232 /* Skip RADIUS queries for Probe Request frames to avoid 233 * excessive load on the authentication server. */ 234 return HOSTAPD_ACL_ACCEPT; 235 }; 236 237 if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED) 238 os_memset(&out->vlan_id, 0, sizeof(out->vlan_id)); 239 240 /* Check whether ACL cache has an entry for this station */ 241 res = hostapd_acl_cache_get(hapd, addr, out); 242 if (res == HOSTAPD_ACL_ACCEPT || 243 res == HOSTAPD_ACL_ACCEPT_TIMEOUT) 244 return res; 245 if (res == HOSTAPD_ACL_REJECT) 246 return HOSTAPD_ACL_REJECT; 247 248 query = hapd->acl_queries; 249 while (query) { 250 if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) { 251 /* pending query in RADIUS retransmit queue; 252 * do not generate a new one */ 253 return HOSTAPD_ACL_PENDING; 254 } 255 query = query->next; 256 } 257 258 if (!hapd->conf->radius->auth_server) 259 return HOSTAPD_ACL_REJECT; 260 261 /* No entry in the cache - query external RADIUS server */ 262 query = os_zalloc(sizeof(*query)); 263 if (query == NULL) { 264 wpa_printf(MSG_ERROR, "malloc for query data failed"); 265 return HOSTAPD_ACL_REJECT; 266 } 267 os_get_reltime(&query->timestamp); 268 os_memcpy(query->addr, addr, ETH_ALEN); 269 if (hostapd_radius_acl_query(hapd, addr, query)) { 270 wpa_printf(MSG_DEBUG, "Failed to send Access-Request " 271 "for ACL query."); 272 hostapd_acl_query_free(query); 273 return HOSTAPD_ACL_REJECT; 274 } 275 276 query->auth_msg = os_memdup(msg, len); 277 if (query->auth_msg == NULL) { 278 wpa_printf(MSG_ERROR, "Failed to allocate memory for " 279 "auth frame."); 280 hostapd_acl_query_free(query); 281 return HOSTAPD_ACL_REJECT; 282 } 283 query->auth_msg_len = len; 284 query->next = hapd->acl_queries; 285 hapd->acl_queries = query; 286 287 /* Queued data will be processed in hostapd_acl_recv_radius() 288 * when RADIUS server replies to the sent Access-Request. */ 289 return HOSTAPD_ACL_PENDING; 290 #endif /* CONFIG_NO_RADIUS */ 291 } 292 293 return HOSTAPD_ACL_REJECT; 294 } 295 296 297 #ifndef CONFIG_NO_RADIUS 298 static void hostapd_acl_expire_cache(struct hostapd_data *hapd, 299 struct os_reltime *now) 300 { 301 struct hostapd_cached_radius_acl *prev, *entry, *tmp; 302 303 prev = NULL; 304 entry = hapd->acl_cache; 305 306 while (entry) { 307 if (os_reltime_expired(now, &entry->timestamp, 308 RADIUS_ACL_TIMEOUT)) { 309 wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR 310 " has expired.", MAC2STR(entry->addr)); 311 if (prev) 312 prev->next = entry->next; 313 else 314 hapd->acl_cache = entry->next; 315 hostapd_drv_set_radius_acl_expire(hapd, entry->addr); 316 tmp = entry; 317 entry = entry->next; 318 hostapd_acl_cache_free_entry(tmp); 319 continue; 320 } 321 322 prev = entry; 323 entry = entry->next; 324 } 325 } 326 327 328 static void hostapd_acl_expire_queries(struct hostapd_data *hapd, 329 struct os_reltime *now) 330 { 331 struct hostapd_acl_query_data *prev, *entry, *tmp; 332 333 prev = NULL; 334 entry = hapd->acl_queries; 335 336 while (entry) { 337 if (os_reltime_expired(now, &entry->timestamp, 338 RADIUS_ACL_TIMEOUT)) { 339 wpa_printf(MSG_DEBUG, "ACL query for " MACSTR 340 " has expired.", MAC2STR(entry->addr)); 341 if (prev) 342 prev->next = entry->next; 343 else 344 hapd->acl_queries = entry->next; 345 346 tmp = entry; 347 entry = entry->next; 348 hostapd_acl_query_free(tmp); 349 continue; 350 } 351 352 prev = entry; 353 entry = entry->next; 354 } 355 } 356 357 358 /** 359 * hostapd_acl_expire - ACL cache expiration callback 360 * @hapd: struct hostapd_data * 361 */ 362 void hostapd_acl_expire(struct hostapd_data *hapd) 363 { 364 struct os_reltime now; 365 366 os_get_reltime(&now); 367 hostapd_acl_expire_cache(hapd, &now); 368 hostapd_acl_expire_queries(hapd, &now); 369 } 370 371 372 static void decode_tunnel_passwords(struct hostapd_data *hapd, 373 const u8 *shared_secret, 374 size_t shared_secret_len, 375 struct radius_msg *msg, 376 struct radius_msg *req, 377 struct hostapd_cached_radius_acl *cache) 378 { 379 int passphraselen; 380 char *passphrase; 381 size_t i; 382 struct hostapd_sta_wpa_psk_short *psk; 383 384 /* 385 * Decode all tunnel passwords as PSK and save them into a linked list. 386 */ 387 for (i = 0; ; i++) { 388 passphrase = radius_msg_get_tunnel_password( 389 msg, &passphraselen, shared_secret, shared_secret_len, 390 req, i); 391 /* 392 * Passphrase is NULL iff there is no i-th Tunnel-Password 393 * attribute in msg. 394 */ 395 if (passphrase == NULL) 396 break; 397 398 /* 399 * Passphase should be 8..63 chars (to be hashed with SSID) 400 * or 64 chars hex string (no separate hashing with SSID). 401 */ 402 403 if (passphraselen < MIN_PASSPHRASE_LEN || 404 passphraselen > MAX_PASSPHRASE_LEN + 1) 405 goto free_pass; 406 407 /* 408 * passphrase does not contain the NULL termination. 409 * Add it here as pbkdf2_sha1() requires it. 410 */ 411 psk = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short)); 412 if (psk) { 413 if ((passphraselen == MAX_PASSPHRASE_LEN + 1) && 414 (hexstr2bin(passphrase, psk->psk, PMK_LEN) < 0)) { 415 hostapd_logger(hapd, cache->addr, 416 HOSTAPD_MODULE_RADIUS, 417 HOSTAPD_LEVEL_WARNING, 418 "invalid hex string (%d chars) in Tunnel-Password", 419 passphraselen); 420 goto skip; 421 } else if (passphraselen <= MAX_PASSPHRASE_LEN) { 422 os_memcpy(psk->passphrase, passphrase, 423 passphraselen); 424 psk->is_passphrase = 1; 425 } 426 psk->next = cache->info.psk; 427 cache->info.psk = psk; 428 psk = NULL; 429 } 430 skip: 431 os_free(psk); 432 free_pass: 433 os_free(passphrase); 434 } 435 } 436 437 438 /** 439 * hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages 440 * @msg: RADIUS response message 441 * @req: RADIUS request message 442 * @shared_secret: RADIUS shared secret 443 * @shared_secret_len: Length of shared_secret in octets 444 * @data: Context data (struct hostapd_data *) 445 * Returns: RADIUS_RX_PROCESSED if RADIUS message was a reply to ACL query (and 446 * was processed here) or RADIUS_RX_UNKNOWN if not. 447 */ 448 static RadiusRxResult 449 hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, 450 const u8 *shared_secret, size_t shared_secret_len, 451 void *data) 452 { 453 struct hostapd_data *hapd = data; 454 struct hostapd_acl_query_data *query, *prev; 455 struct hostapd_cached_radius_acl *cache; 456 struct radius_sta *info; 457 struct radius_hdr *hdr = radius_msg_get_hdr(msg); 458 459 query = hapd->acl_queries; 460 prev = NULL; 461 while (query) { 462 if (query->radius_id == hdr->identifier) 463 break; 464 prev = query; 465 query = query->next; 466 } 467 if (query == NULL) 468 return RADIUS_RX_UNKNOWN; 469 470 wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS " 471 "message (id=%d)", query->radius_id); 472 473 if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) { 474 wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have " 475 "correct authenticator - dropped\n"); 476 return RADIUS_RX_INVALID_AUTHENTICATOR; 477 } 478 479 if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && 480 hdr->code != RADIUS_CODE_ACCESS_REJECT) { 481 wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL " 482 "query", hdr->code); 483 return RADIUS_RX_UNKNOWN; 484 } 485 486 /* Insert Accept/Reject info into ACL cache */ 487 cache = os_zalloc(sizeof(*cache)); 488 if (cache == NULL) { 489 wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry"); 490 goto done; 491 } 492 os_get_reltime(&cache->timestamp); 493 os_memcpy(cache->addr, query->addr, sizeof(cache->addr)); 494 info = &cache->info; 495 if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) { 496 u8 *buf; 497 size_t len; 498 499 if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, 500 &info->session_timeout) == 0) 501 cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT; 502 else 503 cache->accepted = HOSTAPD_ACL_ACCEPT; 504 505 if (radius_msg_get_attr_int32( 506 msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, 507 &info->acct_interim_interval) == 0 && 508 info->acct_interim_interval < 60) { 509 wpa_printf(MSG_DEBUG, "Ignored too small " 510 "Acct-Interim-Interval %d for STA " MACSTR, 511 info->acct_interim_interval, 512 MAC2STR(query->addr)); 513 info->acct_interim_interval = 0; 514 } 515 516 if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED) 517 info->vlan_id.notempty = !!radius_msg_get_vlanid( 518 msg, &info->vlan_id.untagged, 519 MAX_NUM_TAGGED_VLAN, info->vlan_id.tagged); 520 521 decode_tunnel_passwords(hapd, shared_secret, shared_secret_len, 522 msg, req, cache); 523 524 if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, 525 &buf, &len, NULL) == 0) { 526 info->identity = os_zalloc(len + 1); 527 if (info->identity) 528 os_memcpy(info->identity, buf, len); 529 } 530 if (radius_msg_get_attr_ptr( 531 msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 532 &buf, &len, NULL) == 0) { 533 info->radius_cui = os_zalloc(len + 1); 534 if (info->radius_cui) 535 os_memcpy(info->radius_cui, buf, len); 536 } 537 538 if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED && 539 !info->psk) 540 cache->accepted = HOSTAPD_ACL_REJECT; 541 542 if (info->vlan_id.notempty && 543 !hostapd_vlan_valid(hapd->conf->vlan, &info->vlan_id)) { 544 hostapd_logger(hapd, query->addr, 545 HOSTAPD_MODULE_RADIUS, 546 HOSTAPD_LEVEL_INFO, 547 "Invalid VLAN %d%s received from RADIUS server", 548 info->vlan_id.untagged, 549 info->vlan_id.tagged[0] ? "+" : ""); 550 os_memset(&info->vlan_id, 0, sizeof(info->vlan_id)); 551 } 552 if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED && 553 !info->vlan_id.notempty) 554 cache->accepted = HOSTAPD_ACL_REJECT; 555 } else 556 cache->accepted = HOSTAPD_ACL_REJECT; 557 cache->next = hapd->acl_cache; 558 hapd->acl_cache = cache; 559 560 #ifdef CONFIG_DRIVER_RADIUS_ACL 561 hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted, 562 info->session_timeout); 563 #else /* CONFIG_DRIVER_RADIUS_ACL */ 564 #ifdef NEED_AP_MLME 565 /* Re-send original authentication frame for 802.11 processing */ 566 wpa_printf(MSG_DEBUG, "Re-sending authentication frame after " 567 "successful RADIUS ACL query"); 568 ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL); 569 #endif /* NEED_AP_MLME */ 570 #endif /* CONFIG_DRIVER_RADIUS_ACL */ 571 572 done: 573 if (prev == NULL) 574 hapd->acl_queries = query->next; 575 else 576 prev->next = query->next; 577 578 hostapd_acl_query_free(query); 579 580 return RADIUS_RX_PROCESSED; 581 } 582 #endif /* CONFIG_NO_RADIUS */ 583 584 585 /** 586 * hostapd_acl_init: Initialize IEEE 802.11 ACL 587 * @hapd: hostapd BSS data 588 * Returns: 0 on success, -1 on failure 589 */ 590 int hostapd_acl_init(struct hostapd_data *hapd) 591 { 592 #ifndef CONFIG_NO_RADIUS 593 if (radius_client_register(hapd->radius, RADIUS_AUTH, 594 hostapd_acl_recv_radius, hapd)) 595 return -1; 596 #endif /* CONFIG_NO_RADIUS */ 597 598 return 0; 599 } 600 601 602 /** 603 * hostapd_acl_deinit - Deinitialize IEEE 802.11 ACL 604 * @hapd: hostapd BSS data 605 */ 606 void hostapd_acl_deinit(struct hostapd_data *hapd) 607 { 608 struct hostapd_acl_query_data *query, *prev; 609 610 #ifndef CONFIG_NO_RADIUS 611 hostapd_acl_cache_free(hapd->acl_cache); 612 hapd->acl_cache = NULL; 613 #endif /* CONFIG_NO_RADIUS */ 614 615 query = hapd->acl_queries; 616 hapd->acl_queries = NULL; 617 while (query) { 618 prev = query; 619 query = query->next; 620 hostapd_acl_query_free(prev); 621 } 622 } 623 624 625 void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk, 626 struct hostapd_sta_wpa_psk_short *src) 627 { 628 if (!psk) 629 return; 630 631 if (src) 632 src->ref++; 633 634 *psk = src; 635 } 636 637 638 void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk) 639 { 640 if (psk && psk->ref) { 641 /* This will be freed when the last reference is dropped. */ 642 psk->ref--; 643 return; 644 } 645 646 while (psk) { 647 struct hostapd_sta_wpa_psk_short *prev = psk; 648 psk = psk->next; 649 os_free(prev); 650 } 651 } 652