radius_client.c revision 61d9df3e62aaa0e87ad05452fcb95142159a17b6
1c3aae25116e66c177579b0b79182b09340b19753Chris Lattner/* 2ea61c358720aa6c7a159d51658b34276316aa841Misha Brukman * RADIUS client 36fbcc26f1460eaee4e0eb8b426fc1ff0c7af11beJohn Criswell * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> 46fbcc26f1460eaee4e0eb8b426fc1ff0c7af11beJohn Criswell * 57ed47a13356daed2a34cd2209a31f92552e3bdd8Chris Lattner * This software may be distributed under the terms of the BSD license. 67ed47a13356daed2a34cd2209a31f92552e3bdd8Chris Lattner * See README for more details. 7ea61c358720aa6c7a159d51658b34276316aa841Misha Brukman */ 86fbcc26f1460eaee4e0eb8b426fc1ff0c7af11beJohn Criswell 9ea61c358720aa6c7a159d51658b34276316aa841Misha Brukman#include "includes.h" 10c3aae25116e66c177579b0b79182b09340b19753Chris Lattner 11c3aae25116e66c177579b0b79182b09340b19753Chris Lattner#include "common.h" 12ea61c358720aa6c7a159d51658b34276316aa841Misha Brukman#include "radius.h" 13cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner#include "radius_client.h" 14cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner#include "eloop.h" 15cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner 16cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner/* Defaults for RADIUS retransmit values (exponential backoff) */ 17cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner 18fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman/** 19583bd47f777fe3eb8305872fa0eadab31e833dffJim Laskey * RADIUS_CLIENT_FIRST_WAIT - RADIUS client timeout for first retry in seconds 204b84086e89d86fb16f562166d9fea8df37db6be7Dan Gohman */ 21583bd47f777fe3eb8305872fa0eadab31e833dffJim Laskey#define RADIUS_CLIENT_FIRST_WAIT 3 22b80e2be8894db9f843f32ebaffb9b7fd6b57d206Chris Lattner 23acaf09dbe4a6781163857db1321bbd5795e7d410Dan Gohman/** 24109654fae9c5b8b96bd3a829824cdbceb27ced06Chris Lattner * RADIUS_CLIENT_MAX_WAIT - RADIUS client maximum retry timeout in seconds 255892d47a625638a90afeb31dd4f6f80a2f9bacdeChris Lattner */ 26322812e603705e1c2037313633e72f689524b163Evan Cheng#define RADIUS_CLIENT_MAX_WAIT 120 27eb19e40efbd3cae80c908a30cdf4d33450733c45Chris Lattner 28d0fde30ce850b78371fd1386338350591f9ff494Brian Gaeke/** 29d0fde30ce850b78371fd1386338350591f9ff494Brian Gaeke * RADIUS_CLIENT_MAX_RETRIES - RADIUS client maximum retries 30fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * 31fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * Maximum number of retransmit attempts before the entry is removed from 32fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * retransmit list. 33fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman */ 34fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman#define RADIUS_CLIENT_MAX_RETRIES 10 35fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman 36fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman/** 37fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * RADIUS_CLIENT_MAX_ENTRIES - RADIUS client maximum pending messages 38fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * 39fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * Maximum number of entries in retransmit list (oldest entries will be 40fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * removed, if this limit is exceeded). 41fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman */ 42fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman#define RADIUS_CLIENT_MAX_ENTRIES 30 43fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman 44fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman/** 45fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * RADIUS_CLIENT_NUM_FAILOVER - RADIUS client failover point 46fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * 47fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * The number of failed retry attempts after which the RADIUS server will be 48fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * changed (if one of more backup servers are configured). 49fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman */ 50fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman#define RADIUS_CLIENT_NUM_FAILOVER 4 51fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman 52fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman 53fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman/** 54fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * struct radius_rx_handler - RADIUS client RX handler 55fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * 56fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * This data structure is used internally inside the RADIUS client module to 57fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * store registered RX handlers. These handlers are registered by calls to 58fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * radius_client_register() and unregistered when the RADIUS client is 59fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * deinitialized with a call to radius_client_deinit(). 60fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman */ 61fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohmanstruct radius_rx_handler { 62c3aae25116e66c177579b0b79182b09340b19753Chris Lattner /** 63c3aae25116e66c177579b0b79182b09340b19753Chris Lattner * handler - Received RADIUS message handler 64c3aae25116e66c177579b0b79182b09340b19753Chris Lattner */ 65c3aae25116e66c177579b0b79182b09340b19753Chris Lattner RadiusRxResult (*handler)(struct radius_msg *msg, 66c3aae25116e66c177579b0b79182b09340b19753Chris Lattner struct radius_msg *req, 67c3aae25116e66c177579b0b79182b09340b19753Chris Lattner const u8 *shared_secret, 68c3aae25116e66c177579b0b79182b09340b19753Chris Lattner size_t shared_secret_len, 69c3aae25116e66c177579b0b79182b09340b19753Chris Lattner void *data); 70c3aae25116e66c177579b0b79182b09340b19753Chris Lattner 71c3aae25116e66c177579b0b79182b09340b19753Chris Lattner /** 72c3aae25116e66c177579b0b79182b09340b19753Chris Lattner * data - Context data for the handler 73cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner */ 74cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner void *data; 75063287a76b5d1486f498fcf674a26d1155471a3fChris Lattner}; 76c3aae25116e66c177579b0b79182b09340b19753Chris Lattner 77ead0d88ad7659dabd66cc3149af97d98256fca84Chris Lattner 7844c3b9fdd416c79f4b67cde1aecfced5921efd81Jim Laskey/** 79cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner * struct radius_msg_list - RADIUS client message retransmit list 80213a16c637926bfc38ba373d3aba6778e181e3ecChris Lattner * 81475871a144eb604ddaf37503397ba0941442e5fbDan Gohman * This data structure is used internally inside the RADIUS client module to 82cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner * store pending RADIUS requests that may still need to be retransmitted. 83213a16c637926bfc38ba373d3aba6778e181e3ecChris Lattner */ 84fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohmanstruct radius_msg_list { 85fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman /** 86fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * addr - STA/client address 87fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * 88fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * This is used to find RADIUS messages for the same STA. 89fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman */ 90691ef2ba066dda14ae4ac0ad645054fbc967785aAndrew Lenharth u8 addr[ETH_ALEN]; 91213a16c637926bfc38ba373d3aba6778e181e3ecChris Lattner 92213a16c637926bfc38ba373d3aba6778e181e3ecChris Lattner /** 93583bd47f777fe3eb8305872fa0eadab31e833dffJim Laskey * msg - RADIUS message 94213a16c637926bfc38ba373d3aba6778e181e3ecChris Lattner */ 95e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman struct radius_msg *msg; 96e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman 97e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman /** 98e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman * msg_type - Message type 99d038e04188047eca4749d025ef1f05f7ae660bcaDuncan Sands */ 100d038e04188047eca4749d025ef1f05f7ae660bcaDuncan Sands RadiusType msg_type; 101d038e04188047eca4749d025ef1f05f7ae660bcaDuncan Sands 102cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner /** 103ead0d88ad7659dabd66cc3149af97d98256fca84Chris Lattner * first_try - Time of the first transmission attempt 1040e5f1306b059b62d7725f324e087efbc8e7a782dDan Gohman */ 105fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman os_time_t first_try; 106fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman 107c3aae25116e66c177579b0b79182b09340b19753Chris Lattner /** 108c3aae25116e66c177579b0b79182b09340b19753Chris Lattner * next_try - Time for the next transmission attempt 109cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner */ 110cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner os_time_t next_try; 111c3aae25116e66c177579b0b79182b09340b19753Chris Lattner 112063287a76b5d1486f498fcf674a26d1155471a3fChris Lattner /** 113063287a76b5d1486f498fcf674a26d1155471a3fChris Lattner * attempts - Number of transmission attempts 114ead0d88ad7659dabd66cc3149af97d98256fca84Chris Lattner */ 11544c3b9fdd416c79f4b67cde1aecfced5921efd81Jim Laskey int attempts; 116cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner 117ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey /** 1181080b9ee534579c67f7c99364cc6fa11edbcd919Chris Lattner * next_wait - Next retransmission wait time in seconds 119462dc7f4960e5074ddf4769ec8b2ef1ba7a4d2c8Dan Gohman */ 120462dc7f4960e5074ddf4769ec8b2ef1ba7a4d2c8Dan Gohman int next_wait; 121ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey 122ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey /** 123ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey * last_attempt - Time of the last transmission attempt 124ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey */ 1251080b9ee534579c67f7c99364cc6fa11edbcd919Chris Lattner struct os_time last_attempt; 126ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey 127ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey /** 128ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey * shared_secret - Shared secret with the target RADIUS server 129ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey */ 130ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey const u8 *shared_secret; 131ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey 132ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey /** 133ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey * shared_secret_len - shared_secret length in octets 134ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey */ 135ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey size_t shared_secret_len; 136ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey 137ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey /* TODO: server config with failover to backup server(s) */ 138ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey 139ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey /** 140ec20402c90b605afeedbcf0e3aabe6f8054f23ddJim Laskey * next - Next message in the list 1411080b9ee534579c67f7c99364cc6fa11edbcd919Chris Lattner */ 142fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman struct radius_msg_list *next; 143b80e2be8894db9f843f32ebaffb9b7fd6b57d206Chris Lattner}; 144b80e2be8894db9f843f32ebaffb9b7fd6b57d206Chris Lattner 145fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman 146b80e2be8894db9f843f32ebaffb9b7fd6b57d206Chris Lattner/** 147b80e2be8894db9f843f32ebaffb9b7fd6b57d206Chris Lattner * struct radius_client_data - Internal RADIUS client data 148fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman * 1490e5f1306b059b62d7725f324e087efbc8e7a782dDan Gohman * This data structure is used internally inside the RADIUS client module. 1500e5f1306b059b62d7725f324e087efbc8e7a782dDan Gohman * External users allocate this by calling radius_client_init() and free it by 151b80e2be8894db9f843f32ebaffb9b7fd6b57d206Chris Lattner * calling radius_client_deinit(). The pointer to this opaque data is used in 152c3aae25116e66c177579b0b79182b09340b19753Chris Lattner * calls to other functions as an identifier for the RADIUS client instance. 153cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner */ 154475871a144eb604ddaf37503397ba0941442e5fbDan Gohmanstruct radius_client_data { 155cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner /** 156c3aae25116e66c177579b0b79182b09340b19753Chris Lattner * ctx - Context pointer for hostapd_logger() callbacks 157c3aae25116e66c177579b0b79182b09340b19753Chris Lattner */ 158475871a144eb604ddaf37503397ba0941442e5fbDan Gohman void *ctx; 159cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner 160c3aae25116e66c177579b0b79182b09340b19753Chris Lattner /** 161cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner * conf - RADIUS client configuration (list of RADIUS servers to use) 162475871a144eb604ddaf37503397ba0941442e5fbDan Gohman */ 163acaf09dbe4a6781163857db1321bbd5795e7d410Dan Gohman struct hostapd_radius_servers *conf; 164acaf09dbe4a6781163857db1321bbd5795e7d410Dan Gohman 165acaf09dbe4a6781163857db1321bbd5795e7d410Dan Gohman /** 166acaf09dbe4a6781163857db1321bbd5795e7d410Dan Gohman * auth_serv_sock - IPv4 socket for RADIUS authentication messages 167cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner */ 1681d4d41411190dd9e62764e56713753d4155764ddNate Begeman int auth_serv_sock; 1691d4d41411190dd9e62764e56713753d4155764ddNate Begeman 1701d4d41411190dd9e62764e56713753d4155764ddNate Begeman /** 1711d4d41411190dd9e62764e56713753d4155764ddNate Begeman * acct_serv_sock - IPv4 socket for RADIUS accounting messages 172c7c3f110eda0ff8040e4bd99e38d3112b910810fJim Laskey */ 1731d4d41411190dd9e62764e56713753d4155764ddNate Begeman int acct_serv_sock; 17401d029b82cb08367d81aa10cdc94d05360466649Chris Lattner 17501d029b82cb08367d81aa10cdc94d05360466649Chris Lattner /** 17601d029b82cb08367d81aa10cdc94d05360466649Chris Lattner * auth_serv_sock6 - IPv6 socket for RADIUS authentication messages 17701d029b82cb08367d81aa10cdc94d05360466649Chris Lattner */ 17801d029b82cb08367d81aa10cdc94d05360466649Chris Lattner int auth_serv_sock6; 17901d029b82cb08367d81aa10cdc94d05360466649Chris Lattner 18001d029b82cb08367d81aa10cdc94d05360466649Chris Lattner /** 181c3aae25116e66c177579b0b79182b09340b19753Chris Lattner * acct_serv_sock6 - IPv6 socket for RADIUS accounting messages 182c3aae25116e66c177579b0b79182b09340b19753Chris Lattner */ 183c3aae25116e66c177579b0b79182b09340b19753Chris Lattner int acct_serv_sock6; 184cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner 185c3aae25116e66c177579b0b79182b09340b19753Chris Lattner /** 186c3aae25116e66c177579b0b79182b09340b19753Chris Lattner * auth_sock - Currently used socket for RADIUS authentication server 187063287a76b5d1486f498fcf674a26d1155471a3fChris Lattner */ 188c3aae25116e66c177579b0b79182b09340b19753Chris Lattner int auth_sock; 189d1fc96499b7619356c7542200d32da898b79f7c1Chris Lattner 190190a418bf6b49a4ef1c1980229a2f0d516e8a2cdChris Lattner /** 191190a418bf6b49a4ef1c1980229a2f0d516e8a2cdChris Lattner * acct_sock - Currently used socket for RADIUS accounting server 192130a6471b90f66e99b1f9f42877fdf611c330ac6Evan Cheng */ 193130a6471b90f66e99b1f9f42877fdf611c330ac6Evan Cheng int acct_sock; 194130a6471b90f66e99b1f9f42877fdf611c330ac6Evan Cheng 195130a6471b90f66e99b1f9f42877fdf611c330ac6Evan Cheng /** 196130a6471b90f66e99b1f9f42877fdf611c330ac6Evan Cheng * auth_handlers - Authentication message handlers 19770046e920fa37989a041af663ada2b2b646e258fChris Lattner */ 19870046e920fa37989a041af663ada2b2b646e258fChris Lattner struct radius_rx_handler *auth_handlers; 19983ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands 20083ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands /** 20183ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands * num_auth_handlers - Number of handlers in auth_handlers 20283ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands */ 20370046e920fa37989a041af663ada2b2b646e258fChris Lattner size_t num_auth_handlers; 20470046e920fa37989a041af663ada2b2b646e258fChris Lattner 20583ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands /** 20670046e920fa37989a041af663ada2b2b646e258fChris Lattner * acct_handlers - Accounting message handlers 20770046e920fa37989a041af663ada2b2b646e258fChris Lattner */ 20883ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands struct radius_rx_handler *acct_handlers; 20970046e920fa37989a041af663ada2b2b646e258fChris Lattner 21070046e920fa37989a041af663ada2b2b646e258fChris Lattner /** 21183ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands * num_acct_handlers - Number of handlers in acct_handlers 21270046e920fa37989a041af663ada2b2b646e258fChris Lattner */ 21370046e920fa37989a041af663ada2b2b646e258fChris Lattner size_t num_acct_handlers; 214f877b735ad4987f26cafcbaf22aa4c2199458b5dDan Gohman 21513d57320bd212483463d4f8992d5787b29eda5dfBill Wendling /** 21670046e920fa37989a041af663ada2b2b646e258fChris Lattner * msgs - Pending outgoing RADIUS messages 21770046e920fa37989a041af663ada2b2b646e258fChris Lattner */ 21870046e920fa37989a041af663ada2b2b646e258fChris Lattner struct radius_msg_list *msgs; 2191b1a49714ef26225a42199cf2930529f31868322Chris Lattner 22070046e920fa37989a041af663ada2b2b646e258fChris Lattner /** 22170046e920fa37989a041af663ada2b2b646e258fChris Lattner * num_msgs - Number of pending messages in the msgs list 222475871a144eb604ddaf37503397ba0941442e5fbDan Gohman */ 223475871a144eb604ddaf37503397ba0941442e5fbDan Gohman size_t num_msgs; 224475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 225475871a144eb604ddaf37503397ba0941442e5fbDan Gohman /** 226cbea3045ce0bdd061c494a831d0ce2d5834211ccChris Lattner * next_radius_identifier - Next RADIUS message identifier to use 227cbea3045ce0bdd061c494a831d0ce2d5834211ccChris Lattner */ 228475871a144eb604ddaf37503397ba0941442e5fbDan Gohman u8 next_radius_identifier; 2296394b099e836f56a937cdcc7332c9487b504ca68Dan Gohman}; 2306394b099e836f56a937cdcc7332c9487b504ca68Dan Gohman 231475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 232475871a144eb604ddaf37503397ba0941442e5fbDan Gohmanstatic int 233475871a144eb604ddaf37503397ba0941442e5fbDan Gohmanradius_change_server(struct radius_client_data *radius, 234c9f8f416800784ca6453222b307bc44ad24739b0Chris Lattner struct hostapd_radius_server *nserv, 235c9f8f416800784ca6453222b307bc44ad24739b0Chris Lattner struct hostapd_radius_server *oserv, 236475871a144eb604ddaf37503397ba0941442e5fbDan Gohman int sock, int sock6, int auth); 237f04afdbb48568ef09f11fd10ac03426101f2dbf8Dale Johannesenstatic int radius_client_init_acct(struct radius_client_data *radius); 238f04afdbb48568ef09f11fd10ac03426101f2dbf8Dale Johannesenstatic int radius_client_init_auth(struct radius_client_data *radius); 239475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 240cbea3045ce0bdd061c494a831d0ce2d5834211ccChris Lattner 241475871a144eb604ddaf37503397ba0941442e5fbDan Gohmanstatic void radius_client_msg_free(struct radius_msg_list *req) 242cbea3045ce0bdd061c494a831d0ce2d5834211ccChris Lattner{ 243cbea3045ce0bdd061c494a831d0ce2d5834211ccChris Lattner radius_msg_free(req->msg); 244cbea3045ce0bdd061c494a831d0ce2d5834211ccChris Lattner os_free(req); 245475871a144eb604ddaf37503397ba0941442e5fbDan Gohman} 246475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 247c9f8f416800784ca6453222b307bc44ad24739b0Chris Lattner 248c9f8f416800784ca6453222b307bc44ad24739b0Chris Lattner/** 249475871a144eb604ddaf37503397ba0941442e5fbDan Gohman * radius_client_register - Register a RADIUS client RX handler 250475871a144eb604ddaf37503397ba0941442e5fbDan Gohman * @radius: RADIUS client context from radius_client_init() 251c9f8f416800784ca6453222b307bc44ad24739b0Chris Lattner * @msg_type: RADIUS client type (RADIUS_AUTH or RADIUS_ACCT) 252c9f8f416800784ca6453222b307bc44ad24739b0Chris Lattner * @handler: Handler for received RADIUS messages 253475871a144eb604ddaf37503397ba0941442e5fbDan Gohman * @data: Context pointer for handler callbacks 254c9f8f416800784ca6453222b307bc44ad24739b0Chris Lattner * Returns: 0 on success, -1 on failure 255475871a144eb604ddaf37503397ba0941442e5fbDan Gohman * 256c9f8f416800784ca6453222b307bc44ad24739b0Chris Lattner * This function is used to register a handler for processing received RADIUS 257c9f8f416800784ca6453222b307bc44ad24739b0Chris Lattner * authentication and accounting messages. The handler() callback function will 258c9f8f416800784ca6453222b307bc44ad24739b0Chris Lattner * be called whenever a RADIUS message is received from the active server. 259475871a144eb604ddaf37503397ba0941442e5fbDan Gohman * 260d6594ae54cfde4db4d30272192645c0a45fb9902Evan Cheng * There can be multiple registered RADIUS message handlers. The handlers will 261475871a144eb604ddaf37503397ba0941442e5fbDan Gohman * be called in order until one of them indicates that it has processed or 26283ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands * queued the message. 263d6594ae54cfde4db4d30272192645c0a45fb9902Evan Cheng */ 264d6594ae54cfde4db4d30272192645c0a45fb9902Evan Chengint radius_client_register(struct radius_client_data *radius, 265d6594ae54cfde4db4d30272192645c0a45fb9902Evan Cheng RadiusType msg_type, 266475871a144eb604ddaf37503397ba0941442e5fbDan Gohman RadiusRxResult (*handler)(struct radius_msg *msg, 267475871a144eb604ddaf37503397ba0941442e5fbDan Gohman struct radius_msg *req, 268475871a144eb604ddaf37503397ba0941442e5fbDan Gohman const u8 *shared_secret, 269475871a144eb604ddaf37503397ba0941442e5fbDan Gohman size_t shared_secret_len, 270475871a144eb604ddaf37503397ba0941442e5fbDan Gohman void *data), 271475871a144eb604ddaf37503397ba0941442e5fbDan Gohman void *data) 272475871a144eb604ddaf37503397ba0941442e5fbDan Gohman{ 2737f460203b0c5350e9b2c592f438e40f7a7de6e45Dan Gohman struct radius_rx_handler **handlers, *newh; 274475871a144eb604ddaf37503397ba0941442e5fbDan Gohman size_t *num; 275c3aae25116e66c177579b0b79182b09340b19753Chris Lattner 276475871a144eb604ddaf37503397ba0941442e5fbDan Gohman if (msg_type == RADIUS_ACCT) { 277d5d0f9bd20d9df07d6b4d41b7e8ed6d33b6a649dChris Lattner handlers = &radius->acct_handlers; 278d5d0f9bd20d9df07d6b4d41b7e8ed6d33b6a649dChris Lattner num = &radius->num_acct_handlers; 279cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner } else { 280cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner handlers = &radius->auth_handlers; 281e3f1026683c38f6605ccaf698b7082f1b0a0f8c8Chris Lattner num = &radius->num_auth_handlers; 282e3f1026683c38f6605ccaf698b7082f1b0a0f8c8Chris Lattner } 283e3f1026683c38f6605ccaf698b7082f1b0a0f8c8Chris Lattner 284475871a144eb604ddaf37503397ba0941442e5fbDan Gohman newh = os_realloc_array(*handlers, *num + 1, 285475871a144eb604ddaf37503397ba0941442e5fbDan Gohman sizeof(struct radius_rx_handler)); 28683ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands if (newh == NULL) 287475871a144eb604ddaf37503397ba0941442e5fbDan Gohman return -1; 2882fa6d3b1fcadbde90eaee0e8e89aebd81630b662Chris Lattner 289e3f1026683c38f6605ccaf698b7082f1b0a0f8c8Chris Lattner newh[*num].handler = handler; 29066a48bbc3565b40ea0e6f2d58cf5e3a8e64802efEvan Cheng newh[*num].data = data; 291475871a144eb604ddaf37503397ba0941442e5fbDan Gohman (*num)++; 292475871a144eb604ddaf37503397ba0941442e5fbDan Gohman *handlers = newh; 293475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 29483ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands return 0; 295475871a144eb604ddaf37503397ba0941442e5fbDan Gohman} 2962fa6d3b1fcadbde90eaee0e8e89aebd81630b662Chris Lattner 29766a48bbc3565b40ea0e6f2d58cf5e3a8e64802efEvan Cheng 298e3f1026683c38f6605ccaf698b7082f1b0a0f8c8Chris Lattnerstatic void radius_client_handle_send_error(struct radius_client_data *radius, 299475871a144eb604ddaf37503397ba0941442e5fbDan Gohman int s, RadiusType msg_type) 30083ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands{ 301475871a144eb604ddaf37503397ba0941442e5fbDan Gohman#ifndef CONFIG_NATIVE_WINDOWS 3022fa6d3b1fcadbde90eaee0e8e89aebd81630b662Chris Lattner int _errno = errno; 30318c2f13e0f9d0e5d6227cf6d1881e9ee3d1b6109Chris Lattner perror("send[RADIUS]"); 304e3f1026683c38f6605ccaf698b7082f1b0a0f8c8Chris Lattner if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL || 305e3f1026683c38f6605ccaf698b7082f1b0a0f8c8Chris Lattner _errno == EBADF) { 306e3f1026683c38f6605ccaf698b7082f1b0a0f8c8Chris Lattner hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 307e3f1026683c38f6605ccaf698b7082f1b0a0f8c8Chris Lattner HOSTAPD_LEVEL_INFO, 308475871a144eb604ddaf37503397ba0941442e5fbDan Gohman "Send failed - maybe interface status changed -" 309475871a144eb604ddaf37503397ba0941442e5fbDan Gohman " try to connect again"); 31083ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands eloop_unregister_read_sock(s); 311475871a144eb604ddaf37503397ba0941442e5fbDan Gohman close(s); 3122fa6d3b1fcadbde90eaee0e8e89aebd81630b662Chris Lattner if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) 313e3f1026683c38f6605ccaf698b7082f1b0a0f8c8Chris Lattner radius_client_init_acct(radius); 31418c2f13e0f9d0e5d6227cf6d1881e9ee3d1b6109Chris Lattner else 315475871a144eb604ddaf37503397ba0941442e5fbDan Gohman radius_client_init_auth(radius); 316cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner } 3171ccae666f596d5aeca5c9942995763600b622062Chris Lattner#endif /* CONFIG_NATIVE_WINDOWS */ 3181ccae666f596d5aeca5c9942995763600b622062Chris Lattner} 319475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 3206a5b6d7633c96c72ca7d5f8ba0c855e4690ada04Chris Lattner 3216a5b6d7633c96c72ca7d5f8ba0c855e4690ada04Chris Lattnerstatic int radius_client_retransmit(struct radius_client_data *radius, 3226a5b6d7633c96c72ca7d5f8ba0c855e4690ada04Chris Lattner struct radius_msg_list *entry, 323475871a144eb604ddaf37503397ba0941442e5fbDan Gohman os_time_t now) 32483ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands{ 325475871a144eb604ddaf37503397ba0941442e5fbDan Gohman struct hostapd_radius_servers *conf = radius->conf; 3262fa6d3b1fcadbde90eaee0e8e89aebd81630b662Chris Lattner int s; 3276a5b6d7633c96c72ca7d5f8ba0c855e4690ada04Chris Lattner struct wpabuf *buf; 3281ccae666f596d5aeca5c9942995763600b622062Chris Lattner 3290f8d9c04d9feef86cee35cf5fecfb348a6b3de50Bill Wendling if (entry->msg_type == RADIUS_ACCT || 3300f8d9c04d9feef86cee35cf5fecfb348a6b3de50Bill Wendling entry->msg_type == RADIUS_ACCT_INTERIM) { 331475871a144eb604ddaf37503397ba0941442e5fbDan Gohman s = radius->acct_sock; 332475871a144eb604ddaf37503397ba0941442e5fbDan Gohman if (entry->attempts == 0) 3330f8d9c04d9feef86cee35cf5fecfb348a6b3de50Bill Wendling conf->acct_server->requests++; 334475871a144eb604ddaf37503397ba0941442e5fbDan Gohman else { 3350f8d9c04d9feef86cee35cf5fecfb348a6b3de50Bill Wendling conf->acct_server->timeouts++; 3360f8d9c04d9feef86cee35cf5fecfb348a6b3de50Bill Wendling conf->acct_server->retransmissions++; 3370f8d9c04d9feef86cee35cf5fecfb348a6b3de50Bill Wendling } 3380f8d9c04d9feef86cee35cf5fecfb348a6b3de50Bill Wendling } else { 3390f8d9c04d9feef86cee35cf5fecfb348a6b3de50Bill Wendling s = radius->auth_sock; 34034cd4a484e532cc463fd5a4bf59b88d13c5467c1Evan Cheng if (entry->attempts == 0) 3410f8d9c04d9feef86cee35cf5fecfb348a6b3de50Bill Wendling conf->auth_server->requests++; 3420f8d9c04d9feef86cee35cf5fecfb348a6b3de50Bill Wendling else { 343c3aae25116e66c177579b0b79182b09340b19753Chris Lattner conf->auth_server->timeouts++; 344cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner conf->auth_server->retransmissions++; 345475871a144eb604ddaf37503397ba0941442e5fbDan Gohman } 346475871a144eb604ddaf37503397ba0941442e5fbDan Gohman } 347475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 348475871a144eb604ddaf37503397ba0941442e5fbDan Gohman /* retransmit; remove entry if too many attempts */ 349475871a144eb604ddaf37503397ba0941442e5fbDan Gohman entry->attempts++; 350475871a144eb604ddaf37503397ba0941442e5fbDan Gohman hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS, 351475871a144eb604ddaf37503397ba0941442e5fbDan Gohman HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)", 352475871a144eb604ddaf37503397ba0941442e5fbDan Gohman radius_msg_get_hdr(entry->msg)->identifier); 353475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 354475871a144eb604ddaf37503397ba0941442e5fbDan Gohman os_get_time(&entry->last_attempt); 355475871a144eb604ddaf37503397ba0941442e5fbDan Gohman buf = radius_msg_get_buf(entry->msg); 356475871a144eb604ddaf37503397ba0941442e5fbDan Gohman if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) 357475871a144eb604ddaf37503397ba0941442e5fbDan Gohman radius_client_handle_send_error(radius, s, entry->msg_type); 3586d9cdd56173fb915a9e3a8f0f6b5a8ed9bed1098Dan Gohman 359475871a144eb604ddaf37503397ba0941442e5fbDan Gohman entry->next_try = now + entry->next_wait; 360475871a144eb604ddaf37503397ba0941442e5fbDan Gohman entry->next_wait *= 2; 361475871a144eb604ddaf37503397ba0941442e5fbDan Gohman if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT) 362475871a144eb604ddaf37503397ba0941442e5fbDan Gohman entry->next_wait = RADIUS_CLIENT_MAX_WAIT; 363475871a144eb604ddaf37503397ba0941442e5fbDan Gohman if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) { 364475871a144eb604ddaf37503397ba0941442e5fbDan Gohman printf("Removing un-ACKed RADIUS message due to too many " 365475871a144eb604ddaf37503397ba0941442e5fbDan Gohman "failed retransmit attempts\n"); 366475871a144eb604ddaf37503397ba0941442e5fbDan Gohman return 1; 367475871a144eb604ddaf37503397ba0941442e5fbDan Gohman } 368475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 369475871a144eb604ddaf37503397ba0941442e5fbDan Gohman return 0; 370475871a144eb604ddaf37503397ba0941442e5fbDan Gohman} 371475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 372475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 373475871a144eb604ddaf37503397ba0941442e5fbDan Gohmanstatic void radius_client_timer(void *eloop_ctx, void *timeout_ctx) 374475871a144eb604ddaf37503397ba0941442e5fbDan Gohman{ 375475871a144eb604ddaf37503397ba0941442e5fbDan Gohman struct radius_client_data *radius = eloop_ctx; 376475871a144eb604ddaf37503397ba0941442e5fbDan Gohman struct hostapd_radius_servers *conf = radius->conf; 377475871a144eb604ddaf37503397ba0941442e5fbDan Gohman struct os_time now; 378707e0184233f27e0e9f9aee0309f2daab8cfe7f8Dan Gohman os_time_t first; 3791f13c686df75ddbbe15b208606ece4846d7479a8Dan Gohman struct radius_msg_list *entry, *prev, *tmp; 3801f13c686df75ddbbe15b208606ece4846d7479a8Dan Gohman int auth_failover = 0, acct_failover = 0; 3815c0d6ed325417baa5d119af9c2b6790231d8565fRafael Espindola char abuf[50]; 382475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 383475871a144eb604ddaf37503397ba0941442e5fbDan Gohman entry = radius->msgs; 3841f13c686df75ddbbe15b208606ece4846d7479a8Dan Gohman if (!entry) 3851f13c686df75ddbbe15b208606ece4846d7479a8Dan Gohman return; 3865c0d6ed325417baa5d119af9c2b6790231d8565fRafael Espindola 387475871a144eb604ddaf37503397ba0941442e5fbDan Gohman os_get_time(&now); 388475871a144eb604ddaf37503397ba0941442e5fbDan Gohman first = 0; 3891f13c686df75ddbbe15b208606ece4846d7479a8Dan Gohman 3905c0d6ed325417baa5d119af9c2b6790231d8565fRafael Espindola prev = NULL; 3917cf7e3f33f25544d08492d47cc8a1cbba25dc8d7Chris Lattner while (entry) { 392475871a144eb604ddaf37503397ba0941442e5fbDan Gohman if (now.sec >= entry->next_try && 3937cf7e3f33f25544d08492d47cc8a1cbba25dc8d7Chris Lattner radius_client_retransmit(radius, entry, now.sec)) { 394475871a144eb604ddaf37503397ba0941442e5fbDan Gohman if (prev) 3957cf7e3f33f25544d08492d47cc8a1cbba25dc8d7Chris Lattner prev->next = entry->next; 3967cf7e3f33f25544d08492d47cc8a1cbba25dc8d7Chris Lattner else 397b43e9c196542acc80c9e4643809661065710848fNate Begeman radius->msgs = entry->next; 398b43e9c196542acc80c9e4643809661065710848fNate Begeman 399b43e9c196542acc80c9e4643809661065710848fNate Begeman tmp = entry; 400475871a144eb604ddaf37503397ba0941442e5fbDan Gohman entry = entry->next; 401b43e9c196542acc80c9e4643809661065710848fNate Begeman radius_client_msg_free(tmp); 402475871a144eb604ddaf37503397ba0941442e5fbDan Gohman radius->num_msgs--; 403b43e9c196542acc80c9e4643809661065710848fNate Begeman continue; 404b43e9c196542acc80c9e4643809661065710848fNate Begeman } 4057cf7e3f33f25544d08492d47cc8a1cbba25dc8d7Chris Lattner 4069373a81e53ce5f9f2c06c4209b8b886605aece08Nate Begeman if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) { 4079373a81e53ce5f9f2c06c4209b8b886605aece08Nate Begeman if (entry->msg_type == RADIUS_ACCT || 408475871a144eb604ddaf37503397ba0941442e5fbDan Gohman entry->msg_type == RADIUS_ACCT_INTERIM) 4099373a81e53ce5f9f2c06c4209b8b886605aece08Nate Begeman acct_failover++; 410475871a144eb604ddaf37503397ba0941442e5fbDan Gohman else 411475871a144eb604ddaf37503397ba0941442e5fbDan Gohman auth_failover++; 4122fa6d3b1fcadbde90eaee0e8e89aebd81630b662Chris Lattner } 4132fa6d3b1fcadbde90eaee0e8e89aebd81630b662Chris Lattner 4149373a81e53ce5f9f2c06c4209b8b886605aece08Nate Begeman if (first == 0 || entry->next_try < first) 4157cf7e3f33f25544d08492d47cc8a1cbba25dc8d7Chris Lattner first = entry->next_try; 416acc398c195a697795bff3245943d104eb19192b9Nate Begeman 417acc398c195a697795bff3245943d104eb19192b9Nate Begeman prev = entry; 418475871a144eb604ddaf37503397ba0941442e5fbDan Gohman entry = entry->next; 419475871a144eb604ddaf37503397ba0941442e5fbDan Gohman } 4207cbd525ba85ebe440d15fa359ec940e404d14906Nate Begeman 421ab0b949e0e9de452f3b052b11634ab761e008b23Andrew Lenharth if (radius->msgs) { 42228873106309db515d58889a4c4fa3e0a92d1b60eMon P Wang if (first < now.sec) 423475871a144eb604ddaf37503397ba0941442e5fbDan Gohman first = now.sec; 424475871a144eb604ddaf37503397ba0941442e5fbDan Gohman eloop_register_timeout(first - now.sec, 0, 42528873106309db515d58889a4c4fa3e0a92d1b60eMon P Wang radius_client_timer, radius, NULL); 426ab0b949e0e9de452f3b052b11634ab761e008b23Andrew Lenharth hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 427ab0b949e0e9de452f3b052b11634ab761e008b23Andrew Lenharth HOSTAPD_LEVEL_DEBUG, "Next RADIUS client " 42828873106309db515d58889a4c4fa3e0a92d1b60eMon P Wang "retransmit in %ld seconds", 429475871a144eb604ddaf37503397ba0941442e5fbDan Gohman (long int) (first - now.sec)); 430475871a144eb604ddaf37503397ba0941442e5fbDan Gohman } 43128873106309db515d58889a4c4fa3e0a92d1b60eMon P Wang 432ab0b949e0e9de452f3b052b11634ab761e008b23Andrew Lenharth if (auth_failover && conf->num_auth_servers > 1) { 4334bdcb61af33399d4e01fdf3c47ca1f1f5356e370Duncan Sands struct hostapd_radius_server *next, *old; 4344bdcb61af33399d4e01fdf3c47ca1f1f5356e370Duncan Sands old = conf->auth_server; 435475871a144eb604ddaf37503397ba0941442e5fbDan Gohman hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 4364bdcb61af33399d4e01fdf3c47ca1f1f5356e370Duncan Sands HOSTAPD_LEVEL_NOTICE, 4374bdcb61af33399d4e01fdf3c47ca1f1f5356e370Duncan Sands "No response from Authentication server " 438f9516208e57364ab1e7d8748af1f59a2ea5fb572Duncan Sands "%s:%d - failover", 439f9516208e57364ab1e7d8748af1f59a2ea5fb572Duncan Sands hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)), 4404bdcb61af33399d4e01fdf3c47ca1f1f5356e370Duncan Sands old->port); 441475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 442f9516208e57364ab1e7d8748af1f59a2ea5fb572Duncan Sands for (entry = radius->msgs; entry; entry = entry->next) { 443f9516208e57364ab1e7d8748af1f59a2ea5fb572Duncan Sands if (entry->msg_type == RADIUS_AUTH) 444f9516208e57364ab1e7d8748af1f59a2ea5fb572Duncan Sands old->timeouts++; 445f9516208e57364ab1e7d8748af1f59a2ea5fb572Duncan Sands } 446f9516208e57364ab1e7d8748af1f59a2ea5fb572Duncan Sands 447f9516208e57364ab1e7d8748af1f59a2ea5fb572Duncan Sands next = old + 1; 448c3aae25116e66c177579b0b79182b09340b19753Chris Lattner if (next > &(conf->auth_servers[conf->num_auth_servers - 1])) 449c3aae25116e66c177579b0b79182b09340b19753Chris Lattner next = conf->auth_servers; 450cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner conf->auth_server = next; 451475871a144eb604ddaf37503397ba0941442e5fbDan Gohman radius_change_server(radius, next, old, 45295c218a83ecf77590b9dc40c636720772d2b5cd7Christopher Lamb radius->auth_serv_sock, 45395c218a83ecf77590b9dc40c636720772d2b5cd7Christopher Lamb radius->auth_serv_sock6, 1); 454475871a144eb604ddaf37503397ba0941442e5fbDan Gohman } 455475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 45683ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands if (acct_failover && conf->num_acct_servers > 1) { 45795c218a83ecf77590b9dc40c636720772d2b5cd7Christopher Lamb struct hostapd_radius_server *next, *old; 458475871a144eb604ddaf37503397ba0941442e5fbDan Gohman old = conf->acct_server; 459475871a144eb604ddaf37503397ba0941442e5fbDan Gohman hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 460475871a144eb604ddaf37503397ba0941442e5fbDan Gohman HOSTAPD_LEVEL_NOTICE, 461475871a144eb604ddaf37503397ba0941442e5fbDan Gohman "No response from Accounting server " 462475871a144eb604ddaf37503397ba0941442e5fbDan Gohman "%s:%d - failover", 46383ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)), 464e10efce22502d1a1855d25baf1458660f4ba6f33Duncan Sands old->port); 4652d86ea21dd76647cb054fd5d27df9e49efc672b6Andrew Lenharth 466ad071e1cd1a4b880019f1b2e827ee81867815f82Evan Cheng for (entry = radius->msgs; entry; entry = entry->next) { 467ad071e1cd1a4b880019f1b2e827ee81867815f82Evan Cheng if (entry->msg_type == RADIUS_ACCT || 468475871a144eb604ddaf37503397ba0941442e5fbDan Gohman entry->msg_type == RADIUS_ACCT_INTERIM) 46995c218a83ecf77590b9dc40c636720772d2b5cd7Christopher Lamb old->timeouts++; 47095c218a83ecf77590b9dc40c636720772d2b5cd7Christopher Lamb } 471475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 47283ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands next = old + 1; 47395c218a83ecf77590b9dc40c636720772d2b5cd7Christopher Lamb if (next > &conf->acct_servers[conf->num_acct_servers - 1]) 474475871a144eb604ddaf37503397ba0941442e5fbDan Gohman next = conf->acct_servers; 475475871a144eb604ddaf37503397ba0941442e5fbDan Gohman conf->acct_server = next; 476ad071e1cd1a4b880019f1b2e827ee81867815f82Evan Cheng radius_change_server(radius, next, old, 47769de1932b350d7cdfc0ed1f4198d6f78c7822a02Dan Gohman radius->acct_serv_sock, 478475871a144eb604ddaf37503397ba0941442e5fbDan Gohman radius->acct_serv_sock6, 0); 47969de1932b350d7cdfc0ed1f4198d6f78c7822a02Dan Gohman } 48069de1932b350d7cdfc0ed1f4198d6f78c7822a02Dan Gohman} 48169de1932b350d7cdfc0ed1f4198d6f78c7822a02Dan Gohman 482475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 483cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattnerstatic void radius_client_update_timeout(struct radius_client_data *radius) 484b9aff659e82e4ec1a507e6e7fe7969379a431613Chris Lattner{ 485b9aff659e82e4ec1a507e6e7fe7969379a431613Chris Lattner struct os_time now; 486b9aff659e82e4ec1a507e6e7fe7969379a431613Chris Lattner os_time_t first; 487b9aff659e82e4ec1a507e6e7fe7969379a431613Chris Lattner struct radius_msg_list *entry; 488b9aff659e82e4ec1a507e6e7fe7969379a431613Chris Lattner 489b9aff659e82e4ec1a507e6e7fe7969379a431613Chris Lattner eloop_cancel_timeout(radius_client_timer, radius, NULL); 490475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 491475871a144eb604ddaf37503397ba0941442e5fbDan Gohman if (radius->msgs == NULL) { 492475871a144eb604ddaf37503397ba0941442e5fbDan Gohman return; 493475871a144eb604ddaf37503397ba0941442e5fbDan Gohman } 494475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 495475871a144eb604ddaf37503397ba0941442e5fbDan Gohman first = 0; 496475871a144eb604ddaf37503397ba0941442e5fbDan Gohman for (entry = radius->msgs; entry; entry = entry->next) { 497475871a144eb604ddaf37503397ba0941442e5fbDan Gohman if (first == 0 || entry->next_try < first) 498475871a144eb604ddaf37503397ba0941442e5fbDan Gohman first = entry->next_try; 499475871a144eb604ddaf37503397ba0941442e5fbDan Gohman } 5001b95095857b78e12138c22e76c7936611c51355bChris Lattner 5011b95095857b78e12138c22e76c7936611c51355bChris Lattner os_get_time(&now); 5021b95095857b78e12138c22e76c7936611c51355bChris Lattner if (first < now.sec) 5031b95095857b78e12138c22e76c7936611c51355bChris Lattner first = now.sec; 504e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius, 50583ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands NULL); 506475871a144eb604ddaf37503397ba0941442e5fbDan Gohman hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 50783ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in" 508475871a144eb604ddaf37503397ba0941442e5fbDan Gohman " %ld seconds", (long int) (first - now.sec)); 50983ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands} 510475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 51183ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands 512475871a144eb604ddaf37503397ba0941442e5fbDan Gohmanstatic void radius_client_list_add(struct radius_client_data *radius, 513cd920d9ecfcefff13c3619a32b58399cac2e3630Dan Gohman struct radius_msg *msg, 514cd920d9ecfcefff13c3619a32b58399cac2e3630Dan Gohman RadiusType msg_type, 515475871a144eb604ddaf37503397ba0941442e5fbDan Gohman const u8 *shared_secret, 516cd920d9ecfcefff13c3619a32b58399cac2e3630Dan Gohman size_t shared_secret_len, const u8 *addr) 517475871a144eb604ddaf37503397ba0941442e5fbDan Gohman{ 518cd920d9ecfcefff13c3619a32b58399cac2e3630Dan Gohman struct radius_msg_list *entry, *prev; 519475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 52083ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands if (eloop_terminated()) { 521475871a144eb604ddaf37503397ba0941442e5fbDan Gohman /* No point in adding entries to retransmit queue since event 52283ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands * loop has already been terminated. */ 523475871a144eb604ddaf37503397ba0941442e5fbDan Gohman radius_msg_free(msg); 524cd920d9ecfcefff13c3619a32b58399cac2e3630Dan Gohman return; 525475871a144eb604ddaf37503397ba0941442e5fbDan Gohman } 526694481ee01bfe507c6e37de0dc1c64cff455eefdEvan Cheng 527e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman entry = os_zalloc(sizeof(*entry)); 528e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman if (entry == NULL) { 529e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman printf("Failed to add RADIUS packet into retransmit list\n"); 530475871a144eb604ddaf37503397ba0941442e5fbDan Gohman radius_msg_free(msg); 531e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman return; 532475871a144eb604ddaf37503397ba0941442e5fbDan Gohman } 533e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman 534475871a144eb604ddaf37503397ba0941442e5fbDan Gohman if (addr) 535e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman os_memcpy(entry->addr, addr, ETH_ALEN); 536475871a144eb604ddaf37503397ba0941442e5fbDan Gohman entry->msg = msg; 537e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman entry->msg_type = msg_type; 538e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman entry->shared_secret = shared_secret; 539475871a144eb604ddaf37503397ba0941442e5fbDan Gohman entry->shared_secret_len = shared_secret_len; 540e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman os_get_time(&entry->last_attempt); 541475871a144eb604ddaf37503397ba0941442e5fbDan Gohman entry->first_try = entry->last_attempt.sec; 542e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT; 543475871a144eb604ddaf37503397ba0941442e5fbDan Gohman entry->attempts = 1; 544e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2; 545475871a144eb604ddaf37503397ba0941442e5fbDan Gohman entry->next = radius->msgs; 546e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman radius->msgs = entry; 547475871a144eb604ddaf37503397ba0941442e5fbDan Gohman radius_client_update_timeout(radius); 548e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman 549475871a144eb604ddaf37503397ba0941442e5fbDan Gohman if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) { 550753c8f20e45f6e4198c7cf4096ecc8948a029e9cChris Lattner printf("Removing the oldest un-ACKed RADIUS packet due to " 5516ae46c4c8757237bca2b78b589c96c37015bc356Evan Cheng "retransmit list limits.\n"); 5526ae46c4c8757237bca2b78b589c96c37015bc356Evan Cheng prev = NULL; 5536ae46c4c8757237bca2b78b589c96c37015bc356Evan Cheng while (entry->next) { 5546ae46c4c8757237bca2b78b589c96c37015bc356Evan Cheng prev = entry; 5556ae46c4c8757237bca2b78b589c96c37015bc356Evan Cheng entry = entry->next; 5566ae46c4c8757237bca2b78b589c96c37015bc356Evan Cheng } 55783ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands if (prev) { 558475871a144eb604ddaf37503397ba0941442e5fbDan Gohman prev->next = NULL; 559475871a144eb604ddaf37503397ba0941442e5fbDan Gohman radius_client_msg_free(entry); 56083ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands } 561475871a144eb604ddaf37503397ba0941442e5fbDan Gohman } else 56283ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands radius->num_msgs++; 563475871a144eb604ddaf37503397ba0941442e5fbDan Gohman} 56483ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands 565475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 56683ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sandsstatic void radius_client_list_del(struct radius_client_data *radius, 567475871a144eb604ddaf37503397ba0941442e5fbDan Gohman RadiusType msg_type, const u8 *addr) 56883ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands{ 569475871a144eb604ddaf37503397ba0941442e5fbDan Gohman struct radius_msg_list *entry, *prev, *tmp; 57083ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands 571475871a144eb604ddaf37503397ba0941442e5fbDan Gohman if (addr == NULL) 57283ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands return; 573475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 57483ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands entry = radius->msgs; 575475871a144eb604ddaf37503397ba0941442e5fbDan Gohman prev = NULL; 57683ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands while (entry) { 577475871a144eb604ddaf37503397ba0941442e5fbDan Gohman if (entry->msg_type == msg_type && 57883ec4b6711980242ef3c55a4fa36b2d7a39c1bfbDuncan Sands os_memcmp(entry->addr, addr, ETH_ALEN) == 0) { 579475871a144eb604ddaf37503397ba0941442e5fbDan Gohman if (prev) 580f877b735ad4987f26cafcbaf22aa4c2199458b5dDan Gohman prev->next = entry->next; 581475871a144eb604ddaf37503397ba0941442e5fbDan Gohman else 58208b1173971a51eb89d7d6ee0992c39170c86994aEvan Cheng radius->msgs = entry->next; 58308b1173971a51eb89d7d6ee0992c39170c86994aEvan Cheng tmp = entry; 58408b1173971a51eb89d7d6ee0992c39170c86994aEvan Cheng entry = entry->next; 58508b1173971a51eb89d7d6ee0992c39170c86994aEvan Cheng hostapd_logger(radius->ctx, addr, 586475871a144eb604ddaf37503397ba0941442e5fbDan Gohman HOSTAPD_MODULE_RADIUS, 5876542d950609208de3e1cde704c5f89aad864c0d9Chris Lattner HOSTAPD_LEVEL_DEBUG, 588f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner "Removing matching RADIUS message"); 589f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner radius_client_msg_free(tmp); 590f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner radius->num_msgs--; 591f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner continue; 592f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner } 593f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner prev = entry; 594edfcf598faab9ce294712551ecf67093acd1c66eDuncan Sands entry = entry->next; 595edfcf598faab9ce294712551ecf67093acd1c66eDuncan Sands } 596edfcf598faab9ce294712551ecf67093acd1c66eDuncan Sands} 597edfcf598faab9ce294712551ecf67093acd1c66eDuncan Sands 598edfcf598faab9ce294712551ecf67093acd1c66eDuncan Sands 599edfcf598faab9ce294712551ecf67093acd1c66eDuncan Sands/** 600f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner * radius_client_send - Send a RADIUS request 601f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner * @radius: RADIUS client context from radius_client_init() 602f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner * @msg: RADIUS message to be sent 603f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner * @msg_type: Message type (RADIUS_AUTH, RADIUS_ACCT, RADIUS_ACCT_INTERIM) 604f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner * @addr: MAC address of the device related to this message or %NULL 605f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner * Returns: 0 on success, -1 on failure 606f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner * 607f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner * This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or 6080fe9c6e7babb3c0731d9cb864ec498ec4184760fDan Gohman * accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference 6090fe9c6e7babb3c0731d9cb864ec498ec4184760fDan Gohman * between accounting and interim accounting messages is that the interim 6100fe9c6e7babb3c0731d9cb864ec498ec4184760fDan Gohman * message will override any pending interim accounting updates while a new 6110fe9c6e7babb3c0731d9cb864ec498ec4184760fDan Gohman * accounting message does not remove any pending messages. 6120fe9c6e7babb3c0731d9cb864ec498ec4184760fDan Gohman * 6136542d950609208de3e1cde704c5f89aad864c0d9Chris Lattner * The message is added on the retransmission queue and will be retransmitted 61426005b1b672aebd437edc561d381c5dd19a03ddbChris Lattner * automatically until a response is received or maximum number of retries 61526005b1b672aebd437edc561d381c5dd19a03ddbChris Lattner * (RADIUS_CLIENT_MAX_RETRIES) is reached. 61626005b1b672aebd437edc561d381c5dd19a03ddbChris Lattner * 6176542d950609208de3e1cde704c5f89aad864c0d9Chris Lattner * The related device MAC address can be used to identify pending messages that 618f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner * can be removed with radius_client_flush_auth() or with interim accounting 619f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner * updates. 620f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner */ 621fde3f3061d665babeb78443119a09876098fc35eChris Lattnerint radius_client_send(struct radius_client_data *radius, 622475871a144eb604ddaf37503397ba0941442e5fbDan Gohman struct radius_msg *msg, RadiusType msg_type, 623f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner const u8 *addr) 624fde3f3061d665babeb78443119a09876098fc35eChris Lattner{ 625f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner struct hostapd_radius_servers *conf = radius->conf; 626475871a144eb604ddaf37503397ba0941442e5fbDan Gohman const u8 *shared_secret; 627f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner size_t shared_secret_len; 628fae9f1cb34d6d2c4dbd007f2d748a70b67776a82Evan Cheng char *name; 62980274268b99e5a066825c8cc5aba58dbc5ad0a52Chris Lattner int s, res; 630f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner struct wpabuf *buf; 631475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 632f8dc0617baceeba8ccd67c8881eb88eb1be2902cChris Lattner if (msg_type == RADIUS_ACCT_INTERIM) { 63380274268b99e5a066825c8cc5aba58dbc5ad0a52Chris Lattner /* Remove any pending interim acct update for the same STA. */ 634e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman radius_client_list_del(radius, msg_type, addr); 635e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman } 636e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman 637475871a144eb604ddaf37503397ba0941442e5fbDan Gohman if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) { 638e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman if (conf->acct_server == NULL) { 639e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman hostapd_logger(radius->ctx, NULL, 640e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman HOSTAPD_MODULE_RADIUS, 641e6f35d8a5cc92d776cf460200e2b815e8c301b14Evan Cheng HOSTAPD_LEVEL_INFO, 64209fd736058ec3f69b856ae3ad65177bc31904a8cEvan Cheng "No accounting server configured"); 64309fd736058ec3f69b856ae3ad65177bc31904a8cEvan Cheng return -1; 64409fd736058ec3f69b856ae3ad65177bc31904a8cEvan Cheng } 645e6f35d8a5cc92d776cf460200e2b815e8c301b14Evan Cheng shared_secret = conf->acct_server->shared_secret; 6461efba0ecb4d0b3807c48e6e0f74e3ce5c9fad809Evan Cheng shared_secret_len = conf->acct_server->shared_secret_len; 6471efba0ecb4d0b3807c48e6e0f74e3ce5c9fad809Evan Cheng radius_msg_finish_acct(msg, shared_secret, shared_secret_len); 6481efba0ecb4d0b3807c48e6e0f74e3ce5c9fad809Evan Cheng name = "accounting"; 6494ae9e0c5301126d7f2d4b2975eb86ed21f7b574dChris Lattner s = radius->acct_sock; 6504ae9e0c5301126d7f2d4b2975eb86ed21f7b574dChris Lattner conf->acct_server->requests++; 6511efba0ecb4d0b3807c48e6e0f74e3ce5c9fad809Evan Cheng } else { 6521efba0ecb4d0b3807c48e6e0f74e3ce5c9fad809Evan Cheng if (conf->auth_server == NULL) { 6531efba0ecb4d0b3807c48e6e0f74e3ce5c9fad809Evan Cheng hostapd_logger(radius->ctx, NULL, 6541efba0ecb4d0b3807c48e6e0f74e3ce5c9fad809Evan Cheng HOSTAPD_MODULE_RADIUS, 6551efba0ecb4d0b3807c48e6e0f74e3ce5c9fad809Evan Cheng HOSTAPD_LEVEL_INFO, 656b6c7437568f0472548ede2710458f52cfad4532eDan Gohman "No authentication server configured"); 657b6c7437568f0472548ede2710458f52cfad4532eDan Gohman return -1; 6581efba0ecb4d0b3807c48e6e0f74e3ce5c9fad809Evan Cheng } 6591efba0ecb4d0b3807c48e6e0f74e3ce5c9fad809Evan Cheng shared_secret = conf->auth_server->shared_secret; 6601efba0ecb4d0b3807c48e6e0f74e3ce5c9fad809Evan Cheng shared_secret_len = conf->auth_server->shared_secret_len; 6611efba0ecb4d0b3807c48e6e0f74e3ce5c9fad809Evan Cheng radius_msg_finish(msg, shared_secret, shared_secret_len); 6621efba0ecb4d0b3807c48e6e0f74e3ce5c9fad809Evan Cheng name = "authentication"; 6631efba0ecb4d0b3807c48e6e0f74e3ce5c9fad809Evan Cheng s = radius->auth_sock; 6641efba0ecb4d0b3807c48e6e0f74e3ce5c9fad809Evan Cheng conf->auth_server->requests++; 6651efba0ecb4d0b3807c48e6e0f74e3ce5c9fad809Evan Cheng } 6661efba0ecb4d0b3807c48e6e0f74e3ce5c9fad809Evan Cheng 6671efba0ecb4d0b3807c48e6e0f74e3ce5c9fad809Evan Cheng hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 6681efba0ecb4d0b3807c48e6e0f74e3ce5c9fad809Evan Cheng HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s " 669cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner "server", name); 670d1fc96499b7619356c7542200d32da898b79f7c1Chris Lattner if (conf->msg_dumps) 67137ce9df0da6cddc3b8bfef9b63d33d058a0f2f15Chris Lattner radius_msg_dump(msg); 672364d73ddab43b699ab90240f11b7a2eb5cf69bd8Mon P Wang 673364d73ddab43b699ab90240f11b7a2eb5cf69bd8Mon P Wang buf = radius_msg_get_buf(msg); 674475871a144eb604ddaf37503397ba0941442e5fbDan Gohman res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0); 675364d73ddab43b699ab90240f11b7a2eb5cf69bd8Mon P Wang if (res < 0) 67651dabfb28375be7bc5848806ae31cd068b6133f8Chris Lattner radius_client_handle_send_error(radius, s, msg_type); 677475871a144eb604ddaf37503397ba0941442e5fbDan Gohman 678475871a144eb604ddaf37503397ba0941442e5fbDan Gohman radius_client_list_add(radius, msg, msg_type, shared_secret, 67951dabfb28375be7bc5848806ae31cd068b6133f8Chris Lattner shared_secret_len, addr); 6802e68b6f52d0979575b2f02ed29717d907ba0684cDan Gohman 6812e68b6f52d0979575b2f02ed29717d907ba0684cDan Gohman return 0; 682475871a144eb604ddaf37503397ba0941442e5fbDan Gohman} 6832e68b6f52d0979575b2f02ed29717d907ba0684cDan Gohman 684ea859be53ca13a1547c4675549946b74dc3c6f41Dan Gohman 685ea859be53ca13a1547c4675549946b74dc3c6f41Dan Gohmanstatic void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) 686ea859be53ca13a1547c4675549946b74dc3c6f41Dan Gohman{ 687475871a144eb604ddaf37503397ba0941442e5fbDan Gohman struct radius_client_data *radius = eloop_ctx; 688ea859be53ca13a1547c4675549946b74dc3c6f41Dan Gohman struct hostapd_radius_servers *conf = radius->conf; 689ea859be53ca13a1547c4675549946b74dc3c6f41Dan Gohman RadiusType msg_type = (RadiusType) sock_ctx; 690ea859be53ca13a1547c4675549946b74dc3c6f41Dan Gohman int len, roundtrip; 691ea859be53ca13a1547c4675549946b74dc3c6f41Dan Gohman unsigned char buf[3000]; 692ea859be53ca13a1547c4675549946b74dc3c6f41Dan Gohman struct radius_msg *msg; 693ea859be53ca13a1547c4675549946b74dc3c6f41Dan Gohman struct radius_hdr *hdr; 694ea859be53ca13a1547c4675549946b74dc3c6f41Dan Gohman struct radius_rx_handler *handlers; 695475871a144eb604ddaf37503397ba0941442e5fbDan Gohman size_t num_handlers, i; 696fd29e0eb060ea8b4d490860329234d2ae5f5952eDan Gohman struct radius_msg_list *req, *prev_req; 697fd29e0eb060ea8b4d490860329234d2ae5f5952eDan Gohman struct os_time now; 698ea859be53ca13a1547c4675549946b74dc3c6f41Dan Gohman struct hostapd_radius_server *rconf; 699ea859be53ca13a1547c4675549946b74dc3c6f41Dan Gohman int invalid_authenticator = 0; 700ea859be53ca13a1547c4675549946b74dc3c6f41Dan Gohman 701ea859be53ca13a1547c4675549946b74dc3c6f41Dan Gohman if (msg_type == RADIUS_ACCT) { 702ea859be53ca13a1547c4675549946b74dc3c6f41Dan Gohman handlers = radius->acct_handlers; 703ea859be53ca13a1547c4675549946b74dc3c6f41Dan Gohman num_handlers = radius->num_acct_handlers; 704ea859be53ca13a1547c4675549946b74dc3c6f41Dan Gohman rconf = conf->acct_server; 705475871a144eb604ddaf37503397ba0941442e5fbDan Gohman } else { 706a844bdeab31ef04221e7ef59a8467893584cc14dEvan Cheng handlers = radius->auth_handlers; 707475871a144eb604ddaf37503397ba0941442e5fbDan Gohman num_handlers = radius->num_auth_handlers; 708a844bdeab31ef04221e7ef59a8467893584cc14dEvan Cheng rconf = conf->auth_server; 709475871a144eb604ddaf37503397ba0941442e5fbDan Gohman } 71077f0b7a50a08614b5ffd58f1864b68a9a30d0cb0Evan Cheng 71177f0b7a50a08614b5ffd58f1864b68a9a30d0cb0Evan Cheng len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT); 71277f0b7a50a08614b5ffd58f1864b68a9a30d0cb0Evan Cheng if (len < 0) { 713475871a144eb604ddaf37503397ba0941442e5fbDan Gohman perror("recv[RADIUS]"); 714ea859be53ca13a1547c4675549946b74dc3c6f41Dan Gohman return; 715d1fc96499b7619356c7542200d32da898b79f7c1Chris Lattner } 7161b95095857b78e12138c22e76c7936611c51355bChris Lattner hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 7176542d950609208de3e1cde704c5f89aad864c0d9Chris Lattner HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS " 718475871a144eb604ddaf37503397ba0941442e5fbDan Gohman "server", len); 719475871a144eb604ddaf37503397ba0941442e5fbDan Gohman if (len == sizeof(buf)) { 720a5682853b9921bbb0dd2ee175c9bd44142d4819eChris Lattner printf("Possibly too long UDP frame for our buffer - " 721475871a144eb604ddaf37503397ba0941442e5fbDan Gohman "dropping it\n"); 722a5682853b9921bbb0dd2ee175c9bd44142d4819eChris Lattner return; 723b9aff659e82e4ec1a507e6e7fe7969379a431613Chris Lattner } 724fde3f3061d665babeb78443119a09876098fc35eChris Lattner 7259c6e70eca9a49c146b26621cbcbb9464ceeac024Dan Gohman msg = radius_msg_parse(buf, len); 7269c6e70eca9a49c146b26621cbcbb9464ceeac024Dan Gohman if (msg == NULL) { 7277cf7e3f33f25544d08492d47cc8a1cbba25dc8d7Chris Lattner printf("Parsing incoming RADIUS frame failed\n"); 728109654fae9c5b8b96bd3a829824cdbceb27ced06Chris Lattner rconf->malformed_responses++; 729e8be6c63915e0389f1eef6b53c64300d13b2ce99Dan Gohman return; 730109654fae9c5b8b96bd3a829824cdbceb27ced06Chris Lattner } 7311cff05c7c216eea0e9173738c2a60b70c2b3c013Chris Lattner hdr = radius_msg_get_hdr(msg); 7327cf7e3f33f25544d08492d47cc8a1cbba25dc8d7Chris Lattner 7331cff05c7c216eea0e9173738c2a60b70c2b3c013Chris Lattner hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 73415e4b01920d6a0ffbe35d3e5aa88a4b42970b6a7Chris Lattner HOSTAPD_LEVEL_DEBUG, "Received RADIUS message"); 7358e4eb09b1e3571965f49edcdfb56b1375b1b7551Duncan Sands if (conf->msg_dumps) 7364b84086e89d86fb16f562166d9fea8df37db6be7Dan Gohman radius_msg_dump(msg); 7374b84086e89d86fb16f562166d9fea8df37db6be7Dan Gohman 738cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner switch (hdr->code) { 739cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner case RADIUS_CODE_ACCESS_ACCEPT: 7401080b9ee534579c67f7c99364cc6fa11edbcd919Chris Lattner rconf->access_accepts++; 7411080b9ee534579c67f7c99364cc6fa11edbcd919Chris Lattner break; 7421080b9ee534579c67f7c99364cc6fa11edbcd919Chris Lattner case RADIUS_CODE_ACCESS_REJECT: 7431080b9ee534579c67f7c99364cc6fa11edbcd919Chris Lattner rconf->access_rejects++; 7441080b9ee534579c67f7c99364cc6fa11edbcd919Chris Lattner break; 7451080b9ee534579c67f7c99364cc6fa11edbcd919Chris Lattner case RADIUS_CODE_ACCESS_CHALLENGE: 7461080b9ee534579c67f7c99364cc6fa11edbcd919Chris Lattner rconf->access_challenges++; 7471080b9ee534579c67f7c99364cc6fa11edbcd919Chris Lattner break; 7481080b9ee534579c67f7c99364cc6fa11edbcd919Chris Lattner case RADIUS_CODE_ACCOUNTING_RESPONSE: 7491080b9ee534579c67f7c99364cc6fa11edbcd919Chris Lattner rconf->responses++; 750b80e2be8894db9f843f32ebaffb9b7fd6b57d206Chris Lattner break; 751cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner } 752cacf462915344c2af25eef1af1f3ee2c7280ff56Chris Lattner 753 prev_req = NULL; 754 req = radius->msgs; 755 while (req) { 756 /* TODO: also match by src addr:port of the packet when using 757 * alternative RADIUS servers (?) */ 758 if ((req->msg_type == msg_type || 759 (req->msg_type == RADIUS_ACCT_INTERIM && 760 msg_type == RADIUS_ACCT)) && 761 radius_msg_get_hdr(req->msg)->identifier == 762 hdr->identifier) 763 break; 764 765 prev_req = req; 766 req = req->next; 767 } 768 769 if (req == NULL) { 770 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 771 HOSTAPD_LEVEL_DEBUG, 772 "No matching RADIUS request found (type=%d " 773 "id=%d) - dropping packet", 774 msg_type, hdr->identifier); 775 goto fail; 776 } 777 778 os_get_time(&now); 779 roundtrip = (now.sec - req->last_attempt.sec) * 100 + 780 (now.usec - req->last_attempt.usec) / 10000; 781 hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS, 782 HOSTAPD_LEVEL_DEBUG, 783 "Received RADIUS packet matched with a pending " 784 "request, round trip time %d.%02d sec", 785 roundtrip / 100, roundtrip % 100); 786 rconf->round_trip_time = roundtrip; 787 788 /* Remove ACKed RADIUS packet from retransmit list */ 789 if (prev_req) 790 prev_req->next = req->next; 791 else 792 radius->msgs = req->next; 793 radius->num_msgs--; 794 795 for (i = 0; i < num_handlers; i++) { 796 RadiusRxResult res; 797 res = handlers[i].handler(msg, req->msg, req->shared_secret, 798 req->shared_secret_len, 799 handlers[i].data); 800 switch (res) { 801 case RADIUS_RX_PROCESSED: 802 radius_msg_free(msg); 803 /* continue */ 804 case RADIUS_RX_QUEUED: 805 radius_client_msg_free(req); 806 return; 807 case RADIUS_RX_INVALID_AUTHENTICATOR: 808 invalid_authenticator++; 809 /* continue */ 810 case RADIUS_RX_UNKNOWN: 811 /* continue with next handler */ 812 break; 813 } 814 } 815 816 if (invalid_authenticator) 817 rconf->bad_authenticators++; 818 else 819 rconf->unknown_types++; 820 hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS, 821 HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found " 822 "(type=%d code=%d id=%d)%s - dropping packet", 823 msg_type, hdr->code, hdr->identifier, 824 invalid_authenticator ? " [INVALID AUTHENTICATOR]" : 825 ""); 826 radius_client_msg_free(req); 827 828 fail: 829 radius_msg_free(msg); 830} 831 832 833/** 834 * radius_client_get_id - Get an identifier for a new RADIUS message 835 * @radius: RADIUS client context from radius_client_init() 836 * Returns: Allocated identifier 837 * 838 * This function is used to fetch a unique (among pending requests) identifier 839 * for a new RADIUS message. 840 */ 841u8 radius_client_get_id(struct radius_client_data *radius) 842{ 843 struct radius_msg_list *entry, *prev, *_remove; 844 u8 id = radius->next_radius_identifier++; 845 846 /* remove entries with matching id from retransmit list to avoid 847 * using new reply from the RADIUS server with an old request */ 848 entry = radius->msgs; 849 prev = NULL; 850 while (entry) { 851 if (radius_msg_get_hdr(entry->msg)->identifier == id) { 852 hostapd_logger(radius->ctx, entry->addr, 853 HOSTAPD_MODULE_RADIUS, 854 HOSTAPD_LEVEL_DEBUG, 855 "Removing pending RADIUS message, " 856 "since its id (%d) is reused", id); 857 if (prev) 858 prev->next = entry->next; 859 else 860 radius->msgs = entry->next; 861 _remove = entry; 862 } else { 863 _remove = NULL; 864 prev = entry; 865 } 866 entry = entry->next; 867 868 if (_remove) 869 radius_client_msg_free(_remove); 870 } 871 872 return id; 873} 874 875 876/** 877 * radius_client_flush - Flush all pending RADIUS client messages 878 * @radius: RADIUS client context from radius_client_init() 879 * @only_auth: Whether only authentication messages are removed 880 */ 881void radius_client_flush(struct radius_client_data *radius, int only_auth) 882{ 883 struct radius_msg_list *entry, *prev, *tmp; 884 885 if (!radius) 886 return; 887 888 prev = NULL; 889 entry = radius->msgs; 890 891 while (entry) { 892 if (!only_auth || entry->msg_type == RADIUS_AUTH) { 893 if (prev) 894 prev->next = entry->next; 895 else 896 radius->msgs = entry->next; 897 898 tmp = entry; 899 entry = entry->next; 900 radius_client_msg_free(tmp); 901 radius->num_msgs--; 902 } else { 903 prev = entry; 904 entry = entry->next; 905 } 906 } 907 908 if (radius->msgs == NULL) 909 eloop_cancel_timeout(radius_client_timer, radius, NULL); 910} 911 912 913static void radius_client_update_acct_msgs(struct radius_client_data *radius, 914 const u8 *shared_secret, 915 size_t shared_secret_len) 916{ 917 struct radius_msg_list *entry; 918 919 if (!radius) 920 return; 921 922 for (entry = radius->msgs; entry; entry = entry->next) { 923 if (entry->msg_type == RADIUS_ACCT) { 924 entry->shared_secret = shared_secret; 925 entry->shared_secret_len = shared_secret_len; 926 radius_msg_finish_acct(entry->msg, shared_secret, 927 shared_secret_len); 928 } 929 } 930} 931 932 933static int 934radius_change_server(struct radius_client_data *radius, 935 struct hostapd_radius_server *nserv, 936 struct hostapd_radius_server *oserv, 937 int sock, int sock6, int auth) 938{ 939 struct sockaddr_in serv, claddr; 940#ifdef CONFIG_IPV6 941 struct sockaddr_in6 serv6, claddr6; 942#endif /* CONFIG_IPV6 */ 943 struct sockaddr *addr, *cl_addr; 944 socklen_t addrlen, claddrlen; 945 char abuf[50]; 946 int sel_sock; 947 struct radius_msg_list *entry; 948 struct hostapd_radius_servers *conf = radius->conf; 949 950 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 951 HOSTAPD_LEVEL_INFO, 952 "%s server %s:%d", 953 auth ? "Authentication" : "Accounting", 954 hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)), 955 nserv->port); 956 957 if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len || 958 os_memcmp(nserv->shared_secret, oserv->shared_secret, 959 nserv->shared_secret_len) != 0) { 960 /* Pending RADIUS packets used different shared secret, so 961 * they need to be modified. Update accounting message 962 * authenticators here. Authentication messages are removed 963 * since they would require more changes and the new RADIUS 964 * server may not be prepared to receive them anyway due to 965 * missing state information. Client will likely retry 966 * authentication, so this should not be an issue. */ 967 if (auth) 968 radius_client_flush(radius, 1); 969 else { 970 radius_client_update_acct_msgs( 971 radius, nserv->shared_secret, 972 nserv->shared_secret_len); 973 } 974 } 975 976 /* Reset retry counters for the new server */ 977 for (entry = radius->msgs; entry; entry = entry->next) { 978 if ((auth && entry->msg_type != RADIUS_AUTH) || 979 (!auth && entry->msg_type != RADIUS_ACCT)) 980 continue; 981 entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT; 982 entry->attempts = 0; 983 entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2; 984 } 985 986 if (radius->msgs) { 987 eloop_cancel_timeout(radius_client_timer, radius, NULL); 988 eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0, 989 radius_client_timer, radius, NULL); 990 } 991 992 switch (nserv->addr.af) { 993 case AF_INET: 994 os_memset(&serv, 0, sizeof(serv)); 995 serv.sin_family = AF_INET; 996 serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr; 997 serv.sin_port = htons(nserv->port); 998 addr = (struct sockaddr *) &serv; 999 addrlen = sizeof(serv); 1000 sel_sock = sock; 1001 break; 1002#ifdef CONFIG_IPV6 1003 case AF_INET6: 1004 os_memset(&serv6, 0, sizeof(serv6)); 1005 serv6.sin6_family = AF_INET6; 1006 os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6, 1007 sizeof(struct in6_addr)); 1008 serv6.sin6_port = htons(nserv->port); 1009 addr = (struct sockaddr *) &serv6; 1010 addrlen = sizeof(serv6); 1011 sel_sock = sock6; 1012 break; 1013#endif /* CONFIG_IPV6 */ 1014 default: 1015 return -1; 1016 } 1017 1018 if (conf->force_client_addr) { 1019 switch (conf->client_addr.af) { 1020 case AF_INET: 1021 os_memset(&claddr, 0, sizeof(claddr)); 1022 claddr.sin_family = AF_INET; 1023 claddr.sin_addr.s_addr = conf->client_addr.u.v4.s_addr; 1024 claddr.sin_port = htons(0); 1025 cl_addr = (struct sockaddr *) &claddr; 1026 claddrlen = sizeof(claddr); 1027 break; 1028#ifdef CONFIG_IPV6 1029 case AF_INET6: 1030 os_memset(&claddr6, 0, sizeof(claddr6)); 1031 claddr6.sin6_family = AF_INET6; 1032 os_memcpy(&claddr6.sin6_addr, &conf->client_addr.u.v6, 1033 sizeof(struct in6_addr)); 1034 claddr6.sin6_port = htons(0); 1035 cl_addr = (struct sockaddr *) &claddr6; 1036 claddrlen = sizeof(claddr6); 1037 break; 1038#endif /* CONFIG_IPV6 */ 1039 default: 1040 return -1; 1041 } 1042 1043 if (bind(sel_sock, cl_addr, claddrlen) < 0) { 1044 perror("bind[radius]"); 1045 return -1; 1046 } 1047 } 1048 1049 if (connect(sel_sock, addr, addrlen) < 0) { 1050 perror("connect[radius]"); 1051 return -1; 1052 } 1053 1054#ifndef CONFIG_NATIVE_WINDOWS 1055 switch (nserv->addr.af) { 1056 case AF_INET: 1057 claddrlen = sizeof(claddr); 1058 getsockname(sel_sock, (struct sockaddr *) &claddr, &claddrlen); 1059 wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u", 1060 inet_ntoa(claddr.sin_addr), ntohs(claddr.sin_port)); 1061 break; 1062#ifdef CONFIG_IPV6 1063 case AF_INET6: { 1064 claddrlen = sizeof(claddr6); 1065 getsockname(sel_sock, (struct sockaddr *) &claddr6, 1066 &claddrlen); 1067 wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u", 1068 inet_ntop(AF_INET6, &claddr6.sin6_addr, 1069 abuf, sizeof(abuf)), 1070 ntohs(claddr6.sin6_port)); 1071 break; 1072 } 1073#endif /* CONFIG_IPV6 */ 1074 } 1075#endif /* CONFIG_NATIVE_WINDOWS */ 1076 1077 if (auth) 1078 radius->auth_sock = sel_sock; 1079 else 1080 radius->acct_sock = sel_sock; 1081 1082 return 0; 1083} 1084 1085 1086static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx) 1087{ 1088 struct radius_client_data *radius = eloop_ctx; 1089 struct hostapd_radius_servers *conf = radius->conf; 1090 struct hostapd_radius_server *oserv; 1091 1092 if (radius->auth_sock >= 0 && conf->auth_servers && 1093 conf->auth_server != conf->auth_servers) { 1094 oserv = conf->auth_server; 1095 conf->auth_server = conf->auth_servers; 1096 radius_change_server(radius, conf->auth_server, oserv, 1097 radius->auth_serv_sock, 1098 radius->auth_serv_sock6, 1); 1099 } 1100 1101 if (radius->acct_sock >= 0 && conf->acct_servers && 1102 conf->acct_server != conf->acct_servers) { 1103 oserv = conf->acct_server; 1104 conf->acct_server = conf->acct_servers; 1105 radius_change_server(radius, conf->acct_server, oserv, 1106 radius->acct_serv_sock, 1107 radius->acct_serv_sock6, 0); 1108 } 1109 1110 if (conf->retry_primary_interval) 1111 eloop_register_timeout(conf->retry_primary_interval, 0, 1112 radius_retry_primary_timer, radius, 1113 NULL); 1114} 1115 1116 1117static int radius_client_disable_pmtu_discovery(int s) 1118{ 1119 int r = -1; 1120#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) 1121 /* Turn off Path MTU discovery on IPv4/UDP sockets. */ 1122 int action = IP_PMTUDISC_DONT; 1123 r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action, 1124 sizeof(action)); 1125 if (r == -1) 1126 wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: " 1127 "%s", strerror(errno)); 1128#endif 1129 return r; 1130} 1131 1132 1133static int radius_client_init_auth(struct radius_client_data *radius) 1134{ 1135 struct hostapd_radius_servers *conf = radius->conf; 1136 int ok = 0; 1137 1138 radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0); 1139 if (radius->auth_serv_sock < 0) 1140 perror("socket[PF_INET,SOCK_DGRAM]"); 1141 else { 1142 radius_client_disable_pmtu_discovery(radius->auth_serv_sock); 1143 ok++; 1144 } 1145 1146#ifdef CONFIG_IPV6 1147 radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0); 1148 if (radius->auth_serv_sock6 < 0) 1149 perror("socket[PF_INET6,SOCK_DGRAM]"); 1150 else 1151 ok++; 1152#endif /* CONFIG_IPV6 */ 1153 1154 if (ok == 0) 1155 return -1; 1156 1157 radius_change_server(radius, conf->auth_server, NULL, 1158 radius->auth_serv_sock, radius->auth_serv_sock6, 1159 1); 1160 1161 if (radius->auth_serv_sock >= 0 && 1162 eloop_register_read_sock(radius->auth_serv_sock, 1163 radius_client_receive, radius, 1164 (void *) RADIUS_AUTH)) { 1165 printf("Could not register read socket for authentication " 1166 "server\n"); 1167 return -1; 1168 } 1169 1170#ifdef CONFIG_IPV6 1171 if (radius->auth_serv_sock6 >= 0 && 1172 eloop_register_read_sock(radius->auth_serv_sock6, 1173 radius_client_receive, radius, 1174 (void *) RADIUS_AUTH)) { 1175 printf("Could not register read socket for authentication " 1176 "server\n"); 1177 return -1; 1178 } 1179#endif /* CONFIG_IPV6 */ 1180 1181 return 0; 1182} 1183 1184 1185static int radius_client_init_acct(struct radius_client_data *radius) 1186{ 1187 struct hostapd_radius_servers *conf = radius->conf; 1188 int ok = 0; 1189 1190 radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0); 1191 if (radius->acct_serv_sock < 0) 1192 perror("socket[PF_INET,SOCK_DGRAM]"); 1193 else { 1194 radius_client_disable_pmtu_discovery(radius->acct_serv_sock); 1195 ok++; 1196 } 1197 1198#ifdef CONFIG_IPV6 1199 radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0); 1200 if (radius->acct_serv_sock6 < 0) 1201 perror("socket[PF_INET6,SOCK_DGRAM]"); 1202 else 1203 ok++; 1204#endif /* CONFIG_IPV6 */ 1205 1206 if (ok == 0) 1207 return -1; 1208 1209 radius_change_server(radius, conf->acct_server, NULL, 1210 radius->acct_serv_sock, radius->acct_serv_sock6, 1211 0); 1212 1213 if (radius->acct_serv_sock >= 0 && 1214 eloop_register_read_sock(radius->acct_serv_sock, 1215 radius_client_receive, radius, 1216 (void *) RADIUS_ACCT)) { 1217 printf("Could not register read socket for accounting " 1218 "server\n"); 1219 return -1; 1220 } 1221 1222#ifdef CONFIG_IPV6 1223 if (radius->acct_serv_sock6 >= 0 && 1224 eloop_register_read_sock(radius->acct_serv_sock6, 1225 radius_client_receive, radius, 1226 (void *) RADIUS_ACCT)) { 1227 printf("Could not register read socket for accounting " 1228 "server\n"); 1229 return -1; 1230 } 1231#endif /* CONFIG_IPV6 */ 1232 1233 return 0; 1234} 1235 1236 1237/** 1238 * radius_client_init - Initialize RADIUS client 1239 * @ctx: Callback context to be used in hostapd_logger() calls 1240 * @conf: RADIUS client configuration (RADIUS servers) 1241 * Returns: Pointer to private RADIUS client context or %NULL on failure 1242 * 1243 * The caller is responsible for keeping the configuration data available for 1244 * the lifetime of the RADIUS client, i.e., until radius_client_deinit() is 1245 * called for the returned context pointer. 1246 */ 1247struct radius_client_data * 1248radius_client_init(void *ctx, struct hostapd_radius_servers *conf) 1249{ 1250 struct radius_client_data *radius; 1251 1252 radius = os_zalloc(sizeof(struct radius_client_data)); 1253 if (radius == NULL) 1254 return NULL; 1255 1256 radius->ctx = ctx; 1257 radius->conf = conf; 1258 radius->auth_serv_sock = radius->acct_serv_sock = 1259 radius->auth_serv_sock6 = radius->acct_serv_sock6 = 1260 radius->auth_sock = radius->acct_sock = -1; 1261 1262 if (conf->auth_server && radius_client_init_auth(radius)) { 1263 radius_client_deinit(radius); 1264 return NULL; 1265 } 1266 1267 if (conf->acct_server && radius_client_init_acct(radius)) { 1268 radius_client_deinit(radius); 1269 return NULL; 1270 } 1271 1272 if (conf->retry_primary_interval) 1273 eloop_register_timeout(conf->retry_primary_interval, 0, 1274 radius_retry_primary_timer, radius, 1275 NULL); 1276 1277 return radius; 1278} 1279 1280 1281/** 1282 * radius_client_deinit - Deinitialize RADIUS client 1283 * @radius: RADIUS client context from radius_client_init() 1284 */ 1285void radius_client_deinit(struct radius_client_data *radius) 1286{ 1287 if (!radius) 1288 return; 1289 1290 if (radius->auth_serv_sock >= 0) 1291 eloop_unregister_read_sock(radius->auth_serv_sock); 1292 if (radius->acct_serv_sock >= 0) 1293 eloop_unregister_read_sock(radius->acct_serv_sock); 1294#ifdef CONFIG_IPV6 1295 if (radius->auth_serv_sock6 >= 0) 1296 eloop_unregister_read_sock(radius->auth_serv_sock6); 1297 if (radius->acct_serv_sock6 >= 0) 1298 eloop_unregister_read_sock(radius->acct_serv_sock6); 1299#endif /* CONFIG_IPV6 */ 1300 1301 eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL); 1302 1303 radius_client_flush(radius, 0); 1304 os_free(radius->auth_handlers); 1305 os_free(radius->acct_handlers); 1306 os_free(radius); 1307} 1308 1309 1310/** 1311 * radius_client_flush_auth - Flush pending RADIUS messages for an address 1312 * @radius: RADIUS client context from radius_client_init() 1313 * @addr: MAC address of the related device 1314 * 1315 * This function can be used to remove pending RADIUS authentication messages 1316 * that are related to a specific device. The addr parameter is matched with 1317 * the one used in radius_client_send() call that was used to transmit the 1318 * authentication request. 1319 */ 1320void radius_client_flush_auth(struct radius_client_data *radius, 1321 const u8 *addr) 1322{ 1323 struct radius_msg_list *entry, *prev, *tmp; 1324 1325 prev = NULL; 1326 entry = radius->msgs; 1327 while (entry) { 1328 if (entry->msg_type == RADIUS_AUTH && 1329 os_memcmp(entry->addr, addr, ETH_ALEN) == 0) { 1330 hostapd_logger(radius->ctx, addr, 1331 HOSTAPD_MODULE_RADIUS, 1332 HOSTAPD_LEVEL_DEBUG, 1333 "Removing pending RADIUS authentication" 1334 " message for removed client"); 1335 1336 if (prev) 1337 prev->next = entry->next; 1338 else 1339 radius->msgs = entry->next; 1340 1341 tmp = entry; 1342 entry = entry->next; 1343 radius_client_msg_free(tmp); 1344 radius->num_msgs--; 1345 continue; 1346 } 1347 1348 prev = entry; 1349 entry = entry->next; 1350 } 1351} 1352 1353 1354static int radius_client_dump_auth_server(char *buf, size_t buflen, 1355 struct hostapd_radius_server *serv, 1356 struct radius_client_data *cli) 1357{ 1358 int pending = 0; 1359 struct radius_msg_list *msg; 1360 char abuf[50]; 1361 1362 if (cli) { 1363 for (msg = cli->msgs; msg; msg = msg->next) { 1364 if (msg->msg_type == RADIUS_AUTH) 1365 pending++; 1366 } 1367 } 1368 1369 return os_snprintf(buf, buflen, 1370 "radiusAuthServerIndex=%d\n" 1371 "radiusAuthServerAddress=%s\n" 1372 "radiusAuthClientServerPortNumber=%d\n" 1373 "radiusAuthClientRoundTripTime=%d\n" 1374 "radiusAuthClientAccessRequests=%u\n" 1375 "radiusAuthClientAccessRetransmissions=%u\n" 1376 "radiusAuthClientAccessAccepts=%u\n" 1377 "radiusAuthClientAccessRejects=%u\n" 1378 "radiusAuthClientAccessChallenges=%u\n" 1379 "radiusAuthClientMalformedAccessResponses=%u\n" 1380 "radiusAuthClientBadAuthenticators=%u\n" 1381 "radiusAuthClientPendingRequests=%u\n" 1382 "radiusAuthClientTimeouts=%u\n" 1383 "radiusAuthClientUnknownTypes=%u\n" 1384 "radiusAuthClientPacketsDropped=%u\n", 1385 serv->index, 1386 hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)), 1387 serv->port, 1388 serv->round_trip_time, 1389 serv->requests, 1390 serv->retransmissions, 1391 serv->access_accepts, 1392 serv->access_rejects, 1393 serv->access_challenges, 1394 serv->malformed_responses, 1395 serv->bad_authenticators, 1396 pending, 1397 serv->timeouts, 1398 serv->unknown_types, 1399 serv->packets_dropped); 1400} 1401 1402 1403static int radius_client_dump_acct_server(char *buf, size_t buflen, 1404 struct hostapd_radius_server *serv, 1405 struct radius_client_data *cli) 1406{ 1407 int pending = 0; 1408 struct radius_msg_list *msg; 1409 char abuf[50]; 1410 1411 if (cli) { 1412 for (msg = cli->msgs; msg; msg = msg->next) { 1413 if (msg->msg_type == RADIUS_ACCT || 1414 msg->msg_type == RADIUS_ACCT_INTERIM) 1415 pending++; 1416 } 1417 } 1418 1419 return os_snprintf(buf, buflen, 1420 "radiusAccServerIndex=%d\n" 1421 "radiusAccServerAddress=%s\n" 1422 "radiusAccClientServerPortNumber=%d\n" 1423 "radiusAccClientRoundTripTime=%d\n" 1424 "radiusAccClientRequests=%u\n" 1425 "radiusAccClientRetransmissions=%u\n" 1426 "radiusAccClientResponses=%u\n" 1427 "radiusAccClientMalformedResponses=%u\n" 1428 "radiusAccClientBadAuthenticators=%u\n" 1429 "radiusAccClientPendingRequests=%u\n" 1430 "radiusAccClientTimeouts=%u\n" 1431 "radiusAccClientUnknownTypes=%u\n" 1432 "radiusAccClientPacketsDropped=%u\n", 1433 serv->index, 1434 hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)), 1435 serv->port, 1436 serv->round_trip_time, 1437 serv->requests, 1438 serv->retransmissions, 1439 serv->responses, 1440 serv->malformed_responses, 1441 serv->bad_authenticators, 1442 pending, 1443 serv->timeouts, 1444 serv->unknown_types, 1445 serv->packets_dropped); 1446} 1447 1448 1449/** 1450 * radius_client_get_mib - Get RADIUS client MIB information 1451 * @radius: RADIUS client context from radius_client_init() 1452 * @buf: Buffer for returning MIB data in text format 1453 * @buflen: Maximum buf length in octets 1454 * Returns: Number of octets written into the buffer 1455 */ 1456int radius_client_get_mib(struct radius_client_data *radius, char *buf, 1457 size_t buflen) 1458{ 1459 struct hostapd_radius_servers *conf = radius->conf; 1460 int i; 1461 struct hostapd_radius_server *serv; 1462 int count = 0; 1463 1464 if (conf->auth_servers) { 1465 for (i = 0; i < conf->num_auth_servers; i++) { 1466 serv = &conf->auth_servers[i]; 1467 count += radius_client_dump_auth_server( 1468 buf + count, buflen - count, serv, 1469 serv == conf->auth_server ? 1470 radius : NULL); 1471 } 1472 } 1473 1474 if (conf->acct_servers) { 1475 for (i = 0; i < conf->num_acct_servers; i++) { 1476 serv = &conf->acct_servers[i]; 1477 count += radius_client_dump_acct_server( 1478 buf + count, buflen - count, serv, 1479 serv == conf->acct_server ? 1480 radius : NULL); 1481 } 1482 } 1483 1484 return count; 1485} 1486 1487 1488void radius_client_reconfig(struct radius_client_data *radius, 1489 struct hostapd_radius_servers *conf) 1490{ 1491 if (radius) 1492 radius->conf = conf; 1493} 1494