139beb93cSSam Leffler /* 2*e28a4053SRui Paulo * RADIUS authentication server 3*e28a4053SRui Paulo * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 539beb93cSSam Leffler * This program is free software; you can redistribute it and/or modify 639beb93cSSam Leffler * it under the terms of the GNU General Public License version 2 as 739beb93cSSam Leffler * published by the Free Software Foundation. 839beb93cSSam Leffler * 939beb93cSSam Leffler * Alternatively, this software may be distributed under the terms of BSD 1039beb93cSSam Leffler * license. 1139beb93cSSam Leffler * 1239beb93cSSam Leffler * See README and COPYING for more details. 1339beb93cSSam Leffler */ 1439beb93cSSam Leffler 1539beb93cSSam Leffler #include "includes.h" 1639beb93cSSam Leffler #include <net/if.h> 1739beb93cSSam Leffler 1839beb93cSSam Leffler #include "common.h" 1939beb93cSSam Leffler #include "radius.h" 2039beb93cSSam Leffler #include "eloop.h" 2139beb93cSSam Leffler #include "eap_server/eap.h" 2239beb93cSSam Leffler #include "radius_server.h" 2339beb93cSSam Leffler 24*e28a4053SRui Paulo /** 25*e28a4053SRui Paulo * RADIUS_SESSION_TIMEOUT - Session timeout in seconds 26*e28a4053SRui Paulo */ 2739beb93cSSam Leffler #define RADIUS_SESSION_TIMEOUT 60 28*e28a4053SRui Paulo 29*e28a4053SRui Paulo /** 30*e28a4053SRui Paulo * RADIUS_MAX_SESSION - Maximum number of active sessions 31*e28a4053SRui Paulo */ 3239beb93cSSam Leffler #define RADIUS_MAX_SESSION 100 33*e28a4053SRui Paulo 34*e28a4053SRui Paulo /** 35*e28a4053SRui Paulo * RADIUS_MAX_MSG_LEN - Maximum message length for incoming RADIUS messages 36*e28a4053SRui Paulo */ 3739beb93cSSam Leffler #define RADIUS_MAX_MSG_LEN 3000 3839beb93cSSam Leffler 3939beb93cSSam Leffler static struct eapol_callbacks radius_server_eapol_cb; 4039beb93cSSam Leffler 4139beb93cSSam Leffler struct radius_client; 4239beb93cSSam Leffler struct radius_server_data; 4339beb93cSSam Leffler 44*e28a4053SRui Paulo /** 45*e28a4053SRui Paulo * struct radius_server_counters - RADIUS server statistics counters 46*e28a4053SRui Paulo */ 4739beb93cSSam Leffler struct radius_server_counters { 4839beb93cSSam Leffler u32 access_requests; 4939beb93cSSam Leffler u32 invalid_requests; 5039beb93cSSam Leffler u32 dup_access_requests; 5139beb93cSSam Leffler u32 access_accepts; 5239beb93cSSam Leffler u32 access_rejects; 5339beb93cSSam Leffler u32 access_challenges; 5439beb93cSSam Leffler u32 malformed_access_requests; 5539beb93cSSam Leffler u32 bad_authenticators; 5639beb93cSSam Leffler u32 packets_dropped; 5739beb93cSSam Leffler u32 unknown_types; 5839beb93cSSam Leffler }; 5939beb93cSSam Leffler 60*e28a4053SRui Paulo /** 61*e28a4053SRui Paulo * struct radius_session - Internal RADIUS server data for a session 62*e28a4053SRui Paulo */ 6339beb93cSSam Leffler struct radius_session { 6439beb93cSSam Leffler struct radius_session *next; 6539beb93cSSam Leffler struct radius_client *client; 6639beb93cSSam Leffler struct radius_server_data *server; 6739beb93cSSam Leffler unsigned int sess_id; 6839beb93cSSam Leffler struct eap_sm *eap; 6939beb93cSSam Leffler struct eap_eapol_interface *eap_if; 7039beb93cSSam Leffler 7139beb93cSSam Leffler struct radius_msg *last_msg; 7239beb93cSSam Leffler char *last_from_addr; 7339beb93cSSam Leffler int last_from_port; 7439beb93cSSam Leffler struct sockaddr_storage last_from; 7539beb93cSSam Leffler socklen_t last_fromlen; 7639beb93cSSam Leffler u8 last_identifier; 7739beb93cSSam Leffler struct radius_msg *last_reply; 7839beb93cSSam Leffler u8 last_authenticator[16]; 7939beb93cSSam Leffler }; 8039beb93cSSam Leffler 81*e28a4053SRui Paulo /** 82*e28a4053SRui Paulo * struct radius_client - Internal RADIUS server data for a client 83*e28a4053SRui Paulo */ 8439beb93cSSam Leffler struct radius_client { 8539beb93cSSam Leffler struct radius_client *next; 8639beb93cSSam Leffler struct in_addr addr; 8739beb93cSSam Leffler struct in_addr mask; 8839beb93cSSam Leffler #ifdef CONFIG_IPV6 8939beb93cSSam Leffler struct in6_addr addr6; 9039beb93cSSam Leffler struct in6_addr mask6; 9139beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 9239beb93cSSam Leffler char *shared_secret; 9339beb93cSSam Leffler int shared_secret_len; 9439beb93cSSam Leffler struct radius_session *sessions; 9539beb93cSSam Leffler struct radius_server_counters counters; 9639beb93cSSam Leffler }; 9739beb93cSSam Leffler 98*e28a4053SRui Paulo /** 99*e28a4053SRui Paulo * struct radius_server_data - Internal RADIUS server data 100*e28a4053SRui Paulo */ 10139beb93cSSam Leffler struct radius_server_data { 102*e28a4053SRui Paulo /** 103*e28a4053SRui Paulo * auth_sock - Socket for RADIUS authentication messages 104*e28a4053SRui Paulo */ 10539beb93cSSam Leffler int auth_sock; 106*e28a4053SRui Paulo 107*e28a4053SRui Paulo /** 108*e28a4053SRui Paulo * clients - List of authorized RADIUS clients 109*e28a4053SRui Paulo */ 11039beb93cSSam Leffler struct radius_client *clients; 111*e28a4053SRui Paulo 112*e28a4053SRui Paulo /** 113*e28a4053SRui Paulo * next_sess_id - Next session identifier 114*e28a4053SRui Paulo */ 11539beb93cSSam Leffler unsigned int next_sess_id; 116*e28a4053SRui Paulo 117*e28a4053SRui Paulo /** 118*e28a4053SRui Paulo * conf_ctx - Context pointer for callbacks 119*e28a4053SRui Paulo * 120*e28a4053SRui Paulo * This is used as the ctx argument in get_eap_user() calls. 121*e28a4053SRui Paulo */ 12239beb93cSSam Leffler void *conf_ctx; 123*e28a4053SRui Paulo 124*e28a4053SRui Paulo /** 125*e28a4053SRui Paulo * num_sess - Number of active sessions 126*e28a4053SRui Paulo */ 12739beb93cSSam Leffler int num_sess; 128*e28a4053SRui Paulo 129*e28a4053SRui Paulo /** 130*e28a4053SRui Paulo * eap_sim_db_priv - EAP-SIM/AKA database context 131*e28a4053SRui Paulo * 132*e28a4053SRui Paulo * This is passed to the EAP-SIM/AKA server implementation as a 133*e28a4053SRui Paulo * callback context. 134*e28a4053SRui Paulo */ 13539beb93cSSam Leffler void *eap_sim_db_priv; 136*e28a4053SRui Paulo 137*e28a4053SRui Paulo /** 138*e28a4053SRui Paulo * ssl_ctx - TLS context 139*e28a4053SRui Paulo * 140*e28a4053SRui Paulo * This is passed to the EAP server implementation as a callback 141*e28a4053SRui Paulo * context for TLS operations. 142*e28a4053SRui Paulo */ 14339beb93cSSam Leffler void *ssl_ctx; 144*e28a4053SRui Paulo 145*e28a4053SRui Paulo /** 146*e28a4053SRui Paulo * pac_opaque_encr_key - PAC-Opaque encryption key for EAP-FAST 147*e28a4053SRui Paulo * 148*e28a4053SRui Paulo * This parameter is used to set a key for EAP-FAST to encrypt the 149*e28a4053SRui Paulo * PAC-Opaque data. It can be set to %NULL if EAP-FAST is not used. If 150*e28a4053SRui Paulo * set, must point to a 16-octet key. 151*e28a4053SRui Paulo */ 15239beb93cSSam Leffler u8 *pac_opaque_encr_key; 153*e28a4053SRui Paulo 154*e28a4053SRui Paulo /** 155*e28a4053SRui Paulo * eap_fast_a_id - EAP-FAST authority identity (A-ID) 156*e28a4053SRui Paulo * 157*e28a4053SRui Paulo * If EAP-FAST is not used, this can be set to %NULL. In theory, this 158*e28a4053SRui Paulo * is a variable length field, but due to some existing implementations 159*e28a4053SRui Paulo * requiring A-ID to be 16 octets in length, it is recommended to use 160*e28a4053SRui Paulo * that length for the field to provide interoperability with deployed 161*e28a4053SRui Paulo * peer implementations. 162*e28a4053SRui Paulo */ 16339beb93cSSam Leffler u8 *eap_fast_a_id; 164*e28a4053SRui Paulo 165*e28a4053SRui Paulo /** 166*e28a4053SRui Paulo * eap_fast_a_id_len - Length of eap_fast_a_id buffer in octets 167*e28a4053SRui Paulo */ 16839beb93cSSam Leffler size_t eap_fast_a_id_len; 169*e28a4053SRui Paulo 170*e28a4053SRui Paulo /** 171*e28a4053SRui Paulo * eap_fast_a_id_info - EAP-FAST authority identifier information 172*e28a4053SRui Paulo * 173*e28a4053SRui Paulo * This A-ID-Info contains a user-friendly name for the A-ID. For 174*e28a4053SRui Paulo * example, this could be the enterprise and server names in 175*e28a4053SRui Paulo * human-readable format. This field is encoded as UTF-8. If EAP-FAST 176*e28a4053SRui Paulo * is not used, this can be set to %NULL. 177*e28a4053SRui Paulo */ 17839beb93cSSam Leffler char *eap_fast_a_id_info; 179*e28a4053SRui Paulo 180*e28a4053SRui Paulo /** 181*e28a4053SRui Paulo * eap_fast_prov - EAP-FAST provisioning modes 182*e28a4053SRui Paulo * 183*e28a4053SRui Paulo * 0 = provisioning disabled, 1 = only anonymous provisioning allowed, 184*e28a4053SRui Paulo * 2 = only authenticated provisioning allowed, 3 = both provisioning 185*e28a4053SRui Paulo * modes allowed. 186*e28a4053SRui Paulo */ 18739beb93cSSam Leffler int eap_fast_prov; 188*e28a4053SRui Paulo 189*e28a4053SRui Paulo /** 190*e28a4053SRui Paulo * pac_key_lifetime - EAP-FAST PAC-Key lifetime in seconds 191*e28a4053SRui Paulo * 192*e28a4053SRui Paulo * This is the hard limit on how long a provisioned PAC-Key can be 193*e28a4053SRui Paulo * used. 194*e28a4053SRui Paulo */ 19539beb93cSSam Leffler int pac_key_lifetime; 196*e28a4053SRui Paulo 197*e28a4053SRui Paulo /** 198*e28a4053SRui Paulo * pac_key_refresh_time - EAP-FAST PAC-Key refresh time in seconds 199*e28a4053SRui Paulo * 200*e28a4053SRui Paulo * This is a soft limit on the PAC-Key. The server will automatically 201*e28a4053SRui Paulo * generate a new PAC-Key when this number of seconds (or fewer) of the 202*e28a4053SRui Paulo * lifetime remains. 203*e28a4053SRui Paulo */ 20439beb93cSSam Leffler int pac_key_refresh_time; 205*e28a4053SRui Paulo 206*e28a4053SRui Paulo /** 207*e28a4053SRui Paulo * eap_sim_aka_result_ind - EAP-SIM/AKA protected success indication 208*e28a4053SRui Paulo * 209*e28a4053SRui Paulo * This controls whether the protected success/failure indication 210*e28a4053SRui Paulo * (AT_RESULT_IND) is used with EAP-SIM and EAP-AKA. 211*e28a4053SRui Paulo */ 21239beb93cSSam Leffler int eap_sim_aka_result_ind; 213*e28a4053SRui Paulo 214*e28a4053SRui Paulo /** 215*e28a4053SRui Paulo * tnc - Trusted Network Connect (TNC) 216*e28a4053SRui Paulo * 217*e28a4053SRui Paulo * This controls whether TNC is enabled and will be required before the 218*e28a4053SRui Paulo * peer is allowed to connect. Note: This is only used with EAP-TTLS 219*e28a4053SRui Paulo * and EAP-FAST. If any other EAP method is enabled, the peer will be 220*e28a4053SRui Paulo * allowed to connect without TNC. 221*e28a4053SRui Paulo */ 22239beb93cSSam Leffler int tnc; 223*e28a4053SRui Paulo 224*e28a4053SRui Paulo /** 225*e28a4053SRui Paulo * wps - Wi-Fi Protected Setup context 226*e28a4053SRui Paulo * 227*e28a4053SRui Paulo * If WPS is used with an external RADIUS server (which is quite 228*e28a4053SRui Paulo * unlikely configuration), this is used to provide a pointer to WPS 229*e28a4053SRui Paulo * context data. Normally, this can be set to %NULL. 230*e28a4053SRui Paulo */ 23139beb93cSSam Leffler struct wps_context *wps; 232*e28a4053SRui Paulo 233*e28a4053SRui Paulo /** 234*e28a4053SRui Paulo * ipv6 - Whether to enable IPv6 support in the RADIUS server 235*e28a4053SRui Paulo */ 23639beb93cSSam Leffler int ipv6; 237*e28a4053SRui Paulo 238*e28a4053SRui Paulo /** 239*e28a4053SRui Paulo * start_time - Timestamp of server start 240*e28a4053SRui Paulo */ 24139beb93cSSam Leffler struct os_time start_time; 242*e28a4053SRui Paulo 243*e28a4053SRui Paulo /** 244*e28a4053SRui Paulo * counters - Statistics counters for server operations 245*e28a4053SRui Paulo * 246*e28a4053SRui Paulo * These counters are the sum over all clients. 247*e28a4053SRui Paulo */ 24839beb93cSSam Leffler struct radius_server_counters counters; 249*e28a4053SRui Paulo 250*e28a4053SRui Paulo /** 251*e28a4053SRui Paulo * get_eap_user - Callback for fetching EAP user information 252*e28a4053SRui Paulo * @ctx: Context data from conf_ctx 253*e28a4053SRui Paulo * @identity: User identity 254*e28a4053SRui Paulo * @identity_len: identity buffer length in octets 255*e28a4053SRui Paulo * @phase2: Whether this is for Phase 2 identity 256*e28a4053SRui Paulo * @user: Data structure for filling in the user information 257*e28a4053SRui Paulo * Returns: 0 on success, -1 on failure 258*e28a4053SRui Paulo * 259*e28a4053SRui Paulo * This is used to fetch information from user database. The callback 260*e28a4053SRui Paulo * will fill in information about allowed EAP methods and the user 261*e28a4053SRui Paulo * password. The password field will be an allocated copy of the 262*e28a4053SRui Paulo * password data and RADIUS server will free it after use. 263*e28a4053SRui Paulo */ 26439beb93cSSam Leffler int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len, 26539beb93cSSam Leffler int phase2, struct eap_user *user); 266*e28a4053SRui Paulo 267*e28a4053SRui Paulo /** 268*e28a4053SRui Paulo * eap_req_id_text - Optional data for EAP-Request/Identity 269*e28a4053SRui Paulo * 270*e28a4053SRui Paulo * This can be used to configure an optional, displayable message that 271*e28a4053SRui Paulo * will be sent in EAP-Request/Identity. This string can contain an 272*e28a4053SRui Paulo * ASCII-0 character (nul) to separate network infromation per RFC 273*e28a4053SRui Paulo * 4284. The actual string length is explicit provided in 274*e28a4053SRui Paulo * eap_req_id_text_len since nul character will not be used as a string 275*e28a4053SRui Paulo * terminator. 276*e28a4053SRui Paulo */ 27739beb93cSSam Leffler char *eap_req_id_text; 278*e28a4053SRui Paulo 279*e28a4053SRui Paulo /** 280*e28a4053SRui Paulo * eap_req_id_text_len - Length of eap_req_id_text buffer in octets 281*e28a4053SRui Paulo */ 28239beb93cSSam Leffler size_t eap_req_id_text_len; 283*e28a4053SRui Paulo 284*e28a4053SRui Paulo /* 285*e28a4053SRui Paulo * msg_ctx - Context data for wpa_msg() calls 286*e28a4053SRui Paulo */ 287*e28a4053SRui Paulo void *msg_ctx; 28839beb93cSSam Leffler }; 28939beb93cSSam Leffler 29039beb93cSSam Leffler 29139beb93cSSam Leffler extern int wpa_debug_level; 29239beb93cSSam Leffler 29339beb93cSSam Leffler #define RADIUS_DEBUG(args...) \ 29439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "RADIUS SRV: " args) 29539beb93cSSam Leffler #define RADIUS_ERROR(args...) \ 29639beb93cSSam Leffler wpa_printf(MSG_ERROR, "RADIUS SRV: " args) 29739beb93cSSam Leffler #define RADIUS_DUMP(args...) \ 29839beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "RADIUS SRV: " args) 29939beb93cSSam Leffler #define RADIUS_DUMP_ASCII(args...) \ 30039beb93cSSam Leffler wpa_hexdump_ascii(MSG_MSGDUMP, "RADIUS SRV: " args) 30139beb93cSSam Leffler 30239beb93cSSam Leffler 30339beb93cSSam Leffler static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx); 3043157ba21SRui Paulo static void radius_server_session_remove_timeout(void *eloop_ctx, 3053157ba21SRui Paulo void *timeout_ctx); 30639beb93cSSam Leffler 30739beb93cSSam Leffler 30839beb93cSSam Leffler static struct radius_client * 30939beb93cSSam Leffler radius_server_get_client(struct radius_server_data *data, struct in_addr *addr, 31039beb93cSSam Leffler int ipv6) 31139beb93cSSam Leffler { 31239beb93cSSam Leffler struct radius_client *client = data->clients; 31339beb93cSSam Leffler 31439beb93cSSam Leffler while (client) { 31539beb93cSSam Leffler #ifdef CONFIG_IPV6 31639beb93cSSam Leffler if (ipv6) { 31739beb93cSSam Leffler struct in6_addr *addr6; 31839beb93cSSam Leffler int i; 31939beb93cSSam Leffler 32039beb93cSSam Leffler addr6 = (struct in6_addr *) addr; 32139beb93cSSam Leffler for (i = 0; i < 16; i++) { 32239beb93cSSam Leffler if ((addr6->s6_addr[i] & 32339beb93cSSam Leffler client->mask6.s6_addr[i]) != 32439beb93cSSam Leffler (client->addr6.s6_addr[i] & 32539beb93cSSam Leffler client->mask6.s6_addr[i])) { 32639beb93cSSam Leffler i = 17; 32739beb93cSSam Leffler break; 32839beb93cSSam Leffler } 32939beb93cSSam Leffler } 33039beb93cSSam Leffler if (i == 16) { 33139beb93cSSam Leffler break; 33239beb93cSSam Leffler } 33339beb93cSSam Leffler } 33439beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 33539beb93cSSam Leffler if (!ipv6 && (client->addr.s_addr & client->mask.s_addr) == 33639beb93cSSam Leffler (addr->s_addr & client->mask.s_addr)) { 33739beb93cSSam Leffler break; 33839beb93cSSam Leffler } 33939beb93cSSam Leffler 34039beb93cSSam Leffler client = client->next; 34139beb93cSSam Leffler } 34239beb93cSSam Leffler 34339beb93cSSam Leffler return client; 34439beb93cSSam Leffler } 34539beb93cSSam Leffler 34639beb93cSSam Leffler 34739beb93cSSam Leffler static struct radius_session * 34839beb93cSSam Leffler radius_server_get_session(struct radius_client *client, unsigned int sess_id) 34939beb93cSSam Leffler { 35039beb93cSSam Leffler struct radius_session *sess = client->sessions; 35139beb93cSSam Leffler 35239beb93cSSam Leffler while (sess) { 35339beb93cSSam Leffler if (sess->sess_id == sess_id) { 35439beb93cSSam Leffler break; 35539beb93cSSam Leffler } 35639beb93cSSam Leffler sess = sess->next; 35739beb93cSSam Leffler } 35839beb93cSSam Leffler 35939beb93cSSam Leffler return sess; 36039beb93cSSam Leffler } 36139beb93cSSam Leffler 36239beb93cSSam Leffler 36339beb93cSSam Leffler static void radius_server_session_free(struct radius_server_data *data, 36439beb93cSSam Leffler struct radius_session *sess) 36539beb93cSSam Leffler { 36639beb93cSSam Leffler eloop_cancel_timeout(radius_server_session_timeout, data, sess); 3673157ba21SRui Paulo eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess); 36839beb93cSSam Leffler eap_server_sm_deinit(sess->eap); 36939beb93cSSam Leffler radius_msg_free(sess->last_msg); 37039beb93cSSam Leffler os_free(sess->last_from_addr); 37139beb93cSSam Leffler radius_msg_free(sess->last_reply); 37239beb93cSSam Leffler os_free(sess); 37339beb93cSSam Leffler data->num_sess--; 37439beb93cSSam Leffler } 37539beb93cSSam Leffler 37639beb93cSSam Leffler 37739beb93cSSam Leffler static void radius_server_session_remove(struct radius_server_data *data, 37839beb93cSSam Leffler struct radius_session *sess) 37939beb93cSSam Leffler { 38039beb93cSSam Leffler struct radius_client *client = sess->client; 38139beb93cSSam Leffler struct radius_session *session, *prev; 38239beb93cSSam Leffler 38339beb93cSSam Leffler eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess); 38439beb93cSSam Leffler 38539beb93cSSam Leffler prev = NULL; 38639beb93cSSam Leffler session = client->sessions; 38739beb93cSSam Leffler while (session) { 38839beb93cSSam Leffler if (session == sess) { 38939beb93cSSam Leffler if (prev == NULL) { 39039beb93cSSam Leffler client->sessions = sess->next; 39139beb93cSSam Leffler } else { 39239beb93cSSam Leffler prev->next = sess->next; 39339beb93cSSam Leffler } 39439beb93cSSam Leffler radius_server_session_free(data, sess); 39539beb93cSSam Leffler break; 39639beb93cSSam Leffler } 39739beb93cSSam Leffler prev = session; 39839beb93cSSam Leffler session = session->next; 39939beb93cSSam Leffler } 40039beb93cSSam Leffler } 40139beb93cSSam Leffler 40239beb93cSSam Leffler 40339beb93cSSam Leffler static void radius_server_session_remove_timeout(void *eloop_ctx, 40439beb93cSSam Leffler void *timeout_ctx) 40539beb93cSSam Leffler { 40639beb93cSSam Leffler struct radius_server_data *data = eloop_ctx; 40739beb93cSSam Leffler struct radius_session *sess = timeout_ctx; 40839beb93cSSam Leffler RADIUS_DEBUG("Removing completed session 0x%x", sess->sess_id); 40939beb93cSSam Leffler radius_server_session_remove(data, sess); 41039beb93cSSam Leffler } 41139beb93cSSam Leffler 41239beb93cSSam Leffler 41339beb93cSSam Leffler static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx) 41439beb93cSSam Leffler { 41539beb93cSSam Leffler struct radius_server_data *data = eloop_ctx; 41639beb93cSSam Leffler struct radius_session *sess = timeout_ctx; 41739beb93cSSam Leffler 41839beb93cSSam Leffler RADIUS_DEBUG("Timing out authentication session 0x%x", sess->sess_id); 41939beb93cSSam Leffler radius_server_session_remove(data, sess); 42039beb93cSSam Leffler } 42139beb93cSSam Leffler 42239beb93cSSam Leffler 42339beb93cSSam Leffler static struct radius_session * 42439beb93cSSam Leffler radius_server_new_session(struct radius_server_data *data, 42539beb93cSSam Leffler struct radius_client *client) 42639beb93cSSam Leffler { 42739beb93cSSam Leffler struct radius_session *sess; 42839beb93cSSam Leffler 42939beb93cSSam Leffler if (data->num_sess >= RADIUS_MAX_SESSION) { 43039beb93cSSam Leffler RADIUS_DEBUG("Maximum number of existing session - no room " 43139beb93cSSam Leffler "for a new session"); 43239beb93cSSam Leffler return NULL; 43339beb93cSSam Leffler } 43439beb93cSSam Leffler 43539beb93cSSam Leffler sess = os_zalloc(sizeof(*sess)); 43639beb93cSSam Leffler if (sess == NULL) 43739beb93cSSam Leffler return NULL; 43839beb93cSSam Leffler 43939beb93cSSam Leffler sess->server = data; 44039beb93cSSam Leffler sess->client = client; 44139beb93cSSam Leffler sess->sess_id = data->next_sess_id++; 44239beb93cSSam Leffler sess->next = client->sessions; 44339beb93cSSam Leffler client->sessions = sess; 44439beb93cSSam Leffler eloop_register_timeout(RADIUS_SESSION_TIMEOUT, 0, 44539beb93cSSam Leffler radius_server_session_timeout, data, sess); 44639beb93cSSam Leffler data->num_sess++; 44739beb93cSSam Leffler return sess; 44839beb93cSSam Leffler } 44939beb93cSSam Leffler 45039beb93cSSam Leffler 45139beb93cSSam Leffler static struct radius_session * 45239beb93cSSam Leffler radius_server_get_new_session(struct radius_server_data *data, 45339beb93cSSam Leffler struct radius_client *client, 45439beb93cSSam Leffler struct radius_msg *msg) 45539beb93cSSam Leffler { 45639beb93cSSam Leffler u8 *user; 45739beb93cSSam Leffler size_t user_len; 45839beb93cSSam Leffler int res; 45939beb93cSSam Leffler struct radius_session *sess; 46039beb93cSSam Leffler struct eap_config eap_conf; 46139beb93cSSam Leffler 46239beb93cSSam Leffler RADIUS_DEBUG("Creating a new session"); 46339beb93cSSam Leffler 46439beb93cSSam Leffler user = os_malloc(256); 46539beb93cSSam Leffler if (user == NULL) { 46639beb93cSSam Leffler return NULL; 46739beb93cSSam Leffler } 46839beb93cSSam Leffler res = radius_msg_get_attr(msg, RADIUS_ATTR_USER_NAME, user, 256); 46939beb93cSSam Leffler if (res < 0 || res > 256) { 47039beb93cSSam Leffler RADIUS_DEBUG("Could not get User-Name"); 47139beb93cSSam Leffler os_free(user); 47239beb93cSSam Leffler return NULL; 47339beb93cSSam Leffler } 47439beb93cSSam Leffler user_len = res; 47539beb93cSSam Leffler RADIUS_DUMP_ASCII("User-Name", user, user_len); 47639beb93cSSam Leffler 47739beb93cSSam Leffler res = data->get_eap_user(data->conf_ctx, user, user_len, 0, NULL); 47839beb93cSSam Leffler os_free(user); 47939beb93cSSam Leffler 48039beb93cSSam Leffler if (res == 0) { 48139beb93cSSam Leffler RADIUS_DEBUG("Matching user entry found"); 48239beb93cSSam Leffler sess = radius_server_new_session(data, client); 48339beb93cSSam Leffler if (sess == NULL) { 48439beb93cSSam Leffler RADIUS_DEBUG("Failed to create a new session"); 48539beb93cSSam Leffler return NULL; 48639beb93cSSam Leffler } 48739beb93cSSam Leffler } else { 48839beb93cSSam Leffler RADIUS_DEBUG("User-Name not found from user database"); 48939beb93cSSam Leffler return NULL; 49039beb93cSSam Leffler } 49139beb93cSSam Leffler 49239beb93cSSam Leffler os_memset(&eap_conf, 0, sizeof(eap_conf)); 49339beb93cSSam Leffler eap_conf.ssl_ctx = data->ssl_ctx; 494*e28a4053SRui Paulo eap_conf.msg_ctx = data->msg_ctx; 49539beb93cSSam Leffler eap_conf.eap_sim_db_priv = data->eap_sim_db_priv; 49639beb93cSSam Leffler eap_conf.backend_auth = TRUE; 49739beb93cSSam Leffler eap_conf.eap_server = 1; 49839beb93cSSam Leffler eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key; 49939beb93cSSam Leffler eap_conf.eap_fast_a_id = data->eap_fast_a_id; 50039beb93cSSam Leffler eap_conf.eap_fast_a_id_len = data->eap_fast_a_id_len; 50139beb93cSSam Leffler eap_conf.eap_fast_a_id_info = data->eap_fast_a_id_info; 50239beb93cSSam Leffler eap_conf.eap_fast_prov = data->eap_fast_prov; 50339beb93cSSam Leffler eap_conf.pac_key_lifetime = data->pac_key_lifetime; 50439beb93cSSam Leffler eap_conf.pac_key_refresh_time = data->pac_key_refresh_time; 50539beb93cSSam Leffler eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind; 50639beb93cSSam Leffler eap_conf.tnc = data->tnc; 50739beb93cSSam Leffler eap_conf.wps = data->wps; 50839beb93cSSam Leffler sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb, 50939beb93cSSam Leffler &eap_conf); 51039beb93cSSam Leffler if (sess->eap == NULL) { 51139beb93cSSam Leffler RADIUS_DEBUG("Failed to initialize EAP state machine for the " 51239beb93cSSam Leffler "new session"); 51339beb93cSSam Leffler radius_server_session_free(data, sess); 51439beb93cSSam Leffler return NULL; 51539beb93cSSam Leffler } 51639beb93cSSam Leffler sess->eap_if = eap_get_interface(sess->eap); 51739beb93cSSam Leffler sess->eap_if->eapRestart = TRUE; 51839beb93cSSam Leffler sess->eap_if->portEnabled = TRUE; 51939beb93cSSam Leffler 52039beb93cSSam Leffler RADIUS_DEBUG("New session 0x%x initialized", sess->sess_id); 52139beb93cSSam Leffler 52239beb93cSSam Leffler return sess; 52339beb93cSSam Leffler } 52439beb93cSSam Leffler 52539beb93cSSam Leffler 52639beb93cSSam Leffler static struct radius_msg * 52739beb93cSSam Leffler radius_server_encapsulate_eap(struct radius_server_data *data, 52839beb93cSSam Leffler struct radius_client *client, 52939beb93cSSam Leffler struct radius_session *sess, 53039beb93cSSam Leffler struct radius_msg *request) 53139beb93cSSam Leffler { 53239beb93cSSam Leffler struct radius_msg *msg; 53339beb93cSSam Leffler int code; 53439beb93cSSam Leffler unsigned int sess_id; 535*e28a4053SRui Paulo struct radius_hdr *hdr = radius_msg_get_hdr(request); 53639beb93cSSam Leffler 53739beb93cSSam Leffler if (sess->eap_if->eapFail) { 53839beb93cSSam Leffler sess->eap_if->eapFail = FALSE; 53939beb93cSSam Leffler code = RADIUS_CODE_ACCESS_REJECT; 54039beb93cSSam Leffler } else if (sess->eap_if->eapSuccess) { 54139beb93cSSam Leffler sess->eap_if->eapSuccess = FALSE; 54239beb93cSSam Leffler code = RADIUS_CODE_ACCESS_ACCEPT; 54339beb93cSSam Leffler } else { 54439beb93cSSam Leffler sess->eap_if->eapReq = FALSE; 54539beb93cSSam Leffler code = RADIUS_CODE_ACCESS_CHALLENGE; 54639beb93cSSam Leffler } 54739beb93cSSam Leffler 548*e28a4053SRui Paulo msg = radius_msg_new(code, hdr->identifier); 54939beb93cSSam Leffler if (msg == NULL) { 55039beb93cSSam Leffler RADIUS_DEBUG("Failed to allocate reply message"); 55139beb93cSSam Leffler return NULL; 55239beb93cSSam Leffler } 55339beb93cSSam Leffler 55439beb93cSSam Leffler sess_id = htonl(sess->sess_id); 55539beb93cSSam Leffler if (code == RADIUS_CODE_ACCESS_CHALLENGE && 55639beb93cSSam Leffler !radius_msg_add_attr(msg, RADIUS_ATTR_STATE, 55739beb93cSSam Leffler (u8 *) &sess_id, sizeof(sess_id))) { 55839beb93cSSam Leffler RADIUS_DEBUG("Failed to add State attribute"); 55939beb93cSSam Leffler } 56039beb93cSSam Leffler 56139beb93cSSam Leffler if (sess->eap_if->eapReqData && 56239beb93cSSam Leffler !radius_msg_add_eap(msg, wpabuf_head(sess->eap_if->eapReqData), 56339beb93cSSam Leffler wpabuf_len(sess->eap_if->eapReqData))) { 56439beb93cSSam Leffler RADIUS_DEBUG("Failed to add EAP-Message attribute"); 56539beb93cSSam Leffler } 56639beb93cSSam Leffler 56739beb93cSSam Leffler if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) { 56839beb93cSSam Leffler int len; 56939beb93cSSam Leffler if (sess->eap_if->eapKeyDataLen > 64) { 57039beb93cSSam Leffler len = 32; 57139beb93cSSam Leffler } else { 57239beb93cSSam Leffler len = sess->eap_if->eapKeyDataLen / 2; 57339beb93cSSam Leffler } 574*e28a4053SRui Paulo if (!radius_msg_add_mppe_keys(msg, hdr->authenticator, 57539beb93cSSam Leffler (u8 *) client->shared_secret, 57639beb93cSSam Leffler client->shared_secret_len, 57739beb93cSSam Leffler sess->eap_if->eapKeyData + len, 57839beb93cSSam Leffler len, sess->eap_if->eapKeyData, 57939beb93cSSam Leffler len)) { 58039beb93cSSam Leffler RADIUS_DEBUG("Failed to add MPPE key attributes"); 58139beb93cSSam Leffler } 58239beb93cSSam Leffler } 58339beb93cSSam Leffler 58439beb93cSSam Leffler if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) { 58539beb93cSSam Leffler RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)"); 58639beb93cSSam Leffler radius_msg_free(msg); 58739beb93cSSam Leffler return NULL; 58839beb93cSSam Leffler } 58939beb93cSSam Leffler 59039beb93cSSam Leffler if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret, 59139beb93cSSam Leffler client->shared_secret_len, 592*e28a4053SRui Paulo hdr->authenticator) < 0) { 59339beb93cSSam Leffler RADIUS_DEBUG("Failed to add Message-Authenticator attribute"); 59439beb93cSSam Leffler } 59539beb93cSSam Leffler 59639beb93cSSam Leffler return msg; 59739beb93cSSam Leffler } 59839beb93cSSam Leffler 59939beb93cSSam Leffler 60039beb93cSSam Leffler static int radius_server_reject(struct radius_server_data *data, 60139beb93cSSam Leffler struct radius_client *client, 60239beb93cSSam Leffler struct radius_msg *request, 60339beb93cSSam Leffler struct sockaddr *from, socklen_t fromlen, 60439beb93cSSam Leffler const char *from_addr, int from_port) 60539beb93cSSam Leffler { 60639beb93cSSam Leffler struct radius_msg *msg; 60739beb93cSSam Leffler int ret = 0; 60839beb93cSSam Leffler struct eap_hdr eapfail; 609*e28a4053SRui Paulo struct wpabuf *buf; 610*e28a4053SRui Paulo struct radius_hdr *hdr = radius_msg_get_hdr(request); 61139beb93cSSam Leffler 61239beb93cSSam Leffler RADIUS_DEBUG("Reject invalid request from %s:%d", 61339beb93cSSam Leffler from_addr, from_port); 61439beb93cSSam Leffler 615*e28a4053SRui Paulo msg = radius_msg_new(RADIUS_CODE_ACCESS_REJECT, hdr->identifier); 61639beb93cSSam Leffler if (msg == NULL) { 61739beb93cSSam Leffler return -1; 61839beb93cSSam Leffler } 61939beb93cSSam Leffler 62039beb93cSSam Leffler os_memset(&eapfail, 0, sizeof(eapfail)); 62139beb93cSSam Leffler eapfail.code = EAP_CODE_FAILURE; 62239beb93cSSam Leffler eapfail.identifier = 0; 62339beb93cSSam Leffler eapfail.length = host_to_be16(sizeof(eapfail)); 62439beb93cSSam Leffler 62539beb93cSSam Leffler if (!radius_msg_add_eap(msg, (u8 *) &eapfail, sizeof(eapfail))) { 62639beb93cSSam Leffler RADIUS_DEBUG("Failed to add EAP-Message attribute"); 62739beb93cSSam Leffler } 62839beb93cSSam Leffler 62939beb93cSSam Leffler if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) { 63039beb93cSSam Leffler RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)"); 63139beb93cSSam Leffler radius_msg_free(msg); 63239beb93cSSam Leffler return -1; 63339beb93cSSam Leffler } 63439beb93cSSam Leffler 63539beb93cSSam Leffler if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret, 63639beb93cSSam Leffler client->shared_secret_len, 637*e28a4053SRui Paulo hdr->authenticator) < 638*e28a4053SRui Paulo 0) { 63939beb93cSSam Leffler RADIUS_DEBUG("Failed to add Message-Authenticator attribute"); 64039beb93cSSam Leffler } 64139beb93cSSam Leffler 64239beb93cSSam Leffler if (wpa_debug_level <= MSG_MSGDUMP) { 64339beb93cSSam Leffler radius_msg_dump(msg); 64439beb93cSSam Leffler } 64539beb93cSSam Leffler 64639beb93cSSam Leffler data->counters.access_rejects++; 64739beb93cSSam Leffler client->counters.access_rejects++; 648*e28a4053SRui Paulo buf = radius_msg_get_buf(msg); 649*e28a4053SRui Paulo if (sendto(data->auth_sock, wpabuf_head(buf), wpabuf_len(buf), 0, 65039beb93cSSam Leffler (struct sockaddr *) from, sizeof(*from)) < 0) { 65139beb93cSSam Leffler perror("sendto[RADIUS SRV]"); 65239beb93cSSam Leffler ret = -1; 65339beb93cSSam Leffler } 65439beb93cSSam Leffler 65539beb93cSSam Leffler radius_msg_free(msg); 65639beb93cSSam Leffler 65739beb93cSSam Leffler return ret; 65839beb93cSSam Leffler } 65939beb93cSSam Leffler 66039beb93cSSam Leffler 66139beb93cSSam Leffler static int radius_server_request(struct radius_server_data *data, 66239beb93cSSam Leffler struct radius_msg *msg, 66339beb93cSSam Leffler struct sockaddr *from, socklen_t fromlen, 66439beb93cSSam Leffler struct radius_client *client, 66539beb93cSSam Leffler const char *from_addr, int from_port, 66639beb93cSSam Leffler struct radius_session *force_sess) 66739beb93cSSam Leffler { 66839beb93cSSam Leffler u8 *eap = NULL; 66939beb93cSSam Leffler size_t eap_len; 67039beb93cSSam Leffler int res, state_included = 0; 67139beb93cSSam Leffler u8 statebuf[4]; 67239beb93cSSam Leffler unsigned int state; 67339beb93cSSam Leffler struct radius_session *sess; 67439beb93cSSam Leffler struct radius_msg *reply; 6753157ba21SRui Paulo int is_complete = 0; 67639beb93cSSam Leffler 67739beb93cSSam Leffler if (force_sess) 67839beb93cSSam Leffler sess = force_sess; 67939beb93cSSam Leffler else { 68039beb93cSSam Leffler res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf, 68139beb93cSSam Leffler sizeof(statebuf)); 68239beb93cSSam Leffler state_included = res >= 0; 68339beb93cSSam Leffler if (res == sizeof(statebuf)) { 68439beb93cSSam Leffler state = WPA_GET_BE32(statebuf); 68539beb93cSSam Leffler sess = radius_server_get_session(client, state); 68639beb93cSSam Leffler } else { 68739beb93cSSam Leffler sess = NULL; 68839beb93cSSam Leffler } 68939beb93cSSam Leffler } 69039beb93cSSam Leffler 69139beb93cSSam Leffler if (sess) { 69239beb93cSSam Leffler RADIUS_DEBUG("Request for session 0x%x", sess->sess_id); 69339beb93cSSam Leffler } else if (state_included) { 69439beb93cSSam Leffler RADIUS_DEBUG("State attribute included but no session found"); 69539beb93cSSam Leffler radius_server_reject(data, client, msg, from, fromlen, 69639beb93cSSam Leffler from_addr, from_port); 69739beb93cSSam Leffler return -1; 69839beb93cSSam Leffler } else { 69939beb93cSSam Leffler sess = radius_server_get_new_session(data, client, msg); 70039beb93cSSam Leffler if (sess == NULL) { 70139beb93cSSam Leffler RADIUS_DEBUG("Could not create a new session"); 70239beb93cSSam Leffler radius_server_reject(data, client, msg, from, fromlen, 70339beb93cSSam Leffler from_addr, from_port); 70439beb93cSSam Leffler return -1; 70539beb93cSSam Leffler } 70639beb93cSSam Leffler } 70739beb93cSSam Leffler 70839beb93cSSam Leffler if (sess->last_from_port == from_port && 709*e28a4053SRui Paulo sess->last_identifier == radius_msg_get_hdr(msg)->identifier && 710*e28a4053SRui Paulo os_memcmp(sess->last_authenticator, 711*e28a4053SRui Paulo radius_msg_get_hdr(msg)->authenticator, 16) == 0) { 71239beb93cSSam Leffler RADIUS_DEBUG("Duplicate message from %s", from_addr); 71339beb93cSSam Leffler data->counters.dup_access_requests++; 71439beb93cSSam Leffler client->counters.dup_access_requests++; 71539beb93cSSam Leffler 71639beb93cSSam Leffler if (sess->last_reply) { 717*e28a4053SRui Paulo struct wpabuf *buf; 718*e28a4053SRui Paulo buf = radius_msg_get_buf(sess->last_reply); 719*e28a4053SRui Paulo res = sendto(data->auth_sock, wpabuf_head(buf), 720*e28a4053SRui Paulo wpabuf_len(buf), 0, 72139beb93cSSam Leffler (struct sockaddr *) from, fromlen); 72239beb93cSSam Leffler if (res < 0) { 72339beb93cSSam Leffler perror("sendto[RADIUS SRV]"); 72439beb93cSSam Leffler } 72539beb93cSSam Leffler return 0; 72639beb93cSSam Leffler } 72739beb93cSSam Leffler 72839beb93cSSam Leffler RADIUS_DEBUG("No previous reply available for duplicate " 72939beb93cSSam Leffler "message"); 73039beb93cSSam Leffler return -1; 73139beb93cSSam Leffler } 73239beb93cSSam Leffler 73339beb93cSSam Leffler eap = radius_msg_get_eap(msg, &eap_len); 73439beb93cSSam Leffler if (eap == NULL) { 73539beb93cSSam Leffler RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s", 73639beb93cSSam Leffler from_addr); 73739beb93cSSam Leffler data->counters.packets_dropped++; 73839beb93cSSam Leffler client->counters.packets_dropped++; 73939beb93cSSam Leffler return -1; 74039beb93cSSam Leffler } 74139beb93cSSam Leffler 74239beb93cSSam Leffler RADIUS_DUMP("Received EAP data", eap, eap_len); 74339beb93cSSam Leffler 74439beb93cSSam Leffler /* FIX: if Code is Request, Success, or Failure, send Access-Reject; 74539beb93cSSam Leffler * RFC3579 Sect. 2.6.2. 74639beb93cSSam Leffler * Include EAP-Response/Nak with no preferred method if 74739beb93cSSam Leffler * code == request. 74839beb93cSSam Leffler * If code is not 1-4, discard the packet silently. 74939beb93cSSam Leffler * Or is this already done by the EAP state machine? */ 75039beb93cSSam Leffler 75139beb93cSSam Leffler wpabuf_free(sess->eap_if->eapRespData); 75239beb93cSSam Leffler sess->eap_if->eapRespData = wpabuf_alloc_ext_data(eap, eap_len); 75339beb93cSSam Leffler if (sess->eap_if->eapRespData == NULL) 75439beb93cSSam Leffler os_free(eap); 75539beb93cSSam Leffler eap = NULL; 75639beb93cSSam Leffler sess->eap_if->eapResp = TRUE; 75739beb93cSSam Leffler eap_server_sm_step(sess->eap); 75839beb93cSSam Leffler 75939beb93cSSam Leffler if ((sess->eap_if->eapReq || sess->eap_if->eapSuccess || 76039beb93cSSam Leffler sess->eap_if->eapFail) && sess->eap_if->eapReqData) { 76139beb93cSSam Leffler RADIUS_DUMP("EAP data from the state machine", 76239beb93cSSam Leffler wpabuf_head(sess->eap_if->eapReqData), 76339beb93cSSam Leffler wpabuf_len(sess->eap_if->eapReqData)); 76439beb93cSSam Leffler } else if (sess->eap_if->eapFail) { 76539beb93cSSam Leffler RADIUS_DEBUG("No EAP data from the state machine, but eapFail " 76639beb93cSSam Leffler "set"); 76739beb93cSSam Leffler } else if (eap_sm_method_pending(sess->eap)) { 76839beb93cSSam Leffler radius_msg_free(sess->last_msg); 76939beb93cSSam Leffler sess->last_msg = msg; 77039beb93cSSam Leffler sess->last_from_port = from_port; 77139beb93cSSam Leffler os_free(sess->last_from_addr); 77239beb93cSSam Leffler sess->last_from_addr = os_strdup(from_addr); 77339beb93cSSam Leffler sess->last_fromlen = fromlen; 77439beb93cSSam Leffler os_memcpy(&sess->last_from, from, fromlen); 77539beb93cSSam Leffler return -2; 77639beb93cSSam Leffler } else { 77739beb93cSSam Leffler RADIUS_DEBUG("No EAP data from the state machine - ignore this" 77839beb93cSSam Leffler " Access-Request silently (assuming it was a " 77939beb93cSSam Leffler "duplicate)"); 78039beb93cSSam Leffler data->counters.packets_dropped++; 78139beb93cSSam Leffler client->counters.packets_dropped++; 78239beb93cSSam Leffler return -1; 78339beb93cSSam Leffler } 78439beb93cSSam Leffler 7853157ba21SRui Paulo if (sess->eap_if->eapSuccess || sess->eap_if->eapFail) 7863157ba21SRui Paulo is_complete = 1; 7873157ba21SRui Paulo 78839beb93cSSam Leffler reply = radius_server_encapsulate_eap(data, client, sess, msg); 78939beb93cSSam Leffler 79039beb93cSSam Leffler if (reply) { 791*e28a4053SRui Paulo struct wpabuf *buf; 792*e28a4053SRui Paulo struct radius_hdr *hdr; 793*e28a4053SRui Paulo 79439beb93cSSam Leffler RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port); 79539beb93cSSam Leffler if (wpa_debug_level <= MSG_MSGDUMP) { 79639beb93cSSam Leffler radius_msg_dump(reply); 79739beb93cSSam Leffler } 79839beb93cSSam Leffler 799*e28a4053SRui Paulo switch (radius_msg_get_hdr(reply)->code) { 80039beb93cSSam Leffler case RADIUS_CODE_ACCESS_ACCEPT: 80139beb93cSSam Leffler data->counters.access_accepts++; 80239beb93cSSam Leffler client->counters.access_accepts++; 80339beb93cSSam Leffler break; 80439beb93cSSam Leffler case RADIUS_CODE_ACCESS_REJECT: 80539beb93cSSam Leffler data->counters.access_rejects++; 80639beb93cSSam Leffler client->counters.access_rejects++; 80739beb93cSSam Leffler break; 80839beb93cSSam Leffler case RADIUS_CODE_ACCESS_CHALLENGE: 80939beb93cSSam Leffler data->counters.access_challenges++; 81039beb93cSSam Leffler client->counters.access_challenges++; 81139beb93cSSam Leffler break; 81239beb93cSSam Leffler } 813*e28a4053SRui Paulo buf = radius_msg_get_buf(reply); 814*e28a4053SRui Paulo res = sendto(data->auth_sock, wpabuf_head(buf), 815*e28a4053SRui Paulo wpabuf_len(buf), 0, 81639beb93cSSam Leffler (struct sockaddr *) from, fromlen); 81739beb93cSSam Leffler if (res < 0) { 81839beb93cSSam Leffler perror("sendto[RADIUS SRV]"); 81939beb93cSSam Leffler } 82039beb93cSSam Leffler radius_msg_free(sess->last_reply); 82139beb93cSSam Leffler sess->last_reply = reply; 82239beb93cSSam Leffler sess->last_from_port = from_port; 823*e28a4053SRui Paulo hdr = radius_msg_get_hdr(msg); 824*e28a4053SRui Paulo sess->last_identifier = hdr->identifier; 825*e28a4053SRui Paulo os_memcpy(sess->last_authenticator, hdr->authenticator, 16); 82639beb93cSSam Leffler } else { 82739beb93cSSam Leffler data->counters.packets_dropped++; 82839beb93cSSam Leffler client->counters.packets_dropped++; 82939beb93cSSam Leffler } 83039beb93cSSam Leffler 8313157ba21SRui Paulo if (is_complete) { 83239beb93cSSam Leffler RADIUS_DEBUG("Removing completed session 0x%x after timeout", 83339beb93cSSam Leffler sess->sess_id); 83439beb93cSSam Leffler eloop_cancel_timeout(radius_server_session_remove_timeout, 83539beb93cSSam Leffler data, sess); 83639beb93cSSam Leffler eloop_register_timeout(10, 0, 83739beb93cSSam Leffler radius_server_session_remove_timeout, 83839beb93cSSam Leffler data, sess); 83939beb93cSSam Leffler } 84039beb93cSSam Leffler 84139beb93cSSam Leffler return 0; 84239beb93cSSam Leffler } 84339beb93cSSam Leffler 84439beb93cSSam Leffler 84539beb93cSSam Leffler static void radius_server_receive_auth(int sock, void *eloop_ctx, 84639beb93cSSam Leffler void *sock_ctx) 84739beb93cSSam Leffler { 84839beb93cSSam Leffler struct radius_server_data *data = eloop_ctx; 84939beb93cSSam Leffler u8 *buf = NULL; 8503157ba21SRui Paulo union { 8513157ba21SRui Paulo struct sockaddr_storage ss; 8523157ba21SRui Paulo struct sockaddr_in sin; 8533157ba21SRui Paulo #ifdef CONFIG_IPV6 8543157ba21SRui Paulo struct sockaddr_in6 sin6; 8553157ba21SRui Paulo #endif /* CONFIG_IPV6 */ 8563157ba21SRui Paulo } from; 85739beb93cSSam Leffler socklen_t fromlen; 85839beb93cSSam Leffler int len; 85939beb93cSSam Leffler struct radius_client *client = NULL; 86039beb93cSSam Leffler struct radius_msg *msg = NULL; 86139beb93cSSam Leffler char abuf[50]; 86239beb93cSSam Leffler int from_port = 0; 86339beb93cSSam Leffler 86439beb93cSSam Leffler buf = os_malloc(RADIUS_MAX_MSG_LEN); 86539beb93cSSam Leffler if (buf == NULL) { 86639beb93cSSam Leffler goto fail; 86739beb93cSSam Leffler } 86839beb93cSSam Leffler 86939beb93cSSam Leffler fromlen = sizeof(from); 87039beb93cSSam Leffler len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0, 8713157ba21SRui Paulo (struct sockaddr *) &from.ss, &fromlen); 87239beb93cSSam Leffler if (len < 0) { 87339beb93cSSam Leffler perror("recvfrom[radius_server]"); 87439beb93cSSam Leffler goto fail; 87539beb93cSSam Leffler } 87639beb93cSSam Leffler 87739beb93cSSam Leffler #ifdef CONFIG_IPV6 87839beb93cSSam Leffler if (data->ipv6) { 8793157ba21SRui Paulo if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf, 8803157ba21SRui Paulo sizeof(abuf)) == NULL) 88139beb93cSSam Leffler abuf[0] = '\0'; 8823157ba21SRui Paulo from_port = ntohs(from.sin6.sin6_port); 88339beb93cSSam Leffler RADIUS_DEBUG("Received %d bytes from %s:%d", 88439beb93cSSam Leffler len, abuf, from_port); 88539beb93cSSam Leffler 88639beb93cSSam Leffler client = radius_server_get_client(data, 88739beb93cSSam Leffler (struct in_addr *) 8883157ba21SRui Paulo &from.sin6.sin6_addr, 1); 88939beb93cSSam Leffler } 89039beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 89139beb93cSSam Leffler 89239beb93cSSam Leffler if (!data->ipv6) { 8933157ba21SRui Paulo os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf)); 8943157ba21SRui Paulo from_port = ntohs(from.sin.sin_port); 89539beb93cSSam Leffler RADIUS_DEBUG("Received %d bytes from %s:%d", 89639beb93cSSam Leffler len, abuf, from_port); 89739beb93cSSam Leffler 8983157ba21SRui Paulo client = radius_server_get_client(data, &from.sin.sin_addr, 0); 89939beb93cSSam Leffler } 90039beb93cSSam Leffler 90139beb93cSSam Leffler RADIUS_DUMP("Received data", buf, len); 90239beb93cSSam Leffler 90339beb93cSSam Leffler if (client == NULL) { 90439beb93cSSam Leffler RADIUS_DEBUG("Unknown client %s - packet ignored", abuf); 90539beb93cSSam Leffler data->counters.invalid_requests++; 90639beb93cSSam Leffler goto fail; 90739beb93cSSam Leffler } 90839beb93cSSam Leffler 90939beb93cSSam Leffler msg = radius_msg_parse(buf, len); 91039beb93cSSam Leffler if (msg == NULL) { 91139beb93cSSam Leffler RADIUS_DEBUG("Parsing incoming RADIUS frame failed"); 91239beb93cSSam Leffler data->counters.malformed_access_requests++; 91339beb93cSSam Leffler client->counters.malformed_access_requests++; 91439beb93cSSam Leffler goto fail; 91539beb93cSSam Leffler } 91639beb93cSSam Leffler 91739beb93cSSam Leffler os_free(buf); 91839beb93cSSam Leffler buf = NULL; 91939beb93cSSam Leffler 92039beb93cSSam Leffler if (wpa_debug_level <= MSG_MSGDUMP) { 92139beb93cSSam Leffler radius_msg_dump(msg); 92239beb93cSSam Leffler } 92339beb93cSSam Leffler 924*e28a4053SRui Paulo if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCESS_REQUEST) { 925*e28a4053SRui Paulo RADIUS_DEBUG("Unexpected RADIUS code %d", 926*e28a4053SRui Paulo radius_msg_get_hdr(msg)->code); 92739beb93cSSam Leffler data->counters.unknown_types++; 92839beb93cSSam Leffler client->counters.unknown_types++; 92939beb93cSSam Leffler goto fail; 93039beb93cSSam Leffler } 93139beb93cSSam Leffler 93239beb93cSSam Leffler data->counters.access_requests++; 93339beb93cSSam Leffler client->counters.access_requests++; 93439beb93cSSam Leffler 93539beb93cSSam Leffler if (radius_msg_verify_msg_auth(msg, (u8 *) client->shared_secret, 93639beb93cSSam Leffler client->shared_secret_len, NULL)) { 93739beb93cSSam Leffler RADIUS_DEBUG("Invalid Message-Authenticator from %s", abuf); 93839beb93cSSam Leffler data->counters.bad_authenticators++; 93939beb93cSSam Leffler client->counters.bad_authenticators++; 94039beb93cSSam Leffler goto fail; 94139beb93cSSam Leffler } 94239beb93cSSam Leffler 94339beb93cSSam Leffler if (radius_server_request(data, msg, (struct sockaddr *) &from, 94439beb93cSSam Leffler fromlen, client, abuf, from_port, NULL) == 94539beb93cSSam Leffler -2) 94639beb93cSSam Leffler return; /* msg was stored with the session */ 94739beb93cSSam Leffler 94839beb93cSSam Leffler fail: 94939beb93cSSam Leffler radius_msg_free(msg); 95039beb93cSSam Leffler os_free(buf); 95139beb93cSSam Leffler } 95239beb93cSSam Leffler 95339beb93cSSam Leffler 9543157ba21SRui Paulo static int radius_server_disable_pmtu_discovery(int s) 9553157ba21SRui Paulo { 9563157ba21SRui Paulo int r = -1; 9573157ba21SRui Paulo #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) 9583157ba21SRui Paulo /* Turn off Path MTU discovery on IPv4/UDP sockets. */ 9593157ba21SRui Paulo int action = IP_PMTUDISC_DONT; 9603157ba21SRui Paulo r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action, 9613157ba21SRui Paulo sizeof(action)); 9623157ba21SRui Paulo if (r == -1) 9633157ba21SRui Paulo wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: " 9643157ba21SRui Paulo "%s", strerror(errno)); 9653157ba21SRui Paulo #endif 9663157ba21SRui Paulo return r; 9673157ba21SRui Paulo } 9683157ba21SRui Paulo 9693157ba21SRui Paulo 97039beb93cSSam Leffler static int radius_server_open_socket(int port) 97139beb93cSSam Leffler { 97239beb93cSSam Leffler int s; 97339beb93cSSam Leffler struct sockaddr_in addr; 97439beb93cSSam Leffler 97539beb93cSSam Leffler s = socket(PF_INET, SOCK_DGRAM, 0); 97639beb93cSSam Leffler if (s < 0) { 97739beb93cSSam Leffler perror("socket"); 97839beb93cSSam Leffler return -1; 97939beb93cSSam Leffler } 98039beb93cSSam Leffler 9813157ba21SRui Paulo radius_server_disable_pmtu_discovery(s); 9823157ba21SRui Paulo 98339beb93cSSam Leffler os_memset(&addr, 0, sizeof(addr)); 98439beb93cSSam Leffler addr.sin_family = AF_INET; 98539beb93cSSam Leffler addr.sin_port = htons(port); 98639beb93cSSam Leffler if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 98739beb93cSSam Leffler perror("bind"); 98839beb93cSSam Leffler close(s); 98939beb93cSSam Leffler return -1; 99039beb93cSSam Leffler } 99139beb93cSSam Leffler 99239beb93cSSam Leffler return s; 99339beb93cSSam Leffler } 99439beb93cSSam Leffler 99539beb93cSSam Leffler 99639beb93cSSam Leffler #ifdef CONFIG_IPV6 99739beb93cSSam Leffler static int radius_server_open_socket6(int port) 99839beb93cSSam Leffler { 99939beb93cSSam Leffler int s; 100039beb93cSSam Leffler struct sockaddr_in6 addr; 100139beb93cSSam Leffler 100239beb93cSSam Leffler s = socket(PF_INET6, SOCK_DGRAM, 0); 100339beb93cSSam Leffler if (s < 0) { 100439beb93cSSam Leffler perror("socket[IPv6]"); 100539beb93cSSam Leffler return -1; 100639beb93cSSam Leffler } 100739beb93cSSam Leffler 100839beb93cSSam Leffler os_memset(&addr, 0, sizeof(addr)); 100939beb93cSSam Leffler addr.sin6_family = AF_INET6; 101039beb93cSSam Leffler os_memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any)); 101139beb93cSSam Leffler addr.sin6_port = htons(port); 101239beb93cSSam Leffler if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 101339beb93cSSam Leffler perror("bind"); 101439beb93cSSam Leffler close(s); 101539beb93cSSam Leffler return -1; 101639beb93cSSam Leffler } 101739beb93cSSam Leffler 101839beb93cSSam Leffler return s; 101939beb93cSSam Leffler } 102039beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 102139beb93cSSam Leffler 102239beb93cSSam Leffler 102339beb93cSSam Leffler static void radius_server_free_sessions(struct radius_server_data *data, 102439beb93cSSam Leffler struct radius_session *sessions) 102539beb93cSSam Leffler { 102639beb93cSSam Leffler struct radius_session *session, *prev; 102739beb93cSSam Leffler 102839beb93cSSam Leffler session = sessions; 102939beb93cSSam Leffler while (session) { 103039beb93cSSam Leffler prev = session; 103139beb93cSSam Leffler session = session->next; 103239beb93cSSam Leffler radius_server_session_free(data, prev); 103339beb93cSSam Leffler } 103439beb93cSSam Leffler } 103539beb93cSSam Leffler 103639beb93cSSam Leffler 103739beb93cSSam Leffler static void radius_server_free_clients(struct radius_server_data *data, 103839beb93cSSam Leffler struct radius_client *clients) 103939beb93cSSam Leffler { 104039beb93cSSam Leffler struct radius_client *client, *prev; 104139beb93cSSam Leffler 104239beb93cSSam Leffler client = clients; 104339beb93cSSam Leffler while (client) { 104439beb93cSSam Leffler prev = client; 104539beb93cSSam Leffler client = client->next; 104639beb93cSSam Leffler 104739beb93cSSam Leffler radius_server_free_sessions(data, prev->sessions); 104839beb93cSSam Leffler os_free(prev->shared_secret); 104939beb93cSSam Leffler os_free(prev); 105039beb93cSSam Leffler } 105139beb93cSSam Leffler } 105239beb93cSSam Leffler 105339beb93cSSam Leffler 105439beb93cSSam Leffler static struct radius_client * 105539beb93cSSam Leffler radius_server_read_clients(const char *client_file, int ipv6) 105639beb93cSSam Leffler { 105739beb93cSSam Leffler FILE *f; 105839beb93cSSam Leffler const int buf_size = 1024; 105939beb93cSSam Leffler char *buf, *pos; 106039beb93cSSam Leffler struct radius_client *clients, *tail, *entry; 106139beb93cSSam Leffler int line = 0, mask, failed = 0, i; 106239beb93cSSam Leffler struct in_addr addr; 106339beb93cSSam Leffler #ifdef CONFIG_IPV6 106439beb93cSSam Leffler struct in6_addr addr6; 106539beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 106639beb93cSSam Leffler unsigned int val; 106739beb93cSSam Leffler 106839beb93cSSam Leffler f = fopen(client_file, "r"); 106939beb93cSSam Leffler if (f == NULL) { 107039beb93cSSam Leffler RADIUS_ERROR("Could not open client file '%s'", client_file); 107139beb93cSSam Leffler return NULL; 107239beb93cSSam Leffler } 107339beb93cSSam Leffler 107439beb93cSSam Leffler buf = os_malloc(buf_size); 107539beb93cSSam Leffler if (buf == NULL) { 107639beb93cSSam Leffler fclose(f); 107739beb93cSSam Leffler return NULL; 107839beb93cSSam Leffler } 107939beb93cSSam Leffler 108039beb93cSSam Leffler clients = tail = NULL; 108139beb93cSSam Leffler while (fgets(buf, buf_size, f)) { 108239beb93cSSam Leffler /* Configuration file format: 108339beb93cSSam Leffler * 192.168.1.0/24 secret 108439beb93cSSam Leffler * 192.168.1.2 secret 108539beb93cSSam Leffler * fe80::211:22ff:fe33:4455/64 secretipv6 108639beb93cSSam Leffler */ 108739beb93cSSam Leffler line++; 108839beb93cSSam Leffler buf[buf_size - 1] = '\0'; 108939beb93cSSam Leffler pos = buf; 109039beb93cSSam Leffler while (*pos != '\0' && *pos != '\n') 109139beb93cSSam Leffler pos++; 109239beb93cSSam Leffler if (*pos == '\n') 109339beb93cSSam Leffler *pos = '\0'; 109439beb93cSSam Leffler if (*buf == '\0' || *buf == '#') 109539beb93cSSam Leffler continue; 109639beb93cSSam Leffler 109739beb93cSSam Leffler pos = buf; 109839beb93cSSam Leffler while ((*pos >= '0' && *pos <= '9') || *pos == '.' || 109939beb93cSSam Leffler (*pos >= 'a' && *pos <= 'f') || *pos == ':' || 110039beb93cSSam Leffler (*pos >= 'A' && *pos <= 'F')) { 110139beb93cSSam Leffler pos++; 110239beb93cSSam Leffler } 110339beb93cSSam Leffler 110439beb93cSSam Leffler if (*pos == '\0') { 110539beb93cSSam Leffler failed = 1; 110639beb93cSSam Leffler break; 110739beb93cSSam Leffler } 110839beb93cSSam Leffler 110939beb93cSSam Leffler if (*pos == '/') { 111039beb93cSSam Leffler char *end; 111139beb93cSSam Leffler *pos++ = '\0'; 111239beb93cSSam Leffler mask = strtol(pos, &end, 10); 111339beb93cSSam Leffler if ((pos == end) || 111439beb93cSSam Leffler (mask < 0 || mask > (ipv6 ? 128 : 32))) { 111539beb93cSSam Leffler failed = 1; 111639beb93cSSam Leffler break; 111739beb93cSSam Leffler } 111839beb93cSSam Leffler pos = end; 111939beb93cSSam Leffler } else { 112039beb93cSSam Leffler mask = ipv6 ? 128 : 32; 112139beb93cSSam Leffler *pos++ = '\0'; 112239beb93cSSam Leffler } 112339beb93cSSam Leffler 112439beb93cSSam Leffler if (!ipv6 && inet_aton(buf, &addr) == 0) { 112539beb93cSSam Leffler failed = 1; 112639beb93cSSam Leffler break; 112739beb93cSSam Leffler } 112839beb93cSSam Leffler #ifdef CONFIG_IPV6 112939beb93cSSam Leffler if (ipv6 && inet_pton(AF_INET6, buf, &addr6) <= 0) { 113039beb93cSSam Leffler if (inet_pton(AF_INET, buf, &addr) <= 0) { 113139beb93cSSam Leffler failed = 1; 113239beb93cSSam Leffler break; 113339beb93cSSam Leffler } 113439beb93cSSam Leffler /* Convert IPv4 address to IPv6 */ 113539beb93cSSam Leffler if (mask <= 32) 113639beb93cSSam Leffler mask += (128 - 32); 113739beb93cSSam Leffler os_memset(addr6.s6_addr, 0, 10); 113839beb93cSSam Leffler addr6.s6_addr[10] = 0xff; 113939beb93cSSam Leffler addr6.s6_addr[11] = 0xff; 114039beb93cSSam Leffler os_memcpy(addr6.s6_addr + 12, (char *) &addr.s_addr, 114139beb93cSSam Leffler 4); 114239beb93cSSam Leffler } 114339beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 114439beb93cSSam Leffler 114539beb93cSSam Leffler while (*pos == ' ' || *pos == '\t') { 114639beb93cSSam Leffler pos++; 114739beb93cSSam Leffler } 114839beb93cSSam Leffler 114939beb93cSSam Leffler if (*pos == '\0') { 115039beb93cSSam Leffler failed = 1; 115139beb93cSSam Leffler break; 115239beb93cSSam Leffler } 115339beb93cSSam Leffler 115439beb93cSSam Leffler entry = os_zalloc(sizeof(*entry)); 115539beb93cSSam Leffler if (entry == NULL) { 115639beb93cSSam Leffler failed = 1; 115739beb93cSSam Leffler break; 115839beb93cSSam Leffler } 115939beb93cSSam Leffler entry->shared_secret = os_strdup(pos); 116039beb93cSSam Leffler if (entry->shared_secret == NULL) { 116139beb93cSSam Leffler failed = 1; 116239beb93cSSam Leffler os_free(entry); 116339beb93cSSam Leffler break; 116439beb93cSSam Leffler } 116539beb93cSSam Leffler entry->shared_secret_len = os_strlen(entry->shared_secret); 116639beb93cSSam Leffler entry->addr.s_addr = addr.s_addr; 116739beb93cSSam Leffler if (!ipv6) { 116839beb93cSSam Leffler val = 0; 116939beb93cSSam Leffler for (i = 0; i < mask; i++) 117039beb93cSSam Leffler val |= 1 << (31 - i); 117139beb93cSSam Leffler entry->mask.s_addr = htonl(val); 117239beb93cSSam Leffler } 117339beb93cSSam Leffler #ifdef CONFIG_IPV6 117439beb93cSSam Leffler if (ipv6) { 117539beb93cSSam Leffler int offset = mask / 8; 117639beb93cSSam Leffler 117739beb93cSSam Leffler os_memcpy(entry->addr6.s6_addr, addr6.s6_addr, 16); 117839beb93cSSam Leffler os_memset(entry->mask6.s6_addr, 0xff, offset); 117939beb93cSSam Leffler val = 0; 118039beb93cSSam Leffler for (i = 0; i < (mask % 8); i++) 118139beb93cSSam Leffler val |= 1 << (7 - i); 118239beb93cSSam Leffler if (offset < 16) 118339beb93cSSam Leffler entry->mask6.s6_addr[offset] = val; 118439beb93cSSam Leffler } 118539beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 118639beb93cSSam Leffler 118739beb93cSSam Leffler if (tail == NULL) { 118839beb93cSSam Leffler clients = tail = entry; 118939beb93cSSam Leffler } else { 119039beb93cSSam Leffler tail->next = entry; 119139beb93cSSam Leffler tail = entry; 119239beb93cSSam Leffler } 119339beb93cSSam Leffler } 119439beb93cSSam Leffler 119539beb93cSSam Leffler if (failed) { 119639beb93cSSam Leffler RADIUS_ERROR("Invalid line %d in '%s'", line, client_file); 119739beb93cSSam Leffler radius_server_free_clients(NULL, clients); 119839beb93cSSam Leffler clients = NULL; 119939beb93cSSam Leffler } 120039beb93cSSam Leffler 120139beb93cSSam Leffler os_free(buf); 120239beb93cSSam Leffler fclose(f); 120339beb93cSSam Leffler 120439beb93cSSam Leffler return clients; 120539beb93cSSam Leffler } 120639beb93cSSam Leffler 120739beb93cSSam Leffler 1208*e28a4053SRui Paulo /** 1209*e28a4053SRui Paulo * radius_server_init - Initialize RADIUS server 1210*e28a4053SRui Paulo * @conf: Configuration for the RADIUS server 1211*e28a4053SRui Paulo * Returns: Pointer to private RADIUS server context or %NULL on failure 1212*e28a4053SRui Paulo * 1213*e28a4053SRui Paulo * This initializes a RADIUS server instance and returns a context pointer that 1214*e28a4053SRui Paulo * will be used in other calls to the RADIUS server module. The server can be 1215*e28a4053SRui Paulo * deinitialize by calling radius_server_deinit(). 1216*e28a4053SRui Paulo */ 121739beb93cSSam Leffler struct radius_server_data * 121839beb93cSSam Leffler radius_server_init(struct radius_server_conf *conf) 121939beb93cSSam Leffler { 122039beb93cSSam Leffler struct radius_server_data *data; 122139beb93cSSam Leffler 122239beb93cSSam Leffler #ifndef CONFIG_IPV6 122339beb93cSSam Leffler if (conf->ipv6) { 122439beb93cSSam Leffler fprintf(stderr, "RADIUS server compiled without IPv6 " 122539beb93cSSam Leffler "support.\n"); 122639beb93cSSam Leffler return NULL; 122739beb93cSSam Leffler } 122839beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 122939beb93cSSam Leffler 123039beb93cSSam Leffler data = os_zalloc(sizeof(*data)); 123139beb93cSSam Leffler if (data == NULL) 123239beb93cSSam Leffler return NULL; 123339beb93cSSam Leffler 123439beb93cSSam Leffler os_get_time(&data->start_time); 123539beb93cSSam Leffler data->conf_ctx = conf->conf_ctx; 123639beb93cSSam Leffler data->eap_sim_db_priv = conf->eap_sim_db_priv; 123739beb93cSSam Leffler data->ssl_ctx = conf->ssl_ctx; 1238*e28a4053SRui Paulo data->msg_ctx = conf->msg_ctx; 123939beb93cSSam Leffler data->ipv6 = conf->ipv6; 124039beb93cSSam Leffler if (conf->pac_opaque_encr_key) { 124139beb93cSSam Leffler data->pac_opaque_encr_key = os_malloc(16); 124239beb93cSSam Leffler os_memcpy(data->pac_opaque_encr_key, conf->pac_opaque_encr_key, 124339beb93cSSam Leffler 16); 124439beb93cSSam Leffler } 124539beb93cSSam Leffler if (conf->eap_fast_a_id) { 124639beb93cSSam Leffler data->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len); 124739beb93cSSam Leffler if (data->eap_fast_a_id) { 124839beb93cSSam Leffler os_memcpy(data->eap_fast_a_id, conf->eap_fast_a_id, 124939beb93cSSam Leffler conf->eap_fast_a_id_len); 125039beb93cSSam Leffler data->eap_fast_a_id_len = conf->eap_fast_a_id_len; 125139beb93cSSam Leffler } 125239beb93cSSam Leffler } 125339beb93cSSam Leffler if (conf->eap_fast_a_id_info) 125439beb93cSSam Leffler data->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info); 125539beb93cSSam Leffler data->eap_fast_prov = conf->eap_fast_prov; 125639beb93cSSam Leffler data->pac_key_lifetime = conf->pac_key_lifetime; 125739beb93cSSam Leffler data->pac_key_refresh_time = conf->pac_key_refresh_time; 125839beb93cSSam Leffler data->get_eap_user = conf->get_eap_user; 125939beb93cSSam Leffler data->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind; 126039beb93cSSam Leffler data->tnc = conf->tnc; 126139beb93cSSam Leffler data->wps = conf->wps; 126239beb93cSSam Leffler if (conf->eap_req_id_text) { 126339beb93cSSam Leffler data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len); 126439beb93cSSam Leffler if (data->eap_req_id_text) { 126539beb93cSSam Leffler os_memcpy(data->eap_req_id_text, conf->eap_req_id_text, 126639beb93cSSam Leffler conf->eap_req_id_text_len); 126739beb93cSSam Leffler data->eap_req_id_text_len = conf->eap_req_id_text_len; 126839beb93cSSam Leffler } 126939beb93cSSam Leffler } 127039beb93cSSam Leffler 127139beb93cSSam Leffler data->clients = radius_server_read_clients(conf->client_file, 127239beb93cSSam Leffler conf->ipv6); 127339beb93cSSam Leffler if (data->clients == NULL) { 127439beb93cSSam Leffler printf("No RADIUS clients configured.\n"); 127539beb93cSSam Leffler radius_server_deinit(data); 127639beb93cSSam Leffler return NULL; 127739beb93cSSam Leffler } 127839beb93cSSam Leffler 127939beb93cSSam Leffler #ifdef CONFIG_IPV6 128039beb93cSSam Leffler if (conf->ipv6) 128139beb93cSSam Leffler data->auth_sock = radius_server_open_socket6(conf->auth_port); 128239beb93cSSam Leffler else 128339beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 128439beb93cSSam Leffler data->auth_sock = radius_server_open_socket(conf->auth_port); 128539beb93cSSam Leffler if (data->auth_sock < 0) { 128639beb93cSSam Leffler printf("Failed to open UDP socket for RADIUS authentication " 128739beb93cSSam Leffler "server\n"); 128839beb93cSSam Leffler radius_server_deinit(data); 128939beb93cSSam Leffler return NULL; 129039beb93cSSam Leffler } 129139beb93cSSam Leffler if (eloop_register_read_sock(data->auth_sock, 129239beb93cSSam Leffler radius_server_receive_auth, 129339beb93cSSam Leffler data, NULL)) { 129439beb93cSSam Leffler radius_server_deinit(data); 129539beb93cSSam Leffler return NULL; 129639beb93cSSam Leffler } 129739beb93cSSam Leffler 129839beb93cSSam Leffler return data; 129939beb93cSSam Leffler } 130039beb93cSSam Leffler 130139beb93cSSam Leffler 1302*e28a4053SRui Paulo /** 1303*e28a4053SRui Paulo * radius_server_deinit - Deinitialize RADIUS server 1304*e28a4053SRui Paulo * @data: RADIUS server context from radius_server_init() 1305*e28a4053SRui Paulo */ 130639beb93cSSam Leffler void radius_server_deinit(struct radius_server_data *data) 130739beb93cSSam Leffler { 130839beb93cSSam Leffler if (data == NULL) 130939beb93cSSam Leffler return; 131039beb93cSSam Leffler 131139beb93cSSam Leffler if (data->auth_sock >= 0) { 131239beb93cSSam Leffler eloop_unregister_read_sock(data->auth_sock); 131339beb93cSSam Leffler close(data->auth_sock); 131439beb93cSSam Leffler } 131539beb93cSSam Leffler 131639beb93cSSam Leffler radius_server_free_clients(data, data->clients); 131739beb93cSSam Leffler 131839beb93cSSam Leffler os_free(data->pac_opaque_encr_key); 131939beb93cSSam Leffler os_free(data->eap_fast_a_id); 132039beb93cSSam Leffler os_free(data->eap_fast_a_id_info); 132139beb93cSSam Leffler os_free(data->eap_req_id_text); 132239beb93cSSam Leffler os_free(data); 132339beb93cSSam Leffler } 132439beb93cSSam Leffler 132539beb93cSSam Leffler 1326*e28a4053SRui Paulo /** 1327*e28a4053SRui Paulo * radius_server_get_mib - Get RADIUS server MIB information 1328*e28a4053SRui Paulo * @data: RADIUS server context from radius_server_init() 1329*e28a4053SRui Paulo * @buf: Buffer for returning the MIB data in text format 1330*e28a4053SRui Paulo * @buflen: buf length in octets 1331*e28a4053SRui Paulo * Returns: Number of octets written into buf 1332*e28a4053SRui Paulo */ 133339beb93cSSam Leffler int radius_server_get_mib(struct radius_server_data *data, char *buf, 133439beb93cSSam Leffler size_t buflen) 133539beb93cSSam Leffler { 133639beb93cSSam Leffler int ret, uptime; 133739beb93cSSam Leffler unsigned int idx; 133839beb93cSSam Leffler char *end, *pos; 133939beb93cSSam Leffler struct os_time now; 134039beb93cSSam Leffler struct radius_client *cli; 134139beb93cSSam Leffler 134239beb93cSSam Leffler /* RFC 2619 - RADIUS Authentication Server MIB */ 134339beb93cSSam Leffler 134439beb93cSSam Leffler if (data == NULL || buflen == 0) 134539beb93cSSam Leffler return 0; 134639beb93cSSam Leffler 134739beb93cSSam Leffler pos = buf; 134839beb93cSSam Leffler end = buf + buflen; 134939beb93cSSam Leffler 135039beb93cSSam Leffler os_get_time(&now); 135139beb93cSSam Leffler uptime = (now.sec - data->start_time.sec) * 100 + 135239beb93cSSam Leffler ((now.usec - data->start_time.usec) / 10000) % 100; 135339beb93cSSam Leffler ret = os_snprintf(pos, end - pos, 135439beb93cSSam Leffler "RADIUS-AUTH-SERVER-MIB\n" 135539beb93cSSam Leffler "radiusAuthServIdent=hostapd\n" 135639beb93cSSam Leffler "radiusAuthServUpTime=%d\n" 135739beb93cSSam Leffler "radiusAuthServResetTime=0\n" 135839beb93cSSam Leffler "radiusAuthServConfigReset=4\n", 135939beb93cSSam Leffler uptime); 136039beb93cSSam Leffler if (ret < 0 || ret >= end - pos) { 136139beb93cSSam Leffler *pos = '\0'; 136239beb93cSSam Leffler return pos - buf; 136339beb93cSSam Leffler } 136439beb93cSSam Leffler pos += ret; 136539beb93cSSam Leffler 136639beb93cSSam Leffler ret = os_snprintf(pos, end - pos, 136739beb93cSSam Leffler "radiusAuthServTotalAccessRequests=%u\n" 136839beb93cSSam Leffler "radiusAuthServTotalInvalidRequests=%u\n" 136939beb93cSSam Leffler "radiusAuthServTotalDupAccessRequests=%u\n" 137039beb93cSSam Leffler "radiusAuthServTotalAccessAccepts=%u\n" 137139beb93cSSam Leffler "radiusAuthServTotalAccessRejects=%u\n" 137239beb93cSSam Leffler "radiusAuthServTotalAccessChallenges=%u\n" 137339beb93cSSam Leffler "radiusAuthServTotalMalformedAccessRequests=%u\n" 137439beb93cSSam Leffler "radiusAuthServTotalBadAuthenticators=%u\n" 137539beb93cSSam Leffler "radiusAuthServTotalPacketsDropped=%u\n" 137639beb93cSSam Leffler "radiusAuthServTotalUnknownTypes=%u\n", 137739beb93cSSam Leffler data->counters.access_requests, 137839beb93cSSam Leffler data->counters.invalid_requests, 137939beb93cSSam Leffler data->counters.dup_access_requests, 138039beb93cSSam Leffler data->counters.access_accepts, 138139beb93cSSam Leffler data->counters.access_rejects, 138239beb93cSSam Leffler data->counters.access_challenges, 138339beb93cSSam Leffler data->counters.malformed_access_requests, 138439beb93cSSam Leffler data->counters.bad_authenticators, 138539beb93cSSam Leffler data->counters.packets_dropped, 138639beb93cSSam Leffler data->counters.unknown_types); 138739beb93cSSam Leffler if (ret < 0 || ret >= end - pos) { 138839beb93cSSam Leffler *pos = '\0'; 138939beb93cSSam Leffler return pos - buf; 139039beb93cSSam Leffler } 139139beb93cSSam Leffler pos += ret; 139239beb93cSSam Leffler 139339beb93cSSam Leffler for (cli = data->clients, idx = 0; cli; cli = cli->next, idx++) { 139439beb93cSSam Leffler char abuf[50], mbuf[50]; 139539beb93cSSam Leffler #ifdef CONFIG_IPV6 139639beb93cSSam Leffler if (data->ipv6) { 139739beb93cSSam Leffler if (inet_ntop(AF_INET6, &cli->addr6, abuf, 139839beb93cSSam Leffler sizeof(abuf)) == NULL) 139939beb93cSSam Leffler abuf[0] = '\0'; 140039beb93cSSam Leffler if (inet_ntop(AF_INET6, &cli->mask6, abuf, 140139beb93cSSam Leffler sizeof(mbuf)) == NULL) 140239beb93cSSam Leffler mbuf[0] = '\0'; 140339beb93cSSam Leffler } 140439beb93cSSam Leffler #endif /* CONFIG_IPV6 */ 140539beb93cSSam Leffler if (!data->ipv6) { 140639beb93cSSam Leffler os_strlcpy(abuf, inet_ntoa(cli->addr), sizeof(abuf)); 140739beb93cSSam Leffler os_strlcpy(mbuf, inet_ntoa(cli->mask), sizeof(mbuf)); 140839beb93cSSam Leffler } 140939beb93cSSam Leffler 141039beb93cSSam Leffler ret = os_snprintf(pos, end - pos, 141139beb93cSSam Leffler "radiusAuthClientIndex=%u\n" 141239beb93cSSam Leffler "radiusAuthClientAddress=%s/%s\n" 141339beb93cSSam Leffler "radiusAuthServAccessRequests=%u\n" 141439beb93cSSam Leffler "radiusAuthServDupAccessRequests=%u\n" 141539beb93cSSam Leffler "radiusAuthServAccessAccepts=%u\n" 141639beb93cSSam Leffler "radiusAuthServAccessRejects=%u\n" 141739beb93cSSam Leffler "radiusAuthServAccessChallenges=%u\n" 141839beb93cSSam Leffler "radiusAuthServMalformedAccessRequests=%u\n" 141939beb93cSSam Leffler "radiusAuthServBadAuthenticators=%u\n" 142039beb93cSSam Leffler "radiusAuthServPacketsDropped=%u\n" 142139beb93cSSam Leffler "radiusAuthServUnknownTypes=%u\n", 142239beb93cSSam Leffler idx, 142339beb93cSSam Leffler abuf, mbuf, 142439beb93cSSam Leffler cli->counters.access_requests, 142539beb93cSSam Leffler cli->counters.dup_access_requests, 142639beb93cSSam Leffler cli->counters.access_accepts, 142739beb93cSSam Leffler cli->counters.access_rejects, 142839beb93cSSam Leffler cli->counters.access_challenges, 142939beb93cSSam Leffler cli->counters.malformed_access_requests, 143039beb93cSSam Leffler cli->counters.bad_authenticators, 143139beb93cSSam Leffler cli->counters.packets_dropped, 143239beb93cSSam Leffler cli->counters.unknown_types); 143339beb93cSSam Leffler if (ret < 0 || ret >= end - pos) { 143439beb93cSSam Leffler *pos = '\0'; 143539beb93cSSam Leffler return pos - buf; 143639beb93cSSam Leffler } 143739beb93cSSam Leffler pos += ret; 143839beb93cSSam Leffler } 143939beb93cSSam Leffler 144039beb93cSSam Leffler return pos - buf; 144139beb93cSSam Leffler } 144239beb93cSSam Leffler 144339beb93cSSam Leffler 144439beb93cSSam Leffler static int radius_server_get_eap_user(void *ctx, const u8 *identity, 144539beb93cSSam Leffler size_t identity_len, int phase2, 144639beb93cSSam Leffler struct eap_user *user) 144739beb93cSSam Leffler { 144839beb93cSSam Leffler struct radius_session *sess = ctx; 144939beb93cSSam Leffler struct radius_server_data *data = sess->server; 145039beb93cSSam Leffler 145139beb93cSSam Leffler return data->get_eap_user(data->conf_ctx, identity, identity_len, 145239beb93cSSam Leffler phase2, user); 145339beb93cSSam Leffler } 145439beb93cSSam Leffler 145539beb93cSSam Leffler 145639beb93cSSam Leffler static const char * radius_server_get_eap_req_id_text(void *ctx, size_t *len) 145739beb93cSSam Leffler { 145839beb93cSSam Leffler struct radius_session *sess = ctx; 145939beb93cSSam Leffler struct radius_server_data *data = sess->server; 146039beb93cSSam Leffler *len = data->eap_req_id_text_len; 146139beb93cSSam Leffler return data->eap_req_id_text; 146239beb93cSSam Leffler } 146339beb93cSSam Leffler 146439beb93cSSam Leffler 146539beb93cSSam Leffler static struct eapol_callbacks radius_server_eapol_cb = 146639beb93cSSam Leffler { 146739beb93cSSam Leffler .get_eap_user = radius_server_get_eap_user, 146839beb93cSSam Leffler .get_eap_req_id_text = radius_server_get_eap_req_id_text, 146939beb93cSSam Leffler }; 147039beb93cSSam Leffler 147139beb93cSSam Leffler 1472*e28a4053SRui Paulo /** 1473*e28a4053SRui Paulo * radius_server_eap_pending_cb - Pending EAP data notification 1474*e28a4053SRui Paulo * @data: RADIUS server context from radius_server_init() 1475*e28a4053SRui Paulo * @ctx: Pending EAP context pointer 1476*e28a4053SRui Paulo * 1477*e28a4053SRui Paulo * This function is used to notify EAP server module that a pending operation 1478*e28a4053SRui Paulo * has been completed and processing of the EAP session can proceed. 1479*e28a4053SRui Paulo */ 148039beb93cSSam Leffler void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx) 148139beb93cSSam Leffler { 148239beb93cSSam Leffler struct radius_client *cli; 148339beb93cSSam Leffler struct radius_session *s, *sess = NULL; 148439beb93cSSam Leffler struct radius_msg *msg; 148539beb93cSSam Leffler 148639beb93cSSam Leffler if (data == NULL) 148739beb93cSSam Leffler return; 148839beb93cSSam Leffler 148939beb93cSSam Leffler for (cli = data->clients; cli; cli = cli->next) { 149039beb93cSSam Leffler for (s = cli->sessions; s; s = s->next) { 149139beb93cSSam Leffler if (s->eap == ctx && s->last_msg) { 149239beb93cSSam Leffler sess = s; 149339beb93cSSam Leffler break; 149439beb93cSSam Leffler } 149539beb93cSSam Leffler if (sess) 149639beb93cSSam Leffler break; 149739beb93cSSam Leffler } 149839beb93cSSam Leffler if (sess) 149939beb93cSSam Leffler break; 150039beb93cSSam Leffler } 150139beb93cSSam Leffler 150239beb93cSSam Leffler if (sess == NULL) { 150339beb93cSSam Leffler RADIUS_DEBUG("No session matched callback ctx"); 150439beb93cSSam Leffler return; 150539beb93cSSam Leffler } 150639beb93cSSam Leffler 150739beb93cSSam Leffler msg = sess->last_msg; 150839beb93cSSam Leffler sess->last_msg = NULL; 150939beb93cSSam Leffler eap_sm_pending_cb(sess->eap); 151039beb93cSSam Leffler if (radius_server_request(data, msg, 151139beb93cSSam Leffler (struct sockaddr *) &sess->last_from, 151239beb93cSSam Leffler sess->last_fromlen, cli, 151339beb93cSSam Leffler sess->last_from_addr, 151439beb93cSSam Leffler sess->last_from_port, sess) == -2) 151539beb93cSSam Leffler return; /* msg was stored with the session */ 151639beb93cSSam Leffler 151739beb93cSSam Leffler radius_msg_free(msg); 151839beb93cSSam Leffler } 1519