xref: /freebsd/contrib/wpa/src/radius/radius_server.c (revision 5b9c547c072b84410b50897cc53710c75b2f6b74)
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