1214501Srpaulo/* 2214501Srpaulo * hostapd / IEEE 802.11 authentication (ACL) 3252726Srpaulo * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo * 8214501Srpaulo * Access control list for IEEE 802.11 authentication can uses statically 9214501Srpaulo * configured ACL from configuration files or an external RADIUS server. 10214501Srpaulo * Results from external RADIUS queries are cached to allow faster 11214501Srpaulo * authentication frame processing. 12214501Srpaulo */ 13214501Srpaulo 14214501Srpaulo#include "utils/includes.h" 15214501Srpaulo 16214501Srpaulo#include "utils/common.h" 17214501Srpaulo#include "utils/eloop.h" 18252726Srpaulo#include "crypto/sha1.h" 19214501Srpaulo#include "radius/radius.h" 20214501Srpaulo#include "radius/radius_client.h" 21214501Srpaulo#include "hostapd.h" 22214501Srpaulo#include "ap_config.h" 23252726Srpaulo#include "ap_drv_ops.h" 24214501Srpaulo#include "ieee802_11.h" 25252726Srpaulo#include "ieee802_1x.h" 26214501Srpaulo#include "ieee802_11_auth.h" 27214501Srpaulo 28214501Srpaulo#define RADIUS_ACL_TIMEOUT 30 29214501Srpaulo 30214501Srpaulo 31214501Srpaulostruct hostapd_cached_radius_acl { 32252726Srpaulo os_time_t timestamp; 33214501Srpaulo macaddr addr; 34214501Srpaulo int accepted; /* HOSTAPD_ACL_* */ 35214501Srpaulo struct hostapd_cached_radius_acl *next; 36214501Srpaulo u32 session_timeout; 37214501Srpaulo u32 acct_interim_interval; 38214501Srpaulo int vlan_id; 39252726Srpaulo struct hostapd_sta_wpa_psk_short *psk; 40252726Srpaulo char *identity; 41252726Srpaulo char *radius_cui; 42214501Srpaulo}; 43214501Srpaulo 44214501Srpaulo 45214501Srpaulostruct hostapd_acl_query_data { 46252726Srpaulo os_time_t timestamp; 47214501Srpaulo u8 radius_id; 48214501Srpaulo macaddr addr; 49214501Srpaulo u8 *auth_msg; /* IEEE 802.11 authentication frame from station */ 50214501Srpaulo size_t auth_msg_len; 51214501Srpaulo struct hostapd_acl_query_data *next; 52214501Srpaulo}; 53214501Srpaulo 54214501Srpaulo 55214501Srpaulo#ifndef CONFIG_NO_RADIUS 56252726Srpaulostatic void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e) 57252726Srpaulo{ 58252726Srpaulo os_free(e->identity); 59252726Srpaulo os_free(e->radius_cui); 60252726Srpaulo hostapd_free_psk_list(e->psk); 61252726Srpaulo os_free(e); 62252726Srpaulo} 63252726Srpaulo 64252726Srpaulo 65214501Srpaulostatic void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache) 66214501Srpaulo{ 67214501Srpaulo struct hostapd_cached_radius_acl *prev; 68214501Srpaulo 69214501Srpaulo while (acl_cache) { 70214501Srpaulo prev = acl_cache; 71214501Srpaulo acl_cache = acl_cache->next; 72252726Srpaulo hostapd_acl_cache_free_entry(prev); 73214501Srpaulo } 74214501Srpaulo} 75214501Srpaulo 76214501Srpaulo 77252726Srpaulostatic void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk, 78252726Srpaulo struct hostapd_sta_wpa_psk_short *src) 79252726Srpaulo{ 80252726Srpaulo struct hostapd_sta_wpa_psk_short **copy_to; 81252726Srpaulo struct hostapd_sta_wpa_psk_short *copy_from; 82252726Srpaulo 83252726Srpaulo /* Copy PSK linked list */ 84252726Srpaulo copy_to = psk; 85252726Srpaulo copy_from = src; 86252726Srpaulo while (copy_from && copy_to) { 87252726Srpaulo *copy_to = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short)); 88252726Srpaulo if (*copy_to == NULL) 89252726Srpaulo break; 90252726Srpaulo os_memcpy(*copy_to, copy_from, 91252726Srpaulo sizeof(struct hostapd_sta_wpa_psk_short)); 92252726Srpaulo copy_from = copy_from->next; 93252726Srpaulo copy_to = &((*copy_to)->next); 94252726Srpaulo } 95252726Srpaulo if (copy_to) 96252726Srpaulo *copy_to = NULL; 97252726Srpaulo} 98252726Srpaulo 99252726Srpaulo 100214501Srpaulostatic int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr, 101214501Srpaulo u32 *session_timeout, 102252726Srpaulo u32 *acct_interim_interval, int *vlan_id, 103252726Srpaulo struct hostapd_sta_wpa_psk_short **psk, 104252726Srpaulo char **identity, char **radius_cui) 105214501Srpaulo{ 106214501Srpaulo struct hostapd_cached_radius_acl *entry; 107252726Srpaulo struct os_time now; 108214501Srpaulo 109252726Srpaulo os_get_time(&now); 110214501Srpaulo 111252726Srpaulo for (entry = hapd->acl_cache; entry; entry = entry->next) { 112252726Srpaulo if (os_memcmp(entry->addr, addr, ETH_ALEN) != 0) 113252726Srpaulo continue; 114252726Srpaulo 115252726Srpaulo if (now.sec - entry->timestamp > RADIUS_ACL_TIMEOUT) 116252726Srpaulo return -1; /* entry has expired */ 117252726Srpaulo if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT) 118252726Srpaulo if (session_timeout) 119252726Srpaulo *session_timeout = entry->session_timeout; 120252726Srpaulo if (acct_interim_interval) 121252726Srpaulo *acct_interim_interval = 122252726Srpaulo entry->acct_interim_interval; 123252726Srpaulo if (vlan_id) 124252726Srpaulo *vlan_id = entry->vlan_id; 125252726Srpaulo copy_psk_list(psk, entry->psk); 126252726Srpaulo if (identity) { 127252726Srpaulo if (entry->identity) 128252726Srpaulo *identity = os_strdup(entry->identity); 129252726Srpaulo else 130252726Srpaulo *identity = NULL; 131214501Srpaulo } 132252726Srpaulo if (radius_cui) { 133252726Srpaulo if (entry->radius_cui) 134252726Srpaulo *radius_cui = os_strdup(entry->radius_cui); 135252726Srpaulo else 136252726Srpaulo *radius_cui = NULL; 137252726Srpaulo } 138252726Srpaulo return entry->accepted; 139214501Srpaulo } 140214501Srpaulo 141214501Srpaulo return -1; 142214501Srpaulo} 143214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 144214501Srpaulo 145214501Srpaulo 146214501Srpaulostatic void hostapd_acl_query_free(struct hostapd_acl_query_data *query) 147214501Srpaulo{ 148214501Srpaulo if (query == NULL) 149214501Srpaulo return; 150214501Srpaulo os_free(query->auth_msg); 151214501Srpaulo os_free(query); 152214501Srpaulo} 153214501Srpaulo 154214501Srpaulo 155214501Srpaulo#ifndef CONFIG_NO_RADIUS 156214501Srpaulostatic int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr, 157214501Srpaulo struct hostapd_acl_query_data *query) 158214501Srpaulo{ 159214501Srpaulo struct radius_msg *msg; 160214501Srpaulo char buf[128]; 161214501Srpaulo 162214501Srpaulo query->radius_id = radius_client_get_id(hapd->radius); 163214501Srpaulo msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id); 164214501Srpaulo if (msg == NULL) 165214501Srpaulo return -1; 166214501Srpaulo 167214501Srpaulo radius_msg_make_authenticator(msg, addr, ETH_ALEN); 168214501Srpaulo 169214501Srpaulo os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr)); 170214501Srpaulo if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf, 171214501Srpaulo os_strlen(buf))) { 172214501Srpaulo wpa_printf(MSG_DEBUG, "Could not add User-Name"); 173214501Srpaulo goto fail; 174214501Srpaulo } 175214501Srpaulo 176214501Srpaulo if (!radius_msg_add_attr_user_password( 177214501Srpaulo msg, (u8 *) buf, os_strlen(buf), 178214501Srpaulo hapd->conf->radius->auth_server->shared_secret, 179214501Srpaulo hapd->conf->radius->auth_server->shared_secret_len)) { 180214501Srpaulo wpa_printf(MSG_DEBUG, "Could not add User-Password"); 181214501Srpaulo goto fail; 182214501Srpaulo } 183214501Srpaulo 184252726Srpaulo if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, 185252726Srpaulo NULL, msg) < 0) 186214501Srpaulo goto fail; 187214501Srpaulo 188214501Srpaulo os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, 189214501Srpaulo MAC2STR(addr)); 190214501Srpaulo if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, 191214501Srpaulo (u8 *) buf, os_strlen(buf))) { 192214501Srpaulo wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id"); 193214501Srpaulo goto fail; 194214501Srpaulo } 195214501Srpaulo 196214501Srpaulo os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b"); 197214501Srpaulo if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, 198214501Srpaulo (u8 *) buf, os_strlen(buf))) { 199214501Srpaulo wpa_printf(MSG_DEBUG, "Could not add Connect-Info"); 200214501Srpaulo goto fail; 201214501Srpaulo } 202214501Srpaulo 203252726Srpaulo if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0) 204252726Srpaulo goto fail; 205214501Srpaulo return 0; 206214501Srpaulo 207214501Srpaulo fail: 208214501Srpaulo radius_msg_free(msg); 209214501Srpaulo return -1; 210214501Srpaulo} 211214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 212214501Srpaulo 213214501Srpaulo 214214501Srpaulo/** 215214501Srpaulo * hostapd_allowed_address - Check whether a specified STA can be authenticated 216214501Srpaulo * @hapd: hostapd BSS data 217214501Srpaulo * @addr: MAC address of the STA 218214501Srpaulo * @msg: Authentication message 219214501Srpaulo * @len: Length of msg in octets 220214501Srpaulo * @session_timeout: Buffer for returning session timeout (from RADIUS) 221214501Srpaulo * @acct_interim_interval: Buffer for returning account interval (from RADIUS) 222214501Srpaulo * @vlan_id: Buffer for returning VLAN ID 223252726Srpaulo * @psk: Linked list buffer for returning WPA PSK 224252726Srpaulo * @identity: Buffer for returning identity (from RADIUS) 225252726Srpaulo * @radius_cui: Buffer for returning CUI (from RADIUS) 226214501Srpaulo * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING 227252726Srpaulo * 228252726Srpaulo * The caller is responsible for freeing the returned *identity and *radius_cui 229252726Srpaulo * values with os_free(). 230214501Srpaulo */ 231214501Srpauloint hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, 232214501Srpaulo const u8 *msg, size_t len, u32 *session_timeout, 233252726Srpaulo u32 *acct_interim_interval, int *vlan_id, 234252726Srpaulo struct hostapd_sta_wpa_psk_short **psk, 235252726Srpaulo char **identity, char **radius_cui) 236214501Srpaulo{ 237214501Srpaulo if (session_timeout) 238214501Srpaulo *session_timeout = 0; 239214501Srpaulo if (acct_interim_interval) 240214501Srpaulo *acct_interim_interval = 0; 241214501Srpaulo if (vlan_id) 242214501Srpaulo *vlan_id = 0; 243252726Srpaulo if (psk) 244252726Srpaulo *psk = NULL; 245252726Srpaulo if (identity) 246252726Srpaulo *identity = NULL; 247252726Srpaulo if (radius_cui) 248252726Srpaulo *radius_cui = NULL; 249214501Srpaulo 250214501Srpaulo if (hostapd_maclist_found(hapd->conf->accept_mac, 251214501Srpaulo hapd->conf->num_accept_mac, addr, vlan_id)) 252214501Srpaulo return HOSTAPD_ACL_ACCEPT; 253214501Srpaulo 254214501Srpaulo if (hostapd_maclist_found(hapd->conf->deny_mac, 255214501Srpaulo hapd->conf->num_deny_mac, addr, vlan_id)) 256214501Srpaulo return HOSTAPD_ACL_REJECT; 257214501Srpaulo 258214501Srpaulo if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED) 259214501Srpaulo return HOSTAPD_ACL_ACCEPT; 260214501Srpaulo if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED) 261214501Srpaulo return HOSTAPD_ACL_REJECT; 262214501Srpaulo 263214501Srpaulo if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) { 264214501Srpaulo#ifdef CONFIG_NO_RADIUS 265214501Srpaulo return HOSTAPD_ACL_REJECT; 266214501Srpaulo#else /* CONFIG_NO_RADIUS */ 267214501Srpaulo struct hostapd_acl_query_data *query; 268252726Srpaulo struct os_time t; 269214501Srpaulo 270214501Srpaulo /* Check whether ACL cache has an entry for this station */ 271214501Srpaulo int res = hostapd_acl_cache_get(hapd, addr, session_timeout, 272214501Srpaulo acct_interim_interval, 273252726Srpaulo vlan_id, psk, 274252726Srpaulo identity, radius_cui); 275214501Srpaulo if (res == HOSTAPD_ACL_ACCEPT || 276214501Srpaulo res == HOSTAPD_ACL_ACCEPT_TIMEOUT) 277214501Srpaulo return res; 278214501Srpaulo if (res == HOSTAPD_ACL_REJECT) 279214501Srpaulo return HOSTAPD_ACL_REJECT; 280214501Srpaulo 281214501Srpaulo query = hapd->acl_queries; 282214501Srpaulo while (query) { 283214501Srpaulo if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) { 284214501Srpaulo /* pending query in RADIUS retransmit queue; 285214501Srpaulo * do not generate a new one */ 286252726Srpaulo if (identity) { 287252726Srpaulo os_free(*identity); 288252726Srpaulo *identity = NULL; 289252726Srpaulo } 290252726Srpaulo if (radius_cui) { 291252726Srpaulo os_free(*radius_cui); 292252726Srpaulo *radius_cui = NULL; 293252726Srpaulo } 294214501Srpaulo return HOSTAPD_ACL_PENDING; 295214501Srpaulo } 296214501Srpaulo query = query->next; 297214501Srpaulo } 298214501Srpaulo 299214501Srpaulo if (!hapd->conf->radius->auth_server) 300214501Srpaulo return HOSTAPD_ACL_REJECT; 301214501Srpaulo 302214501Srpaulo /* No entry in the cache - query external RADIUS server */ 303214501Srpaulo query = os_zalloc(sizeof(*query)); 304214501Srpaulo if (query == NULL) { 305214501Srpaulo wpa_printf(MSG_ERROR, "malloc for query data failed"); 306214501Srpaulo return HOSTAPD_ACL_REJECT; 307214501Srpaulo } 308252726Srpaulo os_get_time(&t); 309252726Srpaulo query->timestamp = t.sec; 310214501Srpaulo os_memcpy(query->addr, addr, ETH_ALEN); 311214501Srpaulo if (hostapd_radius_acl_query(hapd, addr, query)) { 312214501Srpaulo wpa_printf(MSG_DEBUG, "Failed to send Access-Request " 313214501Srpaulo "for ACL query."); 314214501Srpaulo hostapd_acl_query_free(query); 315214501Srpaulo return HOSTAPD_ACL_REJECT; 316214501Srpaulo } 317214501Srpaulo 318214501Srpaulo query->auth_msg = os_malloc(len); 319214501Srpaulo if (query->auth_msg == NULL) { 320214501Srpaulo wpa_printf(MSG_ERROR, "Failed to allocate memory for " 321214501Srpaulo "auth frame."); 322214501Srpaulo hostapd_acl_query_free(query); 323214501Srpaulo return HOSTAPD_ACL_REJECT; 324214501Srpaulo } 325214501Srpaulo os_memcpy(query->auth_msg, msg, len); 326214501Srpaulo query->auth_msg_len = len; 327214501Srpaulo query->next = hapd->acl_queries; 328214501Srpaulo hapd->acl_queries = query; 329214501Srpaulo 330214501Srpaulo /* Queued data will be processed in hostapd_acl_recv_radius() 331214501Srpaulo * when RADIUS server replies to the sent Access-Request. */ 332214501Srpaulo return HOSTAPD_ACL_PENDING; 333214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 334214501Srpaulo } 335214501Srpaulo 336214501Srpaulo return HOSTAPD_ACL_REJECT; 337214501Srpaulo} 338214501Srpaulo 339214501Srpaulo 340214501Srpaulo#ifndef CONFIG_NO_RADIUS 341252726Srpaulostatic void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now) 342214501Srpaulo{ 343214501Srpaulo struct hostapd_cached_radius_acl *prev, *entry, *tmp; 344214501Srpaulo 345214501Srpaulo prev = NULL; 346214501Srpaulo entry = hapd->acl_cache; 347214501Srpaulo 348214501Srpaulo while (entry) { 349214501Srpaulo if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) { 350214501Srpaulo wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR 351214501Srpaulo " has expired.", MAC2STR(entry->addr)); 352214501Srpaulo if (prev) 353214501Srpaulo prev->next = entry->next; 354214501Srpaulo else 355214501Srpaulo hapd->acl_cache = entry->next; 356252726Srpaulo hostapd_drv_set_radius_acl_expire(hapd, entry->addr); 357214501Srpaulo tmp = entry; 358214501Srpaulo entry = entry->next; 359252726Srpaulo hostapd_acl_cache_free_entry(tmp); 360214501Srpaulo continue; 361214501Srpaulo } 362214501Srpaulo 363214501Srpaulo prev = entry; 364214501Srpaulo entry = entry->next; 365214501Srpaulo } 366214501Srpaulo} 367214501Srpaulo 368214501Srpaulo 369252726Srpaulostatic void hostapd_acl_expire_queries(struct hostapd_data *hapd, 370252726Srpaulo os_time_t now) 371214501Srpaulo{ 372214501Srpaulo struct hostapd_acl_query_data *prev, *entry, *tmp; 373214501Srpaulo 374214501Srpaulo prev = NULL; 375214501Srpaulo entry = hapd->acl_queries; 376214501Srpaulo 377214501Srpaulo while (entry) { 378214501Srpaulo if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) { 379214501Srpaulo wpa_printf(MSG_DEBUG, "ACL query for " MACSTR 380214501Srpaulo " has expired.", MAC2STR(entry->addr)); 381214501Srpaulo if (prev) 382214501Srpaulo prev->next = entry->next; 383214501Srpaulo else 384214501Srpaulo hapd->acl_queries = entry->next; 385214501Srpaulo 386214501Srpaulo tmp = entry; 387214501Srpaulo entry = entry->next; 388214501Srpaulo hostapd_acl_query_free(tmp); 389214501Srpaulo continue; 390214501Srpaulo } 391214501Srpaulo 392214501Srpaulo prev = entry; 393214501Srpaulo entry = entry->next; 394214501Srpaulo } 395214501Srpaulo} 396214501Srpaulo 397214501Srpaulo 398214501Srpaulo/** 399214501Srpaulo * hostapd_acl_expire - ACL cache expiration callback 400214501Srpaulo * @eloop_ctx: struct hostapd_data * 401214501Srpaulo * @timeout_ctx: Not used 402214501Srpaulo */ 403214501Srpaulostatic void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx) 404214501Srpaulo{ 405214501Srpaulo struct hostapd_data *hapd = eloop_ctx; 406252726Srpaulo struct os_time now; 407214501Srpaulo 408252726Srpaulo os_get_time(&now); 409252726Srpaulo hostapd_acl_expire_cache(hapd, now.sec); 410252726Srpaulo hostapd_acl_expire_queries(hapd, now.sec); 411214501Srpaulo 412214501Srpaulo eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL); 413214501Srpaulo} 414214501Srpaulo 415214501Srpaulo 416252726Srpaulostatic void decode_tunnel_passwords(struct hostapd_data *hapd, 417252726Srpaulo const u8 *shared_secret, 418252726Srpaulo size_t shared_secret_len, 419252726Srpaulo struct radius_msg *msg, 420252726Srpaulo struct radius_msg *req, 421252726Srpaulo struct hostapd_cached_radius_acl *cache) 422252726Srpaulo{ 423252726Srpaulo int passphraselen; 424252726Srpaulo char *passphrase, *strpassphrase; 425252726Srpaulo size_t i; 426252726Srpaulo struct hostapd_sta_wpa_psk_short *psk; 427252726Srpaulo 428252726Srpaulo /* 429252726Srpaulo * Decode all tunnel passwords as PSK and save them into a linked list. 430252726Srpaulo */ 431252726Srpaulo for (i = 0; ; i++) { 432252726Srpaulo passphrase = radius_msg_get_tunnel_password( 433252726Srpaulo msg, &passphraselen, shared_secret, shared_secret_len, 434252726Srpaulo req, i); 435252726Srpaulo /* 436252726Srpaulo * Passphrase is NULL iff there is no i-th Tunnel-Password 437252726Srpaulo * attribute in msg. 438252726Srpaulo */ 439252726Srpaulo if (passphrase == NULL) 440252726Srpaulo break; 441252726Srpaulo /* 442252726Srpaulo * passphrase does not contain the NULL termination. 443252726Srpaulo * Add it here as pbkdf2_sha1() requires it. 444252726Srpaulo */ 445252726Srpaulo strpassphrase = os_zalloc(passphraselen + 1); 446252726Srpaulo psk = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short)); 447252726Srpaulo if (strpassphrase && psk) { 448252726Srpaulo os_memcpy(strpassphrase, passphrase, passphraselen); 449252726Srpaulo pbkdf2_sha1(strpassphrase, 450252726Srpaulo hapd->conf->ssid.ssid, 451252726Srpaulo hapd->conf->ssid.ssid_len, 4096, 452252726Srpaulo psk->psk, PMK_LEN); 453252726Srpaulo psk->next = cache->psk; 454252726Srpaulo cache->psk = psk; 455252726Srpaulo psk = NULL; 456252726Srpaulo } 457252726Srpaulo os_free(strpassphrase); 458252726Srpaulo os_free(psk); 459252726Srpaulo os_free(passphrase); 460252726Srpaulo } 461252726Srpaulo} 462252726Srpaulo 463252726Srpaulo 464214501Srpaulo/** 465214501Srpaulo * hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages 466214501Srpaulo * @msg: RADIUS response message 467214501Srpaulo * @req: RADIUS request message 468214501Srpaulo * @shared_secret: RADIUS shared secret 469214501Srpaulo * @shared_secret_len: Length of shared_secret in octets 470214501Srpaulo * @data: Context data (struct hostapd_data *) 471214501Srpaulo * Returns: RADIUS_RX_PROCESSED if RADIUS message was a reply to ACL query (and 472214501Srpaulo * was processed here) or RADIUS_RX_UNKNOWN if not. 473214501Srpaulo */ 474214501Srpaulostatic RadiusRxResult 475214501Srpaulohostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, 476214501Srpaulo const u8 *shared_secret, size_t shared_secret_len, 477214501Srpaulo void *data) 478214501Srpaulo{ 479214501Srpaulo struct hostapd_data *hapd = data; 480214501Srpaulo struct hostapd_acl_query_data *query, *prev; 481214501Srpaulo struct hostapd_cached_radius_acl *cache; 482214501Srpaulo struct radius_hdr *hdr = radius_msg_get_hdr(msg); 483252726Srpaulo struct os_time t; 484214501Srpaulo 485214501Srpaulo query = hapd->acl_queries; 486214501Srpaulo prev = NULL; 487214501Srpaulo while (query) { 488214501Srpaulo if (query->radius_id == hdr->identifier) 489214501Srpaulo break; 490214501Srpaulo prev = query; 491214501Srpaulo query = query->next; 492214501Srpaulo } 493214501Srpaulo if (query == NULL) 494214501Srpaulo return RADIUS_RX_UNKNOWN; 495214501Srpaulo 496214501Srpaulo wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS " 497214501Srpaulo "message (id=%d)", query->radius_id); 498214501Srpaulo 499214501Srpaulo if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) { 500214501Srpaulo wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have " 501214501Srpaulo "correct authenticator - dropped\n"); 502214501Srpaulo return RADIUS_RX_INVALID_AUTHENTICATOR; 503214501Srpaulo } 504214501Srpaulo 505214501Srpaulo if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && 506214501Srpaulo hdr->code != RADIUS_CODE_ACCESS_REJECT) { 507214501Srpaulo wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL " 508214501Srpaulo "query", hdr->code); 509214501Srpaulo return RADIUS_RX_UNKNOWN; 510214501Srpaulo } 511214501Srpaulo 512214501Srpaulo /* Insert Accept/Reject info into ACL cache */ 513214501Srpaulo cache = os_zalloc(sizeof(*cache)); 514214501Srpaulo if (cache == NULL) { 515214501Srpaulo wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry"); 516214501Srpaulo goto done; 517214501Srpaulo } 518252726Srpaulo os_get_time(&t); 519252726Srpaulo cache->timestamp = t.sec; 520214501Srpaulo os_memcpy(cache->addr, query->addr, sizeof(cache->addr)); 521214501Srpaulo if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) { 522252726Srpaulo u8 *buf; 523252726Srpaulo size_t len; 524252726Srpaulo 525214501Srpaulo if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, 526214501Srpaulo &cache->session_timeout) == 0) 527214501Srpaulo cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT; 528214501Srpaulo else 529214501Srpaulo cache->accepted = HOSTAPD_ACL_ACCEPT; 530214501Srpaulo 531214501Srpaulo if (radius_msg_get_attr_int32( 532214501Srpaulo msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, 533214501Srpaulo &cache->acct_interim_interval) == 0 && 534214501Srpaulo cache->acct_interim_interval < 60) { 535214501Srpaulo wpa_printf(MSG_DEBUG, "Ignored too small " 536214501Srpaulo "Acct-Interim-Interval %d for STA " MACSTR, 537214501Srpaulo cache->acct_interim_interval, 538214501Srpaulo MAC2STR(query->addr)); 539214501Srpaulo cache->acct_interim_interval = 0; 540214501Srpaulo } 541214501Srpaulo 542214501Srpaulo cache->vlan_id = radius_msg_get_vlanid(msg); 543252726Srpaulo 544252726Srpaulo decode_tunnel_passwords(hapd, shared_secret, shared_secret_len, 545252726Srpaulo msg, req, cache); 546252726Srpaulo 547252726Srpaulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, 548252726Srpaulo &buf, &len, NULL) == 0) { 549252726Srpaulo cache->identity = os_zalloc(len + 1); 550252726Srpaulo if (cache->identity) 551252726Srpaulo os_memcpy(cache->identity, buf, len); 552252726Srpaulo } 553252726Srpaulo if (radius_msg_get_attr_ptr( 554252726Srpaulo msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 555252726Srpaulo &buf, &len, NULL) == 0) { 556252726Srpaulo cache->radius_cui = os_zalloc(len + 1); 557252726Srpaulo if (cache->radius_cui) 558252726Srpaulo os_memcpy(cache->radius_cui, buf, len); 559252726Srpaulo } 560252726Srpaulo 561252726Srpaulo if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED && 562252726Srpaulo !cache->psk) 563252726Srpaulo cache->accepted = HOSTAPD_ACL_REJECT; 564214501Srpaulo } else 565214501Srpaulo cache->accepted = HOSTAPD_ACL_REJECT; 566214501Srpaulo cache->next = hapd->acl_cache; 567214501Srpaulo hapd->acl_cache = cache; 568214501Srpaulo 569214501Srpaulo#ifdef CONFIG_DRIVER_RADIUS_ACL 570252726Srpaulo hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted, 571252726Srpaulo cache->session_timeout); 572214501Srpaulo#else /* CONFIG_DRIVER_RADIUS_ACL */ 573214501Srpaulo#ifdef NEED_AP_MLME 574214501Srpaulo /* Re-send original authentication frame for 802.11 processing */ 575214501Srpaulo wpa_printf(MSG_DEBUG, "Re-sending authentication frame after " 576214501Srpaulo "successful RADIUS ACL query"); 577214501Srpaulo ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL); 578214501Srpaulo#endif /* NEED_AP_MLME */ 579214501Srpaulo#endif /* CONFIG_DRIVER_RADIUS_ACL */ 580214501Srpaulo 581214501Srpaulo done: 582214501Srpaulo if (prev == NULL) 583214501Srpaulo hapd->acl_queries = query->next; 584214501Srpaulo else 585214501Srpaulo prev->next = query->next; 586214501Srpaulo 587214501Srpaulo hostapd_acl_query_free(query); 588214501Srpaulo 589214501Srpaulo return RADIUS_RX_PROCESSED; 590214501Srpaulo} 591214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 592214501Srpaulo 593214501Srpaulo 594214501Srpaulo/** 595214501Srpaulo * hostapd_acl_init: Initialize IEEE 802.11 ACL 596214501Srpaulo * @hapd: hostapd BSS data 597214501Srpaulo * Returns: 0 on success, -1 on failure 598214501Srpaulo */ 599214501Srpauloint hostapd_acl_init(struct hostapd_data *hapd) 600214501Srpaulo{ 601214501Srpaulo#ifndef CONFIG_NO_RADIUS 602214501Srpaulo if (radius_client_register(hapd->radius, RADIUS_AUTH, 603214501Srpaulo hostapd_acl_recv_radius, hapd)) 604214501Srpaulo return -1; 605214501Srpaulo 606214501Srpaulo eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL); 607214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 608214501Srpaulo 609214501Srpaulo return 0; 610214501Srpaulo} 611214501Srpaulo 612214501Srpaulo 613214501Srpaulo/** 614214501Srpaulo * hostapd_acl_deinit - Deinitialize IEEE 802.11 ACL 615214501Srpaulo * @hapd: hostapd BSS data 616214501Srpaulo */ 617214501Srpaulovoid hostapd_acl_deinit(struct hostapd_data *hapd) 618214501Srpaulo{ 619214501Srpaulo struct hostapd_acl_query_data *query, *prev; 620214501Srpaulo 621214501Srpaulo#ifndef CONFIG_NO_RADIUS 622214501Srpaulo eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL); 623214501Srpaulo 624214501Srpaulo hostapd_acl_cache_free(hapd->acl_cache); 625214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 626214501Srpaulo 627214501Srpaulo query = hapd->acl_queries; 628214501Srpaulo while (query) { 629214501Srpaulo prev = query; 630214501Srpaulo query = query->next; 631214501Srpaulo hostapd_acl_query_free(prev); 632214501Srpaulo } 633214501Srpaulo} 634252726Srpaulo 635252726Srpaulo 636252726Srpaulovoid hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk) 637252726Srpaulo{ 638252726Srpaulo while (psk) { 639252726Srpaulo struct hostapd_sta_wpa_psk_short *prev = psk; 640252726Srpaulo psk = psk->next; 641252726Srpaulo os_free(prev); 642252726Srpaulo } 643252726Srpaulo} 644