139beb93cSSam Leffler /* 2e28a4053SRui Paulo * RADIUS authentication server 3*5b9c547cSRui 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> 11*5b9c547cSRui Paulo #ifdef CONFIG_SQLITE 12*5b9c547cSRui Paulo #include <sqlite3.h> 13*5b9c547cSRui 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" 19*5b9c547cSRui Paulo #include "ap/ap_config.h" 20*5b9c547cSRui 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 /** 29e28a4053SRui Paulo * RADIUS_MAX_SESSION - Maximum number of active sessions 30e28a4053SRui Paulo */ 3139beb93cSSam Leffler #define RADIUS_MAX_SESSION 100 32e28a4053SRui Paulo 33e28a4053SRui Paulo /** 34e28a4053SRui Paulo * RADIUS_MAX_MSG_LEN - Maximum message length for incoming RADIUS messages 35e28a4053SRui Paulo */ 3639beb93cSSam Leffler #define RADIUS_MAX_MSG_LEN 3000 3739beb93cSSam Leffler 3839beb93cSSam Leffler static struct eapol_callbacks radius_server_eapol_cb; 3939beb93cSSam Leffler 4039beb93cSSam Leffler struct radius_client; 4139beb93cSSam Leffler struct radius_server_data; 4239beb93cSSam Leffler 43e28a4053SRui Paulo /** 44e28a4053SRui Paulo * struct radius_server_counters - RADIUS server statistics counters 45e28a4053SRui Paulo */ 4639beb93cSSam Leffler struct radius_server_counters { 4739beb93cSSam Leffler u32 access_requests; 4839beb93cSSam Leffler u32 invalid_requests; 4939beb93cSSam Leffler u32 dup_access_requests; 5039beb93cSSam Leffler u32 access_accepts; 5139beb93cSSam Leffler u32 access_rejects; 5239beb93cSSam Leffler u32 access_challenges; 5339beb93cSSam Leffler u32 malformed_access_requests; 5439beb93cSSam Leffler u32 bad_authenticators; 5539beb93cSSam Leffler u32 packets_dropped; 5639beb93cSSam Leffler u32 unknown_types; 57*5b9c547cSRui Paulo 58*5b9c547cSRui Paulo u32 acct_requests; 59*5b9c547cSRui Paulo u32 invalid_acct_requests; 60*5b9c547cSRui Paulo u32 acct_responses; 61*5b9c547cSRui Paulo u32 malformed_acct_requests; 62*5b9c547cSRui Paulo u32 acct_bad_authenticators; 63*5b9c547cSRui Paulo u32 unknown_acct_types; 6439beb93cSSam Leffler }; 6539beb93cSSam Leffler 66e28a4053SRui Paulo /** 67e28a4053SRui Paulo * struct radius_session - Internal RADIUS server data for a session 68e28a4053SRui Paulo */ 6939beb93cSSam Leffler struct radius_session { 7039beb93cSSam Leffler struct radius_session *next; 7139beb93cSSam Leffler struct radius_client *client; 7239beb93cSSam Leffler struct radius_server_data *server; 7339beb93cSSam Leffler unsigned int sess_id; 7439beb93cSSam Leffler struct eap_sm *eap; 7539beb93cSSam Leffler struct eap_eapol_interface *eap_if; 76*5b9c547cSRui Paulo char *username; /* from User-Name attribute */ 77*5b9c547cSRui Paulo char *nas_ip; 7839beb93cSSam Leffler 7939beb93cSSam Leffler struct radius_msg *last_msg; 8039beb93cSSam Leffler char *last_from_addr; 8139beb93cSSam Leffler int last_from_port; 8239beb93cSSam Leffler struct sockaddr_storage last_from; 8339beb93cSSam Leffler socklen_t last_fromlen; 8439beb93cSSam Leffler u8 last_identifier; 8539beb93cSSam Leffler struct radius_msg *last_reply; 8639beb93cSSam Leffler u8 last_authenticator[16]; 87*5b9c547cSRui Paulo 88*5b9c547cSRui Paulo unsigned int remediation:1; 89*5b9c547cSRui Paulo unsigned int macacl:1; 90*5b9c547cSRui Paulo 91*5b9c547cSRui Paulo struct hostapd_radius_attr *accept_attr; 9239beb93cSSam Leffler }; 9339beb93cSSam Leffler 94e28a4053SRui Paulo /** 95e28a4053SRui Paulo * struct radius_client - Internal RADIUS server data for a client 96e28a4053SRui Paulo */ 9739beb93cSSam Leffler struct radius_client { 9839beb93cSSam Leffler struct radius_client *next; 9939beb93cSSam Leffler struct in_addr addr; 10039beb93cSSam Leffler struct in_addr mask; 10139beb93cSSam Leffler #ifdef CONFIG_IPV6 10239beb93cSSam Leffler struct in6_addr addr6; 10339beb93cSSam Leffler struct in6_addr mask6; 10439beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 10539beb93cSSam Leffler char *shared_secret; 10639beb93cSSam Leffler int shared_secret_len; 10739beb93cSSam Leffler struct radius_session *sessions; 10839beb93cSSam Leffler struct radius_server_counters counters; 10939beb93cSSam Leffler }; 11039beb93cSSam Leffler 111e28a4053SRui Paulo /** 112e28a4053SRui Paulo * struct radius_server_data - Internal RADIUS server data 113e28a4053SRui Paulo */ 11439beb93cSSam Leffler struct radius_server_data { 115e28a4053SRui Paulo /** 116e28a4053SRui Paulo * auth_sock - Socket for RADIUS authentication messages 117e28a4053SRui Paulo */ 11839beb93cSSam Leffler int auth_sock; 119e28a4053SRui Paulo 120e28a4053SRui Paulo /** 121*5b9c547cSRui Paulo * acct_sock - Socket for RADIUS accounting messages 122*5b9c547cSRui Paulo */ 123*5b9c547cSRui Paulo int acct_sock; 124*5b9c547cSRui Paulo 125*5b9c547cSRui Paulo /** 126e28a4053SRui Paulo * clients - List of authorized RADIUS clients 127e28a4053SRui Paulo */ 12839beb93cSSam Leffler struct radius_client *clients; 129e28a4053SRui Paulo 130e28a4053SRui Paulo /** 131e28a4053SRui Paulo * next_sess_id - Next session identifier 132e28a4053SRui Paulo */ 13339beb93cSSam Leffler unsigned int next_sess_id; 134e28a4053SRui Paulo 135e28a4053SRui Paulo /** 136e28a4053SRui Paulo * conf_ctx - Context pointer for callbacks 137e28a4053SRui Paulo * 138e28a4053SRui Paulo * This is used as the ctx argument in get_eap_user() calls. 139e28a4053SRui Paulo */ 14039beb93cSSam Leffler void *conf_ctx; 141e28a4053SRui Paulo 142e28a4053SRui Paulo /** 143e28a4053SRui Paulo * num_sess - Number of active sessions 144e28a4053SRui Paulo */ 14539beb93cSSam Leffler int num_sess; 146e28a4053SRui Paulo 147e28a4053SRui Paulo /** 148e28a4053SRui Paulo * eap_sim_db_priv - EAP-SIM/AKA database context 149e28a4053SRui Paulo * 150e28a4053SRui Paulo * This is passed to the EAP-SIM/AKA server implementation as a 151e28a4053SRui Paulo * callback context. 152e28a4053SRui Paulo */ 15339beb93cSSam Leffler void *eap_sim_db_priv; 154e28a4053SRui Paulo 155e28a4053SRui Paulo /** 156e28a4053SRui Paulo * ssl_ctx - TLS context 157e28a4053SRui Paulo * 158e28a4053SRui Paulo * This is passed to the EAP server implementation as a callback 159e28a4053SRui Paulo * context for TLS operations. 160e28a4053SRui Paulo */ 16139beb93cSSam Leffler void *ssl_ctx; 162e28a4053SRui Paulo 163e28a4053SRui Paulo /** 164e28a4053SRui Paulo * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST 165e28a4053SRui Paulo * 166e28a4053SRui Paulo * This parameter is used to set a key for EAP-FAST to encrypt the 167e28a4053SRui Paulo * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If 168e28a4053SRui Paulo * set, must point to a 16-octet key. 169e28a4053SRui Paulo */ 17039beb93cSSam Leffler u8 *pac_opaque_encr_key; 171e28a4053SRui Paulo 172e28a4053SRui Paulo /** 173e28a4053SRui Paulo * eap_fast_a_id - EAP-FAST authority identity (A-ID) 174e28a4053SRui Paulo * 175e28a4053SRui Paulo * If EAP-FAST is not used, this can be set to %NULL. In theory, this 176e28a4053SRui Paulo * is a variable length field, but due to some existing implementations 177e28a4053SRui Paulo * requiring A-ID to be 16 octets in length, it is recommended to use 178e28a4053SRui Paulo * that length for the field to provide interoperability with deployed 179e28a4053SRui Paulo * peer implementations. 180e28a4053SRui Paulo */ 18139beb93cSSam Leffler u8 *eap_fast_a_id; 182e28a4053SRui Paulo 183e28a4053SRui Paulo /** 184e28a4053SRui Paulo * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets 185e28a4053SRui Paulo */ 18639beb93cSSam Leffler size_t eap_fast_a_id_len; 187e28a4053SRui Paulo 188e28a4053SRui Paulo /** 189e28a4053SRui Paulo * eap_fast_a_id_info - EAP-FAST authority identifier information 190e28a4053SRui Paulo * 191e28a4053SRui Paulo * This A-ID-Info contains a user-friendly name for the A-ID. For 192e28a4053SRui Paulo * example, this could be the enterprise and server names in 193e28a4053SRui Paulo * human-readable format. This field is encoded as UTF-8. If EAP-FAST 194e28a4053SRui Paulo * is not used, this can be set to %NULL. 195e28a4053SRui Paulo */ 19639beb93cSSam Leffler char *eap_fast_a_id_info; 197e28a4053SRui Paulo 198e28a4053SRui Paulo /** 199e28a4053SRui Paulo * eap_fast_prov - EAP-FAST provisioning modes 200e28a4053SRui Paulo * 201e28a4053SRui Paulo * 0 = provisioning disabled, 1 = only anonymous provisioning allowed, 202e28a4053SRui Paulo * 2 = only authenticated provisioning allowed, 3 = both provisioning 203e28a4053SRui Paulo * modes allowed. 204e28a4053SRui Paulo */ 20539beb93cSSam Leffler int eap_fast_prov; 206e28a4053SRui Paulo 207e28a4053SRui Paulo /** 208e28a4053SRui Paulo * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds 209e28a4053SRui Paulo * 210e28a4053SRui Paulo * This is the hard limit on how long a provisioned PAC-Key can be 211e28a4053SRui Paulo * used. 212e28a4053SRui Paulo */ 21339beb93cSSam Leffler int pac_key_lifetime; 214e28a4053SRui Paulo 215e28a4053SRui Paulo /** 216e28a4053SRui Paulo * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds 217e28a4053SRui Paulo * 218e28a4053SRui Paulo * This is a soft limit on the PAC-Key. The server will automatically 219e28a4053SRui Paulo * generate a new PAC-Key when this number of seconds (or fewer) of the 220e28a4053SRui Paulo * lifetime remains. 221e28a4053SRui Paulo */ 22239beb93cSSam Leffler int pac_key_refresh_time; 223e28a4053SRui Paulo 224e28a4053SRui Paulo /** 225e28a4053SRui Paulo * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication 226e28a4053SRui Paulo * 227e28a4053SRui Paulo * This controls whether the protected success/failure indication 228e28a4053SRui Paulo * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA. 229e28a4053SRui Paulo */ 23039beb93cSSam Leffler int eap_sim_aka_result_ind; 231e28a4053SRui Paulo 232e28a4053SRui Paulo /** 233e28a4053SRui Paulo * tnc - Trusted Network Connect (TNC) 234e28a4053SRui Paulo * 235e28a4053SRui Paulo * This controls whether TNC is enabled and will be required before the 236e28a4053SRui Paulo * peer is allowed to connect. Note: This is only used with EAP-TTLS 237e28a4053SRui Paulo * and EAP-FAST. If any other EAP method is enabled, the peer will be 238e28a4053SRui Paulo * allowed to connect without TNC. 239e28a4053SRui Paulo */ 24039beb93cSSam Leffler int tnc; 241e28a4053SRui Paulo 242e28a4053SRui Paulo /** 243f05cddf9SRui Paulo * pwd_group - The D-H group assigned for EAP-pwd 244f05cddf9SRui Paulo * 245f05cddf9SRui Paulo * If EAP-pwd is not used it can be set to zero. 246f05cddf9SRui Paulo */ 247f05cddf9SRui Paulo u16 pwd_group; 248f05cddf9SRui Paulo 249f05cddf9SRui Paulo /** 250*5b9c547cSRui Paulo * server_id - Server identity 251*5b9c547cSRui Paulo */ 252*5b9c547cSRui Paulo const char *server_id; 253*5b9c547cSRui Paulo 254*5b9c547cSRui Paulo /** 255*5b9c547cSRui Paulo * erp - Whether EAP Re-authentication Protocol (ERP) is enabled 256*5b9c547cSRui Paulo * 257*5b9c547cSRui Paulo * This controls whether the authentication server derives ERP key 258*5b9c547cSRui Paulo * hierarchy (rRK and rIK) from full EAP authentication and allows 259*5b9c547cSRui Paulo * these keys to be used to perform ERP to derive rMSK instead of full 260*5b9c547cSRui Paulo * EAP authentication to derive MSK. 261*5b9c547cSRui Paulo */ 262*5b9c547cSRui Paulo int erp; 263*5b9c547cSRui Paulo 264*5b9c547cSRui Paulo const char *erp_domain; 265*5b9c547cSRui Paulo 266*5b9c547cSRui Paulo struct dl_list erp_keys; /* struct eap_server_erp_key */ 267*5b9c547cSRui Paulo 268*5b9c547cSRui Paulo /** 269e28a4053SRui Paulo * wps - Wi-Fi Protected Setup context 270e28a4053SRui Paulo * 271e28a4053SRui Paulo * If WPS is used with an external RADIUS server (which is quite 272e28a4053SRui Paulo * unlikely configuration), this is used to provide a pointer to WPS 273e28a4053SRui Paulo * context data. Normally, this can be set to %NULL. 274e28a4053SRui Paulo */ 27539beb93cSSam Leffler struct wps_context *wps; 276e28a4053SRui Paulo 277e28a4053SRui Paulo /** 278e28a4053SRui Paulo * ipv6 - Whether to enable IPv6 support in the RADIUS server 279e28a4053SRui Paulo */ 28039beb93cSSam Leffler int ipv6; 281e28a4053SRui Paulo 282e28a4053SRui Paulo /** 283e28a4053SRui Paulo * start_time - Timestamp of server start 284e28a4053SRui Paulo */ 285*5b9c547cSRui Paulo struct os_reltime start_time; 286e28a4053SRui Paulo 287e28a4053SRui Paulo /** 288e28a4053SRui Paulo * counters - Statistics counters for server operations 289e28a4053SRui Paulo * 290e28a4053SRui Paulo * These counters are the sum over all clients. 291e28a4053SRui Paulo */ 29239beb93cSSam Leffler struct radius_server_counters counters; 293e28a4053SRui Paulo 294e28a4053SRui Paulo /** 295e28a4053SRui Paulo * get_eap_user - Callback for fetching EAP user information 296e28a4053SRui Paulo * @ctx: Context data from conf_ctx 297e28a4053SRui Paulo * @identity: User identity 298e28a4053SRui Paulo * @identity_len: identity buffer length in octets 299e28a4053SRui Paulo * @phase2: Whether this is for Phase 2 identity 300e28a4053SRui Paulo * @user: Data structure for filling in the user information 301e28a4053SRui Paulo * Returns: 0 on success, -1 on failure 302e28a4053SRui Paulo * 303e28a4053SRui Paulo * This is used to fetch information from user database. The callback 304e28a4053SRui Paulo * will fill in information about allowed EAP methods and the user 305e28a4053SRui Paulo * password. The password field will be an allocated copy of the 306e28a4053SRui Paulo * password data and RADIUS server will free it after use. 307e28a4053SRui Paulo */ 30839beb93cSSam Leffler int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len, 30939beb93cSSam Leffler int phase2, struct eap_user *user); 310e28a4053SRui Paulo 311e28a4053SRui Paulo /** 312e28a4053SRui Paulo * eap_req_id_text - Optional data for EAP-Request/Identity 313e28a4053SRui Paulo * 314e28a4053SRui Paulo * This can be used to configure an optional, displayable message that 315e28a4053SRui Paulo * will be sent in EAP-Request/Identity. This string can contain an 316e28a4053SRui Paulo * ASCII-0 character (nul) to separate network infromation per RFC 317e28a4053SRui Paulo * 4284. The actual string length is explicit provided in 318e28a4053SRui Paulo * eap_req_id_text_len since nul character will not be used as a string 319e28a4053SRui Paulo * terminator. 320e28a4053SRui Paulo */ 32139beb93cSSam Leffler char *eap_req_id_text; 322e28a4053SRui Paulo 323e28a4053SRui Paulo /** 324e28a4053SRui Paulo * eap_req_id_text_len - Length of eap_req_id_text buffer in octets 325e28a4053SRui Paulo */ 32639beb93cSSam Leffler size_t eap_req_id_text_len; 327e28a4053SRui Paulo 328e28a4053SRui Paulo /* 329e28a4053SRui Paulo * msg_ctx - Context data for wpa_msg() calls 330e28a4053SRui Paulo */ 331e28a4053SRui Paulo void *msg_ctx; 332f05cddf9SRui Paulo 333f05cddf9SRui Paulo #ifdef CONFIG_RADIUS_TEST 334f05cddf9SRui Paulo char *dump_msk_file; 335f05cddf9SRui Paulo #endif /* CONFIG_RADIUS_TEST */ 336*5b9c547cSRui Paulo 337*5b9c547cSRui Paulo char *subscr_remediation_url; 338*5b9c547cSRui Paulo u8 subscr_remediation_method; 339*5b9c547cSRui Paulo 340*5b9c547cSRui Paulo #ifdef CONFIG_SQLITE 341*5b9c547cSRui Paulo sqlite3 *db; 342*5b9c547cSRui Paulo #endif /* CONFIG_SQLITE */ 34339beb93cSSam Leffler }; 34439beb93cSSam Leffler 34539beb93cSSam Leffler 34639beb93cSSam Leffler #define RADIUS_DEBUG(args...) \ 34739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "RADIUS SRV: " args) 34839beb93cSSam Leffler #define RADIUS_ERROR(args...) \ 34939beb93cSSam Leffler wpa_printf(MSG_ERROR, "RADIUS SRV: " args) 35039beb93cSSam Leffler #define RADIUS_DUMP(args...) \ 35139beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "RADIUS SRV: " args) 35239beb93cSSam Leffler #define RADIUS_DUMP_ASCII(args...) \ 35339beb93cSSam Leffler wpa_hexdump_ascii(MSG_MSGDUMP, "RADIUS SRV: " args) 35439beb93cSSam Leffler 35539beb93cSSam Leffler 35639beb93cSSam Leffler static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx); 3573157ba21SRui Paulo static void radius_server_session_remove_timeout(void *eloop_ctx, 3583157ba21SRui Paulo void *timeout_ctx); 35939beb93cSSam Leffler 360*5b9c547cSRui Paulo void srv_log(struct radius_session *sess, const char *fmt, ...) 361*5b9c547cSRui Paulo PRINTF_FORMAT(2, 3); 362*5b9c547cSRui Paulo 363*5b9c547cSRui Paulo void srv_log(struct radius_session *sess, const char *fmt, ...) 364*5b9c547cSRui Paulo { 365*5b9c547cSRui Paulo va_list ap; 366*5b9c547cSRui Paulo char *buf; 367*5b9c547cSRui Paulo int buflen; 368*5b9c547cSRui Paulo 369*5b9c547cSRui Paulo va_start(ap, fmt); 370*5b9c547cSRui Paulo buflen = vsnprintf(NULL, 0, fmt, ap) + 1; 371*5b9c547cSRui Paulo va_end(ap); 372*5b9c547cSRui Paulo 373*5b9c547cSRui Paulo buf = os_malloc(buflen); 374*5b9c547cSRui Paulo if (buf == NULL) 375*5b9c547cSRui Paulo return; 376*5b9c547cSRui Paulo va_start(ap, fmt); 377*5b9c547cSRui Paulo vsnprintf(buf, buflen, fmt, ap); 378*5b9c547cSRui Paulo va_end(ap); 379*5b9c547cSRui Paulo 380*5b9c547cSRui Paulo RADIUS_DEBUG("[0x%x %s] %s", sess->sess_id, sess->nas_ip, buf); 381*5b9c547cSRui Paulo 382*5b9c547cSRui Paulo #ifdef CONFIG_SQLITE 383*5b9c547cSRui Paulo if (sess->server->db) { 384*5b9c547cSRui Paulo char *sql; 385*5b9c547cSRui Paulo sql = sqlite3_mprintf("INSERT INTO authlog" 386*5b9c547cSRui Paulo "(timestamp,session,nas_ip,username,note)" 387*5b9c547cSRui Paulo " VALUES (" 388*5b9c547cSRui Paulo "strftime('%%Y-%%m-%%d %%H:%%M:%%f'," 389*5b9c547cSRui Paulo "'now'),%u,%Q,%Q,%Q)", 390*5b9c547cSRui Paulo sess->sess_id, sess->nas_ip, 391*5b9c547cSRui Paulo sess->username, buf); 392*5b9c547cSRui Paulo if (sql) { 393*5b9c547cSRui Paulo if (sqlite3_exec(sess->server->db, sql, NULL, NULL, 394*5b9c547cSRui Paulo NULL) != SQLITE_OK) { 395*5b9c547cSRui Paulo RADIUS_ERROR("Failed to add authlog entry into sqlite database: %s", 396*5b9c547cSRui Paulo sqlite3_errmsg(sess->server->db)); 397*5b9c547cSRui Paulo } 398*5b9c547cSRui Paulo sqlite3_free(sql); 399*5b9c547cSRui Paulo } 400*5b9c547cSRui Paulo } 401*5b9c547cSRui Paulo #endif /* CONFIG_SQLITE */ 402*5b9c547cSRui Paulo 403*5b9c547cSRui Paulo os_free(buf); 404*5b9c547cSRui Paulo } 405*5b9c547cSRui Paulo 40639beb93cSSam Leffler 40739beb93cSSam Leffler static struct radius_client * 40839beb93cSSam Leffler radius_server_get_client(struct radius_server_data *data, struct in_addr *addr, 40939beb93cSSam Leffler int ipv6) 41039beb93cSSam Leffler { 41139beb93cSSam Leffler struct radius_client *client = data->clients; 41239beb93cSSam Leffler 41339beb93cSSam Leffler while (client) { 41439beb93cSSam Leffler #ifdef CONFIG_IPV6 41539beb93cSSam Leffler if (ipv6) { 41639beb93cSSam Leffler struct in6_addr *addr6; 41739beb93cSSam Leffler int i; 41839beb93cSSam Leffler 41939beb93cSSam Leffler addr6 = (struct in6_addr *) addr; 42039beb93cSSam Leffler for (i = 0; i < 16; i++) { 42139beb93cSSam Leffler if ((addr6->s6_addr[i] & 42239beb93cSSam Leffler client->mask6.s6_addr[i]) != 42339beb93cSSam Leffler (client->addr6.s6_addr[i] & 42439beb93cSSam Leffler client->mask6.s6_addr[i])) { 42539beb93cSSam Leffler i = 17; 42639beb93cSSam Leffler break; 42739beb93cSSam Leffler } 42839beb93cSSam Leffler } 42939beb93cSSam Leffler if (i == 16) { 43039beb93cSSam Leffler break; 43139beb93cSSam Leffler } 43239beb93cSSam Leffler } 43339beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 43439beb93cSSam Leffler if (!ipv6 && (client->addr.s_addr & client->mask.s_addr) == 43539beb93cSSam Leffler (addr->s_addr & client->mask.s_addr)) { 43639beb93cSSam Leffler break; 43739beb93cSSam Leffler } 43839beb93cSSam Leffler 43939beb93cSSam Leffler client = client->next; 44039beb93cSSam Leffler } 44139beb93cSSam Leffler 44239beb93cSSam Leffler return client; 44339beb93cSSam Leffler } 44439beb93cSSam Leffler 44539beb93cSSam Leffler 44639beb93cSSam Leffler static struct radius_session * 44739beb93cSSam Leffler radius_server_get_session(struct radius_client *client, unsigned int sess_id) 44839beb93cSSam Leffler { 44939beb93cSSam Leffler struct radius_session *sess = client->sessions; 45039beb93cSSam Leffler 45139beb93cSSam Leffler while (sess) { 45239beb93cSSam Leffler if (sess->sess_id == sess_id) { 45339beb93cSSam Leffler break; 45439beb93cSSam Leffler } 45539beb93cSSam Leffler sess = sess->next; 45639beb93cSSam Leffler } 45739beb93cSSam Leffler 45839beb93cSSam Leffler return sess; 45939beb93cSSam Leffler } 46039beb93cSSam Leffler 46139beb93cSSam Leffler 46239beb93cSSam Leffler static void radius_server_session_free(struct radius_server_data *data, 46339beb93cSSam Leffler struct radius_session *sess) 46439beb93cSSam Leffler { 46539beb93cSSam Leffler eloop_cancel_timeout(radius_server_session_timeout, data, sess); 4663157ba21SRui Paulo eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess); 46739beb93cSSam Leffler eap_server_sm_deinit(sess->eap); 46839beb93cSSam Leffler radius_msg_free(sess->last_msg); 46939beb93cSSam Leffler os_free(sess->last_from_addr); 47039beb93cSSam Leffler radius_msg_free(sess->last_reply); 471*5b9c547cSRui Paulo os_free(sess->username); 472*5b9c547cSRui Paulo os_free(sess->nas_ip); 47339beb93cSSam Leffler os_free(sess); 47439beb93cSSam Leffler data->num_sess--; 47539beb93cSSam Leffler } 47639beb93cSSam Leffler 47739beb93cSSam Leffler 47839beb93cSSam Leffler static void radius_server_session_remove(struct radius_server_data *data, 47939beb93cSSam Leffler struct radius_session *sess) 48039beb93cSSam Leffler { 48139beb93cSSam Leffler struct radius_client *client = sess->client; 48239beb93cSSam Leffler struct radius_session *session, *prev; 48339beb93cSSam Leffler 48439beb93cSSam Leffler eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess); 48539beb93cSSam Leffler 48639beb93cSSam Leffler prev = NULL; 48739beb93cSSam Leffler session = client->sessions; 48839beb93cSSam Leffler while (session) { 48939beb93cSSam Leffler if (session == sess) { 49039beb93cSSam Leffler if (prev == NULL) { 49139beb93cSSam Leffler client->sessions = sess->next; 49239beb93cSSam Leffler } else { 49339beb93cSSam Leffler prev->next = sess->next; 49439beb93cSSam Leffler } 49539beb93cSSam Leffler radius_server_session_free(data, sess); 49639beb93cSSam Leffler break; 49739beb93cSSam Leffler } 49839beb93cSSam Leffler prev = session; 49939beb93cSSam Leffler session = session->next; 50039beb93cSSam Leffler } 50139beb93cSSam Leffler } 50239beb93cSSam Leffler 50339beb93cSSam Leffler 50439beb93cSSam Leffler static void radius_server_session_remove_timeout(void *eloop_ctx, 50539beb93cSSam Leffler void *timeout_ctx) 50639beb93cSSam Leffler { 50739beb93cSSam Leffler struct radius_server_data *data = eloop_ctx; 50839beb93cSSam Leffler struct radius_session *sess = timeout_ctx; 50939beb93cSSam Leffler RADIUS_DEBUG("Removing completed session 0x%x", sess->sess_id); 51039beb93cSSam Leffler radius_server_session_remove(data, sess); 51139beb93cSSam Leffler } 51239beb93cSSam Leffler 51339beb93cSSam Leffler 51439beb93cSSam Leffler static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx) 51539beb93cSSam Leffler { 51639beb93cSSam Leffler struct radius_server_data *data = eloop_ctx; 51739beb93cSSam Leffler struct radius_session *sess = timeout_ctx; 51839beb93cSSam Leffler 51939beb93cSSam Leffler RADIUS_DEBUG("Timing out authentication session 0x%x", sess->sess_id); 52039beb93cSSam Leffler radius_server_session_remove(data, sess); 52139beb93cSSam Leffler } 52239beb93cSSam Leffler 52339beb93cSSam Leffler 52439beb93cSSam Leffler static struct radius_session * 52539beb93cSSam Leffler radius_server_new_session(struct radius_server_data *data, 52639beb93cSSam Leffler struct radius_client *client) 52739beb93cSSam Leffler { 52839beb93cSSam Leffler struct radius_session *sess; 52939beb93cSSam Leffler 53039beb93cSSam Leffler if (data->num_sess >= RADIUS_MAX_SESSION) { 53139beb93cSSam Leffler RADIUS_DEBUG("Maximum number of existing session - no room " 53239beb93cSSam Leffler "for a new session"); 53339beb93cSSam Leffler return NULL; 53439beb93cSSam Leffler } 53539beb93cSSam Leffler 53639beb93cSSam Leffler sess = os_zalloc(sizeof(*sess)); 53739beb93cSSam Leffler if (sess == NULL) 53839beb93cSSam Leffler return NULL; 53939beb93cSSam Leffler 54039beb93cSSam Leffler sess->server = data; 54139beb93cSSam Leffler sess->client = client; 54239beb93cSSam Leffler sess->sess_id = data->next_sess_id++; 54339beb93cSSam Leffler sess->next = client->sessions; 54439beb93cSSam Leffler client->sessions = sess; 54539beb93cSSam Leffler eloop_register_timeout(RADIUS_SESSION_TIMEOUT, 0, 54639beb93cSSam Leffler radius_server_session_timeout, data, sess); 54739beb93cSSam Leffler data->num_sess++; 54839beb93cSSam Leffler return sess; 54939beb93cSSam Leffler } 55039beb93cSSam Leffler 55139beb93cSSam Leffler 552*5b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS 553*5b9c547cSRui Paulo static void radius_server_testing_options_tls(struct radius_session *sess, 554*5b9c547cSRui Paulo const char *tls, 555*5b9c547cSRui Paulo struct eap_config *eap_conf) 556*5b9c547cSRui Paulo { 557*5b9c547cSRui Paulo int test = atoi(tls); 558*5b9c547cSRui Paulo 559*5b9c547cSRui Paulo switch (test) { 560*5b9c547cSRui Paulo case 1: 561*5b9c547cSRui Paulo srv_log(sess, "TLS test - break VerifyData"); 562*5b9c547cSRui Paulo eap_conf->tls_test_flags = TLS_BREAK_VERIFY_DATA; 563*5b9c547cSRui Paulo break; 564*5b9c547cSRui Paulo case 2: 565*5b9c547cSRui Paulo srv_log(sess, "TLS test - break ServerKeyExchange ServerParams hash"); 566*5b9c547cSRui Paulo eap_conf->tls_test_flags = TLS_BREAK_SRV_KEY_X_HASH; 567*5b9c547cSRui Paulo break; 568*5b9c547cSRui Paulo case 3: 569*5b9c547cSRui Paulo srv_log(sess, "TLS test - break ServerKeyExchange ServerParams Signature"); 570*5b9c547cSRui Paulo eap_conf->tls_test_flags = TLS_BREAK_SRV_KEY_X_SIGNATURE; 571*5b9c547cSRui Paulo break; 572*5b9c547cSRui Paulo case 4: 573*5b9c547cSRui Paulo srv_log(sess, "TLS test - RSA-DHE using a short 511-bit prime"); 574*5b9c547cSRui Paulo eap_conf->tls_test_flags = TLS_DHE_PRIME_511B; 575*5b9c547cSRui Paulo break; 576*5b9c547cSRui Paulo case 5: 577*5b9c547cSRui Paulo srv_log(sess, "TLS test - RSA-DHE using a short 767-bit prime"); 578*5b9c547cSRui Paulo eap_conf->tls_test_flags = TLS_DHE_PRIME_767B; 579*5b9c547cSRui Paulo break; 580*5b9c547cSRui Paulo case 6: 581*5b9c547cSRui Paulo srv_log(sess, "TLS test - RSA-DHE using a bogus 15 \"prime\""); 582*5b9c547cSRui Paulo eap_conf->tls_test_flags = TLS_DHE_PRIME_15; 583*5b9c547cSRui Paulo break; 584*5b9c547cSRui Paulo case 7: 585*5b9c547cSRui Paulo srv_log(sess, "TLS test - RSA-DHE using a short 58-bit prime in long container"); 586*5b9c547cSRui Paulo eap_conf->tls_test_flags = TLS_DHE_PRIME_58B; 587*5b9c547cSRui Paulo break; 588*5b9c547cSRui Paulo case 8: 589*5b9c547cSRui Paulo srv_log(sess, "TLS test - RSA-DHE using a non-prime"); 590*5b9c547cSRui Paulo eap_conf->tls_test_flags = TLS_DHE_NON_PRIME; 591*5b9c547cSRui Paulo break; 592*5b9c547cSRui Paulo default: 593*5b9c547cSRui Paulo srv_log(sess, "Unrecognized TLS test"); 594*5b9c547cSRui Paulo break; 595*5b9c547cSRui Paulo } 596*5b9c547cSRui Paulo } 597*5b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */ 598*5b9c547cSRui Paulo 599*5b9c547cSRui Paulo static void radius_server_testing_options(struct radius_session *sess, 600*5b9c547cSRui Paulo struct eap_config *eap_conf) 601*5b9c547cSRui Paulo { 602*5b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS 603*5b9c547cSRui Paulo const char *pos; 604*5b9c547cSRui Paulo 605*5b9c547cSRui Paulo pos = os_strstr(sess->username, "@test-"); 606*5b9c547cSRui Paulo if (pos == NULL) 607*5b9c547cSRui Paulo return; 608*5b9c547cSRui Paulo pos += 6; 609*5b9c547cSRui Paulo if (os_strncmp(pos, "tls-", 4) == 0) 610*5b9c547cSRui Paulo radius_server_testing_options_tls(sess, pos + 4, eap_conf); 611*5b9c547cSRui Paulo else 612*5b9c547cSRui Paulo srv_log(sess, "Unrecognized test: %s", pos); 613*5b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */ 614*5b9c547cSRui Paulo } 615*5b9c547cSRui Paulo 616*5b9c547cSRui Paulo 61739beb93cSSam Leffler static struct radius_session * 61839beb93cSSam Leffler radius_server_get_new_session(struct radius_server_data *data, 61939beb93cSSam Leffler struct radius_client *client, 620*5b9c547cSRui Paulo struct radius_msg *msg, const char *from_addr) 62139beb93cSSam Leffler { 62239beb93cSSam Leffler u8 *user; 62339beb93cSSam Leffler size_t user_len; 62439beb93cSSam Leffler int res; 62539beb93cSSam Leffler struct radius_session *sess; 62639beb93cSSam Leffler struct eap_config eap_conf; 627*5b9c547cSRui Paulo struct eap_user tmp; 62839beb93cSSam Leffler 62939beb93cSSam Leffler RADIUS_DEBUG("Creating a new session"); 63039beb93cSSam Leffler 631*5b9c547cSRui Paulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &user, 632*5b9c547cSRui Paulo &user_len, NULL) < 0) { 63339beb93cSSam Leffler RADIUS_DEBUG("Could not get User-Name"); 63439beb93cSSam Leffler return NULL; 63539beb93cSSam Leffler } 63639beb93cSSam Leffler RADIUS_DUMP_ASCII("User-Name", user, user_len); 63739beb93cSSam Leffler 638*5b9c547cSRui Paulo os_memset(&tmp, 0, sizeof(tmp)); 639*5b9c547cSRui Paulo res = data->get_eap_user(data->conf_ctx, user, user_len, 0, &tmp); 640*5b9c547cSRui Paulo bin_clear_free(tmp.password, tmp.password_len); 64139beb93cSSam Leffler 642*5b9c547cSRui Paulo if (res != 0) { 643*5b9c547cSRui Paulo RADIUS_DEBUG("User-Name not found from user database"); 644*5b9c547cSRui Paulo return NULL; 645*5b9c547cSRui Paulo } 646*5b9c547cSRui Paulo 64739beb93cSSam Leffler RADIUS_DEBUG("Matching user entry found"); 64839beb93cSSam Leffler sess = radius_server_new_session(data, client); 64939beb93cSSam Leffler if (sess == NULL) { 65039beb93cSSam Leffler RADIUS_DEBUG("Failed to create a new session"); 65139beb93cSSam Leffler return NULL; 65239beb93cSSam Leffler } 653*5b9c547cSRui Paulo sess->accept_attr = tmp.accept_attr; 654*5b9c547cSRui Paulo sess->macacl = tmp.macacl; 655*5b9c547cSRui Paulo 656*5b9c547cSRui Paulo sess->username = os_malloc(user_len * 4 + 1); 657*5b9c547cSRui Paulo if (sess->username == NULL) { 658*5b9c547cSRui Paulo radius_server_session_free(data, sess); 65939beb93cSSam Leffler return NULL; 66039beb93cSSam Leffler } 661*5b9c547cSRui Paulo printf_encode(sess->username, user_len * 4 + 1, user, user_len); 662*5b9c547cSRui Paulo 663*5b9c547cSRui Paulo sess->nas_ip = os_strdup(from_addr); 664*5b9c547cSRui Paulo if (sess->nas_ip == NULL) { 665*5b9c547cSRui Paulo radius_server_session_free(data, sess); 666*5b9c547cSRui Paulo return NULL; 667*5b9c547cSRui Paulo } 668*5b9c547cSRui Paulo 669*5b9c547cSRui Paulo srv_log(sess, "New session created"); 67039beb93cSSam Leffler 67139beb93cSSam Leffler os_memset(&eap_conf, 0, sizeof(eap_conf)); 67239beb93cSSam Leffler eap_conf.ssl_ctx = data->ssl_ctx; 673e28a4053SRui Paulo eap_conf.msg_ctx = data->msg_ctx; 67439beb93cSSam Leffler eap_conf.eap_sim_db_priv = data->eap_sim_db_priv; 67539beb93cSSam Leffler eap_conf.backend_auth = TRUE; 67639beb93cSSam Leffler eap_conf.eap_server = 1; 67739beb93cSSam Leffler eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key; 67839beb93cSSam Leffler eap_conf.eap_fast_a_id = data->eap_fast_a_id; 67939beb93cSSam Leffler eap_conf.eap_fast_a_id_len = data->eap_fast_a_id_len; 68039beb93cSSam Leffler eap_conf.eap_fast_a_id_info = data->eap_fast_a_id_info; 68139beb93cSSam Leffler eap_conf.eap_fast_prov = data->eap_fast_prov; 68239beb93cSSam Leffler eap_conf.pac_key_lifetime = data->pac_key_lifetime; 68339beb93cSSam Leffler eap_conf.pac_key_refresh_time = data->pac_key_refresh_time; 68439beb93cSSam Leffler eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind; 68539beb93cSSam Leffler eap_conf.tnc = data->tnc; 68639beb93cSSam Leffler eap_conf.wps = data->wps; 687f05cddf9SRui Paulo eap_conf.pwd_group = data->pwd_group; 688*5b9c547cSRui Paulo eap_conf.server_id = (const u8 *) data->server_id; 689*5b9c547cSRui Paulo eap_conf.server_id_len = os_strlen(data->server_id); 690*5b9c547cSRui Paulo eap_conf.erp = data->erp; 691*5b9c547cSRui Paulo radius_server_testing_options(sess, &eap_conf); 69239beb93cSSam Leffler sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb, 69339beb93cSSam Leffler &eap_conf); 69439beb93cSSam Leffler if (sess->eap == NULL) { 69539beb93cSSam Leffler RADIUS_DEBUG("Failed to initialize EAP state machine for the " 69639beb93cSSam Leffler "new session"); 69739beb93cSSam Leffler radius_server_session_free(data, sess); 69839beb93cSSam Leffler return NULL; 69939beb93cSSam Leffler } 70039beb93cSSam Leffler sess->eap_if = eap_get_interface(sess->eap); 70139beb93cSSam Leffler sess->eap_if->eapRestart = TRUE; 70239beb93cSSam Leffler sess->eap_if->portEnabled = TRUE; 70339beb93cSSam Leffler 70439beb93cSSam Leffler RADIUS_DEBUG("New session 0x%x initialized", sess->sess_id); 70539beb93cSSam Leffler 70639beb93cSSam Leffler return sess; 70739beb93cSSam Leffler } 70839beb93cSSam Leffler 70939beb93cSSam Leffler 71039beb93cSSam Leffler static struct radius_msg * 71139beb93cSSam Leffler radius_server_encapsulate_eap(struct radius_server_data *data, 71239beb93cSSam Leffler struct radius_client *client, 71339beb93cSSam Leffler struct radius_session *sess, 71439beb93cSSam Leffler struct radius_msg *request) 71539beb93cSSam Leffler { 71639beb93cSSam Leffler struct radius_msg *msg; 71739beb93cSSam Leffler int code; 71839beb93cSSam Leffler unsigned int sess_id; 719e28a4053SRui Paulo struct radius_hdr *hdr = radius_msg_get_hdr(request); 72039beb93cSSam Leffler 72139beb93cSSam Leffler if (sess->eap_if->eapFail) { 72239beb93cSSam Leffler sess->eap_if->eapFail = FALSE; 72339beb93cSSam Leffler code = RADIUS_CODE_ACCESS_REJECT; 72439beb93cSSam Leffler } else if (sess->eap_if->eapSuccess) { 72539beb93cSSam Leffler sess->eap_if->eapSuccess = FALSE; 72639beb93cSSam Leffler code = RADIUS_CODE_ACCESS_ACCEPT; 72739beb93cSSam Leffler } else { 72839beb93cSSam Leffler sess->eap_if->eapReq = FALSE; 72939beb93cSSam Leffler code = RADIUS_CODE_ACCESS_CHALLENGE; 73039beb93cSSam Leffler } 73139beb93cSSam Leffler 732e28a4053SRui Paulo msg = radius_msg_new(code, hdr->identifier); 73339beb93cSSam Leffler if (msg == NULL) { 73439beb93cSSam Leffler RADIUS_DEBUG("Failed to allocate reply message"); 73539beb93cSSam Leffler return NULL; 73639beb93cSSam Leffler } 73739beb93cSSam Leffler 73839beb93cSSam Leffler sess_id = htonl(sess->sess_id); 73939beb93cSSam Leffler if (code == RADIUS_CODE_ACCESS_CHALLENGE && 74039beb93cSSam Leffler !radius_msg_add_attr(msg, RADIUS_ATTR_STATE, 74139beb93cSSam Leffler (u8 *) &sess_id, sizeof(sess_id))) { 74239beb93cSSam Leffler RADIUS_DEBUG("Failed to add State attribute"); 74339beb93cSSam Leffler } 74439beb93cSSam Leffler 74539beb93cSSam Leffler if (sess->eap_if->eapReqData && 74639beb93cSSam Leffler !radius_msg_add_eap(msg, wpabuf_head(sess->eap_if->eapReqData), 74739beb93cSSam Leffler wpabuf_len(sess->eap_if->eapReqData))) { 74839beb93cSSam Leffler RADIUS_DEBUG("Failed to add EAP-Message attribute"); 74939beb93cSSam Leffler } 75039beb93cSSam Leffler 75139beb93cSSam Leffler if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) { 75239beb93cSSam Leffler int len; 753f05cddf9SRui Paulo #ifdef CONFIG_RADIUS_TEST 754f05cddf9SRui Paulo if (data->dump_msk_file) { 755f05cddf9SRui Paulo FILE *f; 756f05cddf9SRui Paulo char buf[2 * 64 + 1]; 757f05cddf9SRui Paulo f = fopen(data->dump_msk_file, "a"); 758f05cddf9SRui Paulo if (f) { 759f05cddf9SRui Paulo len = sess->eap_if->eapKeyDataLen; 760f05cddf9SRui Paulo if (len > 64) 761f05cddf9SRui Paulo len = 64; 762f05cddf9SRui Paulo len = wpa_snprintf_hex( 763f05cddf9SRui Paulo buf, sizeof(buf), 764f05cddf9SRui Paulo sess->eap_if->eapKeyData, len); 765f05cddf9SRui Paulo buf[len] = '\0'; 766f05cddf9SRui Paulo fprintf(f, "%s\n", buf); 767f05cddf9SRui Paulo fclose(f); 768f05cddf9SRui Paulo } 769f05cddf9SRui Paulo } 770f05cddf9SRui Paulo #endif /* CONFIG_RADIUS_TEST */ 77139beb93cSSam Leffler if (sess->eap_if->eapKeyDataLen > 64) { 77239beb93cSSam Leffler len = 32; 77339beb93cSSam Leffler } else { 77439beb93cSSam Leffler len = sess->eap_if->eapKeyDataLen / 2; 77539beb93cSSam Leffler } 776e28a4053SRui Paulo if (!radius_msg_add_mppe_keys(msg, hdr->authenticator, 77739beb93cSSam Leffler (u8 *) client->shared_secret, 77839beb93cSSam Leffler client->shared_secret_len, 77939beb93cSSam Leffler sess->eap_if->eapKeyData + len, 78039beb93cSSam Leffler len, sess->eap_if->eapKeyData, 78139beb93cSSam Leffler len)) { 78239beb93cSSam Leffler RADIUS_DEBUG("Failed to add MPPE key attributes"); 78339beb93cSSam Leffler } 78439beb93cSSam Leffler } 78539beb93cSSam Leffler 786*5b9c547cSRui Paulo #ifdef CONFIG_HS20 787*5b9c547cSRui Paulo if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->remediation && 788*5b9c547cSRui Paulo data->subscr_remediation_url) { 789*5b9c547cSRui Paulo u8 *buf; 790*5b9c547cSRui Paulo size_t url_len = os_strlen(data->subscr_remediation_url); 791*5b9c547cSRui Paulo buf = os_malloc(1 + url_len); 792*5b9c547cSRui Paulo if (buf == NULL) { 793*5b9c547cSRui Paulo radius_msg_free(msg); 794*5b9c547cSRui Paulo return NULL; 795*5b9c547cSRui Paulo } 796*5b9c547cSRui Paulo buf[0] = data->subscr_remediation_method; 797*5b9c547cSRui Paulo os_memcpy(&buf[1], data->subscr_remediation_url, url_len); 798*5b9c547cSRui Paulo if (!radius_msg_add_wfa( 799*5b9c547cSRui Paulo msg, RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION, 800*5b9c547cSRui Paulo buf, 1 + url_len)) { 801*5b9c547cSRui Paulo RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem"); 802*5b9c547cSRui Paulo } 803*5b9c547cSRui Paulo os_free(buf); 804*5b9c547cSRui Paulo } else if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->remediation) { 805*5b9c547cSRui Paulo u8 buf[1]; 806*5b9c547cSRui Paulo if (!radius_msg_add_wfa( 807*5b9c547cSRui Paulo msg, RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION, 808*5b9c547cSRui Paulo buf, 0)) { 809*5b9c547cSRui Paulo RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem"); 810*5b9c547cSRui Paulo } 811*5b9c547cSRui Paulo } 812*5b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 813*5b9c547cSRui Paulo 81439beb93cSSam Leffler if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) { 81539beb93cSSam Leffler RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)"); 81639beb93cSSam Leffler radius_msg_free(msg); 81739beb93cSSam Leffler return NULL; 81839beb93cSSam Leffler } 81939beb93cSSam Leffler 820*5b9c547cSRui Paulo if (code == RADIUS_CODE_ACCESS_ACCEPT) { 821*5b9c547cSRui Paulo struct hostapd_radius_attr *attr; 822*5b9c547cSRui Paulo for (attr = sess->accept_attr; attr; attr = attr->next) { 823*5b9c547cSRui Paulo if (!radius_msg_add_attr(msg, attr->type, 824*5b9c547cSRui Paulo wpabuf_head(attr->val), 825*5b9c547cSRui Paulo wpabuf_len(attr->val))) { 826*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add RADIUS attribute"); 827*5b9c547cSRui Paulo radius_msg_free(msg); 828*5b9c547cSRui Paulo return NULL; 829*5b9c547cSRui Paulo } 830*5b9c547cSRui Paulo } 831*5b9c547cSRui Paulo } 832*5b9c547cSRui Paulo 833*5b9c547cSRui Paulo if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret, 834*5b9c547cSRui Paulo client->shared_secret_len, 835*5b9c547cSRui Paulo hdr->authenticator) < 0) { 836*5b9c547cSRui Paulo RADIUS_DEBUG("Failed to add Message-Authenticator attribute"); 837*5b9c547cSRui Paulo } 838*5b9c547cSRui Paulo 839*5b9c547cSRui Paulo return msg; 840*5b9c547cSRui Paulo } 841*5b9c547cSRui Paulo 842*5b9c547cSRui Paulo 843*5b9c547cSRui Paulo static struct radius_msg * 844*5b9c547cSRui Paulo radius_server_macacl(struct radius_server_data *data, 845*5b9c547cSRui Paulo struct radius_client *client, 846*5b9c547cSRui Paulo struct radius_session *sess, 847*5b9c547cSRui Paulo struct radius_msg *request) 848*5b9c547cSRui Paulo { 849*5b9c547cSRui Paulo struct radius_msg *msg; 850*5b9c547cSRui Paulo int code; 851*5b9c547cSRui Paulo struct radius_hdr *hdr = radius_msg_get_hdr(request); 852*5b9c547cSRui Paulo u8 *pw; 853*5b9c547cSRui Paulo size_t pw_len; 854*5b9c547cSRui Paulo 855*5b9c547cSRui Paulo code = RADIUS_CODE_ACCESS_ACCEPT; 856*5b9c547cSRui Paulo 857*5b9c547cSRui Paulo if (radius_msg_get_attr_ptr(request, RADIUS_ATTR_USER_PASSWORD, &pw, 858*5b9c547cSRui Paulo &pw_len, NULL) < 0) { 859*5b9c547cSRui Paulo RADIUS_DEBUG("Could not get User-Password"); 860*5b9c547cSRui Paulo code = RADIUS_CODE_ACCESS_REJECT; 861*5b9c547cSRui Paulo } else { 862*5b9c547cSRui Paulo int res; 863*5b9c547cSRui Paulo struct eap_user tmp; 864*5b9c547cSRui Paulo 865*5b9c547cSRui Paulo os_memset(&tmp, 0, sizeof(tmp)); 866*5b9c547cSRui Paulo res = data->get_eap_user(data->conf_ctx, (u8 *) sess->username, 867*5b9c547cSRui Paulo os_strlen(sess->username), 0, &tmp); 868*5b9c547cSRui Paulo if (res || !tmp.macacl || tmp.password == NULL) { 869*5b9c547cSRui Paulo RADIUS_DEBUG("No MAC ACL user entry"); 870*5b9c547cSRui Paulo bin_clear_free(tmp.password, tmp.password_len); 871*5b9c547cSRui Paulo code = RADIUS_CODE_ACCESS_REJECT; 872*5b9c547cSRui Paulo } else { 873*5b9c547cSRui Paulo u8 buf[128]; 874*5b9c547cSRui Paulo res = radius_user_password_hide( 875*5b9c547cSRui Paulo request, tmp.password, tmp.password_len, 876*5b9c547cSRui Paulo (u8 *) client->shared_secret, 877*5b9c547cSRui Paulo client->shared_secret_len, 878*5b9c547cSRui Paulo buf, sizeof(buf)); 879*5b9c547cSRui Paulo bin_clear_free(tmp.password, tmp.password_len); 880*5b9c547cSRui Paulo 881*5b9c547cSRui Paulo if (res < 0 || pw_len != (size_t) res || 882*5b9c547cSRui Paulo os_memcmp_const(pw, buf, res) != 0) { 883*5b9c547cSRui Paulo RADIUS_DEBUG("Incorrect User-Password"); 884*5b9c547cSRui Paulo code = RADIUS_CODE_ACCESS_REJECT; 885*5b9c547cSRui Paulo } 886*5b9c547cSRui Paulo } 887*5b9c547cSRui Paulo } 888*5b9c547cSRui Paulo 889*5b9c547cSRui Paulo msg = radius_msg_new(code, hdr->identifier); 890*5b9c547cSRui Paulo if (msg == NULL) { 891*5b9c547cSRui Paulo RADIUS_DEBUG("Failed to allocate reply message"); 892*5b9c547cSRui Paulo return NULL; 893*5b9c547cSRui Paulo } 894*5b9c547cSRui Paulo 895*5b9c547cSRui Paulo if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) { 896*5b9c547cSRui Paulo RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)"); 897*5b9c547cSRui Paulo radius_msg_free(msg); 898*5b9c547cSRui Paulo return NULL; 899*5b9c547cSRui Paulo } 900*5b9c547cSRui Paulo 901*5b9c547cSRui Paulo if (code == RADIUS_CODE_ACCESS_ACCEPT) { 902*5b9c547cSRui Paulo struct hostapd_radius_attr *attr; 903*5b9c547cSRui Paulo for (attr = sess->accept_attr; attr; attr = attr->next) { 904*5b9c547cSRui Paulo if (!radius_msg_add_attr(msg, attr->type, 905*5b9c547cSRui Paulo wpabuf_head(attr->val), 906*5b9c547cSRui Paulo wpabuf_len(attr->val))) { 907*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add RADIUS attribute"); 908*5b9c547cSRui Paulo radius_msg_free(msg); 909*5b9c547cSRui Paulo return NULL; 910*5b9c547cSRui Paulo } 911*5b9c547cSRui Paulo } 912*5b9c547cSRui Paulo } 913*5b9c547cSRui Paulo 91439beb93cSSam Leffler if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret, 91539beb93cSSam Leffler client->shared_secret_len, 916e28a4053SRui Paulo hdr->authenticator) < 0) { 91739beb93cSSam Leffler RADIUS_DEBUG("Failed to add Message-Authenticator attribute"); 91839beb93cSSam Leffler } 91939beb93cSSam Leffler 92039beb93cSSam Leffler return msg; 92139beb93cSSam Leffler } 92239beb93cSSam Leffler 92339beb93cSSam Leffler 92439beb93cSSam Leffler static int radius_server_reject(struct radius_server_data *data, 92539beb93cSSam Leffler struct radius_client *client, 92639beb93cSSam Leffler struct radius_msg *request, 92739beb93cSSam Leffler struct sockaddr *from, socklen_t fromlen, 92839beb93cSSam Leffler const char *from_addr, int from_port) 92939beb93cSSam Leffler { 93039beb93cSSam Leffler struct radius_msg *msg; 93139beb93cSSam Leffler int ret = 0; 93239beb93cSSam Leffler struct eap_hdr eapfail; 933e28a4053SRui Paulo struct wpabuf *buf; 934e28a4053SRui Paulo struct radius_hdr *hdr = radius_msg_get_hdr(request); 93539beb93cSSam Leffler 93639beb93cSSam Leffler RADIUS_DEBUG("Reject invalid request from %s:%d", 93739beb93cSSam Leffler from_addr, from_port); 93839beb93cSSam Leffler 939e28a4053SRui Paulo msg = radius_msg_new(RADIUS_CODE_ACCESS_REJECT, hdr->identifier); 94039beb93cSSam Leffler if (msg == NULL) { 94139beb93cSSam Leffler return -1; 94239beb93cSSam Leffler } 94339beb93cSSam Leffler 94439beb93cSSam Leffler os_memset(&eapfail, 0, sizeof(eapfail)); 94539beb93cSSam Leffler eapfail.code = EAP_CODE_FAILURE; 94639beb93cSSam Leffler eapfail.identifier = 0; 94739beb93cSSam Leffler eapfail.length = host_to_be16(sizeof(eapfail)); 94839beb93cSSam Leffler 94939beb93cSSam Leffler if (!radius_msg_add_eap(msg, (u8 *) &eapfail, sizeof(eapfail))) { 95039beb93cSSam Leffler RADIUS_DEBUG("Failed to add EAP-Message attribute"); 95139beb93cSSam Leffler } 95239beb93cSSam Leffler 95339beb93cSSam Leffler if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) { 95439beb93cSSam Leffler RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)"); 95539beb93cSSam Leffler radius_msg_free(msg); 95639beb93cSSam Leffler return -1; 95739beb93cSSam Leffler } 95839beb93cSSam Leffler 95939beb93cSSam Leffler if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret, 96039beb93cSSam Leffler client->shared_secret_len, 961e28a4053SRui Paulo hdr->authenticator) < 962e28a4053SRui Paulo 0) { 96339beb93cSSam Leffler RADIUS_DEBUG("Failed to add Message-Authenticator attribute"); 96439beb93cSSam Leffler } 96539beb93cSSam Leffler 96639beb93cSSam Leffler if (wpa_debug_level <= MSG_MSGDUMP) { 96739beb93cSSam Leffler radius_msg_dump(msg); 96839beb93cSSam Leffler } 96939beb93cSSam Leffler 97039beb93cSSam Leffler data->counters.access_rejects++; 97139beb93cSSam Leffler client->counters.access_rejects++; 972e28a4053SRui Paulo buf = radius_msg_get_buf(msg); 973e28a4053SRui Paulo if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0, 97439beb93cSSam Leffler (struct sockaddr *) from, sizeof(*from)) < 0) { 975*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", strerror(errno)); 97639beb93cSSam Leffler ret = -1; 97739beb93cSSam Leffler } 97839beb93cSSam Leffler 97939beb93cSSam Leffler radius_msg_free(msg); 98039beb93cSSam Leffler 98139beb93cSSam Leffler return ret; 98239beb93cSSam Leffler } 98339beb93cSSam Leffler 98439beb93cSSam Leffler 98539beb93cSSam Leffler static int radius_server_request(struct radius_server_data *data, 98639beb93cSSam Leffler struct radius_msg *msg, 98739beb93cSSam Leffler struct sockaddr *from, socklen_t fromlen, 98839beb93cSSam Leffler struct radius_client *client, 98939beb93cSSam Leffler const char *from_addr, int from_port, 99039beb93cSSam Leffler struct radius_session *force_sess) 99139beb93cSSam Leffler { 992f05cddf9SRui Paulo struct wpabuf *eap = NULL; 99339beb93cSSam Leffler int res, state_included = 0; 99439beb93cSSam Leffler u8 statebuf[4]; 99539beb93cSSam Leffler unsigned int state; 99639beb93cSSam Leffler struct radius_session *sess; 99739beb93cSSam Leffler struct radius_msg *reply; 9983157ba21SRui Paulo int is_complete = 0; 99939beb93cSSam Leffler 100039beb93cSSam Leffler if (force_sess) 100139beb93cSSam Leffler sess = force_sess; 100239beb93cSSam Leffler else { 100339beb93cSSam Leffler res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf, 100439beb93cSSam Leffler sizeof(statebuf)); 100539beb93cSSam Leffler state_included = res >= 0; 100639beb93cSSam Leffler if (res == sizeof(statebuf)) { 100739beb93cSSam Leffler state = WPA_GET_BE32(statebuf); 100839beb93cSSam Leffler sess = radius_server_get_session(client, state); 100939beb93cSSam Leffler } else { 101039beb93cSSam Leffler sess = NULL; 101139beb93cSSam Leffler } 101239beb93cSSam Leffler } 101339beb93cSSam Leffler 101439beb93cSSam Leffler if (sess) { 101539beb93cSSam Leffler RADIUS_DEBUG("Request for session 0x%x", sess->sess_id); 101639beb93cSSam Leffler } else if (state_included) { 101739beb93cSSam Leffler RADIUS_DEBUG("State attribute included but no session found"); 101839beb93cSSam Leffler radius_server_reject(data, client, msg, from, fromlen, 101939beb93cSSam Leffler from_addr, from_port); 102039beb93cSSam Leffler return -1; 102139beb93cSSam Leffler } else { 1022*5b9c547cSRui Paulo sess = radius_server_get_new_session(data, client, msg, 1023*5b9c547cSRui Paulo from_addr); 102439beb93cSSam Leffler if (sess == NULL) { 102539beb93cSSam Leffler RADIUS_DEBUG("Could not create a new session"); 102639beb93cSSam Leffler radius_server_reject(data, client, msg, from, fromlen, 102739beb93cSSam Leffler from_addr, from_port); 102839beb93cSSam Leffler return -1; 102939beb93cSSam Leffler } 103039beb93cSSam Leffler } 103139beb93cSSam Leffler 103239beb93cSSam Leffler if (sess->last_from_port == from_port && 1033e28a4053SRui Paulo sess->last_identifier == radius_msg_get_hdr(msg)->identifier && 1034e28a4053SRui Paulo os_memcmp(sess->last_authenticator, 1035e28a4053SRui Paulo radius_msg_get_hdr(msg)->authenticator, 16) == 0) { 103639beb93cSSam Leffler RADIUS_DEBUG("Duplicate message from %s", from_addr); 103739beb93cSSam Leffler data->counters.dup_access_requests++; 103839beb93cSSam Leffler client->counters.dup_access_requests++; 103939beb93cSSam Leffler 104039beb93cSSam Leffler if (sess->last_reply) { 1041e28a4053SRui Paulo struct wpabuf *buf; 1042e28a4053SRui Paulo buf = radius_msg_get_buf(sess->last_reply); 1043e28a4053SRui Paulo res = sendto(data->auth_sock, wpabuf_head(buf), 1044e28a4053SRui Paulo wpabuf_len(buf), 0, 104539beb93cSSam Leffler (struct sockaddr *) from, fromlen); 104639beb93cSSam Leffler if (res < 0) { 1047*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", 1048*5b9c547cSRui Paulo strerror(errno)); 104939beb93cSSam Leffler } 105039beb93cSSam Leffler return 0; 105139beb93cSSam Leffler } 105239beb93cSSam Leffler 105339beb93cSSam Leffler RADIUS_DEBUG("No previous reply available for duplicate " 105439beb93cSSam Leffler "message"); 105539beb93cSSam Leffler return -1; 105639beb93cSSam Leffler } 105739beb93cSSam Leffler 1058f05cddf9SRui Paulo eap = radius_msg_get_eap(msg); 1059*5b9c547cSRui Paulo if (eap == NULL && sess->macacl) { 1060*5b9c547cSRui Paulo reply = radius_server_macacl(data, client, sess, msg); 1061*5b9c547cSRui Paulo if (reply == NULL) 1062*5b9c547cSRui Paulo return -1; 1063*5b9c547cSRui Paulo goto send_reply; 1064*5b9c547cSRui Paulo } 106539beb93cSSam Leffler if (eap == NULL) { 106639beb93cSSam Leffler RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s", 106739beb93cSSam Leffler from_addr); 106839beb93cSSam Leffler data->counters.packets_dropped++; 106939beb93cSSam Leffler client->counters.packets_dropped++; 107039beb93cSSam Leffler return -1; 107139beb93cSSam Leffler } 107239beb93cSSam Leffler 1073f05cddf9SRui Paulo RADIUS_DUMP("Received EAP data", wpabuf_head(eap), wpabuf_len(eap)); 107439beb93cSSam Leffler 107539beb93cSSam Leffler /* FIX: if Code is Request, Success, or Failure, send Access-Reject; 107639beb93cSSam Leffler * RFC3579 Sect. 2.6.2. 107739beb93cSSam Leffler * Include EAP-Response/Nak with no preferred method if 107839beb93cSSam Leffler * code == request. 107939beb93cSSam Leffler * If code is not 1-4, discard the packet silently. 108039beb93cSSam Leffler * Or is this already done by the EAP state machine? */ 108139beb93cSSam Leffler 108239beb93cSSam Leffler wpabuf_free(sess->eap_if->eapRespData); 1083f05cddf9SRui Paulo sess->eap_if->eapRespData = eap; 108439beb93cSSam Leffler sess->eap_if->eapResp = TRUE; 108539beb93cSSam Leffler eap_server_sm_step(sess->eap); 108639beb93cSSam Leffler 108739beb93cSSam Leffler if ((sess->eap_if->eapReq || sess->eap_if->eapSuccess || 108839beb93cSSam Leffler sess->eap_if->eapFail) && sess->eap_if->eapReqData) { 108939beb93cSSam Leffler RADIUS_DUMP("EAP data from the state machine", 109039beb93cSSam Leffler wpabuf_head(sess->eap_if->eapReqData), 109139beb93cSSam Leffler wpabuf_len(sess->eap_if->eapReqData)); 109239beb93cSSam Leffler } else if (sess->eap_if->eapFail) { 109339beb93cSSam Leffler RADIUS_DEBUG("No EAP data from the state machine, but eapFail " 109439beb93cSSam Leffler "set"); 109539beb93cSSam Leffler } else if (eap_sm_method_pending(sess->eap)) { 109639beb93cSSam Leffler radius_msg_free(sess->last_msg); 109739beb93cSSam Leffler sess->last_msg = msg; 109839beb93cSSam Leffler sess->last_from_port = from_port; 109939beb93cSSam Leffler os_free(sess->last_from_addr); 110039beb93cSSam Leffler sess->last_from_addr = os_strdup(from_addr); 110139beb93cSSam Leffler sess->last_fromlen = fromlen; 110239beb93cSSam Leffler os_memcpy(&sess->last_from, from, fromlen); 110339beb93cSSam Leffler return -2; 110439beb93cSSam Leffler } else { 110539beb93cSSam Leffler RADIUS_DEBUG("No EAP data from the state machine - ignore this" 110639beb93cSSam Leffler " Access-Request silently (assuming it was a " 110739beb93cSSam Leffler "duplicate)"); 110839beb93cSSam Leffler data->counters.packets_dropped++; 110939beb93cSSam Leffler client->counters.packets_dropped++; 111039beb93cSSam Leffler return -1; 111139beb93cSSam Leffler } 111239beb93cSSam Leffler 11133157ba21SRui Paulo if (sess->eap_if->eapSuccess || sess->eap_if->eapFail) 11143157ba21SRui Paulo is_complete = 1; 1115*5b9c547cSRui Paulo if (sess->eap_if->eapFail) 1116*5b9c547cSRui Paulo srv_log(sess, "EAP authentication failed"); 1117*5b9c547cSRui Paulo else if (sess->eap_if->eapSuccess) 1118*5b9c547cSRui Paulo srv_log(sess, "EAP authentication succeeded"); 11193157ba21SRui Paulo 112039beb93cSSam Leffler reply = radius_server_encapsulate_eap(data, client, sess, msg); 112139beb93cSSam Leffler 1122*5b9c547cSRui Paulo send_reply: 112339beb93cSSam Leffler if (reply) { 1124e28a4053SRui Paulo struct wpabuf *buf; 1125e28a4053SRui Paulo struct radius_hdr *hdr; 1126e28a4053SRui Paulo 112739beb93cSSam Leffler RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port); 112839beb93cSSam Leffler if (wpa_debug_level <= MSG_MSGDUMP) { 112939beb93cSSam Leffler radius_msg_dump(reply); 113039beb93cSSam Leffler } 113139beb93cSSam Leffler 1132e28a4053SRui Paulo switch (radius_msg_get_hdr(reply)->code) { 113339beb93cSSam Leffler case RADIUS_CODE_ACCESS_ACCEPT: 1134*5b9c547cSRui Paulo srv_log(sess, "Sending Access-Accept"); 113539beb93cSSam Leffler data->counters.access_accepts++; 113639beb93cSSam Leffler client->counters.access_accepts++; 113739beb93cSSam Leffler break; 113839beb93cSSam Leffler case RADIUS_CODE_ACCESS_REJECT: 1139*5b9c547cSRui Paulo srv_log(sess, "Sending Access-Reject"); 114039beb93cSSam Leffler data->counters.access_rejects++; 114139beb93cSSam Leffler client->counters.access_rejects++; 114239beb93cSSam Leffler break; 114339beb93cSSam Leffler case RADIUS_CODE_ACCESS_CHALLENGE: 114439beb93cSSam Leffler data->counters.access_challenges++; 114539beb93cSSam Leffler client->counters.access_challenges++; 114639beb93cSSam Leffler break; 114739beb93cSSam Leffler } 1148e28a4053SRui Paulo buf = radius_msg_get_buf(reply); 1149e28a4053SRui Paulo res = sendto(data->auth_sock, wpabuf_head(buf), 1150e28a4053SRui Paulo wpabuf_len(buf), 0, 115139beb93cSSam Leffler (struct sockaddr *) from, fromlen); 115239beb93cSSam Leffler if (res < 0) { 1153*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", 1154*5b9c547cSRui Paulo strerror(errno)); 115539beb93cSSam Leffler } 115639beb93cSSam Leffler radius_msg_free(sess->last_reply); 115739beb93cSSam Leffler sess->last_reply = reply; 115839beb93cSSam Leffler sess->last_from_port = from_port; 1159e28a4053SRui Paulo hdr = radius_msg_get_hdr(msg); 1160e28a4053SRui Paulo sess->last_identifier = hdr->identifier; 1161e28a4053SRui Paulo os_memcpy(sess->last_authenticator, hdr->authenticator, 16); 116239beb93cSSam Leffler } else { 116339beb93cSSam Leffler data->counters.packets_dropped++; 116439beb93cSSam Leffler client->counters.packets_dropped++; 116539beb93cSSam Leffler } 116639beb93cSSam Leffler 11673157ba21SRui Paulo if (is_complete) { 116839beb93cSSam Leffler RADIUS_DEBUG("Removing completed session 0x%x after timeout", 116939beb93cSSam Leffler sess->sess_id); 117039beb93cSSam Leffler eloop_cancel_timeout(radius_server_session_remove_timeout, 117139beb93cSSam Leffler data, sess); 117239beb93cSSam Leffler eloop_register_timeout(10, 0, 117339beb93cSSam Leffler radius_server_session_remove_timeout, 117439beb93cSSam Leffler data, sess); 117539beb93cSSam Leffler } 117639beb93cSSam Leffler 117739beb93cSSam Leffler return 0; 117839beb93cSSam Leffler } 117939beb93cSSam Leffler 118039beb93cSSam Leffler 118139beb93cSSam Leffler static void radius_server_receive_auth(int sock, void *eloop_ctx, 118239beb93cSSam Leffler void *sock_ctx) 118339beb93cSSam Leffler { 118439beb93cSSam Leffler struct radius_server_data *data = eloop_ctx; 118539beb93cSSam Leffler u8 *buf = NULL; 11863157ba21SRui Paulo union { 11873157ba21SRui Paulo struct sockaddr_storage ss; 11883157ba21SRui Paulo struct sockaddr_in sin; 11893157ba21SRui Paulo #ifdef CONFIG_IPV6 11903157ba21SRui Paulo struct sockaddr_in6 sin6; 11913157ba21SRui Paulo #endif /* CONFIG_IPV6 */ 11923157ba21SRui Paulo } from; 119339beb93cSSam Leffler socklen_t fromlen; 119439beb93cSSam Leffler int len; 119539beb93cSSam Leffler struct radius_client *client = NULL; 119639beb93cSSam Leffler struct radius_msg *msg = NULL; 119739beb93cSSam Leffler char abuf[50]; 119839beb93cSSam Leffler int from_port = 0; 119939beb93cSSam Leffler 120039beb93cSSam Leffler buf = os_malloc(RADIUS_MAX_MSG_LEN); 120139beb93cSSam Leffler if (buf == NULL) { 120239beb93cSSam Leffler goto fail; 120339beb93cSSam Leffler } 120439beb93cSSam Leffler 120539beb93cSSam Leffler fromlen = sizeof(from); 120639beb93cSSam Leffler len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0, 12073157ba21SRui Paulo (struct sockaddr *) &from.ss, &fromlen); 120839beb93cSSam Leffler if (len < 0) { 1209*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "recvfrom[radius_server]: %s", 1210*5b9c547cSRui Paulo strerror(errno)); 121139beb93cSSam Leffler goto fail; 121239beb93cSSam Leffler } 121339beb93cSSam Leffler 121439beb93cSSam Leffler #ifdef CONFIG_IPV6 121539beb93cSSam Leffler if (data->ipv6) { 12163157ba21SRui Paulo if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf, 12173157ba21SRui Paulo sizeof(abuf)) == NULL) 121839beb93cSSam Leffler abuf[0] = '\0'; 12193157ba21SRui Paulo from_port = ntohs(from.sin6.sin6_port); 122039beb93cSSam Leffler RADIUS_DEBUG("Received %d bytes from %s:%d", 122139beb93cSSam Leffler len, abuf, from_port); 122239beb93cSSam Leffler 122339beb93cSSam Leffler client = radius_server_get_client(data, 122439beb93cSSam Leffler (struct in_addr *) 12253157ba21SRui Paulo &from.sin6.sin6_addr, 1); 122639beb93cSSam Leffler } 122739beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 122839beb93cSSam Leffler 122939beb93cSSam Leffler if (!data->ipv6) { 12303157ba21SRui Paulo os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf)); 12313157ba21SRui Paulo from_port = ntohs(from.sin.sin_port); 123239beb93cSSam Leffler RADIUS_DEBUG("Received %d bytes from %s:%d", 123339beb93cSSam Leffler len, abuf, from_port); 123439beb93cSSam Leffler 12353157ba21SRui Paulo client = radius_server_get_client(data, &from.sin.sin_addr, 0); 123639beb93cSSam Leffler } 123739beb93cSSam Leffler 123839beb93cSSam Leffler RADIUS_DUMP("Received data", buf, len); 123939beb93cSSam Leffler 124039beb93cSSam Leffler if (client == NULL) { 124139beb93cSSam Leffler RADIUS_DEBUG("Unknown client %s - packet ignored", abuf); 124239beb93cSSam Leffler data->counters.invalid_requests++; 124339beb93cSSam Leffler goto fail; 124439beb93cSSam Leffler } 124539beb93cSSam Leffler 124639beb93cSSam Leffler msg = radius_msg_parse(buf, len); 124739beb93cSSam Leffler if (msg == NULL) { 124839beb93cSSam Leffler RADIUS_DEBUG("Parsing incoming RADIUS frame failed"); 124939beb93cSSam Leffler data->counters.malformed_access_requests++; 125039beb93cSSam Leffler client->counters.malformed_access_requests++; 125139beb93cSSam Leffler goto fail; 125239beb93cSSam Leffler } 125339beb93cSSam Leffler 125439beb93cSSam Leffler os_free(buf); 125539beb93cSSam Leffler buf = NULL; 125639beb93cSSam Leffler 125739beb93cSSam Leffler if (wpa_debug_level <= MSG_MSGDUMP) { 125839beb93cSSam Leffler radius_msg_dump(msg); 125939beb93cSSam Leffler } 126039beb93cSSam Leffler 1261e28a4053SRui Paulo if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCESS_REQUEST) { 1262e28a4053SRui Paulo RADIUS_DEBUG("Unexpected RADIUS code %d", 1263e28a4053SRui Paulo radius_msg_get_hdr(msg)->code); 126439beb93cSSam Leffler data->counters.unknown_types++; 126539beb93cSSam Leffler client->counters.unknown_types++; 126639beb93cSSam Leffler goto fail; 126739beb93cSSam Leffler } 126839beb93cSSam Leffler 126939beb93cSSam Leffler data->counters.access_requests++; 127039beb93cSSam Leffler client->counters.access_requests++; 127139beb93cSSam Leffler 127239beb93cSSam Leffler if (radius_msg_verify_msg_auth(msg, (u8 *) client->shared_secret, 127339beb93cSSam Leffler client->shared_secret_len, NULL)) { 127439beb93cSSam Leffler RADIUS_DEBUG("Invalid Message-Authenticator from %s", abuf); 127539beb93cSSam Leffler data->counters.bad_authenticators++; 127639beb93cSSam Leffler client->counters.bad_authenticators++; 127739beb93cSSam Leffler goto fail; 127839beb93cSSam Leffler } 127939beb93cSSam Leffler 128039beb93cSSam Leffler if (radius_server_request(data, msg, (struct sockaddr *) &from, 128139beb93cSSam Leffler fromlen, client, abuf, from_port, NULL) == 128239beb93cSSam Leffler -2) 128339beb93cSSam Leffler return; /* msg was stored with the session */ 128439beb93cSSam Leffler 128539beb93cSSam Leffler fail: 128639beb93cSSam Leffler radius_msg_free(msg); 128739beb93cSSam Leffler os_free(buf); 128839beb93cSSam Leffler } 128939beb93cSSam Leffler 129039beb93cSSam Leffler 1291*5b9c547cSRui Paulo static void radius_server_receive_acct(int sock, void *eloop_ctx, 1292*5b9c547cSRui Paulo void *sock_ctx) 1293*5b9c547cSRui Paulo { 1294*5b9c547cSRui Paulo struct radius_server_data *data = eloop_ctx; 1295*5b9c547cSRui Paulo u8 *buf = NULL; 1296*5b9c547cSRui Paulo union { 1297*5b9c547cSRui Paulo struct sockaddr_storage ss; 1298*5b9c547cSRui Paulo struct sockaddr_in sin; 1299*5b9c547cSRui Paulo #ifdef CONFIG_IPV6 1300*5b9c547cSRui Paulo struct sockaddr_in6 sin6; 1301*5b9c547cSRui Paulo #endif /* CONFIG_IPV6 */ 1302*5b9c547cSRui Paulo } from; 1303*5b9c547cSRui Paulo socklen_t fromlen; 1304*5b9c547cSRui Paulo int len, res; 1305*5b9c547cSRui Paulo struct radius_client *client = NULL; 1306*5b9c547cSRui Paulo struct radius_msg *msg = NULL, *resp = NULL; 1307*5b9c547cSRui Paulo char abuf[50]; 1308*5b9c547cSRui Paulo int from_port = 0; 1309*5b9c547cSRui Paulo struct radius_hdr *hdr; 1310*5b9c547cSRui Paulo struct wpabuf *rbuf; 1311*5b9c547cSRui Paulo 1312*5b9c547cSRui Paulo buf = os_malloc(RADIUS_MAX_MSG_LEN); 1313*5b9c547cSRui Paulo if (buf == NULL) { 1314*5b9c547cSRui Paulo goto fail; 1315*5b9c547cSRui Paulo } 1316*5b9c547cSRui Paulo 1317*5b9c547cSRui Paulo fromlen = sizeof(from); 1318*5b9c547cSRui Paulo len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0, 1319*5b9c547cSRui Paulo (struct sockaddr *) &from.ss, &fromlen); 1320*5b9c547cSRui Paulo if (len < 0) { 1321*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "recvfrom[radius_server]: %s", 1322*5b9c547cSRui Paulo strerror(errno)); 1323*5b9c547cSRui Paulo goto fail; 1324*5b9c547cSRui Paulo } 1325*5b9c547cSRui Paulo 1326*5b9c547cSRui Paulo #ifdef CONFIG_IPV6 1327*5b9c547cSRui Paulo if (data->ipv6) { 1328*5b9c547cSRui Paulo if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf, 1329*5b9c547cSRui Paulo sizeof(abuf)) == NULL) 1330*5b9c547cSRui Paulo abuf[0] = '\0'; 1331*5b9c547cSRui Paulo from_port = ntohs(from.sin6.sin6_port); 1332*5b9c547cSRui Paulo RADIUS_DEBUG("Received %d bytes from %s:%d", 1333*5b9c547cSRui Paulo len, abuf, from_port); 1334*5b9c547cSRui Paulo 1335*5b9c547cSRui Paulo client = radius_server_get_client(data, 1336*5b9c547cSRui Paulo (struct in_addr *) 1337*5b9c547cSRui Paulo &from.sin6.sin6_addr, 1); 1338*5b9c547cSRui Paulo } 1339*5b9c547cSRui Paulo #endif /* CONFIG_IPV6 */ 1340*5b9c547cSRui Paulo 1341*5b9c547cSRui Paulo if (!data->ipv6) { 1342*5b9c547cSRui Paulo os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf)); 1343*5b9c547cSRui Paulo from_port = ntohs(from.sin.sin_port); 1344*5b9c547cSRui Paulo RADIUS_DEBUG("Received %d bytes from %s:%d", 1345*5b9c547cSRui Paulo len, abuf, from_port); 1346*5b9c547cSRui Paulo 1347*5b9c547cSRui Paulo client = radius_server_get_client(data, &from.sin.sin_addr, 0); 1348*5b9c547cSRui Paulo } 1349*5b9c547cSRui Paulo 1350*5b9c547cSRui Paulo RADIUS_DUMP("Received data", buf, len); 1351*5b9c547cSRui Paulo 1352*5b9c547cSRui Paulo if (client == NULL) { 1353*5b9c547cSRui Paulo RADIUS_DEBUG("Unknown client %s - packet ignored", abuf); 1354*5b9c547cSRui Paulo data->counters.invalid_acct_requests++; 1355*5b9c547cSRui Paulo goto fail; 1356*5b9c547cSRui Paulo } 1357*5b9c547cSRui Paulo 1358*5b9c547cSRui Paulo msg = radius_msg_parse(buf, len); 1359*5b9c547cSRui Paulo if (msg == NULL) { 1360*5b9c547cSRui Paulo RADIUS_DEBUG("Parsing incoming RADIUS frame failed"); 1361*5b9c547cSRui Paulo data->counters.malformed_acct_requests++; 1362*5b9c547cSRui Paulo client->counters.malformed_acct_requests++; 1363*5b9c547cSRui Paulo goto fail; 1364*5b9c547cSRui Paulo } 1365*5b9c547cSRui Paulo 1366*5b9c547cSRui Paulo os_free(buf); 1367*5b9c547cSRui Paulo buf = NULL; 1368*5b9c547cSRui Paulo 1369*5b9c547cSRui Paulo if (wpa_debug_level <= MSG_MSGDUMP) { 1370*5b9c547cSRui Paulo radius_msg_dump(msg); 1371*5b9c547cSRui Paulo } 1372*5b9c547cSRui Paulo 1373*5b9c547cSRui Paulo if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_REQUEST) { 1374*5b9c547cSRui Paulo RADIUS_DEBUG("Unexpected RADIUS code %d", 1375*5b9c547cSRui Paulo radius_msg_get_hdr(msg)->code); 1376*5b9c547cSRui Paulo data->counters.unknown_acct_types++; 1377*5b9c547cSRui Paulo client->counters.unknown_acct_types++; 1378*5b9c547cSRui Paulo goto fail; 1379*5b9c547cSRui Paulo } 1380*5b9c547cSRui Paulo 1381*5b9c547cSRui Paulo data->counters.acct_requests++; 1382*5b9c547cSRui Paulo client->counters.acct_requests++; 1383*5b9c547cSRui Paulo 1384*5b9c547cSRui Paulo if (radius_msg_verify_acct_req(msg, (u8 *) client->shared_secret, 1385*5b9c547cSRui Paulo client->shared_secret_len)) { 1386*5b9c547cSRui Paulo RADIUS_DEBUG("Invalid Authenticator from %s", abuf); 1387*5b9c547cSRui Paulo data->counters.acct_bad_authenticators++; 1388*5b9c547cSRui Paulo client->counters.acct_bad_authenticators++; 1389*5b9c547cSRui Paulo goto fail; 1390*5b9c547cSRui Paulo } 1391*5b9c547cSRui Paulo 1392*5b9c547cSRui Paulo /* TODO: Write accounting information to a file or database */ 1393*5b9c547cSRui Paulo 1394*5b9c547cSRui Paulo hdr = radius_msg_get_hdr(msg); 1395*5b9c547cSRui Paulo 1396*5b9c547cSRui Paulo resp = radius_msg_new(RADIUS_CODE_ACCOUNTING_RESPONSE, hdr->identifier); 1397*5b9c547cSRui Paulo if (resp == NULL) 1398*5b9c547cSRui Paulo goto fail; 1399*5b9c547cSRui Paulo 1400*5b9c547cSRui Paulo radius_msg_finish_acct_resp(resp, (u8 *) client->shared_secret, 1401*5b9c547cSRui Paulo client->shared_secret_len, 1402*5b9c547cSRui Paulo hdr->authenticator); 1403*5b9c547cSRui Paulo 1404*5b9c547cSRui Paulo RADIUS_DEBUG("Reply to %s:%d", abuf, from_port); 1405*5b9c547cSRui Paulo if (wpa_debug_level <= MSG_MSGDUMP) { 1406*5b9c547cSRui Paulo radius_msg_dump(resp); 1407*5b9c547cSRui Paulo } 1408*5b9c547cSRui Paulo rbuf = radius_msg_get_buf(resp); 1409*5b9c547cSRui Paulo data->counters.acct_responses++; 1410*5b9c547cSRui Paulo client->counters.acct_responses++; 1411*5b9c547cSRui Paulo res = sendto(data->acct_sock, wpabuf_head(rbuf), wpabuf_len(rbuf), 0, 1412*5b9c547cSRui Paulo (struct sockaddr *) &from.ss, fromlen); 1413*5b9c547cSRui Paulo if (res < 0) { 1414*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s", 1415*5b9c547cSRui Paulo strerror(errno)); 1416*5b9c547cSRui Paulo } 1417*5b9c547cSRui Paulo 1418*5b9c547cSRui Paulo fail: 1419*5b9c547cSRui Paulo radius_msg_free(resp); 1420*5b9c547cSRui Paulo radius_msg_free(msg); 1421*5b9c547cSRui Paulo os_free(buf); 1422*5b9c547cSRui Paulo } 1423*5b9c547cSRui Paulo 1424*5b9c547cSRui Paulo 14253157ba21SRui Paulo static int radius_server_disable_pmtu_discovery(int s) 14263157ba21SRui Paulo { 14273157ba21SRui Paulo int r = -1; 14283157ba21SRui Paulo #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) 14293157ba21SRui Paulo /* Turn off Path MTU discovery on IPv4/UDP sockets. */ 14303157ba21SRui Paulo int action = IP_PMTUDISC_DONT; 14313157ba21SRui Paulo r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action, 14323157ba21SRui Paulo sizeof(action)); 14333157ba21SRui Paulo if (r == -1) 14343157ba21SRui Paulo wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: " 14353157ba21SRui Paulo "%s", strerror(errno)); 14363157ba21SRui Paulo #endif 14373157ba21SRui Paulo return r; 14383157ba21SRui Paulo } 14393157ba21SRui Paulo 14403157ba21SRui Paulo 144139beb93cSSam Leffler static int radius_server_open_socket(int port) 144239beb93cSSam Leffler { 144339beb93cSSam Leffler int s; 144439beb93cSSam Leffler struct sockaddr_in addr; 144539beb93cSSam Leffler 144639beb93cSSam Leffler s = socket(PF_INET, SOCK_DGRAM, 0); 144739beb93cSSam Leffler if (s < 0) { 1448*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "RADIUS: socket: %s", strerror(errno)); 144939beb93cSSam Leffler return -1; 145039beb93cSSam Leffler } 145139beb93cSSam Leffler 14523157ba21SRui Paulo radius_server_disable_pmtu_discovery(s); 14533157ba21SRui Paulo 145439beb93cSSam Leffler os_memset(&addr, 0, sizeof(addr)); 145539beb93cSSam Leffler addr.sin_family = AF_INET; 145639beb93cSSam Leffler addr.sin_port = htons(port); 145739beb93cSSam Leffler if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 1458*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "RADIUS: bind: %s", strerror(errno)); 145939beb93cSSam Leffler close(s); 146039beb93cSSam Leffler return -1; 146139beb93cSSam Leffler } 146239beb93cSSam Leffler 146339beb93cSSam Leffler return s; 146439beb93cSSam Leffler } 146539beb93cSSam Leffler 146639beb93cSSam Leffler 146739beb93cSSam Leffler #ifdef CONFIG_IPV6 146839beb93cSSam Leffler static int radius_server_open_socket6(int port) 146939beb93cSSam Leffler { 147039beb93cSSam Leffler int s; 147139beb93cSSam Leffler struct sockaddr_in6 addr; 147239beb93cSSam Leffler 147339beb93cSSam Leffler s = socket(PF_INET6, SOCK_DGRAM, 0); 147439beb93cSSam Leffler if (s < 0) { 1475*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "RADIUS: socket[IPv6]: %s", 1476*5b9c547cSRui Paulo strerror(errno)); 147739beb93cSSam Leffler return -1; 147839beb93cSSam Leffler } 147939beb93cSSam Leffler 148039beb93cSSam Leffler os_memset(&addr, 0, sizeof(addr)); 148139beb93cSSam Leffler addr.sin6_family = AF_INET6; 148239beb93cSSam Leffler os_memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any)); 148339beb93cSSam Leffler addr.sin6_port = htons(port); 148439beb93cSSam Leffler if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 1485*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "RADIUS: bind: %s", strerror(errno)); 148639beb93cSSam Leffler close(s); 148739beb93cSSam Leffler return -1; 148839beb93cSSam Leffler } 148939beb93cSSam Leffler 149039beb93cSSam Leffler return s; 149139beb93cSSam Leffler } 149239beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 149339beb93cSSam Leffler 149439beb93cSSam Leffler 149539beb93cSSam Leffler static void radius_server_free_sessions(struct radius_server_data *data, 149639beb93cSSam Leffler struct radius_session *sessions) 149739beb93cSSam Leffler { 149839beb93cSSam Leffler struct radius_session *session, *prev; 149939beb93cSSam Leffler 150039beb93cSSam Leffler session = sessions; 150139beb93cSSam Leffler while (session) { 150239beb93cSSam Leffler prev = session; 150339beb93cSSam Leffler session = session->next; 150439beb93cSSam Leffler radius_server_session_free(data, prev); 150539beb93cSSam Leffler } 150639beb93cSSam Leffler } 150739beb93cSSam Leffler 150839beb93cSSam Leffler 150939beb93cSSam Leffler static void radius_server_free_clients(struct radius_server_data *data, 151039beb93cSSam Leffler struct radius_client *clients) 151139beb93cSSam Leffler { 151239beb93cSSam Leffler struct radius_client *client, *prev; 151339beb93cSSam Leffler 151439beb93cSSam Leffler client = clients; 151539beb93cSSam Leffler while (client) { 151639beb93cSSam Leffler prev = client; 151739beb93cSSam Leffler client = client->next; 151839beb93cSSam Leffler 151939beb93cSSam Leffler radius_server_free_sessions(data, prev->sessions); 152039beb93cSSam Leffler os_free(prev->shared_secret); 152139beb93cSSam Leffler os_free(prev); 152239beb93cSSam Leffler } 152339beb93cSSam Leffler } 152439beb93cSSam Leffler 152539beb93cSSam Leffler 152639beb93cSSam Leffler static struct radius_client * 152739beb93cSSam Leffler radius_server_read_clients(const char *client_file, int ipv6) 152839beb93cSSam Leffler { 152939beb93cSSam Leffler FILE *f; 153039beb93cSSam Leffler const int buf_size = 1024; 153139beb93cSSam Leffler char *buf, *pos; 153239beb93cSSam Leffler struct radius_client *clients, *tail, *entry; 153339beb93cSSam Leffler int line = 0, mask, failed = 0, i; 153439beb93cSSam Leffler struct in_addr addr; 153539beb93cSSam Leffler #ifdef CONFIG_IPV6 153639beb93cSSam Leffler struct in6_addr addr6; 153739beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 153839beb93cSSam Leffler unsigned int val; 153939beb93cSSam Leffler 154039beb93cSSam Leffler f = fopen(client_file, "r"); 154139beb93cSSam Leffler if (f == NULL) { 154239beb93cSSam Leffler RADIUS_ERROR("Could not open client file '%s'", client_file); 154339beb93cSSam Leffler return NULL; 154439beb93cSSam Leffler } 154539beb93cSSam Leffler 154639beb93cSSam Leffler buf = os_malloc(buf_size); 154739beb93cSSam Leffler if (buf == NULL) { 154839beb93cSSam Leffler fclose(f); 154939beb93cSSam Leffler return NULL; 155039beb93cSSam Leffler } 155139beb93cSSam Leffler 155239beb93cSSam Leffler clients = tail = NULL; 155339beb93cSSam Leffler while (fgets(buf, buf_size, f)) { 155439beb93cSSam Leffler /* Configuration file format: 155539beb93cSSam Leffler * 192.168.1.0/24 secret 155639beb93cSSam Leffler * 192.168.1.2 secret 155739beb93cSSam Leffler * fe80::211:22ff:fe33:4455/64 secretipv6 155839beb93cSSam Leffler */ 155939beb93cSSam Leffler line++; 156039beb93cSSam Leffler buf[buf_size - 1] = '\0'; 156139beb93cSSam Leffler pos = buf; 156239beb93cSSam Leffler while (*pos != '\0' && *pos != '\n') 156339beb93cSSam Leffler pos++; 156439beb93cSSam Leffler if (*pos == '\n') 156539beb93cSSam Leffler *pos = '\0'; 156639beb93cSSam Leffler if (*buf == '\0' || *buf == '#') 156739beb93cSSam Leffler continue; 156839beb93cSSam Leffler 156939beb93cSSam Leffler pos = buf; 157039beb93cSSam Leffler while ((*pos >= '0' && *pos <= '9') || *pos == '.' || 157139beb93cSSam Leffler (*pos >= 'a' && *pos <= 'f') || *pos == ':' || 157239beb93cSSam Leffler (*pos >= 'A' && *pos <= 'F')) { 157339beb93cSSam Leffler pos++; 157439beb93cSSam Leffler } 157539beb93cSSam Leffler 157639beb93cSSam Leffler if (*pos == '\0') { 157739beb93cSSam Leffler failed = 1; 157839beb93cSSam Leffler break; 157939beb93cSSam Leffler } 158039beb93cSSam Leffler 158139beb93cSSam Leffler if (*pos == '/') { 158239beb93cSSam Leffler char *end; 158339beb93cSSam Leffler *pos++ = '\0'; 158439beb93cSSam Leffler mask = strtol(pos, &end, 10); 158539beb93cSSam Leffler if ((pos == end) || 158639beb93cSSam Leffler (mask < 0 || mask > (ipv6 ? 128 : 32))) { 158739beb93cSSam Leffler failed = 1; 158839beb93cSSam Leffler break; 158939beb93cSSam Leffler } 159039beb93cSSam Leffler pos = end; 159139beb93cSSam Leffler } else { 159239beb93cSSam Leffler mask = ipv6 ? 128 : 32; 159339beb93cSSam Leffler *pos++ = '\0'; 159439beb93cSSam Leffler } 159539beb93cSSam Leffler 159639beb93cSSam Leffler if (!ipv6 && inet_aton(buf, &addr) == 0) { 159739beb93cSSam Leffler failed = 1; 159839beb93cSSam Leffler break; 159939beb93cSSam Leffler } 160039beb93cSSam Leffler #ifdef CONFIG_IPV6 160139beb93cSSam Leffler if (ipv6 && inet_pton(AF_INET6, buf, &addr6) <= 0) { 160239beb93cSSam Leffler if (inet_pton(AF_INET, buf, &addr) <= 0) { 160339beb93cSSam Leffler failed = 1; 160439beb93cSSam Leffler break; 160539beb93cSSam Leffler } 160639beb93cSSam Leffler /* Convert IPv4 address to IPv6 */ 160739beb93cSSam Leffler if (mask <= 32) 160839beb93cSSam Leffler mask += (128 - 32); 160939beb93cSSam Leffler os_memset(addr6.s6_addr, 0, 10); 161039beb93cSSam Leffler addr6.s6_addr[10] = 0xff; 161139beb93cSSam Leffler addr6.s6_addr[11] = 0xff; 161239beb93cSSam Leffler os_memcpy(addr6.s6_addr + 12, (char *) &addr.s_addr, 161339beb93cSSam Leffler 4); 161439beb93cSSam Leffler } 161539beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 161639beb93cSSam Leffler 161739beb93cSSam Leffler while (*pos == ' ' || *pos == '\t') { 161839beb93cSSam Leffler pos++; 161939beb93cSSam Leffler } 162039beb93cSSam Leffler 162139beb93cSSam Leffler if (*pos == '\0') { 162239beb93cSSam Leffler failed = 1; 162339beb93cSSam Leffler break; 162439beb93cSSam Leffler } 162539beb93cSSam Leffler 162639beb93cSSam Leffler entry = os_zalloc(sizeof(*entry)); 162739beb93cSSam Leffler if (entry == NULL) { 162839beb93cSSam Leffler failed = 1; 162939beb93cSSam Leffler break; 163039beb93cSSam Leffler } 163139beb93cSSam Leffler entry->shared_secret = os_strdup(pos); 163239beb93cSSam Leffler if (entry->shared_secret == NULL) { 163339beb93cSSam Leffler failed = 1; 163439beb93cSSam Leffler os_free(entry); 163539beb93cSSam Leffler break; 163639beb93cSSam Leffler } 163739beb93cSSam Leffler entry->shared_secret_len = os_strlen(entry->shared_secret); 163839beb93cSSam Leffler if (!ipv6) { 1639*5b9c547cSRui Paulo entry->addr.s_addr = addr.s_addr; 164039beb93cSSam Leffler val = 0; 164139beb93cSSam Leffler for (i = 0; i < mask; i++) 164239beb93cSSam Leffler val |= 1 << (31 - i); 164339beb93cSSam Leffler entry->mask.s_addr = htonl(val); 164439beb93cSSam Leffler } 164539beb93cSSam Leffler #ifdef CONFIG_IPV6 164639beb93cSSam Leffler if (ipv6) { 164739beb93cSSam Leffler int offset = mask / 8; 164839beb93cSSam Leffler 164939beb93cSSam Leffler os_memcpy(entry->addr6.s6_addr, addr6.s6_addr, 16); 165039beb93cSSam Leffler os_memset(entry->mask6.s6_addr, 0xff, offset); 165139beb93cSSam Leffler val = 0; 165239beb93cSSam Leffler for (i = 0; i < (mask % 8); i++) 165339beb93cSSam Leffler val |= 1 << (7 - i); 165439beb93cSSam Leffler if (offset < 16) 165539beb93cSSam Leffler entry->mask6.s6_addr[offset] = val; 165639beb93cSSam Leffler } 165739beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 165839beb93cSSam Leffler 165939beb93cSSam Leffler if (tail == NULL) { 166039beb93cSSam Leffler clients = tail = entry; 166139beb93cSSam Leffler } else { 166239beb93cSSam Leffler tail->next = entry; 166339beb93cSSam Leffler tail = entry; 166439beb93cSSam Leffler } 166539beb93cSSam Leffler } 166639beb93cSSam Leffler 166739beb93cSSam Leffler if (failed) { 166839beb93cSSam Leffler RADIUS_ERROR("Invalid line %d in '%s'", line, client_file); 166939beb93cSSam Leffler radius_server_free_clients(NULL, clients); 167039beb93cSSam Leffler clients = NULL; 167139beb93cSSam Leffler } 167239beb93cSSam Leffler 167339beb93cSSam Leffler os_free(buf); 167439beb93cSSam Leffler fclose(f); 167539beb93cSSam Leffler 167639beb93cSSam Leffler return clients; 167739beb93cSSam Leffler } 167839beb93cSSam Leffler 167939beb93cSSam Leffler 1680e28a4053SRui Paulo /** 1681e28a4053SRui Paulo * radius_server_init - Initialize RADIUS server 1682e28a4053SRui Paulo * @conf: Configuration for the RADIUS server 1683e28a4053SRui Paulo * Returns: Pointer to private RADIUS server context or %NULL on failure 1684e28a4053SRui Paulo * 1685e28a4053SRui Paulo * This initializes a RADIUS server instance and returns a context pointer that 1686e28a4053SRui Paulo * will be used in other calls to the RADIUS server module. The server can be 1687e28a4053SRui Paulo * deinitialize by calling radius_server_deinit(). 1688e28a4053SRui Paulo */ 168939beb93cSSam Leffler struct radius_server_data * 169039beb93cSSam Leffler radius_server_init(struct radius_server_conf *conf) 169139beb93cSSam Leffler { 169239beb93cSSam Leffler struct radius_server_data *data; 169339beb93cSSam Leffler 169439beb93cSSam Leffler #ifndef CONFIG_IPV6 169539beb93cSSam Leffler if (conf->ipv6) { 1696*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "RADIUS server compiled without IPv6 support"); 169739beb93cSSam Leffler return NULL; 169839beb93cSSam Leffler } 169939beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 170039beb93cSSam Leffler 170139beb93cSSam Leffler data = os_zalloc(sizeof(*data)); 170239beb93cSSam Leffler if (data == NULL) 170339beb93cSSam Leffler return NULL; 170439beb93cSSam Leffler 1705*5b9c547cSRui Paulo dl_list_init(&data->erp_keys); 1706*5b9c547cSRui Paulo os_get_reltime(&data->start_time); 170739beb93cSSam Leffler data->conf_ctx = conf->conf_ctx; 170839beb93cSSam Leffler data->eap_sim_db_priv = conf->eap_sim_db_priv; 170939beb93cSSam Leffler data->ssl_ctx = conf->ssl_ctx; 1710e28a4053SRui Paulo data->msg_ctx = conf->msg_ctx; 171139beb93cSSam Leffler data->ipv6 = conf->ipv6; 171239beb93cSSam Leffler if (conf->pac_opaque_encr_key) { 171339beb93cSSam Leffler data->pac_opaque_encr_key = os_malloc(16); 171439beb93cSSam Leffler os_memcpy(data->pac_opaque_encr_key, conf->pac_opaque_encr_key, 171539beb93cSSam Leffler 16); 171639beb93cSSam Leffler } 171739beb93cSSam Leffler if (conf->eap_fast_a_id) { 171839beb93cSSam Leffler data->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len); 171939beb93cSSam Leffler if (data->eap_fast_a_id) { 172039beb93cSSam Leffler os_memcpy(data->eap_fast_a_id, conf->eap_fast_a_id, 172139beb93cSSam Leffler conf->eap_fast_a_id_len); 172239beb93cSSam Leffler data->eap_fast_a_id_len = conf->eap_fast_a_id_len; 172339beb93cSSam Leffler } 172439beb93cSSam Leffler } 172539beb93cSSam Leffler if (conf->eap_fast_a_id_info) 172639beb93cSSam Leffler data->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info); 172739beb93cSSam Leffler data->eap_fast_prov = conf->eap_fast_prov; 172839beb93cSSam Leffler data->pac_key_lifetime = conf->pac_key_lifetime; 172939beb93cSSam Leffler data->pac_key_refresh_time = conf->pac_key_refresh_time; 173039beb93cSSam Leffler data->get_eap_user = conf->get_eap_user; 173139beb93cSSam Leffler data->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind; 173239beb93cSSam Leffler data->tnc = conf->tnc; 173339beb93cSSam Leffler data->wps = conf->wps; 1734f05cddf9SRui Paulo data->pwd_group = conf->pwd_group; 1735*5b9c547cSRui Paulo data->server_id = conf->server_id; 173639beb93cSSam Leffler if (conf->eap_req_id_text) { 173739beb93cSSam Leffler data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len); 173839beb93cSSam Leffler if (data->eap_req_id_text) { 173939beb93cSSam Leffler os_memcpy(data->eap_req_id_text, conf->eap_req_id_text, 174039beb93cSSam Leffler conf->eap_req_id_text_len); 174139beb93cSSam Leffler data->eap_req_id_text_len = conf->eap_req_id_text_len; 174239beb93cSSam Leffler } 174339beb93cSSam Leffler } 1744*5b9c547cSRui Paulo data->erp = conf->erp; 1745*5b9c547cSRui Paulo data->erp_domain = conf->erp_domain; 1746*5b9c547cSRui Paulo 1747*5b9c547cSRui Paulo if (conf->subscr_remediation_url) { 1748*5b9c547cSRui Paulo data->subscr_remediation_url = 1749*5b9c547cSRui Paulo os_strdup(conf->subscr_remediation_url); 1750*5b9c547cSRui Paulo } 1751*5b9c547cSRui Paulo data->subscr_remediation_method = conf->subscr_remediation_method; 1752*5b9c547cSRui Paulo 1753*5b9c547cSRui Paulo #ifdef CONFIG_SQLITE 1754*5b9c547cSRui Paulo if (conf->sqlite_file) { 1755*5b9c547cSRui Paulo if (sqlite3_open(conf->sqlite_file, &data->db)) { 1756*5b9c547cSRui Paulo RADIUS_ERROR("Could not open SQLite file '%s'", 1757*5b9c547cSRui Paulo conf->sqlite_file); 1758*5b9c547cSRui Paulo radius_server_deinit(data); 1759*5b9c547cSRui Paulo return NULL; 1760*5b9c547cSRui Paulo } 1761*5b9c547cSRui Paulo } 1762*5b9c547cSRui Paulo #endif /* CONFIG_SQLITE */ 176339beb93cSSam Leffler 1764f05cddf9SRui Paulo #ifdef CONFIG_RADIUS_TEST 1765f05cddf9SRui Paulo if (conf->dump_msk_file) 1766f05cddf9SRui Paulo data->dump_msk_file = os_strdup(conf->dump_msk_file); 1767f05cddf9SRui Paulo #endif /* CONFIG_RADIUS_TEST */ 1768f05cddf9SRui Paulo 176939beb93cSSam Leffler data->clients = radius_server_read_clients(conf->client_file, 177039beb93cSSam Leffler conf->ipv6); 177139beb93cSSam Leffler if (data->clients == NULL) { 1772*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "No RADIUS clients configured"); 177339beb93cSSam Leffler radius_server_deinit(data); 177439beb93cSSam Leffler return NULL; 177539beb93cSSam Leffler } 177639beb93cSSam Leffler 177739beb93cSSam Leffler #ifdef CONFIG_IPV6 177839beb93cSSam Leffler if (conf->ipv6) 177939beb93cSSam Leffler data->auth_sock = radius_server_open_socket6(conf->auth_port); 178039beb93cSSam Leffler else 178139beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 178239beb93cSSam Leffler data->auth_sock = radius_server_open_socket(conf->auth_port); 178339beb93cSSam Leffler if (data->auth_sock < 0) { 1784*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS authentication server"); 178539beb93cSSam Leffler radius_server_deinit(data); 178639beb93cSSam Leffler return NULL; 178739beb93cSSam Leffler } 178839beb93cSSam Leffler if (eloop_register_read_sock(data->auth_sock, 178939beb93cSSam Leffler radius_server_receive_auth, 179039beb93cSSam Leffler data, NULL)) { 179139beb93cSSam Leffler radius_server_deinit(data); 179239beb93cSSam Leffler return NULL; 179339beb93cSSam Leffler } 179439beb93cSSam Leffler 1795*5b9c547cSRui Paulo if (conf->acct_port) { 1796*5b9c547cSRui Paulo #ifdef CONFIG_IPV6 1797*5b9c547cSRui Paulo if (conf->ipv6) 1798*5b9c547cSRui Paulo data->acct_sock = radius_server_open_socket6( 1799*5b9c547cSRui Paulo conf->acct_port); 1800*5b9c547cSRui Paulo else 1801*5b9c547cSRui Paulo #endif /* CONFIG_IPV6 */ 1802*5b9c547cSRui Paulo data->acct_sock = radius_server_open_socket(conf->acct_port); 1803*5b9c547cSRui Paulo if (data->acct_sock < 0) { 1804*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS accounting server"); 1805*5b9c547cSRui Paulo radius_server_deinit(data); 1806*5b9c547cSRui Paulo return NULL; 1807*5b9c547cSRui Paulo } 1808*5b9c547cSRui Paulo if (eloop_register_read_sock(data->acct_sock, 1809*5b9c547cSRui Paulo radius_server_receive_acct, 1810*5b9c547cSRui Paulo data, NULL)) { 1811*5b9c547cSRui Paulo radius_server_deinit(data); 1812*5b9c547cSRui Paulo return NULL; 1813*5b9c547cSRui Paulo } 1814*5b9c547cSRui Paulo } else { 1815*5b9c547cSRui Paulo data->acct_sock = -1; 1816*5b9c547cSRui Paulo } 1817*5b9c547cSRui Paulo 181839beb93cSSam Leffler return data; 181939beb93cSSam Leffler } 182039beb93cSSam Leffler 182139beb93cSSam Leffler 1822e28a4053SRui Paulo /** 1823*5b9c547cSRui Paulo * radius_server_erp_flush - Flush all ERP keys 1824*5b9c547cSRui Paulo * @data: RADIUS server context from radius_server_init() 1825*5b9c547cSRui Paulo */ 1826*5b9c547cSRui Paulo void radius_server_erp_flush(struct radius_server_data *data) 1827*5b9c547cSRui Paulo { 1828*5b9c547cSRui Paulo struct eap_server_erp_key *erp; 1829*5b9c547cSRui Paulo 1830*5b9c547cSRui Paulo if (data == NULL) 1831*5b9c547cSRui Paulo return; 1832*5b9c547cSRui Paulo while ((erp = dl_list_first(&data->erp_keys, struct eap_server_erp_key, 1833*5b9c547cSRui Paulo list)) != NULL) { 1834*5b9c547cSRui Paulo dl_list_del(&erp->list); 1835*5b9c547cSRui Paulo bin_clear_free(erp, sizeof(*erp)); 1836*5b9c547cSRui Paulo } 1837*5b9c547cSRui Paulo } 1838*5b9c547cSRui Paulo 1839*5b9c547cSRui Paulo 1840*5b9c547cSRui Paulo /** 1841e28a4053SRui Paulo * radius_server_deinit - Deinitialize RADIUS server 1842e28a4053SRui Paulo * @data: RADIUS server context from radius_server_init() 1843e28a4053SRui Paulo */ 184439beb93cSSam Leffler void radius_server_deinit(struct radius_server_data *data) 184539beb93cSSam Leffler { 184639beb93cSSam Leffler if (data == NULL) 184739beb93cSSam Leffler return; 184839beb93cSSam Leffler 184939beb93cSSam Leffler if (data->auth_sock >= 0) { 185039beb93cSSam Leffler eloop_unregister_read_sock(data->auth_sock); 185139beb93cSSam Leffler close(data->auth_sock); 185239beb93cSSam Leffler } 185339beb93cSSam Leffler 1854*5b9c547cSRui Paulo if (data->acct_sock >= 0) { 1855*5b9c547cSRui Paulo eloop_unregister_read_sock(data->acct_sock); 1856*5b9c547cSRui Paulo close(data->acct_sock); 1857*5b9c547cSRui Paulo } 1858*5b9c547cSRui Paulo 185939beb93cSSam Leffler radius_server_free_clients(data, data->clients); 186039beb93cSSam Leffler 186139beb93cSSam Leffler os_free(data->pac_opaque_encr_key); 186239beb93cSSam Leffler os_free(data->eap_fast_a_id); 186339beb93cSSam Leffler os_free(data->eap_fast_a_id_info); 186439beb93cSSam Leffler os_free(data->eap_req_id_text); 1865f05cddf9SRui Paulo #ifdef CONFIG_RADIUS_TEST 1866f05cddf9SRui Paulo os_free(data->dump_msk_file); 1867f05cddf9SRui Paulo #endif /* CONFIG_RADIUS_TEST */ 1868*5b9c547cSRui Paulo os_free(data->subscr_remediation_url); 1869*5b9c547cSRui Paulo 1870*5b9c547cSRui Paulo #ifdef CONFIG_SQLITE 1871*5b9c547cSRui Paulo if (data->db) 1872*5b9c547cSRui Paulo sqlite3_close(data->db); 1873*5b9c547cSRui Paulo #endif /* CONFIG_SQLITE */ 1874*5b9c547cSRui Paulo 1875*5b9c547cSRui Paulo radius_server_erp_flush(data); 1876*5b9c547cSRui Paulo 187739beb93cSSam Leffler os_free(data); 187839beb93cSSam Leffler } 187939beb93cSSam Leffler 188039beb93cSSam Leffler 1881e28a4053SRui Paulo /** 1882e28a4053SRui Paulo * radius_server_get_mib - Get RADIUS server MIB information 1883e28a4053SRui Paulo * @data: RADIUS server context from radius_server_init() 1884e28a4053SRui Paulo * @buf: Buffer for returning the MIB data in text format 1885e28a4053SRui Paulo * @buflen: buf length in octets 1886e28a4053SRui Paulo * Returns: Number of octets written into buf 1887e28a4053SRui Paulo */ 188839beb93cSSam Leffler int radius_server_get_mib(struct radius_server_data *data, char *buf, 188939beb93cSSam Leffler size_t buflen) 189039beb93cSSam Leffler { 189139beb93cSSam Leffler int ret, uptime; 189239beb93cSSam Leffler unsigned int idx; 189339beb93cSSam Leffler char *end, *pos; 1894*5b9c547cSRui Paulo struct os_reltime now; 189539beb93cSSam Leffler struct radius_client *cli; 189639beb93cSSam Leffler 189739beb93cSSam Leffler /* RFC 2619 - RADIUS Authentication Server MIB */ 189839beb93cSSam Leffler 189939beb93cSSam Leffler if (data == NULL || buflen == 0) 190039beb93cSSam Leffler return 0; 190139beb93cSSam Leffler 190239beb93cSSam Leffler pos = buf; 190339beb93cSSam Leffler end = buf + buflen; 190439beb93cSSam Leffler 1905*5b9c547cSRui Paulo os_get_reltime(&now); 190639beb93cSSam Leffler uptime = (now.sec - data->start_time.sec) * 100 + 190739beb93cSSam Leffler ((now.usec - data->start_time.usec) / 10000) % 100; 190839beb93cSSam Leffler ret = os_snprintf(pos, end - pos, 190939beb93cSSam Leffler "RADIUS-AUTH-SERVER-MIB\n" 191039beb93cSSam Leffler "radiusAuthServIdent=hostapd\n" 191139beb93cSSam Leffler "radiusAuthServUpTime=%d\n" 191239beb93cSSam Leffler "radiusAuthServResetTime=0\n" 191339beb93cSSam Leffler "radiusAuthServConfigReset=4\n", 191439beb93cSSam Leffler uptime); 1915*5b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret)) { 191639beb93cSSam Leffler *pos = '\0'; 191739beb93cSSam Leffler return pos - buf; 191839beb93cSSam Leffler } 191939beb93cSSam Leffler pos += ret; 192039beb93cSSam Leffler 192139beb93cSSam Leffler ret = os_snprintf(pos, end - pos, 192239beb93cSSam Leffler "radiusAuthServTotalAccessRequests=%u\n" 192339beb93cSSam Leffler "radiusAuthServTotalInvalidRequests=%u\n" 192439beb93cSSam Leffler "radiusAuthServTotalDupAccessRequests=%u\n" 192539beb93cSSam Leffler "radiusAuthServTotalAccessAccepts=%u\n" 192639beb93cSSam Leffler "radiusAuthServTotalAccessRejects=%u\n" 192739beb93cSSam Leffler "radiusAuthServTotalAccessChallenges=%u\n" 192839beb93cSSam Leffler "radiusAuthServTotalMalformedAccessRequests=%u\n" 192939beb93cSSam Leffler "radiusAuthServTotalBadAuthenticators=%u\n" 193039beb93cSSam Leffler "radiusAuthServTotalPacketsDropped=%u\n" 1931*5b9c547cSRui Paulo "radiusAuthServTotalUnknownTypes=%u\n" 1932*5b9c547cSRui Paulo "radiusAccServTotalRequests=%u\n" 1933*5b9c547cSRui Paulo "radiusAccServTotalInvalidRequests=%u\n" 1934*5b9c547cSRui Paulo "radiusAccServTotalResponses=%u\n" 1935*5b9c547cSRui Paulo "radiusAccServTotalMalformedRequests=%u\n" 1936*5b9c547cSRui Paulo "radiusAccServTotalBadAuthenticators=%u\n" 1937*5b9c547cSRui Paulo "radiusAccServTotalUnknownTypes=%u\n", 193839beb93cSSam Leffler data->counters.access_requests, 193939beb93cSSam Leffler data->counters.invalid_requests, 194039beb93cSSam Leffler data->counters.dup_access_requests, 194139beb93cSSam Leffler data->counters.access_accepts, 194239beb93cSSam Leffler data->counters.access_rejects, 194339beb93cSSam Leffler data->counters.access_challenges, 194439beb93cSSam Leffler data->counters.malformed_access_requests, 194539beb93cSSam Leffler data->counters.bad_authenticators, 194639beb93cSSam Leffler data->counters.packets_dropped, 1947*5b9c547cSRui Paulo data->counters.unknown_types, 1948*5b9c547cSRui Paulo data->counters.acct_requests, 1949*5b9c547cSRui Paulo data->counters.invalid_acct_requests, 1950*5b9c547cSRui Paulo data->counters.acct_responses, 1951*5b9c547cSRui Paulo data->counters.malformed_acct_requests, 1952*5b9c547cSRui Paulo data->counters.acct_bad_authenticators, 1953*5b9c547cSRui Paulo data->counters.unknown_acct_types); 1954*5b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret)) { 195539beb93cSSam Leffler *pos = '\0'; 195639beb93cSSam Leffler return pos - buf; 195739beb93cSSam Leffler } 195839beb93cSSam Leffler pos += ret; 195939beb93cSSam Leffler 196039beb93cSSam Leffler for (cli = data->clients, idx = 0; cli; cli = cli->next, idx++) { 196139beb93cSSam Leffler char abuf[50], mbuf[50]; 196239beb93cSSam Leffler #ifdef CONFIG_IPV6 196339beb93cSSam Leffler if (data->ipv6) { 196439beb93cSSam Leffler if (inet_ntop(AF_INET6, &cli->addr6, abuf, 196539beb93cSSam Leffler sizeof(abuf)) == NULL) 196639beb93cSSam Leffler abuf[0] = '\0'; 1967*5b9c547cSRui Paulo if (inet_ntop(AF_INET6, &cli->mask6, mbuf, 196839beb93cSSam Leffler sizeof(mbuf)) == NULL) 196939beb93cSSam Leffler mbuf[0] = '\0'; 197039beb93cSSam Leffler } 197139beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 197239beb93cSSam Leffler if (!data->ipv6) { 197339beb93cSSam Leffler os_strlcpy(abuf, inet_ntoa(cli->addr), sizeof(abuf)); 197439beb93cSSam Leffler os_strlcpy(mbuf, inet_ntoa(cli->mask), sizeof(mbuf)); 197539beb93cSSam Leffler } 197639beb93cSSam Leffler 197739beb93cSSam Leffler ret = os_snprintf(pos, end - pos, 197839beb93cSSam Leffler "radiusAuthClientIndex=%u\n" 197939beb93cSSam Leffler "radiusAuthClientAddress=%s/%s\n" 198039beb93cSSam Leffler "radiusAuthServAccessRequests=%u\n" 198139beb93cSSam Leffler "radiusAuthServDupAccessRequests=%u\n" 198239beb93cSSam Leffler "radiusAuthServAccessAccepts=%u\n" 198339beb93cSSam Leffler "radiusAuthServAccessRejects=%u\n" 198439beb93cSSam Leffler "radiusAuthServAccessChallenges=%u\n" 198539beb93cSSam Leffler "radiusAuthServMalformedAccessRequests=%u\n" 198639beb93cSSam Leffler "radiusAuthServBadAuthenticators=%u\n" 198739beb93cSSam Leffler "radiusAuthServPacketsDropped=%u\n" 1988*5b9c547cSRui Paulo "radiusAuthServUnknownTypes=%u\n" 1989*5b9c547cSRui Paulo "radiusAccServTotalRequests=%u\n" 1990*5b9c547cSRui Paulo "radiusAccServTotalInvalidRequests=%u\n" 1991*5b9c547cSRui Paulo "radiusAccServTotalResponses=%u\n" 1992*5b9c547cSRui Paulo "radiusAccServTotalMalformedRequests=%u\n" 1993*5b9c547cSRui Paulo "radiusAccServTotalBadAuthenticators=%u\n" 1994*5b9c547cSRui Paulo "radiusAccServTotalUnknownTypes=%u\n", 199539beb93cSSam Leffler idx, 199639beb93cSSam Leffler abuf, mbuf, 199739beb93cSSam Leffler cli->counters.access_requests, 199839beb93cSSam Leffler cli->counters.dup_access_requests, 199939beb93cSSam Leffler cli->counters.access_accepts, 200039beb93cSSam Leffler cli->counters.access_rejects, 200139beb93cSSam Leffler cli->counters.access_challenges, 200239beb93cSSam Leffler cli->counters.malformed_access_requests, 200339beb93cSSam Leffler cli->counters.bad_authenticators, 200439beb93cSSam Leffler cli->counters.packets_dropped, 2005*5b9c547cSRui Paulo cli->counters.unknown_types, 2006*5b9c547cSRui Paulo cli->counters.acct_requests, 2007*5b9c547cSRui Paulo cli->counters.invalid_acct_requests, 2008*5b9c547cSRui Paulo cli->counters.acct_responses, 2009*5b9c547cSRui Paulo cli->counters.malformed_acct_requests, 2010*5b9c547cSRui Paulo cli->counters.acct_bad_authenticators, 2011*5b9c547cSRui Paulo cli->counters.unknown_acct_types); 2012*5b9c547cSRui Paulo if (os_snprintf_error(end - pos, ret)) { 201339beb93cSSam Leffler *pos = '\0'; 201439beb93cSSam Leffler return pos - buf; 201539beb93cSSam Leffler } 201639beb93cSSam Leffler pos += ret; 201739beb93cSSam Leffler } 201839beb93cSSam Leffler 201939beb93cSSam Leffler return pos - buf; 202039beb93cSSam Leffler } 202139beb93cSSam Leffler 202239beb93cSSam Leffler 202339beb93cSSam Leffler static int radius_server_get_eap_user(void *ctx, const u8 *identity, 202439beb93cSSam Leffler size_t identity_len, int phase2, 202539beb93cSSam Leffler struct eap_user *user) 202639beb93cSSam Leffler { 202739beb93cSSam Leffler struct radius_session *sess = ctx; 202839beb93cSSam Leffler struct radius_server_data *data = sess->server; 2029*5b9c547cSRui Paulo int ret; 203039beb93cSSam Leffler 2031*5b9c547cSRui Paulo ret = data->get_eap_user(data->conf_ctx, identity, identity_len, 203239beb93cSSam Leffler phase2, user); 2033*5b9c547cSRui Paulo if (ret == 0 && user) { 2034*5b9c547cSRui Paulo sess->accept_attr = user->accept_attr; 2035*5b9c547cSRui Paulo sess->remediation = user->remediation; 2036*5b9c547cSRui Paulo sess->macacl = user->macacl; 2037*5b9c547cSRui Paulo } 2038*5b9c547cSRui Paulo return ret; 203939beb93cSSam Leffler } 204039beb93cSSam Leffler 204139beb93cSSam Leffler 204239beb93cSSam Leffler static const char * radius_server_get_eap_req_id_text(void *ctx, size_t *len) 204339beb93cSSam Leffler { 204439beb93cSSam Leffler struct radius_session *sess = ctx; 204539beb93cSSam Leffler struct radius_server_data *data = sess->server; 204639beb93cSSam Leffler *len = data->eap_req_id_text_len; 204739beb93cSSam Leffler return data->eap_req_id_text; 204839beb93cSSam Leffler } 204939beb93cSSam Leffler 205039beb93cSSam Leffler 2051*5b9c547cSRui Paulo static void radius_server_log_msg(void *ctx, const char *msg) 2052*5b9c547cSRui Paulo { 2053*5b9c547cSRui Paulo struct radius_session *sess = ctx; 2054*5b9c547cSRui Paulo srv_log(sess, "EAP: %s", msg); 2055*5b9c547cSRui Paulo } 2056*5b9c547cSRui Paulo 2057*5b9c547cSRui Paulo 2058*5b9c547cSRui Paulo #ifdef CONFIG_ERP 2059*5b9c547cSRui Paulo 2060*5b9c547cSRui Paulo static const char * radius_server_get_erp_domain(void *ctx) 2061*5b9c547cSRui Paulo { 2062*5b9c547cSRui Paulo struct radius_session *sess = ctx; 2063*5b9c547cSRui Paulo struct radius_server_data *data = sess->server; 2064*5b9c547cSRui Paulo 2065*5b9c547cSRui Paulo return data->erp_domain; 2066*5b9c547cSRui Paulo } 2067*5b9c547cSRui Paulo 2068*5b9c547cSRui Paulo 2069*5b9c547cSRui Paulo static struct eap_server_erp_key * 2070*5b9c547cSRui Paulo radius_server_erp_get_key(void *ctx, const char *keyname) 2071*5b9c547cSRui Paulo { 2072*5b9c547cSRui Paulo struct radius_session *sess = ctx; 2073*5b9c547cSRui Paulo struct radius_server_data *data = sess->server; 2074*5b9c547cSRui Paulo struct eap_server_erp_key *erp; 2075*5b9c547cSRui Paulo 2076*5b9c547cSRui Paulo dl_list_for_each(erp, &data->erp_keys, struct eap_server_erp_key, 2077*5b9c547cSRui Paulo list) { 2078*5b9c547cSRui Paulo if (os_strcmp(erp->keyname_nai, keyname) == 0) 2079*5b9c547cSRui Paulo return erp; 2080*5b9c547cSRui Paulo } 2081*5b9c547cSRui Paulo 2082*5b9c547cSRui Paulo return NULL; 2083*5b9c547cSRui Paulo } 2084*5b9c547cSRui Paulo 2085*5b9c547cSRui Paulo 2086*5b9c547cSRui Paulo static int radius_server_erp_add_key(void *ctx, struct eap_server_erp_key *erp) 2087*5b9c547cSRui Paulo { 2088*5b9c547cSRui Paulo struct radius_session *sess = ctx; 2089*5b9c547cSRui Paulo struct radius_server_data *data = sess->server; 2090*5b9c547cSRui Paulo 2091*5b9c547cSRui Paulo dl_list_add(&data->erp_keys, &erp->list); 2092*5b9c547cSRui Paulo return 0; 2093*5b9c547cSRui Paulo } 2094*5b9c547cSRui Paulo 2095*5b9c547cSRui Paulo #endif /* CONFIG_ERP */ 2096*5b9c547cSRui Paulo 2097*5b9c547cSRui Paulo 209839beb93cSSam Leffler static struct eapol_callbacks radius_server_eapol_cb = 209939beb93cSSam Leffler { 210039beb93cSSam Leffler .get_eap_user = radius_server_get_eap_user, 210139beb93cSSam Leffler .get_eap_req_id_text = radius_server_get_eap_req_id_text, 2102*5b9c547cSRui Paulo .log_msg = radius_server_log_msg, 2103*5b9c547cSRui Paulo #ifdef CONFIG_ERP 2104*5b9c547cSRui Paulo .get_erp_send_reauth_start = NULL, 2105*5b9c547cSRui Paulo .get_erp_domain = radius_server_get_erp_domain, 2106*5b9c547cSRui Paulo .erp_get_key = radius_server_erp_get_key, 2107*5b9c547cSRui Paulo .erp_add_key = radius_server_erp_add_key, 2108*5b9c547cSRui Paulo #endif /* CONFIG_ERP */ 210939beb93cSSam Leffler }; 211039beb93cSSam Leffler 211139beb93cSSam Leffler 2112e28a4053SRui Paulo /** 2113e28a4053SRui Paulo * radius_server_eap_pending_cb - Pending EAP data notification 2114e28a4053SRui Paulo * @data: RADIUS server context from radius_server_init() 2115e28a4053SRui Paulo * @ctx: Pending EAP context pointer 2116e28a4053SRui Paulo * 2117e28a4053SRui Paulo * This function is used to notify EAP server module that a pending operation 2118e28a4053SRui Paulo * has been completed and processing of the EAP session can proceed. 2119e28a4053SRui Paulo */ 212039beb93cSSam Leffler void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx) 212139beb93cSSam Leffler { 212239beb93cSSam Leffler struct radius_client *cli; 212339beb93cSSam Leffler struct radius_session *s, *sess = NULL; 212439beb93cSSam Leffler struct radius_msg *msg; 212539beb93cSSam Leffler 212639beb93cSSam Leffler if (data == NULL) 212739beb93cSSam Leffler return; 212839beb93cSSam Leffler 212939beb93cSSam Leffler for (cli = data->clients; cli; cli = cli->next) { 213039beb93cSSam Leffler for (s = cli->sessions; s; s = s->next) { 213139beb93cSSam Leffler if (s->eap == ctx && s->last_msg) { 213239beb93cSSam Leffler sess = s; 213339beb93cSSam Leffler break; 213439beb93cSSam Leffler } 213539beb93cSSam Leffler } 213639beb93cSSam Leffler if (sess) 213739beb93cSSam Leffler break; 213839beb93cSSam Leffler } 213939beb93cSSam Leffler 214039beb93cSSam Leffler if (sess == NULL) { 214139beb93cSSam Leffler RADIUS_DEBUG("No session matched callback ctx"); 214239beb93cSSam Leffler return; 214339beb93cSSam Leffler } 214439beb93cSSam Leffler 214539beb93cSSam Leffler msg = sess->last_msg; 214639beb93cSSam Leffler sess->last_msg = NULL; 214739beb93cSSam Leffler eap_sm_pending_cb(sess->eap); 214839beb93cSSam Leffler if (radius_server_request(data, msg, 214939beb93cSSam Leffler (struct sockaddr *) &sess->last_from, 215039beb93cSSam Leffler sess->last_fromlen, cli, 215139beb93cSSam Leffler sess->last_from_addr, 215239beb93cSSam Leffler sess->last_from_port, sess) == -2) 215339beb93cSSam Leffler return; /* msg was stored with the session */ 215439beb93cSSam Leffler 215539beb93cSSam Leffler radius_msg_free(msg); 215639beb93cSSam Leffler } 2157