1/*
2 * RADIUS client
3 * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "radius.h"
13#include "radius_client.h"
14#include "eloop.h"
15
16/* Defaults for RADIUS retransmit values (exponential backoff) */
17
18/**
19 * RADIUS_CLIENT_FIRST_WAIT - RADIUS client timeout for first retry in seconds
20 */
21#define RADIUS_CLIENT_FIRST_WAIT 3
22
23/**
24 * RADIUS_CLIENT_MAX_WAIT - RADIUS client maximum retry timeout in seconds
25 */
26#define RADIUS_CLIENT_MAX_WAIT 120
27
28/**
29 * RADIUS_CLIENT_MAX_FAILOVER - RADIUS client maximum retries
30 *
31 * Maximum number of server failovers before the entry is removed from
32 * retransmit list.
33 */
34#define RADIUS_CLIENT_MAX_FAILOVER 3
35
36/**
37 * RADIUS_CLIENT_MAX_ENTRIES - RADIUS client maximum pending messages
38 *
39 * Maximum number of entries in retransmit list (oldest entries will be
40 * removed, if this limit is exceeded).
41 */
42#define RADIUS_CLIENT_MAX_ENTRIES 30
43
44/**
45 * RADIUS_CLIENT_NUM_FAILOVER - RADIUS client failover point
46 *
47 * The number of failed retry attempts after which the RADIUS server will be
48 * changed (if one of more backup servers are configured).
49 */
50#define RADIUS_CLIENT_NUM_FAILOVER 4
51
52
53/**
54 * struct radius_rx_handler - RADIUS client RX handler
55 *
56 * This data structure is used internally inside the RADIUS client module to
57 * store registered RX handlers. These handlers are registered by calls to
58 * radius_client_register() and unregistered when the RADIUS client is
59 * deinitialized with a call to radius_client_deinit().
60 */
61struct radius_rx_handler {
62	/**
63	 * handler - Received RADIUS message handler
64	 */
65	RadiusRxResult (*handler)(struct radius_msg *msg,
66				  struct radius_msg *req,
67				  const u8 *shared_secret,
68				  size_t shared_secret_len,
69				  void *data);
70
71	/**
72	 * data - Context data for the handler
73	 */
74	void *data;
75};
76
77
78/**
79 * struct radius_msg_list - RADIUS client message retransmit list
80 *
81 * This data structure is used internally inside the RADIUS client module to
82 * store pending RADIUS requests that may still need to be retransmitted.
83 */
84struct radius_msg_list {
85	/**
86	 * addr - STA/client address
87	 *
88	 * This is used to find RADIUS messages for the same STA.
89	 */
90	u8 addr[ETH_ALEN];
91
92	/**
93	 * msg - RADIUS message
94	 */
95	struct radius_msg *msg;
96
97	/**
98	 * msg_type - Message type
99	 */
100	RadiusType msg_type;
101
102	/**
103	 * first_try - Time of the first transmission attempt
104	 */
105	os_time_t first_try;
106
107	/**
108	 * next_try - Time for the next transmission attempt
109	 */
110	os_time_t next_try;
111
112	/**
113	 * attempts - Number of transmission attempts for one server
114	 */
115	int attempts;
116
117	/**
118	 * accu_attempts - Number of accumulated attempts
119	 */
120	int accu_attempts;
121
122	/**
123	 * next_wait - Next retransmission wait time in seconds
124	 */
125	int next_wait;
126
127	/**
128	 * last_attempt - Time of the last transmission attempt
129	 */
130	struct os_reltime last_attempt;
131
132	/**
133	 * shared_secret - Shared secret with the target RADIUS server
134	 */
135	const u8 *shared_secret;
136
137	/**
138	 * shared_secret_len - shared_secret length in octets
139	 */
140	size_t shared_secret_len;
141
142	/* TODO: server config with failover to backup server(s) */
143
144	/**
145	 * next - Next message in the list
146	 */
147	struct radius_msg_list *next;
148};
149
150
151/**
152 * struct radius_client_data - Internal RADIUS client data
153 *
154 * This data structure is used internally inside the RADIUS client module.
155 * External users allocate this by calling radius_client_init() and free it by
156 * calling radius_client_deinit(). The pointer to this opaque data is used in
157 * calls to other functions as an identifier for the RADIUS client instance.
158 */
159struct radius_client_data {
160	/**
161	 * ctx - Context pointer for hostapd_logger() callbacks
162	 */
163	void *ctx;
164
165	/**
166	 * conf - RADIUS client configuration (list of RADIUS servers to use)
167	 */
168	struct hostapd_radius_servers *conf;
169
170	/**
171	 * auth_serv_sock - IPv4 socket for RADIUS authentication messages
172	 */
173	int auth_serv_sock;
174
175	/**
176	 * acct_serv_sock - IPv4 socket for RADIUS accounting messages
177	 */
178	int acct_serv_sock;
179
180	/**
181	 * auth_serv_sock6 - IPv6 socket for RADIUS authentication messages
182	 */
183	int auth_serv_sock6;
184
185	/**
186	 * acct_serv_sock6 - IPv6 socket for RADIUS accounting messages
187	 */
188	int acct_serv_sock6;
189
190	/**
191	 * auth_sock - Currently used socket for RADIUS authentication server
192	 */
193	int auth_sock;
194
195	/**
196	 * acct_sock - Currently used socket for RADIUS accounting server
197	 */
198	int acct_sock;
199
200	/**
201	 * auth_handlers - Authentication message handlers
202	 */
203	struct radius_rx_handler *auth_handlers;
204
205	/**
206	 * num_auth_handlers - Number of handlers in auth_handlers
207	 */
208	size_t num_auth_handlers;
209
210	/**
211	 * acct_handlers - Accounting message handlers
212	 */
213	struct radius_rx_handler *acct_handlers;
214
215	/**
216	 * num_acct_handlers - Number of handlers in acct_handlers
217	 */
218	size_t num_acct_handlers;
219
220	/**
221	 * msgs - Pending outgoing RADIUS messages
222	 */
223	struct radius_msg_list *msgs;
224
225	/**
226	 * num_msgs - Number of pending messages in the msgs list
227	 */
228	size_t num_msgs;
229
230	/**
231	 * next_radius_identifier - Next RADIUS message identifier to use
232	 */
233	u8 next_radius_identifier;
234
235	/**
236	 * interim_error_cb - Interim accounting error callback
237	 */
238	void (*interim_error_cb)(const u8 *addr, void *ctx);
239
240	/**
241	 * interim_error_cb_ctx - interim_error_cb() context data
242	 */
243	void *interim_error_cb_ctx;
244};
245
246
247static int
248radius_change_server(struct radius_client_data *radius,
249		     struct hostapd_radius_server *nserv,
250		     struct hostapd_radius_server *oserv,
251		     int sock, int sock6, int auth);
252static int radius_client_init_acct(struct radius_client_data *radius);
253static int radius_client_init_auth(struct radius_client_data *radius);
254static void radius_client_auth_failover(struct radius_client_data *radius);
255static void radius_client_acct_failover(struct radius_client_data *radius);
256
257
258static void radius_client_msg_free(struct radius_msg_list *req)
259{
260	radius_msg_free(req->msg);
261	os_free(req);
262}
263
264
265/**
266 * radius_client_register - Register a RADIUS client RX handler
267 * @radius: RADIUS client context from radius_client_init()
268 * @msg_type: RADIUS client type (RADIUS_AUTH or RADIUS_ACCT)
269 * @handler: Handler for received RADIUS messages
270 * @data: Context pointer for handler callbacks
271 * Returns: 0 on success, -1 on failure
272 *
273 * This function is used to register a handler for processing received RADIUS
274 * authentication and accounting messages. The handler() callback function will
275 * be called whenever a RADIUS message is received from the active server.
276 *
277 * There can be multiple registered RADIUS message handlers. The handlers will
278 * be called in order until one of them indicates that it has processed or
279 * queued the message.
280 */
281int radius_client_register(struct radius_client_data *radius,
282			   RadiusType msg_type,
283			   RadiusRxResult (*handler)(struct radius_msg *msg,
284						     struct radius_msg *req,
285						     const u8 *shared_secret,
286						     size_t shared_secret_len,
287						     void *data),
288			   void *data)
289{
290	struct radius_rx_handler **handlers, *newh;
291	size_t *num;
292
293	if (msg_type == RADIUS_ACCT) {
294		handlers = &radius->acct_handlers;
295		num = &radius->num_acct_handlers;
296	} else {
297		handlers = &radius->auth_handlers;
298		num = &radius->num_auth_handlers;
299	}
300
301	newh = os_realloc_array(*handlers, *num + 1,
302				sizeof(struct radius_rx_handler));
303	if (newh == NULL)
304		return -1;
305
306	newh[*num].handler = handler;
307	newh[*num].data = data;
308	(*num)++;
309	*handlers = newh;
310
311	return 0;
312}
313
314
315/**
316 * radius_client_set_interim_erro_cb - Register an interim acct error callback
317 * @radius: RADIUS client context from radius_client_init()
318 * @addr: Station address from the failed message
319 * @cb: Handler for interim accounting errors
320 * @ctx: Context pointer for handler callbacks
321 *
322 * This function is used to register a handler for processing failed
323 * transmission attempts of interim accounting update messages.
324 */
325void radius_client_set_interim_error_cb(struct radius_client_data *radius,
326					void (*cb)(const u8 *addr, void *ctx),
327					void *ctx)
328{
329	radius->interim_error_cb = cb;
330	radius->interim_error_cb_ctx = ctx;
331}
332
333
334/*
335 * Returns >0 if message queue was flushed (i.e., the message that triggered
336 * the error is not available anymore)
337 */
338static int radius_client_handle_send_error(struct radius_client_data *radius,
339					   int s, RadiusType msg_type)
340{
341#ifndef CONFIG_NATIVE_WINDOWS
342	int _errno = errno;
343	wpa_printf(MSG_INFO, "send[RADIUS,s=%d]: %s", s, strerror(errno));
344	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
345	    _errno == EBADF || _errno == ENETUNREACH || _errno == EACCES) {
346		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
347			       HOSTAPD_LEVEL_INFO,
348			       "Send failed - maybe interface status changed -"
349			       " try to connect again");
350		if (msg_type == RADIUS_ACCT ||
351		    msg_type == RADIUS_ACCT_INTERIM) {
352			radius_client_init_acct(radius);
353			return 0;
354		} else {
355			radius_client_init_auth(radius);
356			return 1;
357		}
358	}
359#endif /* CONFIG_NATIVE_WINDOWS */
360
361	return 0;
362}
363
364
365static int radius_client_retransmit(struct radius_client_data *radius,
366				    struct radius_msg_list *entry,
367				    os_time_t now)
368{
369	struct hostapd_radius_servers *conf = radius->conf;
370	int s;
371	struct wpabuf *buf;
372	size_t prev_num_msgs;
373	u8 *acct_delay_time;
374	size_t acct_delay_time_len;
375	int num_servers;
376
377	if (entry->msg_type == RADIUS_ACCT ||
378	    entry->msg_type == RADIUS_ACCT_INTERIM) {
379		num_servers = conf->num_acct_servers;
380		if (radius->acct_sock < 0)
381			radius_client_init_acct(radius);
382		if (radius->acct_sock < 0 && conf->num_acct_servers > 1) {
383			prev_num_msgs = radius->num_msgs;
384			radius_client_acct_failover(radius);
385			if (prev_num_msgs != radius->num_msgs)
386				return 0;
387		}
388		s = radius->acct_sock;
389		if (entry->attempts == 0)
390			conf->acct_server->requests++;
391		else {
392			conf->acct_server->timeouts++;
393			conf->acct_server->retransmissions++;
394		}
395	} else {
396		num_servers = conf->num_auth_servers;
397		if (radius->auth_sock < 0)
398			radius_client_init_auth(radius);
399		if (radius->auth_sock < 0 && conf->num_auth_servers > 1) {
400			prev_num_msgs = radius->num_msgs;
401			radius_client_auth_failover(radius);
402			if (prev_num_msgs != radius->num_msgs)
403				return 0;
404		}
405		s = radius->auth_sock;
406		if (entry->attempts == 0)
407			conf->auth_server->requests++;
408		else {
409			conf->auth_server->timeouts++;
410			conf->auth_server->retransmissions++;
411		}
412	}
413
414	if (entry->msg_type == RADIUS_ACCT_INTERIM) {
415		wpa_printf(MSG_DEBUG,
416			   "RADIUS: Failed to transmit interim accounting update to "
417			   MACSTR " - drop message and request a new update",
418			   MAC2STR(entry->addr));
419		if (radius->interim_error_cb)
420			radius->interim_error_cb(entry->addr,
421						 radius->interim_error_cb_ctx);
422		return 1;
423	}
424
425	if (s < 0) {
426		wpa_printf(MSG_INFO,
427			   "RADIUS: No valid socket for retransmission");
428		return 1;
429	}
430
431	if (entry->msg_type == RADIUS_ACCT &&
432	    radius_msg_get_attr_ptr(entry->msg, RADIUS_ATTR_ACCT_DELAY_TIME,
433				    &acct_delay_time, &acct_delay_time_len,
434				    NULL) == 0 &&
435	    acct_delay_time_len == 4) {
436		struct radius_hdr *hdr;
437		u32 delay_time;
438
439		/*
440		 * Need to assign a new identifier since attribute contents
441		 * changes.
442		 */
443		hdr = radius_msg_get_hdr(entry->msg);
444		hdr->identifier = radius_client_get_id(radius);
445
446		/* Update Acct-Delay-Time to show wait time in queue */
447		delay_time = now - entry->first_try;
448		WPA_PUT_BE32(acct_delay_time, delay_time);
449
450		wpa_printf(MSG_DEBUG,
451			   "RADIUS: Updated Acct-Delay-Time to %u for retransmission",
452			   delay_time);
453		radius_msg_finish_acct(entry->msg, entry->shared_secret,
454				       entry->shared_secret_len);
455		if (radius->conf->msg_dumps)
456			radius_msg_dump(entry->msg);
457	}
458
459	/* retransmit; remove entry if too many attempts */
460	if (entry->accu_attempts > RADIUS_CLIENT_MAX_FAILOVER *
461	    RADIUS_CLIENT_NUM_FAILOVER * num_servers) {
462		wpa_printf(MSG_INFO,
463			   "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
464		return 1;
465	}
466
467	entry->attempts++;
468	entry->accu_attempts++;
469	hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
470		       HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
471		       radius_msg_get_hdr(entry->msg)->identifier);
472
473	os_get_reltime(&entry->last_attempt);
474	buf = radius_msg_get_buf(entry->msg);
475	if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
476		if (radius_client_handle_send_error(radius, s, entry->msg_type)
477		    > 0)
478			return 0;
479	}
480
481	entry->next_try = now + entry->next_wait;
482	entry->next_wait *= 2;
483	if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
484		entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
485
486	return 0;
487}
488
489
490static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
491{
492	struct radius_client_data *radius = eloop_ctx;
493	struct os_reltime now;
494	os_time_t first;
495	struct radius_msg_list *entry, *prev, *tmp;
496	int auth_failover = 0, acct_failover = 0;
497	size_t prev_num_msgs;
498	int s;
499
500	entry = radius->msgs;
501	if (!entry)
502		return;
503
504	os_get_reltime(&now);
505
506	while (entry) {
507		if (now.sec >= entry->next_try) {
508			s = entry->msg_type == RADIUS_AUTH ? radius->auth_sock :
509				radius->acct_sock;
510			if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER ||
511			    (s < 0 && entry->attempts > 0)) {
512				if (entry->msg_type == RADIUS_ACCT ||
513				    entry->msg_type == RADIUS_ACCT_INTERIM)
514					acct_failover++;
515				else
516					auth_failover++;
517			}
518		}
519		entry = entry->next;
520	}
521
522	if (auth_failover)
523		radius_client_auth_failover(radius);
524
525	if (acct_failover)
526		radius_client_acct_failover(radius);
527
528	entry = radius->msgs;
529	first = 0;
530
531	prev = NULL;
532	while (entry) {
533		prev_num_msgs = radius->num_msgs;
534		if (now.sec >= entry->next_try &&
535		    radius_client_retransmit(radius, entry, now.sec)) {
536			if (prev)
537				prev->next = entry->next;
538			else
539				radius->msgs = entry->next;
540
541			tmp = entry;
542			entry = entry->next;
543			radius_client_msg_free(tmp);
544			radius->num_msgs--;
545			continue;
546		}
547
548		if (prev_num_msgs != radius->num_msgs) {
549			wpa_printf(MSG_DEBUG,
550				   "RADIUS: Message removed from queue - restart from beginning");
551			entry = radius->msgs;
552			prev = NULL;
553			continue;
554		}
555
556		if (first == 0 || entry->next_try < first)
557			first = entry->next_try;
558
559		prev = entry;
560		entry = entry->next;
561	}
562
563	if (radius->msgs) {
564		if (first < now.sec)
565			first = now.sec;
566		eloop_cancel_timeout(radius_client_timer, radius, NULL);
567		eloop_register_timeout(first - now.sec, 0,
568				       radius_client_timer, radius, NULL);
569		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
570			       HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
571			       "retransmit in %ld seconds",
572			       (long int) (first - now.sec));
573	}
574}
575
576
577static void radius_client_auth_failover(struct radius_client_data *radius)
578{
579	struct hostapd_radius_servers *conf = radius->conf;
580	struct hostapd_radius_server *next, *old;
581	struct radius_msg_list *entry;
582	char abuf[50];
583
584	old = conf->auth_server;
585	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
586		       HOSTAPD_LEVEL_NOTICE,
587		       "No response from Authentication server %s:%d - failover",
588		       hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
589		       old->port);
590
591	for (entry = radius->msgs; entry; entry = entry->next) {
592		if (entry->msg_type == RADIUS_AUTH)
593			old->timeouts++;
594	}
595
596	next = old + 1;
597	if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
598		next = conf->auth_servers;
599	conf->auth_server = next;
600	radius_change_server(radius, next, old,
601			     radius->auth_serv_sock,
602			     radius->auth_serv_sock6, 1);
603}
604
605
606static void radius_client_acct_failover(struct radius_client_data *radius)
607{
608	struct hostapd_radius_servers *conf = radius->conf;
609	struct hostapd_radius_server *next, *old;
610	struct radius_msg_list *entry;
611	char abuf[50];
612
613	old = conf->acct_server;
614	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
615		       HOSTAPD_LEVEL_NOTICE,
616		       "No response from Accounting server %s:%d - failover",
617		       hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
618		       old->port);
619
620	for (entry = radius->msgs; entry; entry = entry->next) {
621		if (entry->msg_type == RADIUS_ACCT ||
622		    entry->msg_type == RADIUS_ACCT_INTERIM)
623			old->timeouts++;
624	}
625
626	next = old + 1;
627	if (next > &conf->acct_servers[conf->num_acct_servers - 1])
628		next = conf->acct_servers;
629	conf->acct_server = next;
630	radius_change_server(radius, next, old,
631			     radius->acct_serv_sock,
632			     radius->acct_serv_sock6, 0);
633}
634
635
636static void radius_client_update_timeout(struct radius_client_data *radius)
637{
638	struct os_reltime now;
639	os_time_t first;
640	struct radius_msg_list *entry;
641
642	eloop_cancel_timeout(radius_client_timer, radius, NULL);
643
644	if (radius->msgs == NULL) {
645		return;
646	}
647
648	first = 0;
649	for (entry = radius->msgs; entry; entry = entry->next) {
650		if (first == 0 || entry->next_try < first)
651			first = entry->next_try;
652	}
653
654	os_get_reltime(&now);
655	if (first < now.sec)
656		first = now.sec;
657	eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius,
658			       NULL);
659	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
660		       HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
661		       " %ld seconds", (long int) (first - now.sec));
662}
663
664
665static void radius_client_list_add(struct radius_client_data *radius,
666				   struct radius_msg *msg,
667				   RadiusType msg_type,
668				   const u8 *shared_secret,
669				   size_t shared_secret_len, const u8 *addr)
670{
671	struct radius_msg_list *entry, *prev;
672
673	if (eloop_terminated()) {
674		/* No point in adding entries to retransmit queue since event
675		 * loop has already been terminated. */
676		radius_msg_free(msg);
677		return;
678	}
679
680	entry = os_zalloc(sizeof(*entry));
681	if (entry == NULL) {
682		wpa_printf(MSG_INFO, "RADIUS: Failed to add packet into retransmit list");
683		radius_msg_free(msg);
684		return;
685	}
686
687	if (addr)
688		os_memcpy(entry->addr, addr, ETH_ALEN);
689	entry->msg = msg;
690	entry->msg_type = msg_type;
691	entry->shared_secret = shared_secret;
692	entry->shared_secret_len = shared_secret_len;
693	os_get_reltime(&entry->last_attempt);
694	entry->first_try = entry->last_attempt.sec;
695	entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
696	entry->attempts = 1;
697	entry->accu_attempts = 1;
698	entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
699	if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
700		entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
701	entry->next = radius->msgs;
702	radius->msgs = entry;
703	radius_client_update_timeout(radius);
704
705	if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
706		wpa_printf(MSG_INFO, "RADIUS: Removing the oldest un-ACKed packet due to retransmit list limits");
707		prev = NULL;
708		while (entry->next) {
709			prev = entry;
710			entry = entry->next;
711		}
712		if (prev) {
713			prev->next = NULL;
714			radius_client_msg_free(entry);
715		}
716	} else
717		radius->num_msgs++;
718}
719
720
721/**
722 * radius_client_send - Send a RADIUS request
723 * @radius: RADIUS client context from radius_client_init()
724 * @msg: RADIUS message to be sent
725 * @msg_type: Message type (RADIUS_AUTH, RADIUS_ACCT, RADIUS_ACCT_INTERIM)
726 * @addr: MAC address of the device related to this message or %NULL
727 * Returns: 0 on success, -1 on failure
728 *
729 * This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or
730 * accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference
731 * between accounting and interim accounting messages is that the interim
732 * message will not be retransmitted. Instead, a callback is used to indicate
733 * that the transmission failed for the specific station @addr so that a new
734 * interim accounting update message can be generated with up-to-date session
735 * data instead of trying to resend old information.
736 *
737 * The message is added on the retransmission queue and will be retransmitted
738 * automatically until a response is received or maximum number of retries
739 * (RADIUS_CLIENT_MAX_FAILOVER * RADIUS_CLIENT_NUM_FAILOVER) is reached. No
740 * such retries are used with RADIUS_ACCT_INTERIM, i.e., such a pending message
741 * is removed from the queue automatically on transmission failure.
742 *
743 * The related device MAC address can be used to identify pending messages that
744 * can be removed with radius_client_flush_auth().
745 */
746int radius_client_send(struct radius_client_data *radius,
747		       struct radius_msg *msg, RadiusType msg_type,
748		       const u8 *addr)
749{
750	struct hostapd_radius_servers *conf = radius->conf;
751	const u8 *shared_secret;
752	size_t shared_secret_len;
753	char *name;
754	int s, res;
755	struct wpabuf *buf;
756
757	if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
758		if (conf->acct_server && radius->acct_sock < 0)
759			radius_client_init_acct(radius);
760
761		if (conf->acct_server == NULL || radius->acct_sock < 0 ||
762		    conf->acct_server->shared_secret == NULL) {
763			hostapd_logger(radius->ctx, NULL,
764				       HOSTAPD_MODULE_RADIUS,
765				       HOSTAPD_LEVEL_INFO,
766				       "No accounting server configured");
767			return -1;
768		}
769		shared_secret = conf->acct_server->shared_secret;
770		shared_secret_len = conf->acct_server->shared_secret_len;
771		radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
772		name = "accounting";
773		s = radius->acct_sock;
774		conf->acct_server->requests++;
775	} else {
776		if (conf->auth_server && radius->auth_sock < 0)
777			radius_client_init_auth(radius);
778
779		if (conf->auth_server == NULL || radius->auth_sock < 0 ||
780		    conf->auth_server->shared_secret == NULL) {
781			hostapd_logger(radius->ctx, NULL,
782				       HOSTAPD_MODULE_RADIUS,
783				       HOSTAPD_LEVEL_INFO,
784				       "No authentication server configured");
785			return -1;
786		}
787		shared_secret = conf->auth_server->shared_secret;
788		shared_secret_len = conf->auth_server->shared_secret_len;
789		radius_msg_finish(msg, shared_secret, shared_secret_len);
790		name = "authentication";
791		s = radius->auth_sock;
792		conf->auth_server->requests++;
793	}
794
795	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
796		       HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
797		       "server", name);
798	if (conf->msg_dumps)
799		radius_msg_dump(msg);
800
801	buf = radius_msg_get_buf(msg);
802	res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0);
803	if (res < 0)
804		radius_client_handle_send_error(radius, s, msg_type);
805
806	radius_client_list_add(radius, msg, msg_type, shared_secret,
807			       shared_secret_len, addr);
808
809	return 0;
810}
811
812
813static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
814{
815	struct radius_client_data *radius = eloop_ctx;
816	struct hostapd_radius_servers *conf = radius->conf;
817	RadiusType msg_type = (RadiusType) sock_ctx;
818	int len, roundtrip;
819	unsigned char buf[3000];
820	struct radius_msg *msg;
821	struct radius_hdr *hdr;
822	struct radius_rx_handler *handlers;
823	size_t num_handlers, i;
824	struct radius_msg_list *req, *prev_req;
825	struct os_reltime now;
826	struct hostapd_radius_server *rconf;
827	int invalid_authenticator = 0;
828
829	if (msg_type == RADIUS_ACCT) {
830		handlers = radius->acct_handlers;
831		num_handlers = radius->num_acct_handlers;
832		rconf = conf->acct_server;
833	} else {
834		handlers = radius->auth_handlers;
835		num_handlers = radius->num_auth_handlers;
836		rconf = conf->auth_server;
837	}
838
839	len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
840	if (len < 0) {
841		wpa_printf(MSG_INFO, "recv[RADIUS]: %s", strerror(errno));
842		return;
843	}
844	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
845		       HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
846		       "server", len);
847	if (len == sizeof(buf)) {
848		wpa_printf(MSG_INFO, "RADIUS: Possibly too long UDP frame for our buffer - dropping it");
849		return;
850	}
851
852	msg = radius_msg_parse(buf, len);
853	if (msg == NULL) {
854		wpa_printf(MSG_INFO, "RADIUS: Parsing incoming frame failed");
855		rconf->malformed_responses++;
856		return;
857	}
858	hdr = radius_msg_get_hdr(msg);
859
860	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
861		       HOSTAPD_LEVEL_DEBUG, "Received RADIUS message");
862	if (conf->msg_dumps)
863		radius_msg_dump(msg);
864
865	switch (hdr->code) {
866	case RADIUS_CODE_ACCESS_ACCEPT:
867		rconf->access_accepts++;
868		break;
869	case RADIUS_CODE_ACCESS_REJECT:
870		rconf->access_rejects++;
871		break;
872	case RADIUS_CODE_ACCESS_CHALLENGE:
873		rconf->access_challenges++;
874		break;
875	case RADIUS_CODE_ACCOUNTING_RESPONSE:
876		rconf->responses++;
877		break;
878	}
879
880	prev_req = NULL;
881	req = radius->msgs;
882	while (req) {
883		/* TODO: also match by src addr:port of the packet when using
884		 * alternative RADIUS servers (?) */
885		if ((req->msg_type == msg_type ||
886		     (req->msg_type == RADIUS_ACCT_INTERIM &&
887		      msg_type == RADIUS_ACCT)) &&
888		    radius_msg_get_hdr(req->msg)->identifier ==
889		    hdr->identifier)
890			break;
891
892		prev_req = req;
893		req = req->next;
894	}
895
896	if (req == NULL) {
897		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
898			       HOSTAPD_LEVEL_DEBUG,
899			       "No matching RADIUS request found (type=%d "
900			       "id=%d) - dropping packet",
901			       msg_type, hdr->identifier);
902		goto fail;
903	}
904
905	os_get_reltime(&now);
906	roundtrip = (now.sec - req->last_attempt.sec) * 100 +
907		(now.usec - req->last_attempt.usec) / 10000;
908	hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
909		       HOSTAPD_LEVEL_DEBUG,
910		       "Received RADIUS packet matched with a pending "
911		       "request, round trip time %d.%02d sec",
912		       roundtrip / 100, roundtrip % 100);
913	rconf->round_trip_time = roundtrip;
914
915	/* Remove ACKed RADIUS packet from retransmit list */
916	if (prev_req)
917		prev_req->next = req->next;
918	else
919		radius->msgs = req->next;
920	radius->num_msgs--;
921
922	for (i = 0; i < num_handlers; i++) {
923		RadiusRxResult res;
924		res = handlers[i].handler(msg, req->msg, req->shared_secret,
925					  req->shared_secret_len,
926					  handlers[i].data);
927		switch (res) {
928		case RADIUS_RX_PROCESSED:
929			radius_msg_free(msg);
930			/* fall through */
931		case RADIUS_RX_QUEUED:
932			radius_client_msg_free(req);
933			return;
934		case RADIUS_RX_INVALID_AUTHENTICATOR:
935			invalid_authenticator++;
936			/* fall through */
937		case RADIUS_RX_UNKNOWN:
938			/* continue with next handler */
939			break;
940		}
941	}
942
943	if (invalid_authenticator)
944		rconf->bad_authenticators++;
945	else
946		rconf->unknown_types++;
947	hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
948		       HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found "
949		       "(type=%d code=%d id=%d)%s - dropping packet",
950		       msg_type, hdr->code, hdr->identifier,
951		       invalid_authenticator ? " [INVALID AUTHENTICATOR]" :
952		       "");
953	radius_client_msg_free(req);
954
955 fail:
956	radius_msg_free(msg);
957}
958
959
960/**
961 * radius_client_get_id - Get an identifier for a new RADIUS message
962 * @radius: RADIUS client context from radius_client_init()
963 * Returns: Allocated identifier
964 *
965 * This function is used to fetch a unique (among pending requests) identifier
966 * for a new RADIUS message.
967 */
968u8 radius_client_get_id(struct radius_client_data *radius)
969{
970	struct radius_msg_list *entry, *prev, *_remove;
971	u8 id = radius->next_radius_identifier++;
972
973	/* remove entries with matching id from retransmit list to avoid
974	 * using new reply from the RADIUS server with an old request */
975	entry = radius->msgs;
976	prev = NULL;
977	while (entry) {
978		if (radius_msg_get_hdr(entry->msg)->identifier == id) {
979			hostapd_logger(radius->ctx, entry->addr,
980				       HOSTAPD_MODULE_RADIUS,
981				       HOSTAPD_LEVEL_DEBUG,
982				       "Removing pending RADIUS message, "
983				       "since its id (%d) is reused", id);
984			if (prev)
985				prev->next = entry->next;
986			else
987				radius->msgs = entry->next;
988			_remove = entry;
989		} else {
990			_remove = NULL;
991			prev = entry;
992		}
993		entry = entry->next;
994
995		if (_remove)
996			radius_client_msg_free(_remove);
997	}
998
999	return id;
1000}
1001
1002
1003/**
1004 * radius_client_flush - Flush all pending RADIUS client messages
1005 * @radius: RADIUS client context from radius_client_init()
1006 * @only_auth: Whether only authentication messages are removed
1007 */
1008void radius_client_flush(struct radius_client_data *radius, int only_auth)
1009{
1010	struct radius_msg_list *entry, *prev, *tmp;
1011
1012	if (!radius)
1013		return;
1014
1015	prev = NULL;
1016	entry = radius->msgs;
1017
1018	while (entry) {
1019		if (!only_auth || entry->msg_type == RADIUS_AUTH) {
1020			if (prev)
1021				prev->next = entry->next;
1022			else
1023				radius->msgs = entry->next;
1024
1025			tmp = entry;
1026			entry = entry->next;
1027			radius_client_msg_free(tmp);
1028			radius->num_msgs--;
1029		} else {
1030			prev = entry;
1031			entry = entry->next;
1032		}
1033	}
1034
1035	if (radius->msgs == NULL)
1036		eloop_cancel_timeout(radius_client_timer, radius, NULL);
1037}
1038
1039
1040static void radius_client_update_acct_msgs(struct radius_client_data *radius,
1041					   const u8 *shared_secret,
1042					   size_t shared_secret_len)
1043{
1044	struct radius_msg_list *entry;
1045
1046	if (!radius)
1047		return;
1048
1049	for (entry = radius->msgs; entry; entry = entry->next) {
1050		if (entry->msg_type == RADIUS_ACCT) {
1051			entry->shared_secret = shared_secret;
1052			entry->shared_secret_len = shared_secret_len;
1053			radius_msg_finish_acct(entry->msg, shared_secret,
1054					       shared_secret_len);
1055		}
1056	}
1057}
1058
1059
1060static int
1061radius_change_server(struct radius_client_data *radius,
1062		     struct hostapd_radius_server *nserv,
1063		     struct hostapd_radius_server *oserv,
1064		     int sock, int sock6, int auth)
1065{
1066	struct sockaddr_in serv, claddr;
1067#ifdef CONFIG_IPV6
1068	struct sockaddr_in6 serv6, claddr6;
1069#endif /* CONFIG_IPV6 */
1070	struct sockaddr *addr, *cl_addr;
1071	socklen_t addrlen, claddrlen;
1072	char abuf[50];
1073	int sel_sock;
1074	struct radius_msg_list *entry;
1075	struct hostapd_radius_servers *conf = radius->conf;
1076	struct sockaddr_in disconnect_addr = {
1077		.sin_family = AF_UNSPEC,
1078	};
1079
1080	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
1081		       HOSTAPD_LEVEL_INFO,
1082		       "%s server %s:%d",
1083		       auth ? "Authentication" : "Accounting",
1084		       hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
1085		       nserv->port);
1086
1087	if (oserv && oserv == nserv) {
1088		/* Reconnect to same server, flush */
1089		if (auth)
1090			radius_client_flush(radius, 1);
1091	}
1092
1093	if (oserv && oserv != nserv &&
1094	    (nserv->shared_secret_len != oserv->shared_secret_len ||
1095	     os_memcmp(nserv->shared_secret, oserv->shared_secret,
1096		       nserv->shared_secret_len) != 0)) {
1097		/* Pending RADIUS packets used different shared secret, so
1098		 * they need to be modified. Update accounting message
1099		 * authenticators here. Authentication messages are removed
1100		 * since they would require more changes and the new RADIUS
1101		 * server may not be prepared to receive them anyway due to
1102		 * missing state information. Client will likely retry
1103		 * authentication, so this should not be an issue. */
1104		if (auth)
1105			radius_client_flush(radius, 1);
1106		else {
1107			radius_client_update_acct_msgs(
1108				radius, nserv->shared_secret,
1109				nserv->shared_secret_len);
1110		}
1111	}
1112
1113	/* Reset retry counters */
1114	for (entry = radius->msgs; oserv && entry; entry = entry->next) {
1115		if ((auth && entry->msg_type != RADIUS_AUTH) ||
1116		    (!auth && entry->msg_type != RADIUS_ACCT))
1117			continue;
1118		entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
1119		entry->attempts = 1;
1120		entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
1121	}
1122
1123	if (radius->msgs) {
1124		eloop_cancel_timeout(radius_client_timer, radius, NULL);
1125		eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
1126				       radius_client_timer, radius, NULL);
1127	}
1128
1129	switch (nserv->addr.af) {
1130	case AF_INET:
1131		os_memset(&serv, 0, sizeof(serv));
1132		serv.sin_family = AF_INET;
1133		serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
1134		serv.sin_port = htons(nserv->port);
1135		addr = (struct sockaddr *) &serv;
1136		addrlen = sizeof(serv);
1137		sel_sock = sock;
1138		break;
1139#ifdef CONFIG_IPV6
1140	case AF_INET6:
1141		os_memset(&serv6, 0, sizeof(serv6));
1142		serv6.sin6_family = AF_INET6;
1143		os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
1144			  sizeof(struct in6_addr));
1145		serv6.sin6_port = htons(nserv->port);
1146		addr = (struct sockaddr *) &serv6;
1147		addrlen = sizeof(serv6);
1148		sel_sock = sock6;
1149		break;
1150#endif /* CONFIG_IPV6 */
1151	default:
1152		return -1;
1153	}
1154
1155	if (sel_sock < 0) {
1156		wpa_printf(MSG_INFO,
1157			   "RADIUS: No server socket available (af=%d sock=%d sock6=%d auth=%d",
1158			   nserv->addr.af, sock, sock6, auth);
1159		return -1;
1160	}
1161
1162	if (conf->force_client_addr) {
1163		switch (conf->client_addr.af) {
1164		case AF_INET:
1165			os_memset(&claddr, 0, sizeof(claddr));
1166			claddr.sin_family = AF_INET;
1167			claddr.sin_addr.s_addr = conf->client_addr.u.v4.s_addr;
1168			claddr.sin_port = htons(0);
1169			cl_addr = (struct sockaddr *) &claddr;
1170			claddrlen = sizeof(claddr);
1171			break;
1172#ifdef CONFIG_IPV6
1173		case AF_INET6:
1174			os_memset(&claddr6, 0, sizeof(claddr6));
1175			claddr6.sin6_family = AF_INET6;
1176			os_memcpy(&claddr6.sin6_addr, &conf->client_addr.u.v6,
1177				  sizeof(struct in6_addr));
1178			claddr6.sin6_port = htons(0);
1179			cl_addr = (struct sockaddr *) &claddr6;
1180			claddrlen = sizeof(claddr6);
1181			break;
1182#endif /* CONFIG_IPV6 */
1183		default:
1184			return -1;
1185		}
1186
1187		if (bind(sel_sock, cl_addr, claddrlen) < 0) {
1188			wpa_printf(MSG_INFO, "bind[radius]: %s",
1189				   strerror(errno));
1190			return -1;
1191		}
1192	}
1193
1194	/* Force a reconnect by disconnecting the socket first */
1195	if (connect(sel_sock, (struct sockaddr *) &disconnect_addr,
1196		    sizeof(disconnect_addr)) < 0)
1197		wpa_printf(MSG_INFO, "disconnect[radius]: %s", strerror(errno));
1198
1199	if (connect(sel_sock, addr, addrlen) < 0) {
1200		wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno));
1201		return -1;
1202	}
1203
1204#ifndef CONFIG_NATIVE_WINDOWS
1205	switch (nserv->addr.af) {
1206	case AF_INET:
1207		claddrlen = sizeof(claddr);
1208		if (getsockname(sel_sock, (struct sockaddr *) &claddr,
1209				&claddrlen) == 0) {
1210			wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
1211				   inet_ntoa(claddr.sin_addr),
1212				   ntohs(claddr.sin_port));
1213		}
1214		break;
1215#ifdef CONFIG_IPV6
1216	case AF_INET6: {
1217		claddrlen = sizeof(claddr6);
1218		if (getsockname(sel_sock, (struct sockaddr *) &claddr6,
1219				&claddrlen) == 0) {
1220			wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
1221				   inet_ntop(AF_INET6, &claddr6.sin6_addr,
1222					     abuf, sizeof(abuf)),
1223				   ntohs(claddr6.sin6_port));
1224		}
1225		break;
1226	}
1227#endif /* CONFIG_IPV6 */
1228	}
1229#endif /* CONFIG_NATIVE_WINDOWS */
1230
1231	if (auth)
1232		radius->auth_sock = sel_sock;
1233	else
1234		radius->acct_sock = sel_sock;
1235
1236	return 0;
1237}
1238
1239
1240static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
1241{
1242	struct radius_client_data *radius = eloop_ctx;
1243	struct hostapd_radius_servers *conf = radius->conf;
1244	struct hostapd_radius_server *oserv;
1245
1246	if (radius->auth_sock >= 0 && conf->auth_servers &&
1247	    conf->auth_server != conf->auth_servers) {
1248		oserv = conf->auth_server;
1249		conf->auth_server = conf->auth_servers;
1250		if (radius_change_server(radius, conf->auth_server, oserv,
1251					 radius->auth_serv_sock,
1252					 radius->auth_serv_sock6, 1) < 0) {
1253			conf->auth_server = oserv;
1254			radius_change_server(radius, oserv, conf->auth_server,
1255					     radius->auth_serv_sock,
1256					     radius->auth_serv_sock6, 1);
1257		}
1258	}
1259
1260	if (radius->acct_sock >= 0 && conf->acct_servers &&
1261	    conf->acct_server != conf->acct_servers) {
1262		oserv = conf->acct_server;
1263		conf->acct_server = conf->acct_servers;
1264		if (radius_change_server(radius, conf->acct_server, oserv,
1265					 radius->acct_serv_sock,
1266					 radius->acct_serv_sock6, 0) < 0) {
1267			conf->acct_server = oserv;
1268			radius_change_server(radius, oserv, conf->acct_server,
1269					     radius->acct_serv_sock,
1270					     radius->acct_serv_sock6, 0);
1271		}
1272	}
1273
1274	if (conf->retry_primary_interval)
1275		eloop_register_timeout(conf->retry_primary_interval, 0,
1276				       radius_retry_primary_timer, radius,
1277				       NULL);
1278}
1279
1280
1281static int radius_client_disable_pmtu_discovery(int s)
1282{
1283	int r = -1;
1284#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
1285	/* Turn off Path MTU discovery on IPv4/UDP sockets. */
1286	int action = IP_PMTUDISC_DONT;
1287	r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
1288		       sizeof(action));
1289	if (r == -1)
1290		wpa_printf(MSG_ERROR, "RADIUS: Failed to set IP_MTU_DISCOVER: %s",
1291			   strerror(errno));
1292#endif
1293	return r;
1294}
1295
1296
1297static void radius_close_auth_sockets(struct radius_client_data *radius)
1298{
1299	radius->auth_sock = -1;
1300
1301	if (radius->auth_serv_sock >= 0) {
1302		eloop_unregister_read_sock(radius->auth_serv_sock);
1303		close(radius->auth_serv_sock);
1304		radius->auth_serv_sock = -1;
1305	}
1306#ifdef CONFIG_IPV6
1307	if (radius->auth_serv_sock6 >= 0) {
1308		eloop_unregister_read_sock(radius->auth_serv_sock6);
1309		close(radius->auth_serv_sock6);
1310		radius->auth_serv_sock6 = -1;
1311	}
1312#endif /* CONFIG_IPV6 */
1313}
1314
1315
1316static void radius_close_acct_sockets(struct radius_client_data *radius)
1317{
1318	radius->acct_sock = -1;
1319
1320	if (radius->acct_serv_sock >= 0) {
1321		eloop_unregister_read_sock(radius->acct_serv_sock);
1322		close(radius->acct_serv_sock);
1323		radius->acct_serv_sock = -1;
1324	}
1325#ifdef CONFIG_IPV6
1326	if (radius->acct_serv_sock6 >= 0) {
1327		eloop_unregister_read_sock(radius->acct_serv_sock6);
1328		close(radius->acct_serv_sock6);
1329		radius->acct_serv_sock6 = -1;
1330	}
1331#endif /* CONFIG_IPV6 */
1332}
1333
1334
1335static int radius_client_init_auth(struct radius_client_data *radius)
1336{
1337	struct hostapd_radius_servers *conf = radius->conf;
1338	int ok = 0;
1339
1340	radius_close_auth_sockets(radius);
1341
1342	radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
1343	if (radius->auth_serv_sock < 0)
1344		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
1345			   strerror(errno));
1346	else {
1347		radius_client_disable_pmtu_discovery(radius->auth_serv_sock);
1348		ok++;
1349	}
1350
1351#ifdef CONFIG_IPV6
1352	radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
1353	if (radius->auth_serv_sock6 < 0)
1354		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
1355			   strerror(errno));
1356	else
1357		ok++;
1358#endif /* CONFIG_IPV6 */
1359
1360	if (ok == 0)
1361		return -1;
1362
1363	radius_change_server(radius, conf->auth_server, NULL,
1364			     radius->auth_serv_sock, radius->auth_serv_sock6,
1365			     1);
1366
1367	if (radius->auth_serv_sock >= 0 &&
1368	    eloop_register_read_sock(radius->auth_serv_sock,
1369				     radius_client_receive, radius,
1370				     (void *) RADIUS_AUTH)) {
1371		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
1372		radius_close_auth_sockets(radius);
1373		return -1;
1374	}
1375
1376#ifdef CONFIG_IPV6
1377	if (radius->auth_serv_sock6 >= 0 &&
1378	    eloop_register_read_sock(radius->auth_serv_sock6,
1379				     radius_client_receive, radius,
1380				     (void *) RADIUS_AUTH)) {
1381		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
1382		radius_close_auth_sockets(radius);
1383		return -1;
1384	}
1385#endif /* CONFIG_IPV6 */
1386
1387	return 0;
1388}
1389
1390
1391static int radius_client_init_acct(struct radius_client_data *radius)
1392{
1393	struct hostapd_radius_servers *conf = radius->conf;
1394	int ok = 0;
1395
1396	radius_close_acct_sockets(radius);
1397
1398	radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
1399	if (radius->acct_serv_sock < 0)
1400		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
1401			   strerror(errno));
1402	else {
1403		radius_client_disable_pmtu_discovery(radius->acct_serv_sock);
1404		ok++;
1405	}
1406
1407#ifdef CONFIG_IPV6
1408	radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
1409	if (radius->acct_serv_sock6 < 0)
1410		wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
1411			   strerror(errno));
1412	else
1413		ok++;
1414#endif /* CONFIG_IPV6 */
1415
1416	if (ok == 0)
1417		return -1;
1418
1419	radius_change_server(radius, conf->acct_server, NULL,
1420			     radius->acct_serv_sock, radius->acct_serv_sock6,
1421			     0);
1422
1423	if (radius->acct_serv_sock >= 0 &&
1424	    eloop_register_read_sock(radius->acct_serv_sock,
1425				     radius_client_receive, radius,
1426				     (void *) RADIUS_ACCT)) {
1427		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
1428		radius_close_acct_sockets(radius);
1429		return -1;
1430	}
1431
1432#ifdef CONFIG_IPV6
1433	if (radius->acct_serv_sock6 >= 0 &&
1434	    eloop_register_read_sock(radius->acct_serv_sock6,
1435				     radius_client_receive, radius,
1436				     (void *) RADIUS_ACCT)) {
1437		wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
1438		radius_close_acct_sockets(radius);
1439		return -1;
1440	}
1441#endif /* CONFIG_IPV6 */
1442
1443	return 0;
1444}
1445
1446
1447/**
1448 * radius_client_init - Initialize RADIUS client
1449 * @ctx: Callback context to be used in hostapd_logger() calls
1450 * @conf: RADIUS client configuration (RADIUS servers)
1451 * Returns: Pointer to private RADIUS client context or %NULL on failure
1452 *
1453 * The caller is responsible for keeping the configuration data available for
1454 * the lifetime of the RADIUS client, i.e., until radius_client_deinit() is
1455 * called for the returned context pointer.
1456 */
1457struct radius_client_data *
1458radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
1459{
1460	struct radius_client_data *radius;
1461
1462	radius = os_zalloc(sizeof(struct radius_client_data));
1463	if (radius == NULL)
1464		return NULL;
1465
1466	radius->ctx = ctx;
1467	radius->conf = conf;
1468	radius->auth_serv_sock = radius->acct_serv_sock =
1469		radius->auth_serv_sock6 = radius->acct_serv_sock6 =
1470		radius->auth_sock = radius->acct_sock = -1;
1471
1472	if (conf->auth_server && radius_client_init_auth(radius)) {
1473		radius_client_deinit(radius);
1474		return NULL;
1475	}
1476
1477	if (conf->acct_server && radius_client_init_acct(radius)) {
1478		radius_client_deinit(radius);
1479		return NULL;
1480	}
1481
1482	if (conf->retry_primary_interval)
1483		eloop_register_timeout(conf->retry_primary_interval, 0,
1484				       radius_retry_primary_timer, radius,
1485				       NULL);
1486
1487	return radius;
1488}
1489
1490
1491/**
1492 * radius_client_deinit - Deinitialize RADIUS client
1493 * @radius: RADIUS client context from radius_client_init()
1494 */
1495void radius_client_deinit(struct radius_client_data *radius)
1496{
1497	if (!radius)
1498		return;
1499
1500	radius_close_auth_sockets(radius);
1501	radius_close_acct_sockets(radius);
1502
1503	eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
1504
1505	radius_client_flush(radius, 0);
1506	os_free(radius->auth_handlers);
1507	os_free(radius->acct_handlers);
1508	os_free(radius);
1509}
1510
1511
1512/**
1513 * radius_client_flush_auth - Flush pending RADIUS messages for an address
1514 * @radius: RADIUS client context from radius_client_init()
1515 * @addr: MAC address of the related device
1516 *
1517 * This function can be used to remove pending RADIUS authentication messages
1518 * that are related to a specific device. The addr parameter is matched with
1519 * the one used in radius_client_send() call that was used to transmit the
1520 * authentication request.
1521 */
1522void radius_client_flush_auth(struct radius_client_data *radius,
1523			      const u8 *addr)
1524{
1525	struct radius_msg_list *entry, *prev, *tmp;
1526
1527	prev = NULL;
1528	entry = radius->msgs;
1529	while (entry) {
1530		if (entry->msg_type == RADIUS_AUTH &&
1531		    os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
1532			hostapd_logger(radius->ctx, addr,
1533				       HOSTAPD_MODULE_RADIUS,
1534				       HOSTAPD_LEVEL_DEBUG,
1535				       "Removing pending RADIUS authentication"
1536				       " message for removed client");
1537
1538			if (prev)
1539				prev->next = entry->next;
1540			else
1541				radius->msgs = entry->next;
1542
1543			tmp = entry;
1544			entry = entry->next;
1545			radius_client_msg_free(tmp);
1546			radius->num_msgs--;
1547			continue;
1548		}
1549
1550		prev = entry;
1551		entry = entry->next;
1552	}
1553}
1554
1555
1556static int radius_client_dump_auth_server(char *buf, size_t buflen,
1557					  struct hostapd_radius_server *serv,
1558					  struct radius_client_data *cli)
1559{
1560	int pending = 0;
1561	struct radius_msg_list *msg;
1562	char abuf[50];
1563
1564	if (cli) {
1565		for (msg = cli->msgs; msg; msg = msg->next) {
1566			if (msg->msg_type == RADIUS_AUTH)
1567				pending++;
1568		}
1569	}
1570
1571	return os_snprintf(buf, buflen,
1572			   "radiusAuthServerIndex=%d\n"
1573			   "radiusAuthServerAddress=%s\n"
1574			   "radiusAuthClientServerPortNumber=%d\n"
1575			   "radiusAuthClientRoundTripTime=%d\n"
1576			   "radiusAuthClientAccessRequests=%u\n"
1577			   "radiusAuthClientAccessRetransmissions=%u\n"
1578			   "radiusAuthClientAccessAccepts=%u\n"
1579			   "radiusAuthClientAccessRejects=%u\n"
1580			   "radiusAuthClientAccessChallenges=%u\n"
1581			   "radiusAuthClientMalformedAccessResponses=%u\n"
1582			   "radiusAuthClientBadAuthenticators=%u\n"
1583			   "radiusAuthClientPendingRequests=%u\n"
1584			   "radiusAuthClientTimeouts=%u\n"
1585			   "radiusAuthClientUnknownTypes=%u\n"
1586			   "radiusAuthClientPacketsDropped=%u\n",
1587			   serv->index,
1588			   hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1589			   serv->port,
1590			   serv->round_trip_time,
1591			   serv->requests,
1592			   serv->retransmissions,
1593			   serv->access_accepts,
1594			   serv->access_rejects,
1595			   serv->access_challenges,
1596			   serv->malformed_responses,
1597			   serv->bad_authenticators,
1598			   pending,
1599			   serv->timeouts,
1600			   serv->unknown_types,
1601			   serv->packets_dropped);
1602}
1603
1604
1605static int radius_client_dump_acct_server(char *buf, size_t buflen,
1606					  struct hostapd_radius_server *serv,
1607					  struct radius_client_data *cli)
1608{
1609	int pending = 0;
1610	struct radius_msg_list *msg;
1611	char abuf[50];
1612
1613	if (cli) {
1614		for (msg = cli->msgs; msg; msg = msg->next) {
1615			if (msg->msg_type == RADIUS_ACCT ||
1616			    msg->msg_type == RADIUS_ACCT_INTERIM)
1617				pending++;
1618		}
1619	}
1620
1621	return os_snprintf(buf, buflen,
1622			   "radiusAccServerIndex=%d\n"
1623			   "radiusAccServerAddress=%s\n"
1624			   "radiusAccClientServerPortNumber=%d\n"
1625			   "radiusAccClientRoundTripTime=%d\n"
1626			   "radiusAccClientRequests=%u\n"
1627			   "radiusAccClientRetransmissions=%u\n"
1628			   "radiusAccClientResponses=%u\n"
1629			   "radiusAccClientMalformedResponses=%u\n"
1630			   "radiusAccClientBadAuthenticators=%u\n"
1631			   "radiusAccClientPendingRequests=%u\n"
1632			   "radiusAccClientTimeouts=%u\n"
1633			   "radiusAccClientUnknownTypes=%u\n"
1634			   "radiusAccClientPacketsDropped=%u\n",
1635			   serv->index,
1636			   hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1637			   serv->port,
1638			   serv->round_trip_time,
1639			   serv->requests,
1640			   serv->retransmissions,
1641			   serv->responses,
1642			   serv->malformed_responses,
1643			   serv->bad_authenticators,
1644			   pending,
1645			   serv->timeouts,
1646			   serv->unknown_types,
1647			   serv->packets_dropped);
1648}
1649
1650
1651/**
1652 * radius_client_get_mib - Get RADIUS client MIB information
1653 * @radius: RADIUS client context from radius_client_init()
1654 * @buf: Buffer for returning MIB data in text format
1655 * @buflen: Maximum buf length in octets
1656 * Returns: Number of octets written into the buffer
1657 */
1658int radius_client_get_mib(struct radius_client_data *radius, char *buf,
1659			  size_t buflen)
1660{
1661	struct hostapd_radius_servers *conf;
1662	int i;
1663	struct hostapd_radius_server *serv;
1664	int count = 0;
1665
1666	if (!radius)
1667		return 0;
1668
1669	conf = radius->conf;
1670
1671	if (conf->auth_servers) {
1672		for (i = 0; i < conf->num_auth_servers; i++) {
1673			serv = &conf->auth_servers[i];
1674			count += radius_client_dump_auth_server(
1675				buf + count, buflen - count, serv,
1676				serv == conf->auth_server ?
1677				radius : NULL);
1678		}
1679	}
1680
1681	if (conf->acct_servers) {
1682		for (i = 0; i < conf->num_acct_servers; i++) {
1683			serv = &conf->acct_servers[i];
1684			count += radius_client_dump_acct_server(
1685				buf + count, buflen - count, serv,
1686				serv == conf->acct_server ?
1687				radius : NULL);
1688		}
1689	}
1690
1691	return count;
1692}
1693
1694
1695void radius_client_reconfig(struct radius_client_data *radius,
1696			    struct hostapd_radius_servers *conf)
1697{
1698	if (radius)
1699		radius->conf = conf;
1700}
1701