139beb93cSSam Leffler /* 2e28a4053SRui Paulo * RADIUS authentication server 35b9c547cSRui Paulo * Copyright (c) 2005-2009, 2011-2014, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #include "includes.h" 1039beb93cSSam Leffler #include <net/if.h> 115b9c547cSRui Paulo #ifdef CONFIG_SQLITE 125b9c547cSRui Paulo #include <sqlite3.h> 135b9c547cSRui Paulo #endif /* CONFIG_SQLITE */ 1439beb93cSSam Leffler 1539beb93cSSam Leffler #include "common.h" 1639beb93cSSam Leffler #include "radius.h" 1739beb93cSSam Leffler #include "eloop.h" 1839beb93cSSam Leffler #include "eap_server/eap.h" 195b9c547cSRui Paulo #include "ap/ap_config.h" 205b9c547cSRui Paulo #include "crypto/tls.h" 2139beb93cSSam Leffler #include "radius_server.h" 2239beb93cSSam Leffler 23e28a4053SRui Paulo /** 24e28a4053SRui Paulo * RADIUS_SESSION_TIMEOUT - Session timeout in seconds 25e28a4053SRui Paulo */ 2639beb93cSSam Leffler #define RADIUS_SESSION_TIMEOUT 60 27e28a4053SRui Paulo 28e28a4053SRui Paulo /** 29*85732ac8SCy Schubert * RADIUS_SESSION_MAINTAIN - Completed session expiration timeout in seconds 30*85732ac8SCy Schubert */ 31*85732ac8SCy Schubert #define RADIUS_SESSION_MAINTAIN 5 32*85732ac8SCy Schubert 33*85732ac8SCy Schubert /** 34e28a4053SRui Paulo * RADIUS_MAX_SESSION - Maximum number of active sessions 35e28a4053SRui Paulo */ 36*85732ac8SCy Schubert #define RADIUS_MAX_SESSION 1000 37e28a4053SRui Paulo 38e28a4053SRui Paulo /** 39e28a4053SRui Paulo * RADIUS_MAX_MSG_LEN - Maximum message length for incoming RADIUS messages 40e28a4053SRui Paulo */ 4139beb93cSSam Leffler #define RADIUS_MAX_MSG_LEN 3000 4239beb93cSSam Leffler 43325151a3SRui Paulo static const struct eapol_callbacks radius_server_eapol_cb; 4439beb93cSSam Leffler 4539beb93cSSam Leffler struct radius_client; 4639beb93cSSam Leffler struct radius_server_data; 4739beb93cSSam Leffler 48e28a4053SRui Paulo /** 49e28a4053SRui Paulo * struct radius_server_counters - RADIUS server statistics counters 50e28a4053SRui Paulo */ 5139beb93cSSam Leffler struct radius_server_counters { 5239beb93cSSam Leffler u32 access_requests; 5339beb93cSSam Leffler u32 invalid_requests; 5439beb93cSSam Leffler u32 dup_access_requests; 5539beb93cSSam Leffler u32 access_accepts; 5639beb93cSSam Leffler u32 access_rejects; 5739beb93cSSam Leffler u32 access_challenges; 5839beb93cSSam Leffler u32 malformed_access_requests; 5939beb93cSSam Leffler u32 bad_authenticators; 6039beb93cSSam Leffler u32 packets_dropped; 6139beb93cSSam Leffler u32 unknown_types; 625b9c547cSRui Paulo 635b9c547cSRui Paulo u32 acct_requests; 645b9c547cSRui Paulo u32 invalid_acct_requests; 655b9c547cSRui Paulo u32 acct_responses; 665b9c547cSRui Paulo u32 malformed_acct_requests; 675b9c547cSRui Paulo u32 acct_bad_authenticators; 685b9c547cSRui Paulo u32 unknown_acct_types; 6939beb93cSSam Leffler }; 7039beb93cSSam Leffler 71e28a4053SRui Paulo /** 72e28a4053SRui Paulo * struct radius_session - Internal RADIUS server data for a session 73e28a4053SRui Paulo */ 7439beb93cSSam Leffler struct radius_session { 7539beb93cSSam Leffler struct radius_session *next; 7639beb93cSSam Leffler struct radius_client *client; 7739beb93cSSam Leffler struct radius_server_data *server; 7839beb93cSSam Leffler unsigned int sess_id; 7939beb93cSSam Leffler struct eap_sm *eap; 8039beb93cSSam Leffler struct eap_eapol_interface *eap_if; 815b9c547cSRui Paulo char *username; /* from User-Name attribute */ 825b9c547cSRui Paulo char *nas_ip; 83*85732ac8SCy Schubert u8 mac_addr[ETH_ALEN]; /* from Calling-Station-Id attribute */ 8439beb93cSSam Leffler 8539beb93cSSam Leffler struct radius_msg *last_msg; 8639beb93cSSam Leffler char *last_from_addr; 8739beb93cSSam Leffler int last_from_port; 8839beb93cSSam Leffler struct sockaddr_storage last_from; 8939beb93cSSam Leffler socklen_t last_fromlen; 9039beb93cSSam Leffler u8 last_identifier; 9139beb93cSSam Leffler struct radius_msg *last_reply; 9239beb93cSSam Leffler u8 last_authenticator[16]; 935b9c547cSRui Paulo 945b9c547cSRui Paulo unsigned int remediation:1; 955b9c547cSRui Paulo unsigned int macacl:1; 96*85732ac8SCy Schubert unsigned int t_c_filtering:1; 975b9c547cSRui Paulo 985b9c547cSRui Paulo struct hostapd_radius_attr *accept_attr; 99*85732ac8SCy Schubert 100*85732ac8SCy Schubert u32 t_c_timestamp; /* Last read T&C timestamp from user DB */ 10139beb93cSSam Leffler }; 10239beb93cSSam Leffler 103e28a4053SRui Paulo /** 104e28a4053SRui Paulo * struct radius_client - Internal RADIUS server data for a client 105e28a4053SRui Paulo */ 10639beb93cSSam Leffler struct radius_client { 10739beb93cSSam Leffler struct radius_client *next; 10839beb93cSSam Leffler struct in_addr addr; 10939beb93cSSam Leffler struct in_addr mask; 11039beb93cSSam Leffler #ifdef CONFIG_IPV6 11139beb93cSSam Leffler struct in6_addr addr6; 11239beb93cSSam Leffler struct in6_addr mask6; 11339beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 11439beb93cSSam Leffler char *shared_secret; 11539beb93cSSam Leffler int shared_secret_len; 11639beb93cSSam Leffler struct radius_session *sessions; 11739beb93cSSam Leffler struct radius_server_counters counters; 118*85732ac8SCy Schubert 119*85732ac8SCy Schubert u8 next_dac_identifier; 120*85732ac8SCy Schubert struct radius_msg *pending_dac_coa_req; 121*85732ac8SCy Schubert u8 pending_dac_coa_id; 122*85732ac8SCy Schubert u8 pending_dac_coa_addr[ETH_ALEN]; 123*85732ac8SCy Schubert struct radius_msg *pending_dac_disconnect_req; 124*85732ac8SCy Schubert u8 pending_dac_disconnect_id; 125*85732ac8SCy Schubert u8 pending_dac_disconnect_addr[ETH_ALEN]; 12639beb93cSSam Leffler }; 12739beb93cSSam Leffler 128e28a4053SRui Paulo /** 129e28a4053SRui Paulo * struct radius_server_data - Internal RADIUS server data 130e28a4053SRui Paulo */ 13139beb93cSSam Leffler struct radius_server_data { 132e28a4053SRui Paulo /** 133e28a4053SRui Paulo * auth_sock - Socket for RADIUS authentication messages 134e28a4053SRui Paulo */ 13539beb93cSSam Leffler int auth_sock; 136e28a4053SRui Paulo 137e28a4053SRui Paulo /** 1385b9c547cSRui Paulo * acct_sock - Socket for RADIUS accounting messages 1395b9c547cSRui Paulo */ 1405b9c547cSRui Paulo int acct_sock; 1415b9c547cSRui Paulo 1425b9c547cSRui Paulo /** 143e28a4053SRui Paulo * clients - List of authorized RADIUS clients 144e28a4053SRui Paulo */ 14539beb93cSSam Leffler struct radius_client *clients; 146e28a4053SRui Paulo 147e28a4053SRui Paulo /** 148e28a4053SRui Paulo * next_sess_id - Next session identifier 149e28a4053SRui Paulo */ 15039beb93cSSam Leffler unsigned int next_sess_id; 151e28a4053SRui Paulo 152e28a4053SRui Paulo /** 153e28a4053SRui Paulo * conf_ctx - Context pointer for callbacks 154e28a4053SRui Paulo * 155e28a4053SRui Paulo * This is used as the ctx argument in get_eap_user() calls. 156e28a4053SRui Paulo */ 15739beb93cSSam Leffler void *conf_ctx; 158e28a4053SRui Paulo 159e28a4053SRui Paulo /** 160e28a4053SRui Paulo * num_sess - Number of active sessions 161e28a4053SRui Paulo */ 16239beb93cSSam Leffler int num_sess; 163e28a4053SRui Paulo 164e28a4053SRui Paulo /** 165e28a4053SRui Paulo * eap_sim_db_priv - EAP-SIM/AKA database context 166e28a4053SRui Paulo * 167e28a4053SRui Paulo * This is passed to the EAP-SIM/AKA server implementation as a 168e28a4053SRui Paulo * callback context. 169e28a4053SRui Paulo */ 17039beb93cSSam Leffler void *eap_sim_db_priv; 171e28a4053SRui Paulo 172e28a4053SRui Paulo /** 173e28a4053SRui Paulo * ssl_ctx - TLS context 174e28a4053SRui Paulo * 175e28a4053SRui Paulo * This is passed to the EAP server implementation as a callback 176e28a4053SRui Paulo * context for TLS operations. 177e28a4053SRui Paulo */ 17839beb93cSSam Leffler void *ssl_ctx; 179e28a4053SRui Paulo 180e28a4053SRui Paulo /** 181e28a4053SRui Paulo * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST 182e28a4053SRui Paulo * 183e28a4053SRui Paulo * This parameter is used to set a key for EAP-FAST to encrypt the 184e28a4053SRui Paulo * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If 185e28a4053SRui Paulo * set, must point to a 16-octet key. 186e28a4053SRui Paulo */ 18739beb93cSSam Leffler u8 *pac_opaque_encr_key; 188e28a4053SRui Paulo 189e28a4053SRui Paulo /** 190e28a4053SRui Paulo * eap_fast_a_id - EAP-FAST authority identity (A-ID) 191e28a4053SRui Paulo * 192e28a4053SRui Paulo * If EAP-FAST is not used, this can be set to %NULL. In theory, this 193e28a4053SRui Paulo * is a variable length field, but due to some existing implementations 194e28a4053SRui Paulo * requiring A-ID to be 16 octets in length, it is recommended to use 195e28a4053SRui Paulo * that length for the field to provide interoperability with deployed 196e28a4053SRui Paulo * peer implementations. 197e28a4053SRui Paulo */ 19839beb93cSSam Leffler u8 *eap_fast_a_id; 199e28a4053SRui Paulo 200e28a4053SRui Paulo /** 201e28a4053SRui Paulo * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets 202e28a4053SRui Paulo */ 20339beb93cSSam Leffler size_t eap_fast_a_id_len; 204e28a4053SRui Paulo 205e28a4053SRui Paulo /** 206e28a4053SRui Paulo * eap_fast_a_id_info - EAP-FAST authority identifier information 207e28a4053SRui Paulo * 208e28a4053SRui Paulo * This A-ID-Info contains a user-friendly name for the A-ID. For 209e28a4053SRui Paulo * example, this could be the enterprise and server names in 210e28a4053SRui Paulo * human-readable format. This field is encoded as UTF-8. If EAP-FAST 211e28a4053SRui Paulo * is not used, this can be set to %NULL. 212e28a4053SRui Paulo */ 21339beb93cSSam Leffler char *eap_fast_a_id_info; 214e28a4053SRui Paulo 215e28a4053SRui Paulo /** 216e28a4053SRui Paulo * eap_fast_prov - EAP-FAST provisioning modes 217e28a4053SRui Paulo * 218e28a4053SRui Paulo * 0 = provisioning disabled, 1 = only anonymous provisioning allowed, 219e28a4053SRui Paulo * 2 = only authenticated provisioning allowed, 3 = both provisioning 220e28a4053SRui Paulo * modes allowed. 221e28a4053SRui Paulo */ 22239beb93cSSam Leffler int eap_fast_prov; 223e28a4053SRui Paulo 224e28a4053SRui Paulo /** 225e28a4053SRui Paulo * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds 226e28a4053SRui Paulo * 227e28a4053SRui Paulo * This is the hard limit on how long a provisioned PAC-Key can be 228e28a4053SRui Paulo * used. 229e28a4053SRui Paulo */ 23039beb93cSSam Leffler int pac_key_lifetime; 231e28a4053SRui Paulo 232e28a4053SRui Paulo /** 233e28a4053SRui Paulo * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds 234e28a4053SRui Paulo * 235e28a4053SRui Paulo * This is a soft limit on the PAC-Key. The server will automatically 236e28a4053SRui Paulo * generate a new PAC-Key when this number of seconds (or fewer) of the 237e28a4053SRui Paulo * lifetime remains. 238e28a4053SRui Paulo */ 23939beb93cSSam Leffler int pac_key_refresh_time; 240e28a4053SRui Paulo 241e28a4053SRui Paulo /** 242e28a4053SRui Paulo * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication 243e28a4053SRui Paulo * 244e28a4053SRui Paulo * This controls whether the protected success/failure indication 245e28a4053SRui Paulo * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA. 246e28a4053SRui Paulo */ 24739beb93cSSam Leffler int eap_sim_aka_result_ind; 248e28a4053SRui Paulo 249e28a4053SRui Paulo /** 250e28a4053SRui Paulo * tnc - Trusted Network Connect (TNC) 251e28a4053SRui Paulo * 252e28a4053SRui Paulo * This controls whether TNC is enabled and will be required before the 253e28a4053SRui Paulo * peer is allowed to connect. Note: This is only used with EAP-TTLS 254e28a4053SRui Paulo * and EAP-FAST. If any other EAP method is enabled, the peer will be 255e28a4053SRui Paulo * allowed to connect without TNC. 256e28a4053SRui Paulo */ 25739beb93cSSam Leffler int tnc; 258e28a4053SRui Paulo 259e28a4053SRui Paulo /** 260f05cddf9SRui Paulo * pwd_group - The D-H group assigned for EAP-pwd 261f05cddf9SRui Paulo * 262f05cddf9SRui Paulo * If EAP-pwd is not used it can be set to zero. 263f05cddf9SRui Paulo */ 264f05cddf9SRui Paulo u16 pwd_group; 265f05cddf9SRui Paulo 266f05cddf9SRui Paulo /** 2675b9c547cSRui Paulo * server_id - Server identity 2685b9c547cSRui Paulo */ 2695b9c547cSRui Paulo const char *server_id; 2705b9c547cSRui Paulo 2715b9c547cSRui Paulo /** 2725b9c547cSRui Paulo * erp - Whether EAP Re-authentication Protocol (ERP) is enabled 2735b9c547cSRui Paulo * 2745b9c547cSRui Paulo * This controls whether the authentication server derives ERP key 2755b9c547cSRui Paulo * hierarchy (rRK and rIK) from full EAP authentication and allows 2765b9c547cSRui Paulo * these keys to be used to perform ERP to derive rMSK instead of full 2775b9c547cSRui Paulo * EAP authentication to derive MSK. 2785b9c547cSRui Paulo */ 2795b9c547cSRui Paulo int erp; 2805b9c547cSRui Paulo 2815b9c547cSRui Paulo const char *erp_domain; 2825b9c547cSRui Paulo 2835b9c547cSRui Paulo struct dl_list erp_keys; /* struct eap_server_erp_key */ 2845b9c547cSRui Paulo 285325151a3SRui Paulo unsigned int tls_session_lifetime; 286325151a3SRui Paulo 287*85732ac8SCy Schubert unsigned int tls_flags; 288*85732ac8SCy Schubert 2895b9c547cSRui Paulo /** 290e28a4053SRui Paulo * wps - Wi-Fi Protected Setup context 291e28a4053SRui Paulo * 292e28a4053SRui Paulo * If WPS is used with an external RADIUS server (which is quite 293e28a4053SRui Paulo * unlikely configuration), this is used to provide a pointer to WPS 294e28a4053SRui Paulo * context data. Normally, this can be set to %NULL. 295e28a4053SRui Paulo */ 29639beb93cSSam Leffler struct wps_context *wps; 297e28a4053SRui Paulo 298e28a4053SRui Paulo /** 299e28a4053SRui Paulo * ipv6 - Whether to enable IPv6 support in the RADIUS server 300e28a4053SRui Paulo */ 30139beb93cSSam Leffler int ipv6; 302e28a4053SRui Paulo 303e28a4053SRui Paulo /** 304e28a4053SRui Paulo * start_time - Timestamp of server start 305e28a4053SRui Paulo */ 3065b9c547cSRui Paulo struct os_reltime start_time; 307e28a4053SRui Paulo 308e28a4053SRui Paulo /** 309e28a4053SRui Paulo * counters - Statistics counters for server operations 310e28a4053SRui Paulo * 311e28a4053SRui Paulo * These counters are the sum over all clients. 312e28a4053SRui Paulo */ 31339beb93cSSam Leffler struct radius_server_counters counters; 314e28a4053SRui Paulo 315e28a4053SRui Paulo /** 316e28a4053SRui Paulo * get_eap_user - Callback for fetching EAP user information 317e28a4053SRui Paulo * @ctx: Context data from conf_ctx 318e28a4053SRui Paulo * @identity: User identity 319e28a4053SRui Paulo * @identity_len: identity buffer length in octets 320e28a4053SRui Paulo * @phase2: Whether this is for Phase 2 identity 321e28a4053SRui Paulo * @user: Data structure for filling in the user information 322e28a4053SRui Paulo * Returns: 0 on success, -1 on failure 323e28a4053SRui Paulo * 324e28a4053SRui Paulo * This is used to fetch information from user database. The callback 325e28a4053SRui Paulo * will fill in information about allowed EAP methods and the user 326e28a4053SRui Paulo * password. The password field will be an allocated copy of the 327e28a4053SRui Paulo * password data and RADIUS server will free it after use. 328e28a4053SRui Paulo */ 32939beb93cSSam Leffler int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len, 33039beb93cSSam Leffler int phase2, struct eap_user *user); 331e28a4053SRui Paulo 332e28a4053SRui Paulo /** 333e28a4053SRui Paulo * eap_req_id_text - Optional data for EAP-Request/Identity 334e28a4053SRui Paulo * 335e28a4053SRui Paulo * This can be used to configure an optional, displayable message that 336e28a4053SRui Paulo * will be sent in EAP-Request/Identity. This string can contain an 337e28a4053SRui Paulo * ASCII-0 character (nul) to separate network infromation per RFC 338e28a4053SRui Paulo * 4284. The actual string length is explicit provided in 339e28a4053SRui Paulo * eap_req_id_text_len since nul character will not be used as a string 340e28a4053SRui Paulo * terminator. 341e28a4053SRui Paulo */ 34239beb93cSSam Leffler char *eap_req_id_text; 343e28a4053SRui Paulo 344e28a4053SRui Paulo /** 345e28a4053SRui Paulo * eap_req_id_text_len - Length of eap_req_id_text buffer in octets 346e28a4053SRui Paulo */ 34739beb93cSSam Leffler size_t eap_req_id_text_len; 348e28a4053SRui Paulo 349e28a4053SRui Paulo /* 350e28a4053SRui Paulo * msg_ctx - Context data for wpa_msg() calls 351e28a4053SRui Paulo */ 352e28a4053SRui Paulo void *msg_ctx; 353f05cddf9SRui Paulo 354f05cddf9SRui Paulo #ifdef CONFIG_RADIUS_TEST 355f05cddf9SRui Paulo char *dump_msk_file; 356f05cddf9SRui Paulo #endif /* CONFIG_RADIUS_TEST */ 3575b9c547cSRui Paulo 3585b9c547cSRui Paulo char *subscr_remediation_url; 3595b9c547cSRui Paulo u8 subscr_remediation_method; 3605b9c547cSRui Paulo 361*85732ac8SCy Schubert char *t_c_server_url; 362*85732ac8SCy Schubert 3635b9c547cSRui Paulo #ifdef CONFIG_SQLITE 3645b9c547cSRui Paulo sqlite3 *db; 3655b9c547cSRui Paulo #endif /* CONFIG_SQLITE */ 36639beb93cSSam Leffler }; 36739beb93cSSam Leffler 36839beb93cSSam Leffler 36939beb93cSSam Leffler #define RADIUS_DEBUG(args...) \ 37039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "RADIUS SRV: " args) 37139beb93cSSam Leffler #define RADIUS_ERROR(args...) \ 37239beb93cSSam Leffler wpa_printf(MSG_ERROR, "RADIUS SRV: " args) 37339beb93cSSam Leffler #define RADIUS_DUMP(args...) \ 37439beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "RADIUS SRV: " args) 37539beb93cSSam Leffler #define RADIUS_DUMP_ASCII(args...) \ 37639beb93cSSam Leffler wpa_hexdump_ascii(MSG_MSGDUMP, "RADIUS SRV: " args) 37739beb93cSSam Leffler 37839beb93cSSam Leffler 37939beb93cSSam Leffler static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx); 3803157ba21SRui Paulo static void radius_server_session_remove_timeout(void *eloop_ctx, 3813157ba21SRui Paulo void *timeout_ctx); 38239beb93cSSam Leffler 3835b9c547cSRui Paulo void srv_log(struct radius_session *sess, const char *fmt, ...) 3845b9c547cSRui Paulo PRINTF_FORMAT(2, 3); 3855b9c547cSRui Paulo 3865b9c547cSRui Paulo void srv_log(struct radius_session *sess, const char *fmt, ...) 3875b9c547cSRui Paulo { 3885b9c547cSRui Paulo va_list ap; 3895b9c547cSRui Paulo char *buf; 3905b9c547cSRui Paulo int buflen; 3915b9c547cSRui Paulo 3925b9c547cSRui Paulo va_start(ap, fmt); 3935b9c547cSRui Paulo buflen = vsnprintf(NULL, 0, fmt, ap) + 1; 3945b9c547cSRui Paulo va_end(ap); 3955b9c547cSRui Paulo 3965b9c547cSRui Paulo buf = os_malloc(buflen); 3975b9c547cSRui Paulo if (buf == NULL) 3985b9c547cSRui Paulo return; 3995b9c547cSRui Paulo va_start(ap, fmt); 4005b9c547cSRui Paulo vsnprintf(buf, buflen, fmt, ap); 4015b9c547cSRui Paulo va_end(ap); 4025b9c547cSRui Paulo 4035b9c547cSRui Paulo RADIUS_DEBUG("[0x%x %s] %s", sess->sess_id, sess->nas_ip, buf); 4045b9c547cSRui Paulo 4055b9c547cSRui Paulo #ifdef CONFIG_SQLITE 4065b9c547cSRui Paulo if (sess->server->db) { 4075b9c547cSRui Paulo char *sql; 4085b9c547cSRui Paulo sql = sqlite3_mprintf("INSERT INTO authlog" 4095b9c547cSRui Paulo "(timestamp,session,nas_ip,username,note)" 4105b9c547cSRui Paulo " VALUES (" 4115b9c547cSRui Paulo "strftime('%%Y-%%m-%%d %%H:%%M:%%f'," 4125b9c547cSRui Paulo "'now'),%u,%Q,%Q,%Q)", 4135b9c547cSRui Paulo sess->sess_id, sess->nas_ip, 4145b9c547cSRui Paulo sess->username, buf); 4155b9c547cSRui Paulo if (sql) { 4165b9c547cSRui Paulo if (sqlite3_exec(sess->server->db, sql, NULL, NULL, 4175b9c547cSRui Paulo NULL) != SQLITE_OK) { 4185b9c547cSRui Paulo RADIUS_ERROR("Failed to add authlog entry into sqlite database: %s", 4195b9c547cSRui Paulo sqlite3_errmsg(sess->server->db)); 4205b9c547cSRui Paulo } 4215b9c547cSRui Paulo sqlite3_free(sql); 4225b9c547cSRui Paulo } 4235b9c547cSRui Paulo } 4245b9c547cSRui Paulo #endif /* CONFIG_SQLITE */ 4255b9c547cSRui Paulo 4265b9c547cSRui Paulo os_free(buf); 4275b9c547cSRui Paulo } 4285b9c547cSRui Paulo 42939beb93cSSam Leffler 43039beb93cSSam Leffler static struct radius_client * 43139beb93cSSam Leffler radius_server_get_client(struct radius_server_data *data, struct in_addr *addr, 43239beb93cSSam Leffler int ipv6) 43339beb93cSSam Leffler { 43439beb93cSSam Leffler struct radius_client *client = data->clients; 43539beb93cSSam Leffler 43639beb93cSSam Leffler while (client) { 43739beb93cSSam Leffler #ifdef CONFIG_IPV6 43839beb93cSSam Leffler if (ipv6) { 43939beb93cSSam Leffler struct in6_addr *addr6; 44039beb93cSSam Leffler int i; 44139beb93cSSam Leffler 44239beb93cSSam Leffler addr6 = (struct in6_addr *) addr; 44339beb93cSSam Leffler for (i = 0; i < 16; i++) { 44439beb93cSSam Leffler if ((addr6->s6_addr[i] & 44539beb93cSSam Leffler client->mask6.s6_addr[i]) != 44639beb93cSSam Leffler (client->addr6.s6_addr[i] & 44739beb93cSSam Leffler client->mask6.s6_addr[i])) { 44839beb93cSSam Leffler i = 17; 44939beb93cSSam Leffler break; 45039beb93cSSam Leffler } 45139beb93cSSam Leffler } 45239beb93cSSam Leffler if (i == 16) { 45339beb93cSSam Leffler break; 45439beb93cSSam Leffler } 45539beb93cSSam Leffler } 45639beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 45739beb93cSSam Leffler if (!ipv6 && (client->addr.s_addr & client->mask.s_addr) == 45839beb93cSSam Leffler (addr->s_addr & client->mask.s_addr)) { 45939beb93cSSam Leffler break; 46039beb93cSSam Leffler } 46139beb93cSSam Leffler 46239beb93cSSam Leffler client = client->next; 46339beb93cSSam Leffler } 46439beb93cSSam Leffler 46539beb93cSSam Leffler return client; 46639beb93cSSam Leffler } 46739beb93cSSam Leffler 46839beb93cSSam Leffler 46939beb93cSSam Leffler static struct radius_session * 47039beb93cSSam Leffler radius_server_get_session(struct radius_client *client, unsigned int sess_id) 47139beb93cSSam Leffler { 47239beb93cSSam Leffler struct radius_session *sess = client->sessions; 47339beb93cSSam Leffler 47439beb93cSSam Leffler while (sess) { 47539beb93cSSam Leffler if (sess->sess_id == sess_id) { 47639beb93cSSam Leffler break; 47739beb93cSSam Leffler } 47839beb93cSSam Leffler sess = sess->next; 47939beb93cSSam Leffler } 48039beb93cSSam Leffler 48139beb93cSSam Leffler return sess; 48239beb93cSSam Leffler } 48339beb93cSSam Leffler 48439beb93cSSam Leffler 48539beb93cSSam Leffler static void radius_server_session_free(struct radius_server_data *data, 48639beb93cSSam Leffler struct radius_session *sess) 48739beb93cSSam Leffler { 48839beb93cSSam Leffler eloop_cancel_timeout(radius_server_session_timeout, data, sess); 4893157ba21SRui Paulo eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess); 49039beb93cSSam Leffler eap_server_sm_deinit(sess->eap); 49139beb93cSSam Leffler radius_msg_free(sess->last_msg); 49239beb93cSSam Leffler os_free(sess->last_from_addr); 49339beb93cSSam Leffler radius_msg_free(sess->last_reply); 4945b9c547cSRui Paulo os_free(sess->username); 4955b9c547cSRui Paulo os_free(sess->nas_ip); 49639beb93cSSam Leffler os_free(sess); 49739beb93cSSam Leffler data->num_sess--; 49839beb93cSSam Leffler } 49939beb93cSSam Leffler 50039beb93cSSam Leffler 50139beb93cSSam Leffler static void radius_server_session_remove(struct radius_server_data *data, 50239beb93cSSam Leffler struct radius_session *sess) 50339beb93cSSam Leffler { 50439beb93cSSam Leffler struct radius_client *client = sess->client; 50539beb93cSSam Leffler struct radius_session *session, *prev; 50639beb93cSSam Leffler 50739beb93cSSam Leffler eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess); 50839beb93cSSam Leffler 50939beb93cSSam Leffler prev = NULL; 51039beb93cSSam Leffler session = client->sessions; 51139beb93cSSam Leffler while (session) { 51239beb93cSSam Leffler if (session == sess) { 51339beb93cSSam Leffler if (prev == NULL) { 51439beb93cSSam Leffler client->sessions = sess->next; 51539beb93cSSam Leffler } else { 51639beb93cSSam Leffler prev->next = sess->next; 51739beb93cSSam Leffler } 51839beb93cSSam Leffler radius_server_session_free(data, sess); 51939beb93cSSam Leffler break; 52039beb93cSSam Leffler } 52139beb93cSSam Leffler prev = session; 52239beb93cSSam Leffler session = session->next; 52339beb93cSSam Leffler } 52439beb93cSSam Leffler } 52539beb93cSSam Leffler 52639beb93cSSam Leffler 52739beb93cSSam Leffler static void radius_server_session_remove_timeout(void *eloop_ctx, 52839beb93cSSam Leffler void *timeout_ctx) 52939beb93cSSam Leffler { 53039beb93cSSam Leffler struct radius_server_data *data = eloop_ctx; 53139beb93cSSam Leffler struct radius_session *sess = timeout_ctx; 53239beb93cSSam Leffler RADIUS_DEBUG("Removing completed session 0x%x", sess->sess_id); 53339beb93cSSam Leffler radius_server_session_remove(data, sess); 53439beb93cSSam Leffler } 53539beb93cSSam Leffler 53639beb93cSSam Leffler 53739beb93cSSam Leffler static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx) 53839beb93cSSam Leffler { 53939beb93cSSam Leffler struct radius_server_data *data = eloop_ctx; 54039beb93cSSam Leffler struct radius_session *sess = timeout_ctx; 54139beb93cSSam Leffler 54239beb93cSSam Leffler RADIUS_DEBUG("Timing out authentication session 0x%x", sess->sess_id); 54339beb93cSSam Leffler radius_server_session_remove(data, sess); 54439beb93cSSam Leffler } 54539beb93cSSam Leffler 54639beb93cSSam Leffler 54739beb93cSSam Leffler static struct radius_session * 54839beb93cSSam Leffler radius_server_new_session(struct radius_server_data *data, 54939beb93cSSam Leffler struct radius_client *client) 55039beb93cSSam Leffler { 55139beb93cSSam Leffler struct radius_session *sess; 55239beb93cSSam Leffler 55339beb93cSSam Leffler if (data->num_sess >= RADIUS_MAX_SESSION) { 55439beb93cSSam Leffler RADIUS_DEBUG("Maximum number of existing session - no room " 55539beb93cSSam Leffler "for a new session"); 55639beb93cSSam Leffler return NULL; 55739beb93cSSam Leffler } 55839beb93cSSam Leffler 55939beb93cSSam Leffler sess = os_zalloc(sizeof(*sess)); 56039beb93cSSam Leffler if (sess == NULL) 56139beb93cSSam Leffler return NULL; 56239beb93cSSam Leffler 56339beb93cSSam Leffler sess->server = data; 56439beb93cSSam Leffler sess->client = client; 56539beb93cSSam Leffler sess->sess_id = data->next_sess_id++; 56639beb93cSSam Leffler sess->next = client->sessions; 56739beb93cSSam Leffler client->sessions = sess; 56839beb93cSSam Leffler eloop_register_timeout(RADIUS_SESSION_TIMEOUT, 0, 56939beb93cSSam Leffler radius_server_session_timeout, data, sess); 57039beb93cSSam Leffler data->num_sess++; 57139beb93cSSam Leffler return sess; 57239beb93cSSam Leffler } 57339beb93cSSam Leffler 57439beb93cSSam Leffler 5755b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS 5765b9c547cSRui Paulo static void radius_server_testing_options_tls(struct radius_session *sess, 5775b9c547cSRui Paulo const char *tls, 5785b9c547cSRui Paulo struct eap_config *eap_conf) 5795b9c547cSRui Paulo { 5805b9c547cSRui Paulo int test = atoi(tls); 5815b9c547cSRui Paulo 5825b9c547cSRui Paulo switch (test) { 5835b9c547cSRui Paulo case 1: 5845b9c547cSRui Paulo srv_log(sess, "TLS test - break VerifyData"); 5855b9c547cSRui Paulo eap_conf->tls_test_flags = TLS_BREAK_VERIFY_DATA; 5865b9c547cSRui Paulo break; 5875b9c547cSRui Paulo case 2: 5885b9c547cSRui Paulo srv_log(sess, "TLS test - break ServerKeyExchange ServerParams hash"); 5895b9c547cSRui Paulo eap_conf->tls_test_flags = TLS_BREAK_SRV_KEY_X_HASH; 5905b9c547cSRui Paulo break; 5915b9c547cSRui Paulo case 3: 5925b9c547cSRui Paulo srv_log(sess, "TLS test - break ServerKeyExchange ServerParams Signature"); 5935b9c547cSRui Paulo eap_conf->tls_test_flags = TLS_BREAK_SRV_KEY_X_SIGNATURE; 5945b9c547cSRui Paulo break; 5955b9c547cSRui Paulo case 4: 5965b9c547cSRui Paulo srv_log(sess, "TLS test - RSA-DHE using a short 511-bit prime"); 5975b9c547cSRui Paulo eap_conf->tls_test_flags = TLS_DHE_PRIME_511B; 5985b9c547cSRui Paulo break; 5995b9c547cSRui Paulo case 5: 6005b9c547cSRui Paulo srv_log(sess, "TLS test - RSA-DHE using a short 767-bit prime"); 6015b9c547cSRui Paulo eap_conf->tls_test_flags = TLS_DHE_PRIME_767B; 6025b9c547cSRui Paulo break; 6035b9c547cSRui Paulo case 6: 6045b9c547cSRui Paulo srv_log(sess, "TLS test - RSA-DHE using a bogus 15 \"prime\""); 6055b9c547cSRui Paulo eap_conf->tls_test_flags = TLS_DHE_PRIME_15; 6065b9c547cSRui Paulo break; 6075b9c547cSRui Paulo case 7: 6085b9c547cSRui Paulo srv_log(sess, "TLS test - RSA-DHE using a short 58-bit prime in long container"); 6095b9c547cSRui Paulo eap_conf->tls_test_flags = TLS_DHE_PRIME_58B; 6105b9c547cSRui Paulo break; 6115b9c547cSRui Paulo case 8: 6125b9c547cSRui Paulo srv_log(sess, "TLS test - RSA-DHE using a non-prime"); 6135b9c547cSRui Paulo eap_conf->tls_test_flags = TLS_DHE_NON_PRIME; 6145b9c547cSRui Paulo break; 6155b9c547cSRui Paulo default: 6165b9c547cSRui Paulo srv_log(sess, "Unrecognized TLS test"); 6175b9c547cSRui Paulo break; 6185b9c547cSRui Paulo } 6195b9c547cSRui Paulo } 6205b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */ 6215b9c547cSRui Paulo 6225b9c547cSRui Paulo static void radius_server_testing_options(struct radius_session *sess, 6235b9c547cSRui Paulo struct eap_config *eap_conf) 6245b9c547cSRui Paulo { 6255b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS 6265b9c547cSRui Paulo const char *pos; 6275b9c547cSRui Paulo 6285b9c547cSRui Paulo pos = os_strstr(sess->username, "@test-"); 6295b9c547cSRui Paulo if (pos == NULL) 6305b9c547cSRui Paulo return; 6315b9c547cSRui Paulo pos += 6; 6325b9c547cSRui Paulo if (os_strncmp(pos, "tls-", 4) == 0) 6335b9c547cSRui Paulo radius_server_testing_options_tls(sess, pos + 4, eap_conf); 6345b9c547cSRui Paulo else 6355b9c547cSRui Paulo srv_log(sess, "Unrecognized test: %s", pos); 6365b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */ 6375b9c547cSRui Paulo } 6385b9c547cSRui Paulo 6395b9c547cSRui Paulo 64039beb93cSSam Leffler static struct radius_session * 64139beb93cSSam Leffler radius_server_get_new_session(struct radius_server_data *data, 64239beb93cSSam Leffler struct radius_client *client, 6435b9c547cSRui Paulo struct radius_msg *msg, const char *from_addr) 64439beb93cSSam Leffler { 645*85732ac8SCy Schubert u8 *user, *id; 646*85732ac8SCy Schubert size_t user_len, id_len; 64739beb93cSSam Leffler int res; 64839beb93cSSam Leffler struct radius_session *sess; 64939beb93cSSam Leffler struct eap_config eap_conf; 6505b9c547cSRui Paulo struct eap_user tmp; 65139beb93cSSam Leffler 65239beb93cSSam Leffler RADIUS_DEBUG("Creating a new session"); 65339beb93cSSam Leffler 6545b9c547cSRui Paulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &user, 6555b9c547cSRui Paulo &user_len, NULL) < 0) { 65639beb93cSSam Leffler RADIUS_DEBUG("Could not get User-Name"); 65739beb93cSSam Leffler return NULL; 65839beb93cSSam Leffler } 65939beb93cSSam Leffler RADIUS_DUMP_ASCII("User-Name", user, user_len); 66039beb93cSSam Leffler 6615b9c547cSRui Paulo os_memset(&tmp, 0, sizeof(tmp)); 6625b9c547cSRui Paulo res = data->get_eap_user(data->conf_ctx, user, user_len, 0, &tmp); 6635b9c547cSRui Paulo bin_clear_free(tmp.password, tmp.password_len); 66439beb93cSSam Leffler 6655b9c547cSRui Paulo if (res != 0) { 6665b9c547cSRui Paulo RADIUS_DEBUG("User-Name not found from user database"); 6675b9c547cSRui Paulo return NULL; 6685b9c547cSRui Paulo } 6695b9c547cSRui Paulo 67039beb93cSSam Leffler RADIUS_DEBUG("Matching user entry found"); 67139beb93cSSam Leffler sess = radius_server_new_session(data, client); 67239beb93cSSam Leffler if (sess == NULL) { 67339beb93cSSam Leffler RADIUS_DEBUG("Failed to create a new session"); 67439beb93cSSam Leffler return NULL; 67539beb93cSSam Leffler } 6765b9c547cSRui Paulo sess->accept_attr = tmp.accept_attr; 6775b9c547cSRui Paulo sess->macacl = tmp.macacl; 6785b9c547cSRui Paulo 6795b9c547cSRui Paulo sess->username = os_malloc(user_len * 4 + 1); 6805b9c547cSRui Paulo if (sess->username == NULL) { 681*85732ac8SCy Schubert radius_server_session_remove(data, sess); 68239beb93cSSam Leffler return NULL; 68339beb93cSSam Leffler } 6845b9c547cSRui Paulo printf_encode(sess->username, user_len * 4 + 1, user, user_len); 6855b9c547cSRui Paulo 6865b9c547cSRui Paulo sess->nas_ip = os_strdup(from_addr); 6875b9c547cSRui Paulo if (sess->nas_ip == NULL) { 688*85732ac8SCy Schubert radius_server_session_remove(data, sess); 6895b9c547cSRui Paulo return NULL; 6905b9c547cSRui Paulo } 6915b9c547cSRui Paulo 692*85732ac8SCy Schubert if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID, &id, 693*85732ac8SCy Schubert &id_len, NULL) == 0) { 694*85732ac8SCy Schubert char buf[3 * ETH_ALEN]; 695*85732ac8SCy Schubert 696*85732ac8SCy Schubert os_memset(buf, 0, sizeof(buf)); 697*85732ac8SCy Schubert if (id_len >= sizeof(buf)) 698*85732ac8SCy Schubert id_len = sizeof(buf) - 1; 699*85732ac8SCy Schubert os_memcpy(buf, id, id_len); 700*85732ac8SCy Schubert if (hwaddr_aton2(buf, sess->mac_addr) < 0) 701*85732ac8SCy Schubert os_memset(sess->mac_addr, 0, ETH_ALEN); 702*85732ac8SCy Schubert else 703*85732ac8SCy Schubert RADIUS_DEBUG("Calling-Station-Id: " MACSTR, 704*85732ac8SCy Schubert MAC2STR(sess->mac_addr)); 705*85732ac8SCy Schubert } 706*85732ac8SCy Schubert 7075b9c547cSRui Paulo srv_log(sess, "New session created"); 70839beb93cSSam Leffler 70939beb93cSSam Leffler os_memset(&eap_conf, 0, sizeof(eap_conf)); 71039beb93cSSam Leffler eap_conf.ssl_ctx = data->ssl_ctx; 711e28a4053SRui Paulo eap_conf.msg_ctx = data->msg_ctx; 71239beb93cSSam Leffler eap_conf.eap_sim_db_priv = data->eap_sim_db_priv; 71339beb93cSSam Leffler eap_conf.backend_auth = TRUE; 71439beb93cSSam Leffler eap_conf.eap_server = 1; 71539beb93cSSam Leffler eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key; 71639beb93cSSam Leffler eap_conf.eap_fast_a_id = data->eap_fast_a_id; 71739beb93cSSam Leffler eap_conf.eap_fast_a_id_len = data->eap_fast_a_id_len; 71839beb93cSSam Leffler eap_conf.eap_fast_a_id_info = data->eap_fast_a_id_info; 71939beb93cSSam Leffler eap_conf.eap_fast_prov = data->eap_fast_prov; 72039beb93cSSam Leffler eap_conf.pac_key_lifetime = data->pac_key_lifetime; 72139beb93cSSam Leffler eap_conf.pac_key_refresh_time = data->pac_key_refresh_time; 72239beb93cSSam Leffler eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind; 72339beb93cSSam Leffler eap_conf.tnc = data->tnc; 72439beb93cSSam Leffler eap_conf.wps = data->wps; 725f05cddf9SRui Paulo eap_conf.pwd_group = data->pwd_group; 7265b9c547cSRui Paulo eap_conf.server_id = (const u8 *) data->server_id; 7275b9c547cSRui Paulo eap_conf.server_id_len = os_strlen(data->server_id); 7285b9c547cSRui Paulo eap_conf.erp = data->erp; 729325151a3SRui Paulo eap_conf.tls_session_lifetime = data->tls_session_lifetime; 730*85732ac8SCy Schubert eap_conf.tls_flags = data->tls_flags; 7315b9c547cSRui Paulo radius_server_testing_options(sess, &eap_conf); 73239beb93cSSam Leffler sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb, 73339beb93cSSam Leffler &eap_conf); 73439beb93cSSam Leffler if (sess->eap == NULL) { 73539beb93cSSam Leffler RADIUS_DEBUG("Failed to initialize EAP state machine for the " 73639beb93cSSam Leffler "new session"); 737*85732ac8SCy Schubert radius_server_session_remove(data, sess); 73839beb93cSSam Leffler return NULL; 73939beb93cSSam Leffler } 74039beb93cSSam Leffler sess->eap_if = eap_get_interface(sess->eap); 74139beb93cSSam Leffler sess->eap_if->eapRestart = TRUE; 74239beb93cSSam Leffler sess->eap_if->portEnabled = TRUE; 74339beb93cSSam Leffler 74439beb93cSSam Leffler RADIUS_DEBUG("New session 0x%x initialized", sess->sess_id); 74539beb93cSSam Leffler 74639beb93cSSam Leffler return sess; 74739beb93cSSam Leffler } 74839beb93cSSam Leffler 74939beb93cSSam Leffler 750*85732ac8SCy Schubert #ifdef CONFIG_HS20 751*85732ac8SCy Schubert static void radius_srv_hs20_t_c_pending(struct radius_session *sess) 752*85732ac8SCy Schubert { 753*85732ac8SCy Schubert #ifdef CONFIG_SQLITE 754*85732ac8SCy Schubert char *sql; 755*85732ac8SCy Schubert char addr[3 * ETH_ALEN], *id_str; 756*85732ac8SCy Schubert const u8 *id; 757*85732ac8SCy Schubert size_t id_len; 758*85732ac8SCy Schubert 759*85732ac8SCy Schubert if (!sess->server->db || !sess->eap || 760*85732ac8SCy Schubert is_zero_ether_addr(sess->mac_addr)) 761*85732ac8SCy Schubert return; 762*85732ac8SCy Schubert 763*85732ac8SCy Schubert os_snprintf(addr, sizeof(addr), MACSTR, MAC2STR(sess->mac_addr)); 764*85732ac8SCy Schubert 765*85732ac8SCy Schubert id = eap_get_identity(sess->eap, &id_len); 766*85732ac8SCy Schubert if (!id) 767*85732ac8SCy Schubert return; 768*85732ac8SCy Schubert id_str = os_malloc(id_len + 1); 769*85732ac8SCy Schubert if (!id_str) 770*85732ac8SCy Schubert return; 771*85732ac8SCy Schubert os_memcpy(id_str, id, id_len); 772*85732ac8SCy Schubert id_str[id_len] = '\0'; 773*85732ac8SCy Schubert 774*85732ac8SCy Schubert sql = sqlite3_mprintf("INSERT OR REPLACE INTO pending_tc (mac_addr,identity) VALUES (%Q,%Q)", 775*85732ac8SCy Schubert addr, id_str); 776*85732ac8SCy Schubert os_free(id_str); 777*85732ac8SCy Schubert if (!sql) 778*85732ac8SCy Schubert return; 779*85732ac8SCy Schubert 780*85732ac8SCy Schubert if (sqlite3_exec(sess->server->db, sql, NULL, NULL, NULL) != 781*85732ac8SCy Schubert SQLITE_OK) { 782*85732ac8SCy Schubert RADIUS_ERROR("Failed to add pending_tc entry into sqlite database: %s", 783*85732ac8SCy Schubert sqlite3_errmsg(sess->server->db)); 784*85732ac8SCy Schubert } 785*85732ac8SCy Schubert sqlite3_free(sql); 786*85732ac8SCy Schubert #endif /* CONFIG_SQLITE */ 787*85732ac8SCy Schubert } 788*85732ac8SCy Schubert #endif /* CONFIG_HS20 */ 789*85732ac8SCy Schubert 790*85732ac8SCy Schubert 791*85732ac8SCy Schubert static void radius_server_add_session(struct radius_session *sess) 792*85732ac8SCy Schubert { 793*85732ac8SCy Schubert #ifdef CONFIG_SQLITE 794*85732ac8SCy Schubert char *sql; 795*85732ac8SCy Schubert char addr_txt[ETH_ALEN * 3]; 796*85732ac8SCy Schubert struct os_time now; 797*85732ac8SCy Schubert 798*85732ac8SCy Schubert if (!sess->server->db) 799*85732ac8SCy Schubert return; 800*85732ac8SCy Schubert 801*85732ac8SCy Schubert 802*85732ac8SCy Schubert os_snprintf(addr_txt, sizeof(addr_txt), MACSTR, 803*85732ac8SCy Schubert MAC2STR(sess->mac_addr)); 804*85732ac8SCy Schubert 805*85732ac8SCy Schubert os_get_time(&now); 806*85732ac8SCy Schubert sql = sqlite3_mprintf("INSERT OR REPLACE INTO current_sessions(mac_addr,identity,start_time,nas,hs20_t_c_filtering) VALUES (%Q,%Q,%d,%Q,%u)", 807*85732ac8SCy Schubert addr_txt, sess->username, now.sec, 808*85732ac8SCy Schubert sess->nas_ip, sess->t_c_filtering); 809*85732ac8SCy Schubert if (sql) { 810*85732ac8SCy Schubert if (sqlite3_exec(sess->server->db, sql, NULL, NULL, 811*85732ac8SCy Schubert NULL) != SQLITE_OK) { 812*85732ac8SCy Schubert RADIUS_ERROR("Failed to add current_sessions entry into sqlite database: %s", 813*85732ac8SCy Schubert sqlite3_errmsg(sess->server->db)); 814*85732ac8SCy Schubert } 815*85732ac8SCy Schubert sqlite3_free(sql); 816*85732ac8SCy Schubert } 817*85732ac8SCy Schubert #endif /* CONFIG_SQLITE */ 818*85732ac8SCy Schubert } 819*85732ac8SCy Schubert 820*85732ac8SCy Schubert 821*85732ac8SCy Schubert static void db_update_last_msk(struct radius_session *sess, const char *msk) 822*85732ac8SCy Schubert { 823*85732ac8SCy Schubert #ifdef CONFIG_RADIUS_TEST 824*85732ac8SCy Schubert #ifdef CONFIG_SQLITE 825*85732ac8SCy Schubert char *sql = NULL; 826*85732ac8SCy Schubert char *id_str = NULL; 827*85732ac8SCy Schubert const u8 *id; 828*85732ac8SCy Schubert size_t id_len; 829*85732ac8SCy Schubert const char *serial_num; 830*85732ac8SCy Schubert 831*85732ac8SCy Schubert if (!sess->server->db) 832*85732ac8SCy Schubert return; 833*85732ac8SCy Schubert 834*85732ac8SCy Schubert serial_num = eap_get_serial_num(sess->eap); 835*85732ac8SCy Schubert if (serial_num) { 836*85732ac8SCy Schubert id_len = 5 + os_strlen(serial_num) + 1; 837*85732ac8SCy Schubert id_str = os_malloc(id_len); 838*85732ac8SCy Schubert if (!id_str) 839*85732ac8SCy Schubert return; 840*85732ac8SCy Schubert os_snprintf(id_str, id_len, "cert-%s", serial_num); 841*85732ac8SCy Schubert } else { 842*85732ac8SCy Schubert id = eap_get_identity(sess->eap, &id_len); 843*85732ac8SCy Schubert if (!id) 844*85732ac8SCy Schubert return; 845*85732ac8SCy Schubert id_str = os_malloc(id_len + 1); 846*85732ac8SCy Schubert if (!id_str) 847*85732ac8SCy Schubert return; 848*85732ac8SCy Schubert os_memcpy(id_str, id, id_len); 849*85732ac8SCy Schubert id_str[id_len] = '\0'; 850*85732ac8SCy Schubert } 851*85732ac8SCy Schubert 852*85732ac8SCy Schubert sql = sqlite3_mprintf("UPDATE users SET last_msk=%Q WHERE identity=%Q", 853*85732ac8SCy Schubert msk, id_str); 854*85732ac8SCy Schubert os_free(id_str); 855*85732ac8SCy Schubert if (!sql) 856*85732ac8SCy Schubert return; 857*85732ac8SCy Schubert 858*85732ac8SCy Schubert if (sqlite3_exec(sess->server->db, sql, NULL, NULL, NULL) != 859*85732ac8SCy Schubert SQLITE_OK) { 860*85732ac8SCy Schubert RADIUS_DEBUG("Failed to update last_msk: %s", 861*85732ac8SCy Schubert sqlite3_errmsg(sess->server->db)); 862*85732ac8SCy Schubert } 863*85732ac8SCy Schubert sqlite3_free(sql); 864*85732ac8SCy Schubert #endif /* CONFIG_SQLITE */ 865*85732ac8SCy Schubert #endif /* CONFIG_RADIUS_TEST */ 866*85732ac8SCy Schubert } 867*85732ac8SCy Schubert 868*85732ac8SCy Schubert 86939beb93cSSam Leffler static struct radius_msg * 87039beb93cSSam Leffler radius_server_encapsulate_eap(struct radius_server_data *data, 87139beb93cSSam Leffler struct radius_client *client, 87239beb93cSSam Leffler struct radius_session *sess, 87339beb93cSSam Leffler struct radius_msg *request) 87439beb93cSSam Leffler { 87539beb93cSSam Leffler struct radius_msg *msg; 87639beb93cSSam Leffler int code; 87739beb93cSSam Leffler unsigned int sess_id; 878e28a4053SRui Paulo struct radius_hdr *hdr = radius_msg_get_hdr(request); 879*85732ac8SCy Schubert u16 reason = WLAN_REASON_IEEE_802_1X_AUTH_FAILED; 88039beb93cSSam Leffler 88139beb93cSSam Leffler if (sess->eap_if->eapFail) { 88239beb93cSSam Leffler sess->eap_if->eapFail = FALSE; 88339beb93cSSam Leffler code = RADIUS_CODE_ACCESS_REJECT; 88439beb93cSSam Leffler } else if (sess->eap_if->eapSuccess) { 88539beb93cSSam Leffler sess->eap_if->eapSuccess = FALSE; 88639beb93cSSam Leffler code = RADIUS_CODE_ACCESS_ACCEPT; 88739beb93cSSam Leffler } else { 88839beb93cSSam Leffler sess->eap_if->eapReq = FALSE; 88939beb93cSSam Leffler code = RADIUS_CODE_ACCESS_CHALLENGE; 89039beb93cSSam Leffler } 89139beb93cSSam Leffler 892e28a4053SRui Paulo msg = radius_msg_new(code, hdr->identifier); 89339beb93cSSam Leffler if (msg == NULL) { 89439beb93cSSam Leffler RADIUS_DEBUG("Failed to allocate reply message"); 89539beb93cSSam Leffler return NULL; 89639beb93cSSam Leffler } 89739beb93cSSam Leffler 89839beb93cSSam Leffler sess_id = htonl(sess->sess_id); 89939beb93cSSam Leffler if (code == RADIUS_CODE_ACCESS_CHALLENGE && 90039beb93cSSam Leffler !radius_msg_add_attr(msg, RADIUS_ATTR_STATE, 90139beb93cSSam Leffler (u8 *) &sess_id, sizeof(sess_id))) { 90239beb93cSSam Leffler RADIUS_DEBUG("Failed to add State attribute"); 90339beb93cSSam Leffler } 90439beb93cSSam Leffler 90539beb93cSSam Leffler if (sess->eap_if->eapReqData && 90639beb93cSSam Leffler !radius_msg_add_eap(msg, wpabuf_head(sess->eap_if->eapReqData), 90739beb93cSSam Leffler wpabuf_len(sess->eap_if->eapReqData))) { 90839beb93cSSam Leffler RADIUS_DEBUG("Failed to add EAP-Message attribute"); 90939beb93cSSam Leffler } 91039beb93cSSam Leffler 91139beb93cSSam Leffler if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) { 91239beb93cSSam Leffler int len; 913f05cddf9SRui Paulo #ifdef CONFIG_RADIUS_TEST 914*85732ac8SCy Schubert char buf[2 * 64 + 1]; 915*85732ac8SCy Schubert 916*85732ac8SCy Schubert len = sess->eap_if->eapKeyDataLen; 917*85732ac8SCy Schubert if (len > 64) 918*85732ac8SCy Schubert len = 64; 919*85732ac8SCy Schubert len = wpa_snprintf_hex(buf, sizeof(buf), 920*85732ac8SCy Schubert sess->eap_if->eapKeyData, len); 921*85732ac8SCy Schubert buf[len] = '\0'; 922*85732ac8SCy Schubert 923f05cddf9SRui Paulo if (data->dump_msk_file) { 924f05cddf9SRui Paulo FILE *f; 925*85732ac8SCy Schubert 926f05cddf9SRui Paulo f = fopen(data->dump_msk_file, "a"); 927f05cddf9SRui Paulo if (f) { 928f05cddf9SRui Paulo len = sess->eap_if->eapKeyDataLen; 929f05cddf9SRui Paulo if (len > 64) 930f05cddf9SRui Paulo len = 64; 931f05cddf9SRui Paulo len = wpa_snprintf_hex( 932f05cddf9SRui Paulo buf, sizeof(buf), 933f05cddf9SRui Paulo sess->eap_if->eapKeyData, len); 934f05cddf9SRui Paulo buf[len] = '\0'; 935f05cddf9SRui Paulo fprintf(f, "%s\n", buf); 936f05cddf9SRui Paulo fclose(f); 937f05cddf9SRui Paulo } 938f05cddf9SRui Paulo } 939*85732ac8SCy Schubert 940*85732ac8SCy Schubert db_update_last_msk(sess, buf); 941f05cddf9SRui Paulo #endif /* CONFIG_RADIUS_TEST */ 94239beb93cSSam Leffler if (sess->eap_if->eapKeyDataLen > 64) { 94339beb93cSSam Leffler len = 32; 94439beb93cSSam Leffler } else { 94539beb93cSSam Leffler len = sess->eap_if->eapKeyDataLen / 2; 94639beb93cSSam Leffler } 947e28a4053SRui Paulo if (!radius_msg_add_mppe_keys(msg, hdr->authenticator, 94839beb93cSSam Leffler (u8 *) client->shared_secret, 94939beb93cSSam Leffler client->shared_secret_len, 95039beb93cSSam Leffler sess->eap_if->eapKeyData + len, 95139beb93cSSam Leffler len, sess->eap_if->eapKeyData, 95239beb93cSSam Leffler len)) { 95339beb93cSSam Leffler RADIUS_DEBUG("Failed to add MPPE key attributes"); 95439beb93cSSam Leffler } 95539beb93cSSam Leffler } 95639beb93cSSam Leffler 9575b9c547cSRui Paulo #ifdef CONFIG_HS20 9585b9c547cSRui Paulo if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->remediation && 9595b9c547cSRui Paulo data->subscr_remediation_url) { 9605b9c547cSRui Paulo u8 *buf; 9615b9c547cSRui Paulo size_t url_len = os_strlen(data->subscr_remediation_url); 9625b9c547cSRui Paulo buf = os_malloc(1 + url_len); 9635b9c547cSRui Paulo if (buf == NULL) { 9645b9c547cSRui Paulo radius_msg_free(msg); 9655b9c547cSRui Paulo return NULL; 9665b9c547cSRui Paulo } 9675b9c547cSRui Paulo buf[0] = data->subscr_remediation_method; 9685b9c547cSRui Paulo os_memcpy(&buf[1], data->subscr_remediation_url, url_len); 9695b9c547cSRui Paulo if (!radius_msg_add_wfa( 9705b9c547cSRui Paulo msg, RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION, 9715b9c547cSRui Paulo buf, 1 + url_len)) { 9725b9c547cSRui Paulo RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem"); 9735b9c547cSRui Paulo } 9745b9c547cSRui Paulo os_free(buf); 9755b9c547cSRui Paulo } else if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->remediation) { 9765b9c547cSRui Paulo u8 buf[1]; 9775b9c547cSRui Paulo if (!radius_msg_add_wfa( 9785b9c547cSRui Paulo msg, RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION, 9795b9c547cSRui Paulo buf, 0)) { 9805b9c547cSRui Paulo RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem"); 9815b9c547cSRui Paulo } 9825b9c547cSRui Paulo } 983*85732ac8SCy Schubert 984*85732ac8SCy Schubert if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->t_c_filtering) { 985*85732ac8SCy Schubert u8 buf[4] = { 0x01, 0x00, 0x00, 0x00 }; /* E=1 */ 986*85732ac8SCy Schubert const char *url = data->t_c_server_url, *pos; 987*85732ac8SCy Schubert char *url2, *end2, *pos2; 988*85732ac8SCy Schubert size_t url_len; 989*85732ac8SCy Schubert 990*85732ac8SCy Schubert if (!radius_msg_add_wfa( 991*85732ac8SCy Schubert msg, RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING, 992*85732ac8SCy Schubert buf, sizeof(buf))) { 993*85732ac8SCy Schubert RADIUS_DEBUG("Failed to add WFA-HS20-T-C-Filtering"); 994*85732ac8SCy Schubert radius_msg_free(msg); 995*85732ac8SCy Schubert return NULL; 996*85732ac8SCy Schubert } 997*85732ac8SCy Schubert 998*85732ac8SCy Schubert if (!url) { 999*85732ac8SCy Schubert RADIUS_DEBUG("No t_c_server_url configured"); 1000*85732ac8SCy Schubert radius_msg_free(msg); 1001*85732ac8SCy Schubert return NULL; 1002*85732ac8SCy Schubert } 1003*85732ac8SCy Schubert 1004*85732ac8SCy Schubert pos = os_strstr(url, "@1@"); 1005*85732ac8SCy Schubert if (!pos) { 1006*85732ac8SCy Schubert RADIUS_DEBUG("No @1@ macro in t_c_server_url"); 1007*85732ac8SCy Schubert radius_msg_free(msg); 1008*85732ac8SCy Schubert return NULL; 1009*85732ac8SCy Schubert } 1010*85732ac8SCy Schubert 1011*85732ac8SCy Schubert url_len = os_strlen(url) + ETH_ALEN * 3 - 1 - 3; 1012*85732ac8SCy Schubert url2 = os_malloc(url_len + 1); 1013*85732ac8SCy Schubert if (!url2) { 1014*85732ac8SCy Schubert RADIUS_DEBUG("Failed to allocate room for T&C Server URL"); 1015*85732ac8SCy Schubert os_free(url2); 1016*85732ac8SCy Schubert radius_msg_free(msg); 1017*85732ac8SCy Schubert return NULL; 1018*85732ac8SCy Schubert } 1019*85732ac8SCy Schubert pos2 = url2; 1020*85732ac8SCy Schubert end2 = url2 + url_len + 1; 1021*85732ac8SCy Schubert os_memcpy(pos2, url, pos - url); 1022*85732ac8SCy Schubert pos2 += pos - url; 1023*85732ac8SCy Schubert os_snprintf(pos2, end2 - pos2, MACSTR, MAC2STR(sess->mac_addr)); 1024*85732ac8SCy Schubert pos2 += ETH_ALEN * 3 - 1; 1025*85732ac8SCy Schubert os_memcpy(pos2, pos + 3, os_strlen(pos + 3)); 1026*85732ac8SCy Schubert if (!radius_msg_add_wfa(msg, 1027*85732ac8SCy Schubert RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL, 1028*85732ac8SCy Schubert (const u8 *) url2, url_len)) { 1029*85732ac8SCy Schubert RADIUS_DEBUG("Failed to add WFA-HS20-T-C-URL"); 1030*85732ac8SCy Schubert os_free(url2); 1031*85732ac8SCy Schubert radius_msg_free(msg); 1032*85732ac8SCy Schubert return NULL; 1033*85732ac8SCy Schubert } 1034*85732ac8SCy Schubert os_free(url2); 1035*85732ac8SCy Schubert 1036*85732ac8SCy Schubert radius_srv_hs20_t_c_pending(sess); 1037*85732ac8SCy Schubert } 10385b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 10395b9c547cSRui Paulo 104039beb93cSSam Leffler if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) { 104139beb93cSSam Leffler RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)"); 104239beb93cSSam Leffler radius_msg_free(msg); 104339beb93cSSam Leffler return NULL; 104439beb93cSSam Leffler } 104539beb93cSSam Leffler 10465b9c547cSRui Paulo if (code == RADIUS_CODE_ACCESS_ACCEPT) { 10475b9c547cSRui Paulo struct hostapd_radius_attr *attr; 10485b9c547cSRui Paulo for (attr = sess->accept_attr; attr; attr = attr->next) { 10495b9c547cSRui Paulo if (!radius_msg_add_attr(msg, attr->type, 10505b9c547cSRui Paulo wpabuf_head(attr->val), 10515b9c547cSRui Paulo wpabuf_len(attr->val))) { 10525b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add RADIUS attribute"); 10535b9c547cSRui Paulo radius_msg_free(msg); 10545b9c547cSRui Paulo return NULL; 10555b9c547cSRui Paulo } 10565b9c547cSRui Paulo } 10575b9c547cSRui Paulo } 10585b9c547cSRui Paulo 1059*85732ac8SCy Schubert if (code == RADIUS_CODE_ACCESS_REJECT) { 1060*85732ac8SCy Schubert if (radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE, 1061*85732ac8SCy Schubert reason) < 0) { 1062*85732ac8SCy Schubert RADIUS_DEBUG("Failed to add WLAN-Reason-Code attribute"); 1063*85732ac8SCy Schubert radius_msg_free(msg); 1064*85732ac8SCy Schubert return NULL; 1065*85732ac8SCy Schubert } 1066*85732ac8SCy Schubert } 1067*85732ac8SCy Schubert 10685b9c547cSRui Paulo if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret, 10695b9c547cSRui Paulo client->shared_secret_len, 10705b9c547cSRui Paulo hdr->authenticator) < 0) { 10715b9c547cSRui Paulo RADIUS_DEBUG("Failed to add Message-Authenticator attribute"); 10725b9c547cSRui Paulo } 10735b9c547cSRui Paulo 1074*85732ac8SCy Schubert if (code == RADIUS_CODE_ACCESS_ACCEPT) 1075*85732ac8SCy Schubert radius_server_add_session(sess); 1076*85732ac8SCy Schubert 10775b9c547cSRui Paulo return msg; 10785b9c547cSRui Paulo } 10795b9c547cSRui Paulo 10805b9c547cSRui Paulo 10815b9c547cSRui Paulo static struct radius_msg * 10825b9c547cSRui Paulo radius_server_macacl(struct radius_server_data *data, 10835b9c547cSRui Paulo struct radius_client *client, 10845b9c547cSRui Paulo struct radius_session *sess, 10855b9c547cSRui Paulo struct radius_msg *request) 10865b9c547cSRui Paulo { 10875b9c547cSRui Paulo struct radius_msg *msg; 10885b9c547cSRui Paulo int code; 10895b9c547cSRui Paulo struct radius_hdr *hdr = radius_msg_get_hdr(request); 10905b9c547cSRui Paulo u8 *pw; 10915b9c547cSRui Paulo size_t pw_len; 10925b9c547cSRui Paulo 10935b9c547cSRui Paulo code = RADIUS_CODE_ACCESS_ACCEPT; 10945b9c547cSRui Paulo 10955b9c547cSRui Paulo if (radius_msg_get_attr_ptr(request, RADIUS_ATTR_USER_PASSWORD, &pw, 10965b9c547cSRui Paulo &pw_len, NULL) < 0) { 10975b9c547cSRui Paulo RADIUS_DEBUG("Could not get User-Password"); 10985b9c547cSRui Paulo code = RADIUS_CODE_ACCESS_REJECT; 10995b9c547cSRui Paulo } else { 11005b9c547cSRui Paulo int res; 11015b9c547cSRui Paulo struct eap_user tmp; 11025b9c547cSRui Paulo 11035b9c547cSRui Paulo os_memset(&tmp, 0, sizeof(tmp)); 11045b9c547cSRui Paulo res = data->get_eap_user(data->conf_ctx, (u8 *) sess->username, 11055b9c547cSRui Paulo os_strlen(sess->username), 0, &tmp); 11065b9c547cSRui Paulo if (res || !tmp.macacl || tmp.password == NULL) { 11075b9c547cSRui Paulo RADIUS_DEBUG("No MAC ACL user entry"); 11085b9c547cSRui Paulo bin_clear_free(tmp.password, tmp.password_len); 11095b9c547cSRui Paulo code = RADIUS_CODE_ACCESS_REJECT; 11105b9c547cSRui Paulo } else { 11115b9c547cSRui Paulo u8 buf[128]; 11125b9c547cSRui Paulo res = radius_user_password_hide( 11135b9c547cSRui Paulo request, tmp.password, tmp.password_len, 11145b9c547cSRui Paulo (u8 *) client->shared_secret, 11155b9c547cSRui Paulo client->shared_secret_len, 11165b9c547cSRui Paulo buf, sizeof(buf)); 11175b9c547cSRui Paulo bin_clear_free(tmp.password, tmp.password_len); 11185b9c547cSRui Paulo 11195b9c547cSRui Paulo if (res < 0 || pw_len != (size_t) res || 11205b9c547cSRui Paulo os_memcmp_const(pw, buf, res) != 0) { 11215b9c547cSRui Paulo RADIUS_DEBUG("Incorrect User-Password"); 11225b9c547cSRui Paulo code = RADIUS_CODE_ACCESS_REJECT; 11235b9c547cSRui Paulo } 11245b9c547cSRui Paulo } 11255b9c547cSRui Paulo } 11265b9c547cSRui Paulo 11275b9c547cSRui Paulo msg = radius_msg_new(code, hdr->identifier); 11285b9c547cSRui Paulo if (msg == NULL) { 11295b9c547cSRui Paulo RADIUS_DEBUG("Failed to allocate reply message"); 11305b9c547cSRui Paulo return NULL; 11315b9c547cSRui Paulo } 11325b9c547cSRui Paulo 11335b9c547cSRui Paulo if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) { 11345b9c547cSRui Paulo RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)"); 11355b9c547cSRui Paulo radius_msg_free(msg); 11365b9c547cSRui Paulo return NULL; 11375b9c547cSRui Paulo } 11385b9c547cSRui Paulo 11395b9c547cSRui Paulo if (code == RADIUS_CODE_ACCESS_ACCEPT) { 11405b9c547cSRui Paulo struct hostapd_radius_attr *attr; 11415b9c547cSRui Paulo for (attr = sess->accept_attr; attr; attr = attr->next) { 11425b9c547cSRui Paulo if (!radius_msg_add_attr(msg, attr->type, 11435b9c547cSRui Paulo wpabuf_head(attr->val), 11445b9c547cSRui Paulo wpabuf_len(attr->val))) { 11455b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add RADIUS attribute"); 11465b9c547cSRui Paulo radius_msg_free(msg); 11475b9c547cSRui Paulo return NULL; 11485b9c547cSRui Paulo } 11495b9c547cSRui Paulo } 11505b9c547cSRui Paulo } 11515b9c547cSRui Paulo 115239beb93cSSam Leffler if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret, 115339beb93cSSam Leffler client->shared_secret_len, 1154e28a4053SRui Paulo hdr->authenticator) < 0) { 115539beb93cSSam Leffler RADIUS_DEBUG("Failed to add Message-Authenticator attribute"); 115639beb93cSSam Leffler } 115739beb93cSSam Leffler 115839beb93cSSam Leffler return msg; 115939beb93cSSam Leffler } 116039beb93cSSam Leffler 116139beb93cSSam Leffler 116239beb93cSSam Leffler static int radius_server_reject(struct radius_server_data *data, 116339beb93cSSam Leffler struct radius_client *client, 116439beb93cSSam Leffler struct radius_msg *request, 116539beb93cSSam Leffler struct sockaddr *from, socklen_t fromlen, 116639beb93cSSam Leffler const char *from_addr, int from_port) 116739beb93cSSam Leffler { 116839beb93cSSam Leffler struct radius_msg *msg; 116939beb93cSSam Leffler int ret = 0; 117039beb93cSSam Leffler struct eap_hdr eapfail; 1171e28a4053SRui Paulo struct wpabuf *buf; 1172e28a4053SRui Paulo struct radius_hdr *hdr = radius_msg_get_hdr(request); 117339beb93cSSam Leffler 117439beb93cSSam Leffler RADIUS_DEBUG("Reject invalid request from %s:%d", 117539beb93cSSam Leffler from_addr, from_port); 117639beb93cSSam Leffler 1177e28a4053SRui Paulo msg = radius_msg_new(RADIUS_CODE_ACCESS_REJECT, hdr->identifier); 117839beb93cSSam Leffler if (msg == NULL) { 117939beb93cSSam Leffler return -1; 118039beb93cSSam Leffler } 118139beb93cSSam Leffler 118239beb93cSSam Leffler os_memset(&eapfail, 0, sizeof(eapfail)); 118339beb93cSSam Leffler eapfail.code = EAP_CODE_FAILURE; 118439beb93cSSam Leffler eapfail.identifier = 0; 118539beb93cSSam Leffler eapfail.length = host_to_be16(sizeof(eapfail)); 118639beb93cSSam Leffler 118739beb93cSSam Leffler if (!radius_msg_add_eap(msg, (u8 *) &eapfail, sizeof(eapfail))) { 118839beb93cSSam Leffler RADIUS_DEBUG("Failed to add EAP-Message attribute"); 118939beb93cSSam Leffler } 119039beb93cSSam Leffler 119139beb93cSSam Leffler if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) { 119239beb93cSSam Leffler RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)"); 119339beb93cSSam Leffler radius_msg_free(msg); 119439beb93cSSam Leffler return -1; 119539beb93cSSam Leffler } 119639beb93cSSam Leffler 119739beb93cSSam Leffler if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret, 119839beb93cSSam Leffler client->shared_secret_len, 1199e28a4053SRui Paulo hdr->authenticator) < 1200e28a4053SRui Paulo 0) { 120139beb93cSSam Leffler RADIUS_DEBUG("Failed to add Message-Authenticator attribute"); 120239beb93cSSam Leffler } 120339beb93cSSam Leffler 120439beb93cSSam Leffler if (wpa_debug_level <= MSG_MSGDUMP) { 120539beb93cSSam Leffler radius_msg_dump(msg); 120639beb93cSSam Leffler } 120739beb93cSSam Leffler 120839beb93cSSam Leffler data->counters.access_rejects++; 120939beb93cSSam Leffler client->counters.access_rejects++; 1210e28a4053SRui Paulo buf = radius_msg_get_buf(msg); 1211e28a4053SRui Paulo if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0, 121239beb93cSSam Leffler (struct sockaddr *) from, sizeof(*from)) < 0) { 12135b9c547cSRui Paulo wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", strerror(errno)); 121439beb93cSSam Leffler ret = -1; 121539beb93cSSam Leffler } 121639beb93cSSam Leffler 121739beb93cSSam Leffler radius_msg_free(msg); 121839beb93cSSam Leffler 121939beb93cSSam Leffler return ret; 122039beb93cSSam Leffler } 122139beb93cSSam Leffler 122239beb93cSSam Leffler 1223*85732ac8SCy Schubert static void radius_server_hs20_t_c_check(struct radius_session *sess, 1224*85732ac8SCy Schubert struct radius_msg *msg) 1225*85732ac8SCy Schubert { 1226*85732ac8SCy Schubert #ifdef CONFIG_HS20 1227*85732ac8SCy Schubert u8 *buf, *pos, *end, type, sublen, *timestamp = NULL; 1228*85732ac8SCy Schubert size_t len; 1229*85732ac8SCy Schubert 1230*85732ac8SCy Schubert buf = NULL; 1231*85732ac8SCy Schubert for (;;) { 1232*85732ac8SCy Schubert if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 1233*85732ac8SCy Schubert &buf, &len, buf) < 0) 1234*85732ac8SCy Schubert break; 1235*85732ac8SCy Schubert if (len < 6) 1236*85732ac8SCy Schubert continue; 1237*85732ac8SCy Schubert pos = buf; 1238*85732ac8SCy Schubert end = buf + len; 1239*85732ac8SCy Schubert if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA) 1240*85732ac8SCy Schubert continue; 1241*85732ac8SCy Schubert pos += 4; 1242*85732ac8SCy Schubert 1243*85732ac8SCy Schubert type = *pos++; 1244*85732ac8SCy Schubert sublen = *pos++; 1245*85732ac8SCy Schubert if (sublen < 2) 1246*85732ac8SCy Schubert continue; /* invalid length */ 1247*85732ac8SCy Schubert sublen -= 2; /* skip header */ 1248*85732ac8SCy Schubert if (pos + sublen > end) 1249*85732ac8SCy Schubert continue; /* invalid WFA VSA */ 1250*85732ac8SCy Schubert 1251*85732ac8SCy Schubert if (type == RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP && len >= 4) { 1252*85732ac8SCy Schubert timestamp = pos; 1253*85732ac8SCy Schubert break; 1254*85732ac8SCy Schubert } 1255*85732ac8SCy Schubert } 1256*85732ac8SCy Schubert 1257*85732ac8SCy Schubert if (!timestamp) 1258*85732ac8SCy Schubert return; 1259*85732ac8SCy Schubert RADIUS_DEBUG("HS20-Timestamp: %u", WPA_GET_BE32(timestamp)); 1260*85732ac8SCy Schubert if (sess->t_c_timestamp != WPA_GET_BE32(timestamp)) { 1261*85732ac8SCy Schubert RADIUS_DEBUG("Last read T&C timestamp does not match HS20-Timestamp --> require filtering"); 1262*85732ac8SCy Schubert sess->t_c_filtering = 1; 1263*85732ac8SCy Schubert } 1264*85732ac8SCy Schubert #endif /* CONFIG_HS20 */ 1265*85732ac8SCy Schubert } 1266*85732ac8SCy Schubert 1267*85732ac8SCy Schubert 126839beb93cSSam Leffler static int radius_server_request(struct radius_server_data *data, 126939beb93cSSam Leffler struct radius_msg *msg, 127039beb93cSSam Leffler struct sockaddr *from, socklen_t fromlen, 127139beb93cSSam Leffler struct radius_client *client, 127239beb93cSSam Leffler const char *from_addr, int from_port, 127339beb93cSSam Leffler struct radius_session *force_sess) 127439beb93cSSam Leffler { 1275f05cddf9SRui Paulo struct wpabuf *eap = NULL; 127639beb93cSSam Leffler int res, state_included = 0; 127739beb93cSSam Leffler u8 statebuf[4]; 127839beb93cSSam Leffler unsigned int state; 127939beb93cSSam Leffler struct radius_session *sess; 128039beb93cSSam Leffler struct radius_msg *reply; 12813157ba21SRui Paulo int is_complete = 0; 128239beb93cSSam Leffler 128339beb93cSSam Leffler if (force_sess) 128439beb93cSSam Leffler sess = force_sess; 128539beb93cSSam Leffler else { 128639beb93cSSam Leffler res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf, 128739beb93cSSam Leffler sizeof(statebuf)); 128839beb93cSSam Leffler state_included = res >= 0; 128939beb93cSSam Leffler if (res == sizeof(statebuf)) { 129039beb93cSSam Leffler state = WPA_GET_BE32(statebuf); 129139beb93cSSam Leffler sess = radius_server_get_session(client, state); 129239beb93cSSam Leffler } else { 129339beb93cSSam Leffler sess = NULL; 129439beb93cSSam Leffler } 129539beb93cSSam Leffler } 129639beb93cSSam Leffler 129739beb93cSSam Leffler if (sess) { 129839beb93cSSam Leffler RADIUS_DEBUG("Request for session 0x%x", sess->sess_id); 129939beb93cSSam Leffler } else if (state_included) { 130039beb93cSSam Leffler RADIUS_DEBUG("State attribute included but no session found"); 130139beb93cSSam Leffler radius_server_reject(data, client, msg, from, fromlen, 130239beb93cSSam Leffler from_addr, from_port); 130339beb93cSSam Leffler return -1; 130439beb93cSSam Leffler } else { 13055b9c547cSRui Paulo sess = radius_server_get_new_session(data, client, msg, 13065b9c547cSRui Paulo from_addr); 130739beb93cSSam Leffler if (sess == NULL) { 130839beb93cSSam Leffler RADIUS_DEBUG("Could not create a new session"); 130939beb93cSSam Leffler radius_server_reject(data, client, msg, from, fromlen, 131039beb93cSSam Leffler from_addr, from_port); 131139beb93cSSam Leffler return -1; 131239beb93cSSam Leffler } 131339beb93cSSam Leffler } 131439beb93cSSam Leffler 131539beb93cSSam Leffler if (sess->last_from_port == from_port && 1316e28a4053SRui Paulo sess->last_identifier == radius_msg_get_hdr(msg)->identifier && 1317e28a4053SRui Paulo os_memcmp(sess->last_authenticator, 1318e28a4053SRui Paulo radius_msg_get_hdr(msg)->authenticator, 16) == 0) { 131939beb93cSSam Leffler RADIUS_DEBUG("Duplicate message from %s", from_addr); 132039beb93cSSam Leffler data->counters.dup_access_requests++; 132139beb93cSSam Leffler client->counters.dup_access_requests++; 132239beb93cSSam Leffler 132339beb93cSSam Leffler if (sess->last_reply) { 1324e28a4053SRui Paulo struct wpabuf *buf; 1325e28a4053SRui Paulo buf = radius_msg_get_buf(sess->last_reply); 1326e28a4053SRui Paulo res = sendto(data->auth_sock, wpabuf_head(buf), 1327e28a4053SRui Paulo wpabuf_len(buf), 0, 132839beb93cSSam Leffler (struct sockaddr *) from, fromlen); 132939beb93cSSam Leffler if (res < 0) { 13305b9c547cSRui Paulo wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", 13315b9c547cSRui Paulo strerror(errno)); 133239beb93cSSam Leffler } 133339beb93cSSam Leffler return 0; 133439beb93cSSam Leffler } 133539beb93cSSam Leffler 133639beb93cSSam Leffler RADIUS_DEBUG("No previous reply available for duplicate " 133739beb93cSSam Leffler "message"); 133839beb93cSSam Leffler return -1; 133939beb93cSSam Leffler } 134039beb93cSSam Leffler 1341f05cddf9SRui Paulo eap = radius_msg_get_eap(msg); 13425b9c547cSRui Paulo if (eap == NULL && sess->macacl) { 13435b9c547cSRui Paulo reply = radius_server_macacl(data, client, sess, msg); 13445b9c547cSRui Paulo if (reply == NULL) 13455b9c547cSRui Paulo return -1; 13465b9c547cSRui Paulo goto send_reply; 13475b9c547cSRui Paulo } 134839beb93cSSam Leffler if (eap == NULL) { 134939beb93cSSam Leffler RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s", 135039beb93cSSam Leffler from_addr); 135139beb93cSSam Leffler data->counters.packets_dropped++; 135239beb93cSSam Leffler client->counters.packets_dropped++; 135339beb93cSSam Leffler return -1; 135439beb93cSSam Leffler } 135539beb93cSSam Leffler 1356f05cddf9SRui Paulo RADIUS_DUMP("Received EAP data", wpabuf_head(eap), wpabuf_len(eap)); 135739beb93cSSam Leffler 135839beb93cSSam Leffler /* FIX: if Code is Request, Success, or Failure, send Access-Reject; 135939beb93cSSam Leffler * RFC3579 Sect. 2.6.2. 136039beb93cSSam Leffler * Include EAP-Response/Nak with no preferred method if 136139beb93cSSam Leffler * code == request. 136239beb93cSSam Leffler * If code is not 1-4, discard the packet silently. 136339beb93cSSam Leffler * Or is this already done by the EAP state machine? */ 136439beb93cSSam Leffler 136539beb93cSSam Leffler wpabuf_free(sess->eap_if->eapRespData); 1366f05cddf9SRui Paulo sess->eap_if->eapRespData = eap; 136739beb93cSSam Leffler sess->eap_if->eapResp = TRUE; 136839beb93cSSam Leffler eap_server_sm_step(sess->eap); 136939beb93cSSam Leffler 137039beb93cSSam Leffler if ((sess->eap_if->eapReq || sess->eap_if->eapSuccess || 137139beb93cSSam Leffler sess->eap_if->eapFail) && sess->eap_if->eapReqData) { 137239beb93cSSam Leffler RADIUS_DUMP("EAP data from the state machine", 137339beb93cSSam Leffler wpabuf_head(sess->eap_if->eapReqData), 137439beb93cSSam Leffler wpabuf_len(sess->eap_if->eapReqData)); 137539beb93cSSam Leffler } else if (sess->eap_if->eapFail) { 137639beb93cSSam Leffler RADIUS_DEBUG("No EAP data from the state machine, but eapFail " 137739beb93cSSam Leffler "set"); 137839beb93cSSam Leffler } else if (eap_sm_method_pending(sess->eap)) { 137939beb93cSSam Leffler radius_msg_free(sess->last_msg); 138039beb93cSSam Leffler sess->last_msg = msg; 138139beb93cSSam Leffler sess->last_from_port = from_port; 138239beb93cSSam Leffler os_free(sess->last_from_addr); 138339beb93cSSam Leffler sess->last_from_addr = os_strdup(from_addr); 138439beb93cSSam Leffler sess->last_fromlen = fromlen; 138539beb93cSSam Leffler os_memcpy(&sess->last_from, from, fromlen); 138639beb93cSSam Leffler return -2; 138739beb93cSSam Leffler } else { 138839beb93cSSam Leffler RADIUS_DEBUG("No EAP data from the state machine - ignore this" 138939beb93cSSam Leffler " Access-Request silently (assuming it was a " 139039beb93cSSam Leffler "duplicate)"); 139139beb93cSSam Leffler data->counters.packets_dropped++; 139239beb93cSSam Leffler client->counters.packets_dropped++; 139339beb93cSSam Leffler return -1; 139439beb93cSSam Leffler } 139539beb93cSSam Leffler 13963157ba21SRui Paulo if (sess->eap_if->eapSuccess || sess->eap_if->eapFail) 13973157ba21SRui Paulo is_complete = 1; 1398*85732ac8SCy Schubert if (sess->eap_if->eapFail) { 13995b9c547cSRui Paulo srv_log(sess, "EAP authentication failed"); 1400*85732ac8SCy Schubert db_update_last_msk(sess, "FAIL"); 1401*85732ac8SCy Schubert } else if (sess->eap_if->eapSuccess) { 14025b9c547cSRui Paulo srv_log(sess, "EAP authentication succeeded"); 1403*85732ac8SCy Schubert } 1404*85732ac8SCy Schubert 1405*85732ac8SCy Schubert if (sess->eap_if->eapSuccess) 1406*85732ac8SCy Schubert radius_server_hs20_t_c_check(sess, msg); 14073157ba21SRui Paulo 140839beb93cSSam Leffler reply = radius_server_encapsulate_eap(data, client, sess, msg); 140939beb93cSSam Leffler 14105b9c547cSRui Paulo send_reply: 141139beb93cSSam Leffler if (reply) { 1412e28a4053SRui Paulo struct wpabuf *buf; 1413e28a4053SRui Paulo struct radius_hdr *hdr; 1414e28a4053SRui Paulo 141539beb93cSSam Leffler RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port); 141639beb93cSSam Leffler if (wpa_debug_level <= MSG_MSGDUMP) { 141739beb93cSSam Leffler radius_msg_dump(reply); 141839beb93cSSam Leffler } 141939beb93cSSam Leffler 1420e28a4053SRui Paulo switch (radius_msg_get_hdr(reply)->code) { 142139beb93cSSam Leffler case RADIUS_CODE_ACCESS_ACCEPT: 14225b9c547cSRui Paulo srv_log(sess, "Sending Access-Accept"); 142339beb93cSSam Leffler data->counters.access_accepts++; 142439beb93cSSam Leffler client->counters.access_accepts++; 142539beb93cSSam Leffler break; 142639beb93cSSam Leffler case RADIUS_CODE_ACCESS_REJECT: 14275b9c547cSRui Paulo srv_log(sess, "Sending Access-Reject"); 142839beb93cSSam Leffler data->counters.access_rejects++; 142939beb93cSSam Leffler client->counters.access_rejects++; 143039beb93cSSam Leffler break; 143139beb93cSSam Leffler case RADIUS_CODE_ACCESS_CHALLENGE: 143239beb93cSSam Leffler data->counters.access_challenges++; 143339beb93cSSam Leffler client->counters.access_challenges++; 143439beb93cSSam Leffler break; 143539beb93cSSam Leffler } 1436e28a4053SRui Paulo buf = radius_msg_get_buf(reply); 1437e28a4053SRui Paulo res = sendto(data->auth_sock, wpabuf_head(buf), 1438e28a4053SRui Paulo wpabuf_len(buf), 0, 143939beb93cSSam Leffler (struct sockaddr *) from, fromlen); 144039beb93cSSam Leffler if (res < 0) { 14415b9c547cSRui Paulo wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", 14425b9c547cSRui Paulo strerror(errno)); 144339beb93cSSam Leffler } 144439beb93cSSam Leffler radius_msg_free(sess->last_reply); 144539beb93cSSam Leffler sess->last_reply = reply; 144639beb93cSSam Leffler sess->last_from_port = from_port; 1447e28a4053SRui Paulo hdr = radius_msg_get_hdr(msg); 1448e28a4053SRui Paulo sess->last_identifier = hdr->identifier; 1449e28a4053SRui Paulo os_memcpy(sess->last_authenticator, hdr->authenticator, 16); 145039beb93cSSam Leffler } else { 145139beb93cSSam Leffler data->counters.packets_dropped++; 145239beb93cSSam Leffler client->counters.packets_dropped++; 145339beb93cSSam Leffler } 145439beb93cSSam Leffler 14553157ba21SRui Paulo if (is_complete) { 145639beb93cSSam Leffler RADIUS_DEBUG("Removing completed session 0x%x after timeout", 145739beb93cSSam Leffler sess->sess_id); 145839beb93cSSam Leffler eloop_cancel_timeout(radius_server_session_remove_timeout, 145939beb93cSSam Leffler data, sess); 1460*85732ac8SCy Schubert eloop_register_timeout(RADIUS_SESSION_MAINTAIN, 0, 146139beb93cSSam Leffler radius_server_session_remove_timeout, 146239beb93cSSam Leffler data, sess); 146339beb93cSSam Leffler } 146439beb93cSSam Leffler 146539beb93cSSam Leffler return 0; 146639beb93cSSam Leffler } 146739beb93cSSam Leffler 146839beb93cSSam Leffler 1469*85732ac8SCy Schubert static void 1470*85732ac8SCy Schubert radius_server_receive_disconnect_resp(struct radius_server_data *data, 1471*85732ac8SCy Schubert struct radius_client *client, 1472*85732ac8SCy Schubert struct radius_msg *msg, int ack) 1473*85732ac8SCy Schubert { 1474*85732ac8SCy Schubert struct radius_hdr *hdr; 1475*85732ac8SCy Schubert 1476*85732ac8SCy Schubert if (!client->pending_dac_disconnect_req) { 1477*85732ac8SCy Schubert RADIUS_DEBUG("Ignore unexpected Disconnect response"); 1478*85732ac8SCy Schubert radius_msg_free(msg); 1479*85732ac8SCy Schubert return; 1480*85732ac8SCy Schubert } 1481*85732ac8SCy Schubert 1482*85732ac8SCy Schubert hdr = radius_msg_get_hdr(msg); 1483*85732ac8SCy Schubert if (hdr->identifier != client->pending_dac_disconnect_id) { 1484*85732ac8SCy Schubert RADIUS_DEBUG("Ignore unexpected Disconnect response with unexpected identifier %u (expected %u)", 1485*85732ac8SCy Schubert hdr->identifier, 1486*85732ac8SCy Schubert client->pending_dac_disconnect_id); 1487*85732ac8SCy Schubert radius_msg_free(msg); 1488*85732ac8SCy Schubert return; 1489*85732ac8SCy Schubert } 1490*85732ac8SCy Schubert 1491*85732ac8SCy Schubert if (radius_msg_verify(msg, (const u8 *) client->shared_secret, 1492*85732ac8SCy Schubert client->shared_secret_len, 1493*85732ac8SCy Schubert client->pending_dac_disconnect_req, 0)) { 1494*85732ac8SCy Schubert RADIUS_DEBUG("Ignore Disconnect response with invalid authenticator"); 1495*85732ac8SCy Schubert radius_msg_free(msg); 1496*85732ac8SCy Schubert return; 1497*85732ac8SCy Schubert } 1498*85732ac8SCy Schubert 1499*85732ac8SCy Schubert RADIUS_DEBUG("Disconnect-%s received for " MACSTR, 1500*85732ac8SCy Schubert ack ? "ACK" : "NAK", 1501*85732ac8SCy Schubert MAC2STR(client->pending_dac_disconnect_addr)); 1502*85732ac8SCy Schubert 1503*85732ac8SCy Schubert radius_msg_free(msg); 1504*85732ac8SCy Schubert radius_msg_free(client->pending_dac_disconnect_req); 1505*85732ac8SCy Schubert client->pending_dac_disconnect_req = NULL; 1506*85732ac8SCy Schubert } 1507*85732ac8SCy Schubert 1508*85732ac8SCy Schubert 1509*85732ac8SCy Schubert static void radius_server_receive_coa_resp(struct radius_server_data *data, 1510*85732ac8SCy Schubert struct radius_client *client, 1511*85732ac8SCy Schubert struct radius_msg *msg, int ack) 1512*85732ac8SCy Schubert { 1513*85732ac8SCy Schubert struct radius_hdr *hdr; 1514*85732ac8SCy Schubert #ifdef CONFIG_SQLITE 1515*85732ac8SCy Schubert char addrtxt[3 * ETH_ALEN]; 1516*85732ac8SCy Schubert char *sql; 1517*85732ac8SCy Schubert int res; 1518*85732ac8SCy Schubert #endif /* CONFIG_SQLITE */ 1519*85732ac8SCy Schubert 1520*85732ac8SCy Schubert if (!client->pending_dac_coa_req) { 1521*85732ac8SCy Schubert RADIUS_DEBUG("Ignore unexpected CoA response"); 1522*85732ac8SCy Schubert radius_msg_free(msg); 1523*85732ac8SCy Schubert return; 1524*85732ac8SCy Schubert } 1525*85732ac8SCy Schubert 1526*85732ac8SCy Schubert hdr = radius_msg_get_hdr(msg); 1527*85732ac8SCy Schubert if (hdr->identifier != client->pending_dac_coa_id) { 1528*85732ac8SCy Schubert RADIUS_DEBUG("Ignore unexpected CoA response with unexpected identifier %u (expected %u)", 1529*85732ac8SCy Schubert hdr->identifier, 1530*85732ac8SCy Schubert client->pending_dac_coa_id); 1531*85732ac8SCy Schubert radius_msg_free(msg); 1532*85732ac8SCy Schubert return; 1533*85732ac8SCy Schubert } 1534*85732ac8SCy Schubert 1535*85732ac8SCy Schubert if (radius_msg_verify(msg, (const u8 *) client->shared_secret, 1536*85732ac8SCy Schubert client->shared_secret_len, 1537*85732ac8SCy Schubert client->pending_dac_coa_req, 0)) { 1538*85732ac8SCy Schubert RADIUS_DEBUG("Ignore CoA response with invalid authenticator"); 1539*85732ac8SCy Schubert radius_msg_free(msg); 1540*85732ac8SCy Schubert return; 1541*85732ac8SCy Schubert } 1542*85732ac8SCy Schubert 1543*85732ac8SCy Schubert RADIUS_DEBUG("CoA-%s received for " MACSTR, 1544*85732ac8SCy Schubert ack ? "ACK" : "NAK", 1545*85732ac8SCy Schubert MAC2STR(client->pending_dac_coa_addr)); 1546*85732ac8SCy Schubert 1547*85732ac8SCy Schubert radius_msg_free(msg); 1548*85732ac8SCy Schubert radius_msg_free(client->pending_dac_coa_req); 1549*85732ac8SCy Schubert client->pending_dac_coa_req = NULL; 1550*85732ac8SCy Schubert 1551*85732ac8SCy Schubert #ifdef CONFIG_SQLITE 1552*85732ac8SCy Schubert if (!data->db) 1553*85732ac8SCy Schubert return; 1554*85732ac8SCy Schubert 1555*85732ac8SCy Schubert os_snprintf(addrtxt, sizeof(addrtxt), MACSTR, 1556*85732ac8SCy Schubert MAC2STR(client->pending_dac_coa_addr)); 1557*85732ac8SCy Schubert 1558*85732ac8SCy Schubert if (ack) { 1559*85732ac8SCy Schubert sql = sqlite3_mprintf("UPDATE current_sessions SET hs20_t_c_filtering=0, waiting_coa_ack=0, coa_ack_received=1 WHERE mac_addr=%Q", 1560*85732ac8SCy Schubert addrtxt); 1561*85732ac8SCy Schubert } else { 1562*85732ac8SCy Schubert sql = sqlite3_mprintf("UPDATE current_sessions SET waiting_coa_ack=0 WHERE mac_addr=%Q", 1563*85732ac8SCy Schubert addrtxt); 1564*85732ac8SCy Schubert } 1565*85732ac8SCy Schubert if (!sql) 1566*85732ac8SCy Schubert return; 1567*85732ac8SCy Schubert 1568*85732ac8SCy Schubert res = sqlite3_exec(data->db, sql, NULL, NULL, NULL); 1569*85732ac8SCy Schubert sqlite3_free(sql); 1570*85732ac8SCy Schubert if (res != SQLITE_OK) { 1571*85732ac8SCy Schubert RADIUS_ERROR("Failed to update current_sessions entry: %s", 1572*85732ac8SCy Schubert sqlite3_errmsg(data->db)); 1573*85732ac8SCy Schubert return; 1574*85732ac8SCy Schubert } 1575*85732ac8SCy Schubert #endif /* CONFIG_SQLITE */ 1576*85732ac8SCy Schubert } 1577*85732ac8SCy Schubert 1578*85732ac8SCy Schubert 157939beb93cSSam Leffler static void radius_server_receive_auth(int sock, void *eloop_ctx, 158039beb93cSSam Leffler void *sock_ctx) 158139beb93cSSam Leffler { 158239beb93cSSam Leffler struct radius_server_data *data = eloop_ctx; 158339beb93cSSam Leffler u8 *buf = NULL; 15843157ba21SRui Paulo union { 15853157ba21SRui Paulo struct sockaddr_storage ss; 15863157ba21SRui Paulo struct sockaddr_in sin; 15873157ba21SRui Paulo #ifdef CONFIG_IPV6 15883157ba21SRui Paulo struct sockaddr_in6 sin6; 15893157ba21SRui Paulo #endif /* CONFIG_IPV6 */ 15903157ba21SRui Paulo } from; 159139beb93cSSam Leffler socklen_t fromlen; 159239beb93cSSam Leffler int len; 159339beb93cSSam Leffler struct radius_client *client = NULL; 159439beb93cSSam Leffler struct radius_msg *msg = NULL; 159539beb93cSSam Leffler char abuf[50]; 159639beb93cSSam Leffler int from_port = 0; 159739beb93cSSam Leffler 159839beb93cSSam Leffler buf = os_malloc(RADIUS_MAX_MSG_LEN); 159939beb93cSSam Leffler if (buf == NULL) { 160039beb93cSSam Leffler goto fail; 160139beb93cSSam Leffler } 160239beb93cSSam Leffler 160339beb93cSSam Leffler fromlen = sizeof(from); 160439beb93cSSam Leffler len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0, 16053157ba21SRui Paulo (struct sockaddr *) &from.ss, &fromlen); 160639beb93cSSam Leffler if (len < 0) { 16075b9c547cSRui Paulo wpa_printf(MSG_INFO, "recvfrom[radius_server]: %s", 16085b9c547cSRui Paulo strerror(errno)); 160939beb93cSSam Leffler goto fail; 161039beb93cSSam Leffler } 161139beb93cSSam Leffler 161239beb93cSSam Leffler #ifdef CONFIG_IPV6 161339beb93cSSam Leffler if (data->ipv6) { 16143157ba21SRui Paulo if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf, 16153157ba21SRui Paulo sizeof(abuf)) == NULL) 161639beb93cSSam Leffler abuf[0] = '\0'; 16173157ba21SRui Paulo from_port = ntohs(from.sin6.sin6_port); 161839beb93cSSam Leffler RADIUS_DEBUG("Received %d bytes from %s:%d", 161939beb93cSSam Leffler len, abuf, from_port); 162039beb93cSSam Leffler 162139beb93cSSam Leffler client = radius_server_get_client(data, 162239beb93cSSam Leffler (struct in_addr *) 16233157ba21SRui Paulo &from.sin6.sin6_addr, 1); 162439beb93cSSam Leffler } 162539beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 162639beb93cSSam Leffler 162739beb93cSSam Leffler if (!data->ipv6) { 16283157ba21SRui Paulo os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf)); 16293157ba21SRui Paulo from_port = ntohs(from.sin.sin_port); 163039beb93cSSam Leffler RADIUS_DEBUG("Received %d bytes from %s:%d", 163139beb93cSSam Leffler len, abuf, from_port); 163239beb93cSSam Leffler 16333157ba21SRui Paulo client = radius_server_get_client(data, &from.sin.sin_addr, 0); 163439beb93cSSam Leffler } 163539beb93cSSam Leffler 163639beb93cSSam Leffler RADIUS_DUMP("Received data", buf, len); 163739beb93cSSam Leffler 163839beb93cSSam Leffler if (client == NULL) { 163939beb93cSSam Leffler RADIUS_DEBUG("Unknown client %s - packet ignored", abuf); 164039beb93cSSam Leffler data->counters.invalid_requests++; 164139beb93cSSam Leffler goto fail; 164239beb93cSSam Leffler } 164339beb93cSSam Leffler 164439beb93cSSam Leffler msg = radius_msg_parse(buf, len); 164539beb93cSSam Leffler if (msg == NULL) { 164639beb93cSSam Leffler RADIUS_DEBUG("Parsing incoming RADIUS frame failed"); 164739beb93cSSam Leffler data->counters.malformed_access_requests++; 164839beb93cSSam Leffler client->counters.malformed_access_requests++; 164939beb93cSSam Leffler goto fail; 165039beb93cSSam Leffler } 165139beb93cSSam Leffler 165239beb93cSSam Leffler os_free(buf); 165339beb93cSSam Leffler buf = NULL; 165439beb93cSSam Leffler 165539beb93cSSam Leffler if (wpa_debug_level <= MSG_MSGDUMP) { 165639beb93cSSam Leffler radius_msg_dump(msg); 165739beb93cSSam Leffler } 165839beb93cSSam Leffler 1659*85732ac8SCy Schubert if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_DISCONNECT_ACK) { 1660*85732ac8SCy Schubert radius_server_receive_disconnect_resp(data, client, msg, 1); 1661*85732ac8SCy Schubert return; 1662*85732ac8SCy Schubert } 1663*85732ac8SCy Schubert 1664*85732ac8SCy Schubert if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_DISCONNECT_NAK) { 1665*85732ac8SCy Schubert radius_server_receive_disconnect_resp(data, client, msg, 0); 1666*85732ac8SCy Schubert return; 1667*85732ac8SCy Schubert } 1668*85732ac8SCy Schubert 1669*85732ac8SCy Schubert if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_COA_ACK) { 1670*85732ac8SCy Schubert radius_server_receive_coa_resp(data, client, msg, 1); 1671*85732ac8SCy Schubert return; 1672*85732ac8SCy Schubert } 1673*85732ac8SCy Schubert 1674*85732ac8SCy Schubert if (radius_msg_get_hdr(msg)->code == RADIUS_CODE_COA_NAK) { 1675*85732ac8SCy Schubert radius_server_receive_coa_resp(data, client, msg, 0); 1676*85732ac8SCy Schubert return; 1677*85732ac8SCy Schubert } 1678*85732ac8SCy Schubert 1679e28a4053SRui Paulo if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCESS_REQUEST) { 1680e28a4053SRui Paulo RADIUS_DEBUG("Unexpected RADIUS code %d", 1681e28a4053SRui Paulo radius_msg_get_hdr(msg)->code); 168239beb93cSSam Leffler data->counters.unknown_types++; 168339beb93cSSam Leffler client->counters.unknown_types++; 168439beb93cSSam Leffler goto fail; 168539beb93cSSam Leffler } 168639beb93cSSam Leffler 168739beb93cSSam Leffler data->counters.access_requests++; 168839beb93cSSam Leffler client->counters.access_requests++; 168939beb93cSSam Leffler 169039beb93cSSam Leffler if (radius_msg_verify_msg_auth(msg, (u8 *) client->shared_secret, 169139beb93cSSam Leffler client->shared_secret_len, NULL)) { 169239beb93cSSam Leffler RADIUS_DEBUG("Invalid Message-Authenticator from %s", abuf); 169339beb93cSSam Leffler data->counters.bad_authenticators++; 169439beb93cSSam Leffler client->counters.bad_authenticators++; 169539beb93cSSam Leffler goto fail; 169639beb93cSSam Leffler } 169739beb93cSSam Leffler 169839beb93cSSam Leffler if (radius_server_request(data, msg, (struct sockaddr *) &from, 169939beb93cSSam Leffler fromlen, client, abuf, from_port, NULL) == 170039beb93cSSam Leffler -2) 170139beb93cSSam Leffler return; /* msg was stored with the session */ 170239beb93cSSam Leffler 170339beb93cSSam Leffler fail: 170439beb93cSSam Leffler radius_msg_free(msg); 170539beb93cSSam Leffler os_free(buf); 170639beb93cSSam Leffler } 170739beb93cSSam Leffler 170839beb93cSSam Leffler 17095b9c547cSRui Paulo static void radius_server_receive_acct(int sock, void *eloop_ctx, 17105b9c547cSRui Paulo void *sock_ctx) 17115b9c547cSRui Paulo { 17125b9c547cSRui Paulo struct radius_server_data *data = eloop_ctx; 17135b9c547cSRui Paulo u8 *buf = NULL; 17145b9c547cSRui Paulo union { 17155b9c547cSRui Paulo struct sockaddr_storage ss; 17165b9c547cSRui Paulo struct sockaddr_in sin; 17175b9c547cSRui Paulo #ifdef CONFIG_IPV6 17185b9c547cSRui Paulo struct sockaddr_in6 sin6; 17195b9c547cSRui Paulo #endif /* CONFIG_IPV6 */ 17205b9c547cSRui Paulo } from; 17215b9c547cSRui Paulo socklen_t fromlen; 17225b9c547cSRui Paulo int len, res; 17235b9c547cSRui Paulo struct radius_client *client = NULL; 17245b9c547cSRui Paulo struct radius_msg *msg = NULL, *resp = NULL; 17255b9c547cSRui Paulo char abuf[50]; 17265b9c547cSRui Paulo int from_port = 0; 17275b9c547cSRui Paulo struct radius_hdr *hdr; 17285b9c547cSRui Paulo struct wpabuf *rbuf; 17295b9c547cSRui Paulo 17305b9c547cSRui Paulo buf = os_malloc(RADIUS_MAX_MSG_LEN); 17315b9c547cSRui Paulo if (buf == NULL) { 17325b9c547cSRui Paulo goto fail; 17335b9c547cSRui Paulo } 17345b9c547cSRui Paulo 17355b9c547cSRui Paulo fromlen = sizeof(from); 17365b9c547cSRui Paulo len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0, 17375b9c547cSRui Paulo (struct sockaddr *) &from.ss, &fromlen); 17385b9c547cSRui Paulo if (len < 0) { 17395b9c547cSRui Paulo wpa_printf(MSG_INFO, "recvfrom[radius_server]: %s", 17405b9c547cSRui Paulo strerror(errno)); 17415b9c547cSRui Paulo goto fail; 17425b9c547cSRui Paulo } 17435b9c547cSRui Paulo 17445b9c547cSRui Paulo #ifdef CONFIG_IPV6 17455b9c547cSRui Paulo if (data->ipv6) { 17465b9c547cSRui Paulo if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf, 17475b9c547cSRui Paulo sizeof(abuf)) == NULL) 17485b9c547cSRui Paulo abuf[0] = '\0'; 17495b9c547cSRui Paulo from_port = ntohs(from.sin6.sin6_port); 17505b9c547cSRui Paulo RADIUS_DEBUG("Received %d bytes from %s:%d", 17515b9c547cSRui Paulo len, abuf, from_port); 17525b9c547cSRui Paulo 17535b9c547cSRui Paulo client = radius_server_get_client(data, 17545b9c547cSRui Paulo (struct in_addr *) 17555b9c547cSRui Paulo &from.sin6.sin6_addr, 1); 17565b9c547cSRui Paulo } 17575b9c547cSRui Paulo #endif /* CONFIG_IPV6 */ 17585b9c547cSRui Paulo 17595b9c547cSRui Paulo if (!data->ipv6) { 17605b9c547cSRui Paulo os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf)); 17615b9c547cSRui Paulo from_port = ntohs(from.sin.sin_port); 17625b9c547cSRui Paulo RADIUS_DEBUG("Received %d bytes from %s:%d", 17635b9c547cSRui Paulo len, abuf, from_port); 17645b9c547cSRui Paulo 17655b9c547cSRui Paulo client = radius_server_get_client(data, &from.sin.sin_addr, 0); 17665b9c547cSRui Paulo } 17675b9c547cSRui Paulo 17685b9c547cSRui Paulo RADIUS_DUMP("Received data", buf, len); 17695b9c547cSRui Paulo 17705b9c547cSRui Paulo if (client == NULL) { 17715b9c547cSRui Paulo RADIUS_DEBUG("Unknown client %s - packet ignored", abuf); 17725b9c547cSRui Paulo data->counters.invalid_acct_requests++; 17735b9c547cSRui Paulo goto fail; 17745b9c547cSRui Paulo } 17755b9c547cSRui Paulo 17765b9c547cSRui Paulo msg = radius_msg_parse(buf, len); 17775b9c547cSRui Paulo if (msg == NULL) { 17785b9c547cSRui Paulo RADIUS_DEBUG("Parsing incoming RADIUS frame failed"); 17795b9c547cSRui Paulo data->counters.malformed_acct_requests++; 17805b9c547cSRui Paulo client->counters.malformed_acct_requests++; 17815b9c547cSRui Paulo goto fail; 17825b9c547cSRui Paulo } 17835b9c547cSRui Paulo 17845b9c547cSRui Paulo os_free(buf); 17855b9c547cSRui Paulo buf = NULL; 17865b9c547cSRui Paulo 17875b9c547cSRui Paulo if (wpa_debug_level <= MSG_MSGDUMP) { 17885b9c547cSRui Paulo radius_msg_dump(msg); 17895b9c547cSRui Paulo } 17905b9c547cSRui Paulo 17915b9c547cSRui Paulo if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_REQUEST) { 17925b9c547cSRui Paulo RADIUS_DEBUG("Unexpected RADIUS code %d", 17935b9c547cSRui Paulo radius_msg_get_hdr(msg)->code); 17945b9c547cSRui Paulo data->counters.unknown_acct_types++; 17955b9c547cSRui Paulo client->counters.unknown_acct_types++; 17965b9c547cSRui Paulo goto fail; 17975b9c547cSRui Paulo } 17985b9c547cSRui Paulo 17995b9c547cSRui Paulo data->counters.acct_requests++; 18005b9c547cSRui Paulo client->counters.acct_requests++; 18015b9c547cSRui Paulo 18025b9c547cSRui Paulo if (radius_msg_verify_acct_req(msg, (u8 *) client->shared_secret, 18035b9c547cSRui Paulo client->shared_secret_len)) { 18045b9c547cSRui Paulo RADIUS_DEBUG("Invalid Authenticator from %s", abuf); 18055b9c547cSRui Paulo data->counters.acct_bad_authenticators++; 18065b9c547cSRui Paulo client->counters.acct_bad_authenticators++; 18075b9c547cSRui Paulo goto fail; 18085b9c547cSRui Paulo } 18095b9c547cSRui Paulo 18105b9c547cSRui Paulo /* TODO: Write accounting information to a file or database */ 18115b9c547cSRui Paulo 18125b9c547cSRui Paulo hdr = radius_msg_get_hdr(msg); 18135b9c547cSRui Paulo 18145b9c547cSRui Paulo resp = radius_msg_new(RADIUS_CODE_ACCOUNTING_RESPONSE, hdr->identifier); 18155b9c547cSRui Paulo if (resp == NULL) 18165b9c547cSRui Paulo goto fail; 18175b9c547cSRui Paulo 18185b9c547cSRui Paulo radius_msg_finish_acct_resp(resp, (u8 *) client->shared_secret, 18195b9c547cSRui Paulo client->shared_secret_len, 18205b9c547cSRui Paulo hdr->authenticator); 18215b9c547cSRui Paulo 18225b9c547cSRui Paulo RADIUS_DEBUG("Reply to %s:%d", abuf, from_port); 18235b9c547cSRui Paulo if (wpa_debug_level <= MSG_MSGDUMP) { 18245b9c547cSRui Paulo radius_msg_dump(resp); 18255b9c547cSRui Paulo } 18265b9c547cSRui Paulo rbuf = radius_msg_get_buf(resp); 18275b9c547cSRui Paulo data->counters.acct_responses++; 18285b9c547cSRui Paulo client->counters.acct_responses++; 18295b9c547cSRui Paulo res = sendto(data->acct_sock, wpabuf_head(rbuf), wpabuf_len(rbuf), 0, 18305b9c547cSRui Paulo (struct sockaddr *) &from.ss, fromlen); 18315b9c547cSRui Paulo if (res < 0) { 18325b9c547cSRui Paulo wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", 18335b9c547cSRui Paulo strerror(errno)); 18345b9c547cSRui Paulo } 18355b9c547cSRui Paulo 18365b9c547cSRui Paulo fail: 18375b9c547cSRui Paulo radius_msg_free(resp); 18385b9c547cSRui Paulo radius_msg_free(msg); 18395b9c547cSRui Paulo os_free(buf); 18405b9c547cSRui Paulo } 18415b9c547cSRui Paulo 18425b9c547cSRui Paulo 18433157ba21SRui Paulo static int radius_server_disable_pmtu_discovery(int s) 18443157ba21SRui Paulo { 18453157ba21SRui Paulo int r = -1; 18463157ba21SRui Paulo #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) 18473157ba21SRui Paulo /* Turn off Path MTU discovery on IPv4/UDP sockets. */ 18483157ba21SRui Paulo int action = IP_PMTUDISC_DONT; 18493157ba21SRui Paulo r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action, 18503157ba21SRui Paulo sizeof(action)); 18513157ba21SRui Paulo if (r == -1) 18523157ba21SRui Paulo wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: " 18533157ba21SRui Paulo "%s", strerror(errno)); 18543157ba21SRui Paulo #endif 18553157ba21SRui Paulo return r; 18563157ba21SRui Paulo } 18573157ba21SRui Paulo 18583157ba21SRui Paulo 185939beb93cSSam Leffler static int radius_server_open_socket(int port) 186039beb93cSSam Leffler { 186139beb93cSSam Leffler int s; 186239beb93cSSam Leffler struct sockaddr_in addr; 186339beb93cSSam Leffler 186439beb93cSSam Leffler s = socket(PF_INET, SOCK_DGRAM, 0); 186539beb93cSSam Leffler if (s < 0) { 18665b9c547cSRui Paulo wpa_printf(MSG_INFO, "RADIUS: socket: %s", strerror(errno)); 186739beb93cSSam Leffler return -1; 186839beb93cSSam Leffler } 186939beb93cSSam Leffler 18703157ba21SRui Paulo radius_server_disable_pmtu_discovery(s); 18713157ba21SRui Paulo 187239beb93cSSam Leffler os_memset(&addr, 0, sizeof(addr)); 187339beb93cSSam Leffler addr.sin_family = AF_INET; 187439beb93cSSam Leffler addr.sin_port = htons(port); 187539beb93cSSam Leffler if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 18765b9c547cSRui Paulo wpa_printf(MSG_INFO, "RADIUS: bind: %s", strerror(errno)); 187739beb93cSSam Leffler close(s); 187839beb93cSSam Leffler return -1; 187939beb93cSSam Leffler } 188039beb93cSSam Leffler 188139beb93cSSam Leffler return s; 188239beb93cSSam Leffler } 188339beb93cSSam Leffler 188439beb93cSSam Leffler 188539beb93cSSam Leffler #ifdef CONFIG_IPV6 188639beb93cSSam Leffler static int radius_server_open_socket6(int port) 188739beb93cSSam Leffler { 188839beb93cSSam Leffler int s; 188939beb93cSSam Leffler struct sockaddr_in6 addr; 189039beb93cSSam Leffler 189139beb93cSSam Leffler s = socket(PF_INET6, SOCK_DGRAM, 0); 189239beb93cSSam Leffler if (s < 0) { 18935b9c547cSRui Paulo wpa_printf(MSG_INFO, "RADIUS: socket[IPv6]: %s", 18945b9c547cSRui Paulo strerror(errno)); 189539beb93cSSam Leffler return -1; 189639beb93cSSam Leffler } 189739beb93cSSam Leffler 189839beb93cSSam Leffler os_memset(&addr, 0, sizeof(addr)); 189939beb93cSSam Leffler addr.sin6_family = AF_INET6; 190039beb93cSSam Leffler os_memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any)); 190139beb93cSSam Leffler addr.sin6_port = htons(port); 190239beb93cSSam Leffler if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 19035b9c547cSRui Paulo wpa_printf(MSG_INFO, "RADIUS: bind: %s", strerror(errno)); 190439beb93cSSam Leffler close(s); 190539beb93cSSam Leffler return -1; 190639beb93cSSam Leffler } 190739beb93cSSam Leffler 190839beb93cSSam Leffler return s; 190939beb93cSSam Leffler } 191039beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 191139beb93cSSam Leffler 191239beb93cSSam Leffler 191339beb93cSSam Leffler static void radius_server_free_sessions(struct radius_server_data *data, 191439beb93cSSam Leffler struct radius_session *sessions) 191539beb93cSSam Leffler { 191639beb93cSSam Leffler struct radius_session *session, *prev; 191739beb93cSSam Leffler 191839beb93cSSam Leffler session = sessions; 191939beb93cSSam Leffler while (session) { 192039beb93cSSam Leffler prev = session; 192139beb93cSSam Leffler session = session->next; 192239beb93cSSam Leffler radius_server_session_free(data, prev); 192339beb93cSSam Leffler } 192439beb93cSSam Leffler } 192539beb93cSSam Leffler 192639beb93cSSam Leffler 192739beb93cSSam Leffler static void radius_server_free_clients(struct radius_server_data *data, 192839beb93cSSam Leffler struct radius_client *clients) 192939beb93cSSam Leffler { 193039beb93cSSam Leffler struct radius_client *client, *prev; 193139beb93cSSam Leffler 193239beb93cSSam Leffler client = clients; 193339beb93cSSam Leffler while (client) { 193439beb93cSSam Leffler prev = client; 193539beb93cSSam Leffler client = client->next; 193639beb93cSSam Leffler 193739beb93cSSam Leffler radius_server_free_sessions(data, prev->sessions); 193839beb93cSSam Leffler os_free(prev->shared_secret); 1939*85732ac8SCy Schubert radius_msg_free(prev->pending_dac_coa_req); 1940*85732ac8SCy Schubert radius_msg_free(prev->pending_dac_disconnect_req); 194139beb93cSSam Leffler os_free(prev); 194239beb93cSSam Leffler } 194339beb93cSSam Leffler } 194439beb93cSSam Leffler 194539beb93cSSam Leffler 194639beb93cSSam Leffler static struct radius_client * 194739beb93cSSam Leffler radius_server_read_clients(const char *client_file, int ipv6) 194839beb93cSSam Leffler { 194939beb93cSSam Leffler FILE *f; 195039beb93cSSam Leffler const int buf_size = 1024; 195139beb93cSSam Leffler char *buf, *pos; 195239beb93cSSam Leffler struct radius_client *clients, *tail, *entry; 195339beb93cSSam Leffler int line = 0, mask, failed = 0, i; 195439beb93cSSam Leffler struct in_addr addr; 195539beb93cSSam Leffler #ifdef CONFIG_IPV6 195639beb93cSSam Leffler struct in6_addr addr6; 195739beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 195839beb93cSSam Leffler unsigned int val; 195939beb93cSSam Leffler 196039beb93cSSam Leffler f = fopen(client_file, "r"); 196139beb93cSSam Leffler if (f == NULL) { 196239beb93cSSam Leffler RADIUS_ERROR("Could not open client file '%s'", client_file); 196339beb93cSSam Leffler return NULL; 196439beb93cSSam Leffler } 196539beb93cSSam Leffler 196639beb93cSSam Leffler buf = os_malloc(buf_size); 196739beb93cSSam Leffler if (buf == NULL) { 196839beb93cSSam Leffler fclose(f); 196939beb93cSSam Leffler return NULL; 197039beb93cSSam Leffler } 197139beb93cSSam Leffler 197239beb93cSSam Leffler clients = tail = NULL; 197339beb93cSSam Leffler while (fgets(buf, buf_size, f)) { 197439beb93cSSam Leffler /* Configuration file format: 197539beb93cSSam Leffler * 192.168.1.0/24 secret 197639beb93cSSam Leffler * 192.168.1.2 secret 197739beb93cSSam Leffler * fe80::211:22ff:fe33:4455/64 secretipv6 197839beb93cSSam Leffler */ 197939beb93cSSam Leffler line++; 198039beb93cSSam Leffler buf[buf_size - 1] = '\0'; 198139beb93cSSam Leffler pos = buf; 198239beb93cSSam Leffler while (*pos != '\0' && *pos != '\n') 198339beb93cSSam Leffler pos++; 198439beb93cSSam Leffler if (*pos == '\n') 198539beb93cSSam Leffler *pos = '\0'; 198639beb93cSSam Leffler if (*buf == '\0' || *buf == '#') 198739beb93cSSam Leffler continue; 198839beb93cSSam Leffler 198939beb93cSSam Leffler pos = buf; 199039beb93cSSam Leffler while ((*pos >= '0' && *pos <= '9') || *pos == '.' || 199139beb93cSSam Leffler (*pos >= 'a' && *pos <= 'f') || *pos == ':' || 199239beb93cSSam Leffler (*pos >= 'A' && *pos <= 'F')) { 199339beb93cSSam Leffler pos++; 199439beb93cSSam Leffler } 199539beb93cSSam Leffler 199639beb93cSSam Leffler if (*pos == '\0') { 199739beb93cSSam Leffler failed = 1; 199839beb93cSSam Leffler break; 199939beb93cSSam Leffler } 200039beb93cSSam Leffler 200139beb93cSSam Leffler if (*pos == '/') { 200239beb93cSSam Leffler char *end; 200339beb93cSSam Leffler *pos++ = '\0'; 200439beb93cSSam Leffler mask = strtol(pos, &end, 10); 200539beb93cSSam Leffler if ((pos == end) || 200639beb93cSSam Leffler (mask < 0 || mask > (ipv6 ? 128 : 32))) { 200739beb93cSSam Leffler failed = 1; 200839beb93cSSam Leffler break; 200939beb93cSSam Leffler } 201039beb93cSSam Leffler pos = end; 201139beb93cSSam Leffler } else { 201239beb93cSSam Leffler mask = ipv6 ? 128 : 32; 201339beb93cSSam Leffler *pos++ = '\0'; 201439beb93cSSam Leffler } 201539beb93cSSam Leffler 201639beb93cSSam Leffler if (!ipv6 && inet_aton(buf, &addr) == 0) { 201739beb93cSSam Leffler failed = 1; 201839beb93cSSam Leffler break; 201939beb93cSSam Leffler } 202039beb93cSSam Leffler #ifdef CONFIG_IPV6 202139beb93cSSam Leffler if (ipv6 && inet_pton(AF_INET6, buf, &addr6) <= 0) { 202239beb93cSSam Leffler if (inet_pton(AF_INET, buf, &addr) <= 0) { 202339beb93cSSam Leffler failed = 1; 202439beb93cSSam Leffler break; 202539beb93cSSam Leffler } 202639beb93cSSam Leffler /* Convert IPv4 address to IPv6 */ 202739beb93cSSam Leffler if (mask <= 32) 202839beb93cSSam Leffler mask += (128 - 32); 202939beb93cSSam Leffler os_memset(addr6.s6_addr, 0, 10); 203039beb93cSSam Leffler addr6.s6_addr[10] = 0xff; 203139beb93cSSam Leffler addr6.s6_addr[11] = 0xff; 203239beb93cSSam Leffler os_memcpy(addr6.s6_addr + 12, (char *) &addr.s_addr, 203339beb93cSSam Leffler 4); 203439beb93cSSam Leffler } 203539beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 203639beb93cSSam Leffler 203739beb93cSSam Leffler while (*pos == ' ' || *pos == '\t') { 203839beb93cSSam Leffler pos++; 203939beb93cSSam Leffler } 204039beb93cSSam Leffler 204139beb93cSSam Leffler if (*pos == '\0') { 204239beb93cSSam Leffler failed = 1; 204339beb93cSSam Leffler break; 204439beb93cSSam Leffler } 204539beb93cSSam Leffler 204639beb93cSSam Leffler entry = os_zalloc(sizeof(*entry)); 204739beb93cSSam Leffler if (entry == NULL) { 204839beb93cSSam Leffler failed = 1; 204939beb93cSSam Leffler break; 205039beb93cSSam Leffler } 205139beb93cSSam Leffler entry->shared_secret = os_strdup(pos); 205239beb93cSSam Leffler if (entry->shared_secret == NULL) { 205339beb93cSSam Leffler failed = 1; 205439beb93cSSam Leffler os_free(entry); 205539beb93cSSam Leffler break; 205639beb93cSSam Leffler } 205739beb93cSSam Leffler entry->shared_secret_len = os_strlen(entry->shared_secret); 205839beb93cSSam Leffler if (!ipv6) { 20595b9c547cSRui Paulo entry->addr.s_addr = addr.s_addr; 206039beb93cSSam Leffler val = 0; 206139beb93cSSam Leffler for (i = 0; i < mask; i++) 206239beb93cSSam Leffler val |= 1 << (31 - i); 206339beb93cSSam Leffler entry->mask.s_addr = htonl(val); 206439beb93cSSam Leffler } 206539beb93cSSam Leffler #ifdef CONFIG_IPV6 206639beb93cSSam Leffler if (ipv6) { 206739beb93cSSam Leffler int offset = mask / 8; 206839beb93cSSam Leffler 206939beb93cSSam Leffler os_memcpy(entry->addr6.s6_addr, addr6.s6_addr, 16); 207039beb93cSSam Leffler os_memset(entry->mask6.s6_addr, 0xff, offset); 207139beb93cSSam Leffler val = 0; 207239beb93cSSam Leffler for (i = 0; i < (mask % 8); i++) 207339beb93cSSam Leffler val |= 1 << (7 - i); 207439beb93cSSam Leffler if (offset < 16) 207539beb93cSSam Leffler entry->mask6.s6_addr[offset] = val; 207639beb93cSSam Leffler } 207739beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 207839beb93cSSam Leffler 207939beb93cSSam Leffler if (tail == NULL) { 208039beb93cSSam Leffler clients = tail = entry; 208139beb93cSSam Leffler } else { 208239beb93cSSam Leffler tail->next = entry; 208339beb93cSSam Leffler tail = entry; 208439beb93cSSam Leffler } 208539beb93cSSam Leffler } 208639beb93cSSam Leffler 208739beb93cSSam Leffler if (failed) { 208839beb93cSSam Leffler RADIUS_ERROR("Invalid line %d in '%s'", line, client_file); 208939beb93cSSam Leffler radius_server_free_clients(NULL, clients); 209039beb93cSSam Leffler clients = NULL; 209139beb93cSSam Leffler } 209239beb93cSSam Leffler 209339beb93cSSam Leffler os_free(buf); 209439beb93cSSam Leffler fclose(f); 209539beb93cSSam Leffler 209639beb93cSSam Leffler return clients; 209739beb93cSSam Leffler } 209839beb93cSSam Leffler 209939beb93cSSam Leffler 2100e28a4053SRui Paulo /** 2101e28a4053SRui Paulo * radius_server_init - Initialize RADIUS server 2102e28a4053SRui Paulo * @conf: Configuration for the RADIUS server 2103e28a4053SRui Paulo * Returns: Pointer to private RADIUS server context or %NULL on failure 2104e28a4053SRui Paulo * 2105e28a4053SRui Paulo * This initializes a RADIUS server instance and returns a context pointer that 2106e28a4053SRui Paulo * will be used in other calls to the RADIUS server module. The server can be 2107e28a4053SRui Paulo * deinitialize by calling radius_server_deinit(). 2108e28a4053SRui Paulo */ 210939beb93cSSam Leffler struct radius_server_data * 211039beb93cSSam Leffler radius_server_init(struct radius_server_conf *conf) 211139beb93cSSam Leffler { 211239beb93cSSam Leffler struct radius_server_data *data; 211339beb93cSSam Leffler 211439beb93cSSam Leffler #ifndef CONFIG_IPV6 211539beb93cSSam Leffler if (conf->ipv6) { 21165b9c547cSRui Paulo wpa_printf(MSG_ERROR, "RADIUS server compiled without IPv6 support"); 211739beb93cSSam Leffler return NULL; 211839beb93cSSam Leffler } 211939beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 212039beb93cSSam Leffler 212139beb93cSSam Leffler data = os_zalloc(sizeof(*data)); 212239beb93cSSam Leffler if (data == NULL) 212339beb93cSSam Leffler return NULL; 212439beb93cSSam Leffler 21255b9c547cSRui Paulo dl_list_init(&data->erp_keys); 21265b9c547cSRui Paulo os_get_reltime(&data->start_time); 212739beb93cSSam Leffler data->conf_ctx = conf->conf_ctx; 212839beb93cSSam Leffler data->eap_sim_db_priv = conf->eap_sim_db_priv; 212939beb93cSSam Leffler data->ssl_ctx = conf->ssl_ctx; 2130e28a4053SRui Paulo data->msg_ctx = conf->msg_ctx; 213139beb93cSSam Leffler data->ipv6 = conf->ipv6; 213239beb93cSSam Leffler if (conf->pac_opaque_encr_key) { 213339beb93cSSam Leffler data->pac_opaque_encr_key = os_malloc(16); 2134325151a3SRui Paulo if (data->pac_opaque_encr_key) { 2135325151a3SRui Paulo os_memcpy(data->pac_opaque_encr_key, 2136325151a3SRui Paulo conf->pac_opaque_encr_key, 16); 2137325151a3SRui Paulo } 213839beb93cSSam Leffler } 213939beb93cSSam Leffler if (conf->eap_fast_a_id) { 214039beb93cSSam Leffler data->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len); 214139beb93cSSam Leffler if (data->eap_fast_a_id) { 214239beb93cSSam Leffler os_memcpy(data->eap_fast_a_id, conf->eap_fast_a_id, 214339beb93cSSam Leffler conf->eap_fast_a_id_len); 214439beb93cSSam Leffler data->eap_fast_a_id_len = conf->eap_fast_a_id_len; 214539beb93cSSam Leffler } 214639beb93cSSam Leffler } 214739beb93cSSam Leffler if (conf->eap_fast_a_id_info) 214839beb93cSSam Leffler data->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info); 214939beb93cSSam Leffler data->eap_fast_prov = conf->eap_fast_prov; 215039beb93cSSam Leffler data->pac_key_lifetime = conf->pac_key_lifetime; 215139beb93cSSam Leffler data->pac_key_refresh_time = conf->pac_key_refresh_time; 215239beb93cSSam Leffler data->get_eap_user = conf->get_eap_user; 215339beb93cSSam Leffler data->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind; 215439beb93cSSam Leffler data->tnc = conf->tnc; 215539beb93cSSam Leffler data->wps = conf->wps; 2156f05cddf9SRui Paulo data->pwd_group = conf->pwd_group; 21575b9c547cSRui Paulo data->server_id = conf->server_id; 215839beb93cSSam Leffler if (conf->eap_req_id_text) { 215939beb93cSSam Leffler data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len); 216039beb93cSSam Leffler if (data->eap_req_id_text) { 216139beb93cSSam Leffler os_memcpy(data->eap_req_id_text, conf->eap_req_id_text, 216239beb93cSSam Leffler conf->eap_req_id_text_len); 216339beb93cSSam Leffler data->eap_req_id_text_len = conf->eap_req_id_text_len; 216439beb93cSSam Leffler } 216539beb93cSSam Leffler } 21665b9c547cSRui Paulo data->erp = conf->erp; 21675b9c547cSRui Paulo data->erp_domain = conf->erp_domain; 2168325151a3SRui Paulo data->tls_session_lifetime = conf->tls_session_lifetime; 2169*85732ac8SCy Schubert data->tls_flags = conf->tls_flags; 21705b9c547cSRui Paulo 21715b9c547cSRui Paulo if (conf->subscr_remediation_url) { 21725b9c547cSRui Paulo data->subscr_remediation_url = 21735b9c547cSRui Paulo os_strdup(conf->subscr_remediation_url); 21745b9c547cSRui Paulo } 21755b9c547cSRui Paulo data->subscr_remediation_method = conf->subscr_remediation_method; 21765b9c547cSRui Paulo 2177*85732ac8SCy Schubert if (conf->t_c_server_url) 2178*85732ac8SCy Schubert data->t_c_server_url = os_strdup(conf->t_c_server_url); 2179*85732ac8SCy Schubert 21805b9c547cSRui Paulo #ifdef CONFIG_SQLITE 21815b9c547cSRui Paulo if (conf->sqlite_file) { 21825b9c547cSRui Paulo if (sqlite3_open(conf->sqlite_file, &data->db)) { 21835b9c547cSRui Paulo RADIUS_ERROR("Could not open SQLite file '%s'", 21845b9c547cSRui Paulo conf->sqlite_file); 21855b9c547cSRui Paulo radius_server_deinit(data); 21865b9c547cSRui Paulo return NULL; 21875b9c547cSRui Paulo } 21885b9c547cSRui Paulo } 21895b9c547cSRui Paulo #endif /* CONFIG_SQLITE */ 219039beb93cSSam Leffler 2191f05cddf9SRui Paulo #ifdef CONFIG_RADIUS_TEST 2192f05cddf9SRui Paulo if (conf->dump_msk_file) 2193f05cddf9SRui Paulo data->dump_msk_file = os_strdup(conf->dump_msk_file); 2194f05cddf9SRui Paulo #endif /* CONFIG_RADIUS_TEST */ 2195f05cddf9SRui Paulo 219639beb93cSSam Leffler data->clients = radius_server_read_clients(conf->client_file, 219739beb93cSSam Leffler conf->ipv6); 219839beb93cSSam Leffler if (data->clients == NULL) { 21995b9c547cSRui Paulo wpa_printf(MSG_ERROR, "No RADIUS clients configured"); 220039beb93cSSam Leffler radius_server_deinit(data); 220139beb93cSSam Leffler return NULL; 220239beb93cSSam Leffler } 220339beb93cSSam Leffler 220439beb93cSSam Leffler #ifdef CONFIG_IPV6 220539beb93cSSam Leffler if (conf->ipv6) 220639beb93cSSam Leffler data->auth_sock = radius_server_open_socket6(conf->auth_port); 220739beb93cSSam Leffler else 220839beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 220939beb93cSSam Leffler data->auth_sock = radius_server_open_socket(conf->auth_port); 221039beb93cSSam Leffler if (data->auth_sock < 0) { 22115b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS authentication server"); 221239beb93cSSam Leffler radius_server_deinit(data); 221339beb93cSSam Leffler return NULL; 221439beb93cSSam Leffler } 221539beb93cSSam Leffler if (eloop_register_read_sock(data->auth_sock, 221639beb93cSSam Leffler radius_server_receive_auth, 221739beb93cSSam Leffler data, NULL)) { 221839beb93cSSam Leffler radius_server_deinit(data); 221939beb93cSSam Leffler return NULL; 222039beb93cSSam Leffler } 222139beb93cSSam Leffler 22225b9c547cSRui Paulo if (conf->acct_port) { 22235b9c547cSRui Paulo #ifdef CONFIG_IPV6 22245b9c547cSRui Paulo if (conf->ipv6) 22255b9c547cSRui Paulo data->acct_sock = radius_server_open_socket6( 22265b9c547cSRui Paulo conf->acct_port); 22275b9c547cSRui Paulo else 22285b9c547cSRui Paulo #endif /* CONFIG_IPV6 */ 22295b9c547cSRui Paulo data->acct_sock = radius_server_open_socket(conf->acct_port); 22305b9c547cSRui Paulo if (data->acct_sock < 0) { 22315b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS accounting server"); 22325b9c547cSRui Paulo radius_server_deinit(data); 22335b9c547cSRui Paulo return NULL; 22345b9c547cSRui Paulo } 22355b9c547cSRui Paulo if (eloop_register_read_sock(data->acct_sock, 22365b9c547cSRui Paulo radius_server_receive_acct, 22375b9c547cSRui Paulo data, NULL)) { 22385b9c547cSRui Paulo radius_server_deinit(data); 22395b9c547cSRui Paulo return NULL; 22405b9c547cSRui Paulo } 22415b9c547cSRui Paulo } else { 22425b9c547cSRui Paulo data->acct_sock = -1; 22435b9c547cSRui Paulo } 22445b9c547cSRui Paulo 224539beb93cSSam Leffler return data; 224639beb93cSSam Leffler } 224739beb93cSSam Leffler 224839beb93cSSam Leffler 2249e28a4053SRui Paulo /** 22505b9c547cSRui Paulo * radius_server_erp_flush - Flush all ERP keys 22515b9c547cSRui Paulo * @data: RADIUS server context from radius_server_init() 22525b9c547cSRui Paulo */ 22535b9c547cSRui Paulo void radius_server_erp_flush(struct radius_server_data *data) 22545b9c547cSRui Paulo { 22555b9c547cSRui Paulo struct eap_server_erp_key *erp; 22565b9c547cSRui Paulo 22575b9c547cSRui Paulo if (data == NULL) 22585b9c547cSRui Paulo return; 22595b9c547cSRui Paulo while ((erp = dl_list_first(&data->erp_keys, struct eap_server_erp_key, 22605b9c547cSRui Paulo list)) != NULL) { 22615b9c547cSRui Paulo dl_list_del(&erp->list); 22625b9c547cSRui Paulo bin_clear_free(erp, sizeof(*erp)); 22635b9c547cSRui Paulo } 22645b9c547cSRui Paulo } 22655b9c547cSRui Paulo 22665b9c547cSRui Paulo 22675b9c547cSRui Paulo /** 2268e28a4053SRui Paulo * radius_server_deinit - Deinitialize RADIUS server 2269e28a4053SRui Paulo * @data: RADIUS server context from radius_server_init() 2270e28a4053SRui Paulo */ 227139beb93cSSam Leffler void radius_server_deinit(struct radius_server_data *data) 227239beb93cSSam Leffler { 227339beb93cSSam Leffler if (data == NULL) 227439beb93cSSam Leffler return; 227539beb93cSSam Leffler 227639beb93cSSam Leffler if (data->auth_sock >= 0) { 227739beb93cSSam Leffler eloop_unregister_read_sock(data->auth_sock); 227839beb93cSSam Leffler close(data->auth_sock); 227939beb93cSSam Leffler } 228039beb93cSSam Leffler 22815b9c547cSRui Paulo if (data->acct_sock >= 0) { 22825b9c547cSRui Paulo eloop_unregister_read_sock(data->acct_sock); 22835b9c547cSRui Paulo close(data->acct_sock); 22845b9c547cSRui Paulo } 22855b9c547cSRui Paulo 228639beb93cSSam Leffler radius_server_free_clients(data, data->clients); 228739beb93cSSam Leffler 228839beb93cSSam Leffler os_free(data->pac_opaque_encr_key); 228939beb93cSSam Leffler os_free(data->eap_fast_a_id); 229039beb93cSSam Leffler os_free(data->eap_fast_a_id_info); 229139beb93cSSam Leffler os_free(data->eap_req_id_text); 2292f05cddf9SRui Paulo #ifdef CONFIG_RADIUS_TEST 2293f05cddf9SRui Paulo os_free(data->dump_msk_file); 2294f05cddf9SRui Paulo #endif /* CONFIG_RADIUS_TEST */ 22955b9c547cSRui Paulo os_free(data->subscr_remediation_url); 2296*85732ac8SCy Schubert os_free(data->t_c_server_url); 22975b9c547cSRui Paulo 22985b9c547cSRui Paulo #ifdef CONFIG_SQLITE 22995b9c547cSRui Paulo if (data->db) 23005b9c547cSRui Paulo sqlite3_close(data->db); 23015b9c547cSRui Paulo #endif /* CONFIG_SQLITE */ 23025b9c547cSRui Paulo 23035b9c547cSRui Paulo radius_server_erp_flush(data); 23045b9c547cSRui Paulo 230539beb93cSSam Leffler os_free(data); 230639beb93cSSam Leffler } 230739beb93cSSam Leffler 230839beb93cSSam Leffler 2309e28a4053SRui Paulo /** 2310e28a4053SRui Paulo * radius_server_get_mib - Get RADIUS server MIB information 2311e28a4053SRui Paulo * @data: RADIUS server context from radius_server_init() 2312e28a4053SRui Paulo * @buf: Buffer for returning the MIB data in text format 2313e28a4053SRui Paulo * @buflen: buf length in octets 2314e28a4053SRui Paulo * Returns: Number of octets written into buf 2315e28a4053SRui Paulo */ 231639beb93cSSam Leffler int radius_server_get_mib(struct radius_server_data *data, char *buf, 231739beb93cSSam Leffler size_t buflen) 231839beb93cSSam Leffler { 231939beb93cSSam Leffler int ret, uptime; 232039beb93cSSam Leffler unsigned int idx; 232139beb93cSSam Leffler char *end, *pos; 23225b9c547cSRui Paulo struct os_reltime now; 232339beb93cSSam Leffler struct radius_client *cli; 232439beb93cSSam Leffler 232539beb93cSSam Leffler /* RFC 2619 - RADIUS Authentication Server MIB */ 232639beb93cSSam Leffler 232739beb93cSSam Leffler if (data == NULL || buflen == 0) 232839beb93cSSam Leffler return 0; 232939beb93cSSam Leffler 233039beb93cSSam Leffler pos = buf; 233139beb93cSSam Leffler end = buf + buflen; 233239beb93cSSam Leffler 23335b9c547cSRui Paulo os_get_reltime(&now); 233439beb93cSSam Leffler uptime = (now.sec - data->start_time.sec) * 100 + 233539beb93cSSam Leffler ((now.usec - data->start_time.usec) / 10000) % 100; 233639beb93cSSam Leffler ret = os_snprintf(pos, end - pos, 233739beb93cSSam Leffler "RADIUS-AUTH-SERVER-MIB\n" 233839beb93cSSam Leffler "radiusAuthServIdent=hostapd\n" 233939beb93cSSam Leffler "radiusAuthServUpTime=%d\n" 234039beb93cSSam Leffler "radiusAuthServResetTime=0\n" 234139beb93cSSam Leffler "radiusAuthServConfigReset=4\n", 234239beb93cSSam Leffler uptime); 23435b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret)) { 234439beb93cSSam Leffler *pos = '\0'; 234539beb93cSSam Leffler return pos - buf; 234639beb93cSSam Leffler } 234739beb93cSSam Leffler pos += ret; 234839beb93cSSam Leffler 234939beb93cSSam Leffler ret = os_snprintf(pos, end - pos, 235039beb93cSSam Leffler "radiusAuthServTotalAccessRequests=%u\n" 235139beb93cSSam Leffler "radiusAuthServTotalInvalidRequests=%u\n" 235239beb93cSSam Leffler "radiusAuthServTotalDupAccessRequests=%u\n" 235339beb93cSSam Leffler "radiusAuthServTotalAccessAccepts=%u\n" 235439beb93cSSam Leffler "radiusAuthServTotalAccessRejects=%u\n" 235539beb93cSSam Leffler "radiusAuthServTotalAccessChallenges=%u\n" 235639beb93cSSam Leffler "radiusAuthServTotalMalformedAccessRequests=%u\n" 235739beb93cSSam Leffler "radiusAuthServTotalBadAuthenticators=%u\n" 235839beb93cSSam Leffler "radiusAuthServTotalPacketsDropped=%u\n" 23595b9c547cSRui Paulo "radiusAuthServTotalUnknownTypes=%u\n" 23605b9c547cSRui Paulo "radiusAccServTotalRequests=%u\n" 23615b9c547cSRui Paulo "radiusAccServTotalInvalidRequests=%u\n" 23625b9c547cSRui Paulo "radiusAccServTotalResponses=%u\n" 23635b9c547cSRui Paulo "radiusAccServTotalMalformedRequests=%u\n" 23645b9c547cSRui Paulo "radiusAccServTotalBadAuthenticators=%u\n" 23655b9c547cSRui Paulo "radiusAccServTotalUnknownTypes=%u\n", 236639beb93cSSam Leffler data->counters.access_requests, 236739beb93cSSam Leffler data->counters.invalid_requests, 236839beb93cSSam Leffler data->counters.dup_access_requests, 236939beb93cSSam Leffler data->counters.access_accepts, 237039beb93cSSam Leffler data->counters.access_rejects, 237139beb93cSSam Leffler data->counters.access_challenges, 237239beb93cSSam Leffler data->counters.malformed_access_requests, 237339beb93cSSam Leffler data->counters.bad_authenticators, 237439beb93cSSam Leffler data->counters.packets_dropped, 23755b9c547cSRui Paulo data->counters.unknown_types, 23765b9c547cSRui Paulo data->counters.acct_requests, 23775b9c547cSRui Paulo data->counters.invalid_acct_requests, 23785b9c547cSRui Paulo data->counters.acct_responses, 23795b9c547cSRui Paulo data->counters.malformed_acct_requests, 23805b9c547cSRui Paulo data->counters.acct_bad_authenticators, 23815b9c547cSRui Paulo data->counters.unknown_acct_types); 23825b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret)) { 238339beb93cSSam Leffler *pos = '\0'; 238439beb93cSSam Leffler return pos - buf; 238539beb93cSSam Leffler } 238639beb93cSSam Leffler pos += ret; 238739beb93cSSam Leffler 238839beb93cSSam Leffler for (cli = data->clients, idx = 0; cli; cli = cli->next, idx++) { 238939beb93cSSam Leffler char abuf[50], mbuf[50]; 239039beb93cSSam Leffler #ifdef CONFIG_IPV6 239139beb93cSSam Leffler if (data->ipv6) { 239239beb93cSSam Leffler if (inet_ntop(AF_INET6, &cli->addr6, abuf, 239339beb93cSSam Leffler sizeof(abuf)) == NULL) 239439beb93cSSam Leffler abuf[0] = '\0'; 23955b9c547cSRui Paulo if (inet_ntop(AF_INET6, &cli->mask6, mbuf, 239639beb93cSSam Leffler sizeof(mbuf)) == NULL) 239739beb93cSSam Leffler mbuf[0] = '\0'; 239839beb93cSSam Leffler } 239939beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 240039beb93cSSam Leffler if (!data->ipv6) { 240139beb93cSSam Leffler os_strlcpy(abuf, inet_ntoa(cli->addr), sizeof(abuf)); 240239beb93cSSam Leffler os_strlcpy(mbuf, inet_ntoa(cli->mask), sizeof(mbuf)); 240339beb93cSSam Leffler } 240439beb93cSSam Leffler 240539beb93cSSam Leffler ret = os_snprintf(pos, end - pos, 240639beb93cSSam Leffler "radiusAuthClientIndex=%u\n" 240739beb93cSSam Leffler "radiusAuthClientAddress=%s/%s\n" 240839beb93cSSam Leffler "radiusAuthServAccessRequests=%u\n" 240939beb93cSSam Leffler "radiusAuthServDupAccessRequests=%u\n" 241039beb93cSSam Leffler "radiusAuthServAccessAccepts=%u\n" 241139beb93cSSam Leffler "radiusAuthServAccessRejects=%u\n" 241239beb93cSSam Leffler "radiusAuthServAccessChallenges=%u\n" 241339beb93cSSam Leffler "radiusAuthServMalformedAccessRequests=%u\n" 241439beb93cSSam Leffler "radiusAuthServBadAuthenticators=%u\n" 241539beb93cSSam Leffler "radiusAuthServPacketsDropped=%u\n" 24165b9c547cSRui Paulo "radiusAuthServUnknownTypes=%u\n" 24175b9c547cSRui Paulo "radiusAccServTotalRequests=%u\n" 24185b9c547cSRui Paulo "radiusAccServTotalInvalidRequests=%u\n" 24195b9c547cSRui Paulo "radiusAccServTotalResponses=%u\n" 24205b9c547cSRui Paulo "radiusAccServTotalMalformedRequests=%u\n" 24215b9c547cSRui Paulo "radiusAccServTotalBadAuthenticators=%u\n" 24225b9c547cSRui Paulo "radiusAccServTotalUnknownTypes=%u\n", 242339beb93cSSam Leffler idx, 242439beb93cSSam Leffler abuf, mbuf, 242539beb93cSSam Leffler cli->counters.access_requests, 242639beb93cSSam Leffler cli->counters.dup_access_requests, 242739beb93cSSam Leffler cli->counters.access_accepts, 242839beb93cSSam Leffler cli->counters.access_rejects, 242939beb93cSSam Leffler cli->counters.access_challenges, 243039beb93cSSam Leffler cli->counters.malformed_access_requests, 243139beb93cSSam Leffler cli->counters.bad_authenticators, 243239beb93cSSam Leffler cli->counters.packets_dropped, 24335b9c547cSRui Paulo cli->counters.unknown_types, 24345b9c547cSRui Paulo cli->counters.acct_requests, 24355b9c547cSRui Paulo cli->counters.invalid_acct_requests, 24365b9c547cSRui Paulo cli->counters.acct_responses, 24375b9c547cSRui Paulo cli->counters.malformed_acct_requests, 24385b9c547cSRui Paulo cli->counters.acct_bad_authenticators, 24395b9c547cSRui Paulo cli->counters.unknown_acct_types); 24405b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret)) { 244139beb93cSSam Leffler *pos = '\0'; 244239beb93cSSam Leffler return pos - buf; 244339beb93cSSam Leffler } 244439beb93cSSam Leffler pos += ret; 244539beb93cSSam Leffler } 244639beb93cSSam Leffler 244739beb93cSSam Leffler return pos - buf; 244839beb93cSSam Leffler } 244939beb93cSSam Leffler 245039beb93cSSam Leffler 245139beb93cSSam Leffler static int radius_server_get_eap_user(void *ctx, const u8 *identity, 245239beb93cSSam Leffler size_t identity_len, int phase2, 245339beb93cSSam Leffler struct eap_user *user) 245439beb93cSSam Leffler { 245539beb93cSSam Leffler struct radius_session *sess = ctx; 245639beb93cSSam Leffler struct radius_server_data *data = sess->server; 24575b9c547cSRui Paulo int ret; 245839beb93cSSam Leffler 24595b9c547cSRui Paulo ret = data->get_eap_user(data->conf_ctx, identity, identity_len, 246039beb93cSSam Leffler phase2, user); 24615b9c547cSRui Paulo if (ret == 0 && user) { 24625b9c547cSRui Paulo sess->accept_attr = user->accept_attr; 24635b9c547cSRui Paulo sess->remediation = user->remediation; 24645b9c547cSRui Paulo sess->macacl = user->macacl; 2465*85732ac8SCy Schubert sess->t_c_timestamp = user->t_c_timestamp; 24665b9c547cSRui Paulo } 2467325151a3SRui Paulo 2468325151a3SRui Paulo if (ret) { 2469325151a3SRui Paulo RADIUS_DEBUG("%s: User-Name not found from user database", 2470325151a3SRui Paulo __func__); 2471325151a3SRui Paulo } 2472325151a3SRui Paulo 24735b9c547cSRui Paulo return ret; 247439beb93cSSam Leffler } 247539beb93cSSam Leffler 247639beb93cSSam Leffler 247739beb93cSSam Leffler static const char * radius_server_get_eap_req_id_text(void *ctx, size_t *len) 247839beb93cSSam Leffler { 247939beb93cSSam Leffler struct radius_session *sess = ctx; 248039beb93cSSam Leffler struct radius_server_data *data = sess->server; 248139beb93cSSam Leffler *len = data->eap_req_id_text_len; 248239beb93cSSam Leffler return data->eap_req_id_text; 248339beb93cSSam Leffler } 248439beb93cSSam Leffler 248539beb93cSSam Leffler 24865b9c547cSRui Paulo static void radius_server_log_msg(void *ctx, const char *msg) 24875b9c547cSRui Paulo { 24885b9c547cSRui Paulo struct radius_session *sess = ctx; 24895b9c547cSRui Paulo srv_log(sess, "EAP: %s", msg); 24905b9c547cSRui Paulo } 24915b9c547cSRui Paulo 24925b9c547cSRui Paulo 24935b9c547cSRui Paulo #ifdef CONFIG_ERP 24945b9c547cSRui Paulo 24955b9c547cSRui Paulo static const char * radius_server_get_erp_domain(void *ctx) 24965b9c547cSRui Paulo { 24975b9c547cSRui Paulo struct radius_session *sess = ctx; 24985b9c547cSRui Paulo struct radius_server_data *data = sess->server; 24995b9c547cSRui Paulo 25005b9c547cSRui Paulo return data->erp_domain; 25015b9c547cSRui Paulo } 25025b9c547cSRui Paulo 25035b9c547cSRui Paulo 25045b9c547cSRui Paulo static struct eap_server_erp_key * 25055b9c547cSRui Paulo radius_server_erp_get_key(void *ctx, const char *keyname) 25065b9c547cSRui Paulo { 25075b9c547cSRui Paulo struct radius_session *sess = ctx; 25085b9c547cSRui Paulo struct radius_server_data *data = sess->server; 25095b9c547cSRui Paulo struct eap_server_erp_key *erp; 25105b9c547cSRui Paulo 25115b9c547cSRui Paulo dl_list_for_each(erp, &data->erp_keys, struct eap_server_erp_key, 25125b9c547cSRui Paulo list) { 25135b9c547cSRui Paulo if (os_strcmp(erp->keyname_nai, keyname) == 0) 25145b9c547cSRui Paulo return erp; 25155b9c547cSRui Paulo } 25165b9c547cSRui Paulo 25175b9c547cSRui Paulo return NULL; 25185b9c547cSRui Paulo } 25195b9c547cSRui Paulo 25205b9c547cSRui Paulo 25215b9c547cSRui Paulo static int radius_server_erp_add_key(void *ctx, struct eap_server_erp_key *erp) 25225b9c547cSRui Paulo { 25235b9c547cSRui Paulo struct radius_session *sess = ctx; 25245b9c547cSRui Paulo struct radius_server_data *data = sess->server; 25255b9c547cSRui Paulo 25265b9c547cSRui Paulo dl_list_add(&data->erp_keys, &erp->list); 25275b9c547cSRui Paulo return 0; 25285b9c547cSRui Paulo } 25295b9c547cSRui Paulo 25305b9c547cSRui Paulo #endif /* CONFIG_ERP */ 25315b9c547cSRui Paulo 25325b9c547cSRui Paulo 2533325151a3SRui Paulo static const struct eapol_callbacks radius_server_eapol_cb = 253439beb93cSSam Leffler { 253539beb93cSSam Leffler .get_eap_user = radius_server_get_eap_user, 253639beb93cSSam Leffler .get_eap_req_id_text = radius_server_get_eap_req_id_text, 25375b9c547cSRui Paulo .log_msg = radius_server_log_msg, 25385b9c547cSRui Paulo #ifdef CONFIG_ERP 25395b9c547cSRui Paulo .get_erp_send_reauth_start = NULL, 25405b9c547cSRui Paulo .get_erp_domain = radius_server_get_erp_domain, 25415b9c547cSRui Paulo .erp_get_key = radius_server_erp_get_key, 25425b9c547cSRui Paulo .erp_add_key = radius_server_erp_add_key, 25435b9c547cSRui Paulo #endif /* CONFIG_ERP */ 254439beb93cSSam Leffler }; 254539beb93cSSam Leffler 254639beb93cSSam Leffler 2547e28a4053SRui Paulo /** 2548e28a4053SRui Paulo * radius_server_eap_pending_cb - Pending EAP data notification 2549e28a4053SRui Paulo * @data: RADIUS server context from radius_server_init() 2550e28a4053SRui Paulo * @ctx: Pending EAP context pointer 2551e28a4053SRui Paulo * 2552e28a4053SRui Paulo * This function is used to notify EAP server module that a pending operation 2553e28a4053SRui Paulo * has been completed and processing of the EAP session can proceed. 2554e28a4053SRui Paulo */ 255539beb93cSSam Leffler void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx) 255639beb93cSSam Leffler { 255739beb93cSSam Leffler struct radius_client *cli; 255839beb93cSSam Leffler struct radius_session *s, *sess = NULL; 255939beb93cSSam Leffler struct radius_msg *msg; 256039beb93cSSam Leffler 256139beb93cSSam Leffler if (data == NULL) 256239beb93cSSam Leffler return; 256339beb93cSSam Leffler 256439beb93cSSam Leffler for (cli = data->clients; cli; cli = cli->next) { 256539beb93cSSam Leffler for (s = cli->sessions; s; s = s->next) { 256639beb93cSSam Leffler if (s->eap == ctx && s->last_msg) { 256739beb93cSSam Leffler sess = s; 256839beb93cSSam Leffler break; 256939beb93cSSam Leffler } 257039beb93cSSam Leffler } 257139beb93cSSam Leffler if (sess) 257239beb93cSSam Leffler break; 257339beb93cSSam Leffler } 257439beb93cSSam Leffler 257539beb93cSSam Leffler if (sess == NULL) { 257639beb93cSSam Leffler RADIUS_DEBUG("No session matched callback ctx"); 257739beb93cSSam Leffler return; 257839beb93cSSam Leffler } 257939beb93cSSam Leffler 258039beb93cSSam Leffler msg = sess->last_msg; 258139beb93cSSam Leffler sess->last_msg = NULL; 258239beb93cSSam Leffler eap_sm_pending_cb(sess->eap); 258339beb93cSSam Leffler if (radius_server_request(data, msg, 258439beb93cSSam Leffler (struct sockaddr *) &sess->last_from, 258539beb93cSSam Leffler sess->last_fromlen, cli, 258639beb93cSSam Leffler sess->last_from_addr, 258739beb93cSSam Leffler sess->last_from_port, sess) == -2) 258839beb93cSSam Leffler return; /* msg was stored with the session */ 258939beb93cSSam Leffler 259039beb93cSSam Leffler radius_msg_free(msg); 259139beb93cSSam Leffler } 2592*85732ac8SCy Schubert 2593*85732ac8SCy Schubert 2594*85732ac8SCy Schubert #ifdef CONFIG_SQLITE 2595*85732ac8SCy Schubert 2596*85732ac8SCy Schubert struct db_session_fields { 2597*85732ac8SCy Schubert char *identity; 2598*85732ac8SCy Schubert char *nas; 2599*85732ac8SCy Schubert int hs20_t_c_filtering; 2600*85732ac8SCy Schubert int waiting_coa_ack; 2601*85732ac8SCy Schubert int coa_ack_received; 2602*85732ac8SCy Schubert }; 2603*85732ac8SCy Schubert 2604*85732ac8SCy Schubert 2605*85732ac8SCy Schubert static int get_db_session_fields(void *ctx, int argc, char *argv[], char *col[]) 2606*85732ac8SCy Schubert { 2607*85732ac8SCy Schubert struct db_session_fields *fields = ctx; 2608*85732ac8SCy Schubert int i; 2609*85732ac8SCy Schubert 2610*85732ac8SCy Schubert for (i = 0; i < argc; i++) { 2611*85732ac8SCy Schubert if (!argv[i]) 2612*85732ac8SCy Schubert continue; 2613*85732ac8SCy Schubert 2614*85732ac8SCy Schubert RADIUS_DEBUG("Session DB: %s=%s", col[i], argv[i]); 2615*85732ac8SCy Schubert 2616*85732ac8SCy Schubert if (os_strcmp(col[i], "identity") == 0) { 2617*85732ac8SCy Schubert os_free(fields->identity); 2618*85732ac8SCy Schubert fields->identity = os_strdup(argv[i]); 2619*85732ac8SCy Schubert } else if (os_strcmp(col[i], "nas") == 0) { 2620*85732ac8SCy Schubert os_free(fields->nas); 2621*85732ac8SCy Schubert fields->nas = os_strdup(argv[i]); 2622*85732ac8SCy Schubert } else if (os_strcmp(col[i], "hs20_t_c_filtering") == 0) { 2623*85732ac8SCy Schubert fields->hs20_t_c_filtering = atoi(argv[i]); 2624*85732ac8SCy Schubert } else if (os_strcmp(col[i], "waiting_coa_ack") == 0) { 2625*85732ac8SCy Schubert fields->waiting_coa_ack = atoi(argv[i]); 2626*85732ac8SCy Schubert } else if (os_strcmp(col[i], "coa_ack_received") == 0) { 2627*85732ac8SCy Schubert fields->coa_ack_received = atoi(argv[i]); 2628*85732ac8SCy Schubert } 2629*85732ac8SCy Schubert } 2630*85732ac8SCy Schubert 2631*85732ac8SCy Schubert return 0; 2632*85732ac8SCy Schubert } 2633*85732ac8SCy Schubert 2634*85732ac8SCy Schubert 2635*85732ac8SCy Schubert static void free_db_session_fields(struct db_session_fields *fields) 2636*85732ac8SCy Schubert { 2637*85732ac8SCy Schubert os_free(fields->identity); 2638*85732ac8SCy Schubert fields->identity = NULL; 2639*85732ac8SCy Schubert os_free(fields->nas); 2640*85732ac8SCy Schubert fields->nas = NULL; 2641*85732ac8SCy Schubert } 2642*85732ac8SCy Schubert 2643*85732ac8SCy Schubert #endif /* CONFIG_SQLITE */ 2644*85732ac8SCy Schubert 2645*85732ac8SCy Schubert 2646*85732ac8SCy Schubert int radius_server_dac_request(struct radius_server_data *data, const char *req) 2647*85732ac8SCy Schubert { 2648*85732ac8SCy Schubert #ifdef CONFIG_SQLITE 2649*85732ac8SCy Schubert char *sql; 2650*85732ac8SCy Schubert int res; 2651*85732ac8SCy Schubert int disconnect; 2652*85732ac8SCy Schubert const char *pos = req; 2653*85732ac8SCy Schubert u8 addr[ETH_ALEN]; 2654*85732ac8SCy Schubert char addrtxt[3 * ETH_ALEN]; 2655*85732ac8SCy Schubert int t_c_clear = 0; 2656*85732ac8SCy Schubert struct db_session_fields fields; 2657*85732ac8SCy Schubert struct sockaddr_in das; 2658*85732ac8SCy Schubert struct radius_client *client; 2659*85732ac8SCy Schubert struct radius_msg *msg; 2660*85732ac8SCy Schubert struct wpabuf *buf; 2661*85732ac8SCy Schubert u8 identifier; 2662*85732ac8SCy Schubert struct os_time now; 2663*85732ac8SCy Schubert 2664*85732ac8SCy Schubert if (!data) 2665*85732ac8SCy Schubert return -1; 2666*85732ac8SCy Schubert 2667*85732ac8SCy Schubert /* req: <disconnect|coa> <MAC Address> [t_c_clear] */ 2668*85732ac8SCy Schubert 2669*85732ac8SCy Schubert if (os_strncmp(pos, "disconnect ", 11) == 0) { 2670*85732ac8SCy Schubert disconnect = 1; 2671*85732ac8SCy Schubert pos += 11; 2672*85732ac8SCy Schubert } else if (os_strncmp(req, "coa ", 4) == 0) { 2673*85732ac8SCy Schubert disconnect = 0; 2674*85732ac8SCy Schubert pos += 4; 2675*85732ac8SCy Schubert } else { 2676*85732ac8SCy Schubert return -1; 2677*85732ac8SCy Schubert } 2678*85732ac8SCy Schubert 2679*85732ac8SCy Schubert if (hwaddr_aton(pos, addr)) 2680*85732ac8SCy Schubert return -1; 2681*85732ac8SCy Schubert pos = os_strchr(pos, ' '); 2682*85732ac8SCy Schubert if (pos) { 2683*85732ac8SCy Schubert if (os_strstr(pos, "t_c_clear")) 2684*85732ac8SCy Schubert t_c_clear = 1; 2685*85732ac8SCy Schubert } 2686*85732ac8SCy Schubert 2687*85732ac8SCy Schubert if (!disconnect && !t_c_clear) { 2688*85732ac8SCy Schubert RADIUS_ERROR("DAC request for CoA without any authorization change"); 2689*85732ac8SCy Schubert return -1; 2690*85732ac8SCy Schubert } 2691*85732ac8SCy Schubert 2692*85732ac8SCy Schubert if (!data->db) { 2693*85732ac8SCy Schubert RADIUS_ERROR("SQLite database not in use"); 2694*85732ac8SCy Schubert return -1; 2695*85732ac8SCy Schubert } 2696*85732ac8SCy Schubert 2697*85732ac8SCy Schubert os_snprintf(addrtxt, sizeof(addrtxt), MACSTR, MAC2STR(addr)); 2698*85732ac8SCy Schubert 2699*85732ac8SCy Schubert sql = sqlite3_mprintf("SELECT * FROM current_sessions WHERE mac_addr=%Q", 2700*85732ac8SCy Schubert addrtxt); 2701*85732ac8SCy Schubert if (!sql) 2702*85732ac8SCy Schubert return -1; 2703*85732ac8SCy Schubert 2704*85732ac8SCy Schubert os_memset(&fields, 0, sizeof(fields)); 2705*85732ac8SCy Schubert res = sqlite3_exec(data->db, sql, get_db_session_fields, &fields, NULL); 2706*85732ac8SCy Schubert sqlite3_free(sql); 2707*85732ac8SCy Schubert if (res != SQLITE_OK) { 2708*85732ac8SCy Schubert RADIUS_ERROR("Failed to find matching current_sessions entry from sqlite database: %s", 2709*85732ac8SCy Schubert sqlite3_errmsg(data->db)); 2710*85732ac8SCy Schubert free_db_session_fields(&fields); 2711*85732ac8SCy Schubert return -1; 2712*85732ac8SCy Schubert } 2713*85732ac8SCy Schubert 2714*85732ac8SCy Schubert if (!fields.nas) { 2715*85732ac8SCy Schubert RADIUS_ERROR("No NAS information found from current_sessions"); 2716*85732ac8SCy Schubert free_db_session_fields(&fields); 2717*85732ac8SCy Schubert return -1; 2718*85732ac8SCy Schubert } 2719*85732ac8SCy Schubert 2720*85732ac8SCy Schubert os_memset(&das, 0, sizeof(das)); 2721*85732ac8SCy Schubert das.sin_family = AF_INET; 2722*85732ac8SCy Schubert das.sin_addr.s_addr = inet_addr(fields.nas); 2723*85732ac8SCy Schubert das.sin_port = htons(3799); 2724*85732ac8SCy Schubert 2725*85732ac8SCy Schubert free_db_session_fields(&fields); 2726*85732ac8SCy Schubert 2727*85732ac8SCy Schubert client = radius_server_get_client(data, &das.sin_addr, 0); 2728*85732ac8SCy Schubert if (!client) { 2729*85732ac8SCy Schubert RADIUS_ERROR("No NAS information available to protect the packet"); 2730*85732ac8SCy Schubert return -1; 2731*85732ac8SCy Schubert } 2732*85732ac8SCy Schubert 2733*85732ac8SCy Schubert identifier = client->next_dac_identifier++; 2734*85732ac8SCy Schubert 2735*85732ac8SCy Schubert msg = radius_msg_new(disconnect ? RADIUS_CODE_DISCONNECT_REQUEST : 2736*85732ac8SCy Schubert RADIUS_CODE_COA_REQUEST, identifier); 2737*85732ac8SCy Schubert if (!msg) 2738*85732ac8SCy Schubert return -1; 2739*85732ac8SCy Schubert 2740*85732ac8SCy Schubert os_snprintf(addrtxt, sizeof(addrtxt), RADIUS_802_1X_ADDR_FORMAT, 2741*85732ac8SCy Schubert MAC2STR(addr)); 2742*85732ac8SCy Schubert if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, 2743*85732ac8SCy Schubert (u8 *) addrtxt, os_strlen(addrtxt))) { 2744*85732ac8SCy Schubert RADIUS_ERROR("Could not add Calling-Station-Id"); 2745*85732ac8SCy Schubert radius_msg_free(msg); 2746*85732ac8SCy Schubert return -1; 2747*85732ac8SCy Schubert } 2748*85732ac8SCy Schubert 2749*85732ac8SCy Schubert if (!disconnect && t_c_clear) { 2750*85732ac8SCy Schubert u8 val[4] = { 0x00, 0x00, 0x00, 0x00 }; /* E=0 */ 2751*85732ac8SCy Schubert 2752*85732ac8SCy Schubert if (!radius_msg_add_wfa( 2753*85732ac8SCy Schubert msg, RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING, 2754*85732ac8SCy Schubert val, sizeof(val))) { 2755*85732ac8SCy Schubert RADIUS_DEBUG("Failed to add WFA-HS20-T-C-Filtering"); 2756*85732ac8SCy Schubert radius_msg_free(msg); 2757*85732ac8SCy Schubert return -1; 2758*85732ac8SCy Schubert } 2759*85732ac8SCy Schubert } 2760*85732ac8SCy Schubert 2761*85732ac8SCy Schubert os_get_time(&now); 2762*85732ac8SCy Schubert if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP, 2763*85732ac8SCy Schubert now.sec)) { 2764*85732ac8SCy Schubert RADIUS_ERROR("Failed to add Event-Timestamp attribute"); 2765*85732ac8SCy Schubert radius_msg_free(msg); 2766*85732ac8SCy Schubert return -1; 2767*85732ac8SCy Schubert } 2768*85732ac8SCy Schubert 2769*85732ac8SCy Schubert radius_msg_finish_acct(msg, (u8 *) client->shared_secret, 2770*85732ac8SCy Schubert client->shared_secret_len); 2771*85732ac8SCy Schubert 2772*85732ac8SCy Schubert if (wpa_debug_level <= MSG_MSGDUMP) 2773*85732ac8SCy Schubert radius_msg_dump(msg); 2774*85732ac8SCy Schubert 2775*85732ac8SCy Schubert buf = radius_msg_get_buf(msg); 2776*85732ac8SCy Schubert if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0, 2777*85732ac8SCy Schubert (struct sockaddr *) &das, sizeof(das)) < 0) { 2778*85732ac8SCy Schubert RADIUS_ERROR("Failed to send packet - sendto: %s", 2779*85732ac8SCy Schubert strerror(errno)); 2780*85732ac8SCy Schubert radius_msg_free(msg); 2781*85732ac8SCy Schubert return -1; 2782*85732ac8SCy Schubert } 2783*85732ac8SCy Schubert 2784*85732ac8SCy Schubert if (disconnect) { 2785*85732ac8SCy Schubert radius_msg_free(client->pending_dac_disconnect_req); 2786*85732ac8SCy Schubert client->pending_dac_disconnect_req = msg; 2787*85732ac8SCy Schubert client->pending_dac_disconnect_id = identifier; 2788*85732ac8SCy Schubert os_memcpy(client->pending_dac_disconnect_addr, addr, ETH_ALEN); 2789*85732ac8SCy Schubert } else { 2790*85732ac8SCy Schubert radius_msg_free(client->pending_dac_coa_req); 2791*85732ac8SCy Schubert client->pending_dac_coa_req = msg; 2792*85732ac8SCy Schubert client->pending_dac_coa_id = identifier; 2793*85732ac8SCy Schubert os_memcpy(client->pending_dac_coa_addr, addr, ETH_ALEN); 2794*85732ac8SCy Schubert } 2795*85732ac8SCy Schubert 2796*85732ac8SCy Schubert return 0; 2797*85732ac8SCy Schubert #else /* CONFIG_SQLITE */ 2798*85732ac8SCy Schubert return -1; 2799*85732ac8SCy Schubert #endif /* CONFIG_SQLITE */ 2800*85732ac8SCy Schubert } 2801