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