Home | History | Annotate | Download | only in wpa_supplicant
      1 /*
      2  * hostapd / RADIUS client
      3  * Copyright (c) 2002-2005, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License version 2 as
      7  * published by the Free Software Foundation.
      8  *
      9  * Alternatively, this software may be distributed under the terms of BSD
     10  * license.
     11  *
     12  * See README and COPYING for more details.
     13  */
     14 
     15 #include "includes.h"
     16 
     17 #include "hostapd.h"
     18 #include "radius.h"
     19 #include "radius_client.h"
     20 #include "eloop.h"
     21 
     22 /* Defaults for RADIUS retransmit values (exponential backoff) */
     23 #define RADIUS_CLIENT_FIRST_WAIT 3 /* seconds */
     24 #define RADIUS_CLIENT_MAX_WAIT 120 /* seconds */
     25 #define RADIUS_CLIENT_MAX_RETRIES 10 /* maximum number of retransmit attempts
     26 				      * before entry is removed from retransmit
     27 				      * list */
     28 #define RADIUS_CLIENT_MAX_ENTRIES 30 /* maximum number of entries in retransmit
     29 				      * list (oldest will be removed, if this
     30 				      * limit is exceeded) */
     31 #define RADIUS_CLIENT_NUM_FAILOVER 4 /* try to change RADIUS server after this
     32 				      * many failed retry attempts */
     33 
     34 
     35 struct radius_rx_handler {
     36 	RadiusRxResult (*handler)(struct radius_msg *msg,
     37 				  struct radius_msg *req,
     38 				  u8 *shared_secret, size_t shared_secret_len,
     39 				  void *data);
     40 	void *data;
     41 };
     42 
     43 
     44 /* RADIUS message retransmit list */
     45 struct radius_msg_list {
     46 	u8 addr[ETH_ALEN]; /* STA/client address; used to find RADIUS messages
     47 			    * for the same STA. */
     48 	struct radius_msg *msg;
     49 	RadiusType msg_type;
     50 	os_time_t first_try;
     51 	os_time_t next_try;
     52 	int attempts;
     53 	int next_wait;
     54 	struct os_time last_attempt;
     55 
     56 	u8 *shared_secret;
     57 	size_t shared_secret_len;
     58 
     59 	/* TODO: server config with failover to backup server(s) */
     60 
     61 	struct radius_msg_list *next;
     62 };
     63 
     64 
     65 struct radius_client_data {
     66 	void *ctx;
     67 	struct hostapd_radius_servers *conf;
     68 
     69 	int auth_serv_sock; /* socket for authentication RADIUS messages */
     70 	int acct_serv_sock; /* socket for accounting RADIUS messages */
     71 	int auth_serv_sock6;
     72 	int acct_serv_sock6;
     73 	int auth_sock; /* currently used socket */
     74 	int acct_sock; /* currently used socket */
     75 
     76 	struct radius_rx_handler *auth_handlers;
     77 	size_t num_auth_handlers;
     78 	struct radius_rx_handler *acct_handlers;
     79 	size_t num_acct_handlers;
     80 
     81 	struct radius_msg_list *msgs;
     82 	size_t num_msgs;
     83 
     84 	u8 next_radius_identifier;
     85 };
     86 
     87 
     88 static int
     89 radius_change_server(struct radius_client_data *radius,
     90 		     struct hostapd_radius_server *nserv,
     91 		     struct hostapd_radius_server *oserv,
     92 		     int sock, int sock6, int auth);
     93 static int radius_client_init_acct(struct radius_client_data *radius);
     94 static int radius_client_init_auth(struct radius_client_data *radius);
     95 
     96 
     97 static void radius_client_msg_free(struct radius_msg_list *req)
     98 {
     99 	radius_msg_free(req->msg);
    100 	os_free(req->msg);
    101 	os_free(req);
    102 }
    103 
    104 
    105 int radius_client_register(struct radius_client_data *radius,
    106 			   RadiusType msg_type,
    107 			   RadiusRxResult (*handler)(struct radius_msg *msg,
    108 						     struct radius_msg *req,
    109 						     u8 *shared_secret,
    110 						     size_t shared_secret_len,
    111 						     void *data),
    112 			   void *data)
    113 {
    114 	struct radius_rx_handler **handlers, *newh;
    115 	size_t *num;
    116 
    117 	if (msg_type == RADIUS_ACCT) {
    118 		handlers = &radius->acct_handlers;
    119 		num = &radius->num_acct_handlers;
    120 	} else {
    121 		handlers = &radius->auth_handlers;
    122 		num = &radius->num_auth_handlers;
    123 	}
    124 
    125 	newh = os_realloc(*handlers,
    126 			  (*num + 1) * sizeof(struct radius_rx_handler));
    127 	if (newh == NULL)
    128 		return -1;
    129 
    130 	newh[*num].handler = handler;
    131 	newh[*num].data = data;
    132 	(*num)++;
    133 	*handlers = newh;
    134 
    135 	return 0;
    136 }
    137 
    138 
    139 static void radius_client_handle_send_error(struct radius_client_data *radius,
    140 					    int s, RadiusType msg_type)
    141 {
    142 #ifndef CONFIG_NATIVE_WINDOWS
    143 	int _errno = errno;
    144 	perror("send[RADIUS]");
    145 	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
    146 	    _errno == EBADF) {
    147 		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
    148 			       HOSTAPD_LEVEL_INFO,
    149 			       "Send failed - maybe interface status changed -"
    150 			       " try to connect again");
    151 		eloop_unregister_read_sock(s);
    152 		close(s);
    153 		if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM)
    154 			radius_client_init_acct(radius);
    155 		else
    156 			radius_client_init_auth(radius);
    157 	}
    158 #endif /* CONFIG_NATIVE_WINDOWS */
    159 }
    160 
    161 
    162 static int radius_client_retransmit(struct radius_client_data *radius,
    163 				    struct radius_msg_list *entry,
    164 				    os_time_t now)
    165 {
    166 	struct hostapd_radius_servers *conf = radius->conf;
    167 	int s;
    168 
    169 	if (entry->msg_type == RADIUS_ACCT ||
    170 	    entry->msg_type == RADIUS_ACCT_INTERIM) {
    171 		s = radius->acct_sock;
    172 		if (entry->attempts == 0)
    173 			conf->acct_server->requests++;
    174 		else {
    175 			conf->acct_server->timeouts++;
    176 			conf->acct_server->retransmissions++;
    177 		}
    178 	} else {
    179 		s = radius->auth_sock;
    180 		if (entry->attempts == 0)
    181 			conf->auth_server->requests++;
    182 		else {
    183 			conf->auth_server->timeouts++;
    184 			conf->auth_server->retransmissions++;
    185 		}
    186 	}
    187 
    188 	/* retransmit; remove entry if too many attempts */
    189 	entry->attempts++;
    190 	hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
    191 		       HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
    192 		       entry->msg->hdr->identifier);
    193 
    194 	os_get_time(&entry->last_attempt);
    195 	if (send(s, entry->msg->buf, entry->msg->buf_used, 0) < 0)
    196 		radius_client_handle_send_error(radius, s, entry->msg_type);
    197 
    198 	entry->next_try = now + entry->next_wait;
    199 	entry->next_wait *= 2;
    200 	if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
    201 		entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
    202 	if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
    203 		printf("Removing un-ACKed RADIUS message due to too many "
    204 		       "failed retransmit attempts\n");
    205 		return 1;
    206 	}
    207 
    208 	return 0;
    209 }
    210 
    211 
    212 static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
    213 {
    214 	struct radius_client_data *radius = eloop_ctx;
    215 	struct hostapd_radius_servers *conf = radius->conf;
    216 	struct os_time now;
    217 	os_time_t first;
    218 	struct radius_msg_list *entry, *prev, *tmp;
    219 	int auth_failover = 0, acct_failover = 0;
    220 	char abuf[50];
    221 
    222 	entry = radius->msgs;
    223 	if (!entry)
    224 		return;
    225 
    226 	os_get_time(&now);
    227 	first = 0;
    228 
    229 	prev = NULL;
    230 	while (entry) {
    231 		if (now.sec >= entry->next_try &&
    232 		    radius_client_retransmit(radius, entry, now.sec)) {
    233 			if (prev)
    234 				prev->next = entry->next;
    235 			else
    236 				radius->msgs = entry->next;
    237 
    238 			tmp = entry;
    239 			entry = entry->next;
    240 			radius_client_msg_free(tmp);
    241 			radius->num_msgs--;
    242 			continue;
    243 		}
    244 
    245 		if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) {
    246 			if (entry->msg_type == RADIUS_ACCT ||
    247 			    entry->msg_type == RADIUS_ACCT_INTERIM)
    248 				acct_failover++;
    249 			else
    250 				auth_failover++;
    251 		}
    252 
    253 		if (first == 0 || entry->next_try < first)
    254 			first = entry->next_try;
    255 
    256 		prev = entry;
    257 		entry = entry->next;
    258 	}
    259 
    260 	if (radius->msgs) {
    261 		if (first < now.sec)
    262 			first = now.sec;
    263 		eloop_register_timeout(first - now.sec, 0,
    264 				       radius_client_timer, radius, NULL);
    265 		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
    266 			       HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
    267 			       "retransmit in %ld seconds",
    268 			       (long int) (first - now.sec));
    269 	}
    270 
    271 	if (auth_failover && conf->num_auth_servers > 1) {
    272 		struct hostapd_radius_server *next, *old;
    273 		old = conf->auth_server;
    274 		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
    275 			       HOSTAPD_LEVEL_NOTICE,
    276 			       "No response from Authentication server "
    277 			       "%s:%d - failover",
    278 			       hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
    279 			       old->port);
    280 
    281 		for (entry = radius->msgs; entry; entry = entry->next) {
    282 			if (entry->msg_type == RADIUS_AUTH)
    283 				old->timeouts++;
    284 		}
    285 
    286 		next = old + 1;
    287 		if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
    288 			next = conf->auth_servers;
    289 		conf->auth_server = next;
    290 		radius_change_server(radius, next, old,
    291 				     radius->auth_serv_sock,
    292 				     radius->auth_serv_sock6, 1);
    293 	}
    294 
    295 	if (acct_failover && conf->num_acct_servers > 1) {
    296 		struct hostapd_radius_server *next, *old;
    297 		old = conf->acct_server;
    298 		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
    299 			       HOSTAPD_LEVEL_NOTICE,
    300 			       "No response from Accounting server "
    301 			       "%s:%d - failover",
    302 			       hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
    303 			       old->port);
    304 
    305 		for (entry = radius->msgs; entry; entry = entry->next) {
    306 			if (entry->msg_type == RADIUS_ACCT ||
    307 			    entry->msg_type == RADIUS_ACCT_INTERIM)
    308 				old->timeouts++;
    309 		}
    310 
    311 		next = old + 1;
    312 		if (next > &conf->acct_servers[conf->num_acct_servers - 1])
    313 			next = conf->acct_servers;
    314 		conf->acct_server = next;
    315 		radius_change_server(radius, next, old,
    316 				     radius->acct_serv_sock,
    317 				     radius->acct_serv_sock6, 0);
    318 	}
    319 }
    320 
    321 
    322 static void radius_client_update_timeout(struct radius_client_data *radius)
    323 {
    324 	struct os_time now;
    325 	os_time_t first;
    326 	struct radius_msg_list *entry;
    327 
    328 	eloop_cancel_timeout(radius_client_timer, radius, NULL);
    329 
    330 	if (radius->msgs == NULL) {
    331 		return;
    332 	}
    333 
    334 	first = 0;
    335 	for (entry = radius->msgs; entry; entry = entry->next) {
    336 		if (first == 0 || entry->next_try < first)
    337 			first = entry->next_try;
    338 	}
    339 
    340 	os_get_time(&now);
    341 	if (first < now.sec)
    342 		first = now.sec;
    343 	eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius,
    344 			       NULL);
    345 	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
    346 		       HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
    347 		       " %ld seconds\n", (long int) (first - now.sec));
    348 }
    349 
    350 
    351 static void radius_client_list_add(struct radius_client_data *radius,
    352 				   struct radius_msg *msg,
    353 				   RadiusType msg_type, u8 *shared_secret,
    354 				   size_t shared_secret_len, const u8 *addr)
    355 {
    356 	struct radius_msg_list *entry, *prev;
    357 
    358 	if (eloop_terminated()) {
    359 		/* No point in adding entries to retransmit queue since event
    360 		 * loop has already been terminated. */
    361 		radius_msg_free(msg);
    362 		os_free(msg);
    363 		return;
    364 	}
    365 
    366 	entry = wpa_zalloc(sizeof(*entry));
    367 	if (entry == NULL) {
    368 		printf("Failed to add RADIUS packet into retransmit list\n");
    369 		radius_msg_free(msg);
    370 		os_free(msg);
    371 		return;
    372 	}
    373 
    374 	if (addr)
    375 		os_memcpy(entry->addr, addr, ETH_ALEN);
    376 	entry->msg = msg;
    377 	entry->msg_type = msg_type;
    378 	entry->shared_secret = shared_secret;
    379 	entry->shared_secret_len = shared_secret_len;
    380 	os_get_time(&entry->last_attempt);
    381 	entry->first_try = entry->last_attempt.sec;
    382 	entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
    383 	entry->attempts = 1;
    384 	entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
    385 	entry->next = radius->msgs;
    386 	radius->msgs = entry;
    387 	radius_client_update_timeout(radius);
    388 
    389 	if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
    390 		printf("Removing the oldest un-ACKed RADIUS packet due to "
    391 		       "retransmit list limits.\n");
    392 		prev = NULL;
    393 		while (entry->next) {
    394 			prev = entry;
    395 			entry = entry->next;
    396 		}
    397 		if (prev) {
    398 			prev->next = NULL;
    399 			radius_client_msg_free(entry);
    400 		}
    401 	} else
    402 		radius->num_msgs++;
    403 }
    404 
    405 
    406 static void radius_client_list_del(struct radius_client_data *radius,
    407 				   RadiusType msg_type, const u8 *addr)
    408 {
    409 	struct radius_msg_list *entry, *prev, *tmp;
    410 
    411 	if (addr == NULL)
    412 		return;
    413 
    414 	entry = radius->msgs;
    415 	prev = NULL;
    416 	while (entry) {
    417 		if (entry->msg_type == msg_type &&
    418 		    os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
    419 			if (prev)
    420 				prev->next = entry->next;
    421 			else
    422 				radius->msgs = entry->next;
    423 			tmp = entry;
    424 			entry = entry->next;
    425 			hostapd_logger(radius->ctx, addr,
    426 				       HOSTAPD_MODULE_RADIUS,
    427 				       HOSTAPD_LEVEL_DEBUG,
    428 				       "Removing matching RADIUS message");
    429 			radius_client_msg_free(tmp);
    430 			radius->num_msgs--;
    431 			continue;
    432 		}
    433 		prev = entry;
    434 		entry = entry->next;
    435 	}
    436 }
    437 
    438 
    439 int radius_client_send(struct radius_client_data *radius,
    440 		       struct radius_msg *msg, RadiusType msg_type,
    441 		       const u8 *addr)
    442 {
    443 	struct hostapd_radius_servers *conf = radius->conf;
    444 	u8 *shared_secret;
    445 	size_t shared_secret_len;
    446 	char *name;
    447 	int s, res;
    448 
    449 	if (msg_type == RADIUS_ACCT_INTERIM) {
    450 		/* Remove any pending interim acct update for the same STA. */
    451 		radius_client_list_del(radius, msg_type, addr);
    452 	}
    453 
    454 	if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
    455 		if (conf->acct_server == NULL) {
    456 			hostapd_logger(radius->ctx, NULL,
    457 				       HOSTAPD_MODULE_RADIUS,
    458 				       HOSTAPD_LEVEL_INFO,
    459 				       "No accounting server configured");
    460 			return -1;
    461 		}
    462 		shared_secret = conf->acct_server->shared_secret;
    463 		shared_secret_len = conf->acct_server->shared_secret_len;
    464 		radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
    465 		name = "accounting";
    466 		s = radius->acct_sock;
    467 		conf->acct_server->requests++;
    468 	} else {
    469 		if (conf->auth_server == NULL) {
    470 			hostapd_logger(radius->ctx, NULL,
    471 				       HOSTAPD_MODULE_RADIUS,
    472 				       HOSTAPD_LEVEL_INFO,
    473 				       "No authentication server configured");
    474 			return -1;
    475 		}
    476 		shared_secret = conf->auth_server->shared_secret;
    477 		shared_secret_len = conf->auth_server->shared_secret_len;
    478 		radius_msg_finish(msg, shared_secret, shared_secret_len);
    479 		name = "authentication";
    480 		s = radius->auth_sock;
    481 		conf->auth_server->requests++;
    482 	}
    483 
    484 	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
    485 		       HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
    486 		       "server", name);
    487 	if (conf->msg_dumps)
    488 		radius_msg_dump(msg);
    489 
    490 	res = send(s, msg->buf, msg->buf_used, 0);
    491 	if (res < 0)
    492 		radius_client_handle_send_error(radius, s, msg_type);
    493 
    494 	radius_client_list_add(radius, msg, msg_type, shared_secret,
    495 			       shared_secret_len, addr);
    496 
    497 	return res;
    498 }
    499 
    500 
    501 static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
    502 {
    503 	struct radius_client_data *radius = eloop_ctx;
    504 	struct hostapd_radius_servers *conf = radius->conf;
    505 	RadiusType msg_type = (RadiusType) sock_ctx;
    506 	int len, roundtrip;
    507 	unsigned char buf[3000];
    508 	struct radius_msg *msg;
    509 	struct radius_rx_handler *handlers;
    510 	size_t num_handlers, i;
    511 	struct radius_msg_list *req, *prev_req;
    512 	struct os_time now;
    513 	struct hostapd_radius_server *rconf;
    514 	int invalid_authenticator = 0;
    515 
    516 	if (msg_type == RADIUS_ACCT) {
    517 		handlers = radius->acct_handlers;
    518 		num_handlers = radius->num_acct_handlers;
    519 		rconf = conf->acct_server;
    520 	} else {
    521 		handlers = radius->auth_handlers;
    522 		num_handlers = radius->num_auth_handlers;
    523 		rconf = conf->auth_server;
    524 	}
    525 
    526 	len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
    527 	if (len < 0) {
    528 		perror("recv[RADIUS]");
    529 		return;
    530 	}
    531 	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
    532 		       HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
    533 		       "server", len);
    534 	if (len == sizeof(buf)) {
    535 		printf("Possibly too long UDP frame for our buffer - "
    536 		       "dropping it\n");
    537 		return;
    538 	}
    539 
    540 	msg = radius_msg_parse(buf, len);
    541 	if (msg == NULL) {
    542 		printf("Parsing incoming RADIUS frame failed\n");
    543 		rconf->malformed_responses++;
    544 		return;
    545 	}
    546 
    547 	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
    548 		       HOSTAPD_LEVEL_DEBUG, "Received RADIUS message");
    549 	if (conf->msg_dumps)
    550 		radius_msg_dump(msg);
    551 
    552 	switch (msg->hdr->code) {
    553 	case RADIUS_CODE_ACCESS_ACCEPT:
    554 		rconf->access_accepts++;
    555 		break;
    556 	case RADIUS_CODE_ACCESS_REJECT:
    557 		rconf->access_rejects++;
    558 		break;
    559 	case RADIUS_CODE_ACCESS_CHALLENGE:
    560 		rconf->access_challenges++;
    561 		break;
    562 	case RADIUS_CODE_ACCOUNTING_RESPONSE:
    563 		rconf->responses++;
    564 		break;
    565 	}
    566 
    567 	prev_req = NULL;
    568 	req = radius->msgs;
    569 	while (req) {
    570 		/* TODO: also match by src addr:port of the packet when using
    571 		 * alternative RADIUS servers (?) */
    572 		if ((req->msg_type == msg_type ||
    573 		     (req->msg_type == RADIUS_ACCT_INTERIM &&
    574 		      msg_type == RADIUS_ACCT)) &&
    575 		    req->msg->hdr->identifier == msg->hdr->identifier)
    576 			break;
    577 
    578 		prev_req = req;
    579 		req = req->next;
    580 	}
    581 
    582 	if (req == NULL) {
    583 		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
    584 			       HOSTAPD_LEVEL_DEBUG,
    585 			       "No matching RADIUS request found (type=%d "
    586 			       "id=%d) - dropping packet",
    587 			       msg_type, msg->hdr->identifier);
    588 		goto fail;
    589 	}
    590 
    591 	os_get_time(&now);
    592 	roundtrip = (now.sec - req->last_attempt.sec) * 100 +
    593 		(now.usec - req->last_attempt.usec) / 10000;
    594 	hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
    595 		       HOSTAPD_LEVEL_DEBUG,
    596 		       "Received RADIUS packet matched with a pending "
    597 		       "request, round trip time %d.%02d sec",
    598 		       roundtrip / 100, roundtrip % 100);
    599 	rconf->round_trip_time = roundtrip;
    600 
    601 	/* Remove ACKed RADIUS packet from retransmit list */
    602 	if (prev_req)
    603 		prev_req->next = req->next;
    604 	else
    605 		radius->msgs = req->next;
    606 	radius->num_msgs--;
    607 
    608 	for (i = 0; i < num_handlers; i++) {
    609 		RadiusRxResult res;
    610 		res = handlers[i].handler(msg, req->msg, req->shared_secret,
    611 					  req->shared_secret_len,
    612 					  handlers[i].data);
    613 		switch (res) {
    614 		case RADIUS_RX_PROCESSED:
    615 			radius_msg_free(msg);
    616 			os_free(msg);
    617 			/* continue */
    618 		case RADIUS_RX_QUEUED:
    619 			radius_client_msg_free(req);
    620 			return;
    621 		case RADIUS_RX_INVALID_AUTHENTICATOR:
    622 			invalid_authenticator++;
    623 			/* continue */
    624 		case RADIUS_RX_UNKNOWN:
    625 			/* continue with next handler */
    626 			break;
    627 		}
    628 	}
    629 
    630 	if (invalid_authenticator)
    631 		rconf->bad_authenticators++;
    632 	else
    633 		rconf->unknown_types++;
    634 	hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
    635 		       HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found "
    636 		       "(type=%d code=%d id=%d)%s - dropping packet",
    637 		       msg_type, msg->hdr->code, msg->hdr->identifier,
    638 		       invalid_authenticator ? " [INVALID AUTHENTICATOR]" :
    639 		       "");
    640 	radius_client_msg_free(req);
    641 
    642  fail:
    643 	radius_msg_free(msg);
    644 	os_free(msg);
    645 }
    646 
    647 
    648 u8 radius_client_get_id(struct radius_client_data *radius)
    649 {
    650 	struct radius_msg_list *entry, *prev, *_remove;
    651 	u8 id = radius->next_radius_identifier++;
    652 
    653 	/* remove entries with matching id from retransmit list to avoid
    654 	 * using new reply from the RADIUS server with an old request */
    655 	entry = radius->msgs;
    656 	prev = NULL;
    657 	while (entry) {
    658 		if (entry->msg->hdr->identifier == id) {
    659 			hostapd_logger(radius->ctx, entry->addr,
    660 				       HOSTAPD_MODULE_RADIUS,
    661 				       HOSTAPD_LEVEL_DEBUG,
    662 				       "Removing pending RADIUS message, "
    663 				       "since its id (%d) is reused", id);
    664 			if (prev)
    665 				prev->next = entry->next;
    666 			else
    667 				radius->msgs = entry->next;
    668 			_remove = entry;
    669 		} else {
    670 			_remove = NULL;
    671 			prev = entry;
    672 		}
    673 		entry = entry->next;
    674 
    675 		if (_remove)
    676 			radius_client_msg_free(_remove);
    677 	}
    678 
    679 	return id;
    680 }
    681 
    682 
    683 void radius_client_flush(struct radius_client_data *radius, int only_auth)
    684 {
    685 	struct radius_msg_list *entry, *prev, *tmp;
    686 
    687 	if (!radius)
    688 		return;
    689 
    690 	prev = NULL;
    691 	entry = radius->msgs;
    692 
    693 	while (entry) {
    694 		if (!only_auth || entry->msg_type == RADIUS_AUTH) {
    695 			if (prev)
    696 				prev->next = entry->next;
    697 			else
    698 				radius->msgs = entry->next;
    699 
    700 			tmp = entry;
    701 			entry = entry->next;
    702 			radius_client_msg_free(tmp);
    703 			radius->num_msgs--;
    704 		} else {
    705 			prev = entry;
    706 			entry = entry->next;
    707 		}
    708 	}
    709 
    710 	if (radius->msgs == NULL)
    711 		eloop_cancel_timeout(radius_client_timer, radius, NULL);
    712 }
    713 
    714 
    715 void radius_client_update_acct_msgs(struct radius_client_data *radius,
    716 				    u8 *shared_secret,
    717 				    size_t shared_secret_len)
    718 {
    719 	struct radius_msg_list *entry;
    720 
    721 	if (!radius)
    722 		return;
    723 
    724 	for (entry = radius->msgs; entry; entry = entry->next) {
    725 		if (entry->msg_type == RADIUS_ACCT) {
    726 			entry->shared_secret = shared_secret;
    727 			entry->shared_secret_len = shared_secret_len;
    728 			radius_msg_finish_acct(entry->msg, shared_secret,
    729 					       shared_secret_len);
    730 		}
    731 	}
    732 }
    733 
    734 
    735 static int
    736 radius_change_server(struct radius_client_data *radius,
    737 		     struct hostapd_radius_server *nserv,
    738 		     struct hostapd_radius_server *oserv,
    739 		     int sock, int sock6, int auth)
    740 {
    741 	struct sockaddr_in serv;
    742 #ifdef CONFIG_IPV6
    743 	struct sockaddr_in6 serv6;
    744 #endif /* CONFIG_IPV6 */
    745 	struct sockaddr *addr;
    746 	socklen_t addrlen;
    747 	char abuf[50];
    748 	int sel_sock;
    749 	struct radius_msg_list *entry;
    750 
    751 	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
    752 		       HOSTAPD_LEVEL_INFO,
    753 		       "%s server %s:%d",
    754 		       auth ? "Authentication" : "Accounting",
    755 		       hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
    756 		       nserv->port);
    757 
    758 	if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
    759 	    os_memcmp(nserv->shared_secret, oserv->shared_secret,
    760 		      nserv->shared_secret_len) != 0) {
    761 		/* Pending RADIUS packets used different shared secret, so
    762 		 * they need to be modified. Update accounting message
    763 		 * authenticators here. Authentication messages are removed
    764 		 * since they would require more changes and the new RADIUS
    765 		 * server may not be prepared to receive them anyway due to
    766 		 * missing state information. Client will likely retry
    767 		 * authentication, so this should not be an issue. */
    768 		if (auth)
    769 			radius_client_flush(radius, 1);
    770 		else {
    771 			radius_client_update_acct_msgs(
    772 				radius, nserv->shared_secret,
    773 				nserv->shared_secret_len);
    774 		}
    775 	}
    776 
    777 	/* Reset retry counters for the new server */
    778 	for (entry = radius->msgs; entry; entry = entry->next) {
    779 		if ((auth && entry->msg_type != RADIUS_AUTH) ||
    780 		    (!auth && entry->msg_type != RADIUS_ACCT))
    781 			continue;
    782 		entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
    783 		entry->attempts = 0;
    784 		entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
    785 	}
    786 
    787 	if (radius->msgs) {
    788 		eloop_cancel_timeout(radius_client_timer, radius, NULL);
    789 		eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
    790 				       radius_client_timer, radius, NULL);
    791 	}
    792 
    793 	switch (nserv->addr.af) {
    794 	case AF_INET:
    795 		os_memset(&serv, 0, sizeof(serv));
    796 		serv.sin_family = AF_INET;
    797 		serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
    798 		serv.sin_port = htons(nserv->port);
    799 		addr = (struct sockaddr *) &serv;
    800 		addrlen = sizeof(serv);
    801 		sel_sock = sock;
    802 		break;
    803 #ifdef CONFIG_IPV6
    804 	case AF_INET6:
    805 		os_memset(&serv6, 0, sizeof(serv6));
    806 		serv6.sin6_family = AF_INET6;
    807 		os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
    808 			  sizeof(struct in6_addr));
    809 		serv6.sin6_port = htons(nserv->port);
    810 		addr = (struct sockaddr *) &serv6;
    811 		addrlen = sizeof(serv6);
    812 		sel_sock = sock6;
    813 		break;
    814 #endif /* CONFIG_IPV6 */
    815 	default:
    816 		return -1;
    817 	}
    818 
    819 	if (connect(sel_sock, addr, addrlen) < 0) {
    820 		perror("connect[radius]");
    821 		return -1;
    822 	}
    823 
    824 	if (auth)
    825 		radius->auth_sock = sel_sock;
    826 	else
    827 		radius->acct_sock = sel_sock;
    828 
    829 	return 0;
    830 }
    831 
    832 
    833 static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
    834 {
    835 	struct radius_client_data *radius = eloop_ctx;
    836 	struct hostapd_radius_servers *conf = radius->conf;
    837 	struct hostapd_radius_server *oserv;
    838 
    839 	if (radius->auth_sock >= 0 && conf->auth_servers &&
    840 	    conf->auth_server != conf->auth_servers) {
    841 		oserv = conf->auth_server;
    842 		conf->auth_server = conf->auth_servers;
    843 		radius_change_server(radius, conf->auth_server, oserv,
    844 				     radius->auth_serv_sock,
    845 				     radius->auth_serv_sock6, 1);
    846 	}
    847 
    848 	if (radius->acct_sock >= 0 && conf->acct_servers &&
    849 	    conf->acct_server != conf->acct_servers) {
    850 		oserv = conf->acct_server;
    851 		conf->acct_server = conf->acct_servers;
    852 		radius_change_server(radius, conf->acct_server, oserv,
    853 				     radius->acct_serv_sock,
    854 				     radius->acct_serv_sock6, 0);
    855 	}
    856 
    857 	if (conf->retry_primary_interval)
    858 		eloop_register_timeout(conf->retry_primary_interval, 0,
    859 				       radius_retry_primary_timer, radius,
    860 				       NULL);
    861 }
    862 
    863 
    864 static int radius_client_init_auth(struct radius_client_data *radius)
    865 {
    866 	struct hostapd_radius_servers *conf = radius->conf;
    867 	int ok = 0;
    868 
    869 	radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
    870 	if (radius->auth_serv_sock < 0)
    871 		perror("socket[PF_INET,SOCK_DGRAM]");
    872 	else
    873 		ok++;
    874 
    875 #ifdef CONFIG_IPV6
    876 	radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
    877 	if (radius->auth_serv_sock6 < 0)
    878 		perror("socket[PF_INET6,SOCK_DGRAM]");
    879 	else
    880 		ok++;
    881 #endif /* CONFIG_IPV6 */
    882 
    883 	if (ok == 0)
    884 		return -1;
    885 
    886 	radius_change_server(radius, conf->auth_server, NULL,
    887 			     radius->auth_serv_sock, radius->auth_serv_sock6,
    888 			     1);
    889 
    890 	if (radius->auth_serv_sock >= 0 &&
    891 	    eloop_register_read_sock(radius->auth_serv_sock,
    892 				     radius_client_receive, radius,
    893 				     (void *) RADIUS_AUTH)) {
    894 		printf("Could not register read socket for authentication "
    895 		       "server\n");
    896 		return -1;
    897 	}
    898 
    899 #ifdef CONFIG_IPV6
    900 	if (radius->auth_serv_sock6 >= 0 &&
    901 	    eloop_register_read_sock(radius->auth_serv_sock6,
    902 				     radius_client_receive, radius,
    903 				     (void *) RADIUS_AUTH)) {
    904 		printf("Could not register read socket for authentication "
    905 		       "server\n");
    906 		return -1;
    907 	}
    908 #endif /* CONFIG_IPV6 */
    909 
    910 	return 0;
    911 }
    912 
    913 
    914 static int radius_client_init_acct(struct radius_client_data *radius)
    915 {
    916 	struct hostapd_radius_servers *conf = radius->conf;
    917 	int ok = 0;
    918 
    919 	radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
    920 	if (radius->acct_serv_sock < 0)
    921 		perror("socket[PF_INET,SOCK_DGRAM]");
    922 	else
    923 		ok++;
    924 
    925 #ifdef CONFIG_IPV6
    926 	radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
    927 	if (radius->acct_serv_sock6 < 0)
    928 		perror("socket[PF_INET6,SOCK_DGRAM]");
    929 	else
    930 		ok++;
    931 #endif /* CONFIG_IPV6 */
    932 
    933 	if (ok == 0)
    934 		return -1;
    935 
    936 	radius_change_server(radius, conf->acct_server, NULL,
    937 			     radius->acct_serv_sock, radius->acct_serv_sock6,
    938 			     0);
    939 
    940 	if (radius->acct_serv_sock >= 0 &&
    941 	    eloop_register_read_sock(radius->acct_serv_sock,
    942 				     radius_client_receive, radius,
    943 				     (void *) RADIUS_ACCT)) {
    944 		printf("Could not register read socket for accounting "
    945 		       "server\n");
    946 		return -1;
    947 	}
    948 
    949 #ifdef CONFIG_IPV6
    950 	if (radius->acct_serv_sock6 >= 0 &&
    951 	    eloop_register_read_sock(radius->acct_serv_sock6,
    952 				     radius_client_receive, radius,
    953 				     (void *) RADIUS_ACCT)) {
    954 		printf("Could not register read socket for accounting "
    955 		       "server\n");
    956 		return -1;
    957 	}
    958 #endif /* CONFIG_IPV6 */
    959 
    960 	return 0;
    961 }
    962 
    963 
    964 struct radius_client_data *
    965 radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
    966 {
    967 	struct radius_client_data *radius;
    968 
    969 	radius = wpa_zalloc(sizeof(struct radius_client_data));
    970 	if (radius == NULL)
    971 		return NULL;
    972 
    973 	radius->ctx = ctx;
    974 	radius->conf = conf;
    975 	radius->auth_serv_sock = radius->acct_serv_sock =
    976 		radius->auth_serv_sock6 = radius->acct_serv_sock6 =
    977 		radius->auth_sock = radius->acct_sock = -1;
    978 
    979 	if (conf->auth_server && radius_client_init_auth(radius)) {
    980 		radius_client_deinit(radius);
    981 		return NULL;
    982 	}
    983 
    984 	if (conf->acct_server && radius_client_init_acct(radius)) {
    985 		radius_client_deinit(radius);
    986 		return NULL;
    987 	}
    988 
    989 	if (conf->retry_primary_interval)
    990 		eloop_register_timeout(conf->retry_primary_interval, 0,
    991 				       radius_retry_primary_timer, radius,
    992 				       NULL);
    993 
    994 	return radius;
    995 }
    996 
    997 
    998 void radius_client_deinit(struct radius_client_data *radius)
    999 {
   1000 	if (!radius)
   1001 		return;
   1002 
   1003 	if (radius->auth_serv_sock >= 0)
   1004 		eloop_unregister_read_sock(radius->auth_serv_sock);
   1005 	if (radius->acct_serv_sock >= 0)
   1006 		eloop_unregister_read_sock(radius->acct_serv_sock);
   1007 
   1008 	eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
   1009 
   1010 	radius_client_flush(radius, 0);
   1011 	os_free(radius->auth_handlers);
   1012 	os_free(radius->acct_handlers);
   1013 	os_free(radius);
   1014 }
   1015 
   1016 
   1017 void radius_client_flush_auth(struct radius_client_data *radius, u8 *addr)
   1018 {
   1019 	struct radius_msg_list *entry, *prev, *tmp;
   1020 
   1021 	prev = NULL;
   1022 	entry = radius->msgs;
   1023 	while (entry) {
   1024 		if (entry->msg_type == RADIUS_AUTH &&
   1025 		    os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
   1026 			hostapd_logger(radius->ctx, addr,
   1027 				       HOSTAPD_MODULE_RADIUS,
   1028 				       HOSTAPD_LEVEL_DEBUG,
   1029 				       "Removing pending RADIUS authentication"
   1030 				       " message for removed client");
   1031 
   1032 			if (prev)
   1033 				prev->next = entry->next;
   1034 			else
   1035 				radius->msgs = entry->next;
   1036 
   1037 			tmp = entry;
   1038 			entry = entry->next;
   1039 			radius_client_msg_free(tmp);
   1040 			radius->num_msgs--;
   1041 			continue;
   1042 		}
   1043 
   1044 		prev = entry;
   1045 		entry = entry->next;
   1046 	}
   1047 }
   1048 
   1049 
   1050 static int radius_client_dump_auth_server(char *buf, size_t buflen,
   1051 					  struct hostapd_radius_server *serv,
   1052 					  struct radius_client_data *cli)
   1053 {
   1054 	int pending = 0;
   1055 	struct radius_msg_list *msg;
   1056 	char abuf[50];
   1057 
   1058 	if (cli) {
   1059 		for (msg = cli->msgs; msg; msg = msg->next) {
   1060 			if (msg->msg_type == RADIUS_AUTH)
   1061 				pending++;
   1062 		}
   1063 	}
   1064 
   1065 	return os_snprintf(buf, buflen,
   1066 			   "radiusAuthServerIndex=%d\n"
   1067 			   "radiusAuthServerAddress=%s\n"
   1068 			   "radiusAuthClientServerPortNumber=%d\n"
   1069 			   "radiusAuthClientRoundTripTime=%d\n"
   1070 			   "radiusAuthClientAccessRequests=%u\n"
   1071 			   "radiusAuthClientAccessRetransmissions=%u\n"
   1072 			   "radiusAuthClientAccessAccepts=%u\n"
   1073 			   "radiusAuthClientAccessRejects=%u\n"
   1074 			   "radiusAuthClientAccessChallenges=%u\n"
   1075 			   "radiusAuthClientMalformedAccessResponses=%u\n"
   1076 			   "radiusAuthClientBadAuthenticators=%u\n"
   1077 			   "radiusAuthClientPendingRequests=%u\n"
   1078 			   "radiusAuthClientTimeouts=%u\n"
   1079 			   "radiusAuthClientUnknownTypes=%u\n"
   1080 			   "radiusAuthClientPacketsDropped=%u\n",
   1081 			   serv->index,
   1082 			   hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
   1083 			   serv->port,
   1084 			   serv->round_trip_time,
   1085 			   serv->requests,
   1086 			   serv->retransmissions,
   1087 			   serv->access_accepts,
   1088 			   serv->access_rejects,
   1089 			   serv->access_challenges,
   1090 			   serv->malformed_responses,
   1091 			   serv->bad_authenticators,
   1092 			   pending,
   1093 			   serv->timeouts,
   1094 			   serv->unknown_types,
   1095 			   serv->packets_dropped);
   1096 }
   1097 
   1098 
   1099 static int radius_client_dump_acct_server(char *buf, size_t buflen,
   1100 					  struct hostapd_radius_server *serv,
   1101 					  struct radius_client_data *cli)
   1102 {
   1103 	int pending = 0;
   1104 	struct radius_msg_list *msg;
   1105 	char abuf[50];
   1106 
   1107 	if (cli) {
   1108 		for (msg = cli->msgs; msg; msg = msg->next) {
   1109 			if (msg->msg_type == RADIUS_ACCT ||
   1110 			    msg->msg_type == RADIUS_ACCT_INTERIM)
   1111 				pending++;
   1112 		}
   1113 	}
   1114 
   1115 	return os_snprintf(buf, buflen,
   1116 			   "radiusAccServerIndex=%d\n"
   1117 			   "radiusAccServerAddress=%s\n"
   1118 			   "radiusAccClientServerPortNumber=%d\n"
   1119 			   "radiusAccClientRoundTripTime=%d\n"
   1120 			   "radiusAccClientRequests=%u\n"
   1121 			   "radiusAccClientRetransmissions=%u\n"
   1122 			   "radiusAccClientResponses=%u\n"
   1123 			   "radiusAccClientMalformedResponses=%u\n"
   1124 			   "radiusAccClientBadAuthenticators=%u\n"
   1125 			   "radiusAccClientPendingRequests=%u\n"
   1126 			   "radiusAccClientTimeouts=%u\n"
   1127 			   "radiusAccClientUnknownTypes=%u\n"
   1128 			   "radiusAccClientPacketsDropped=%u\n",
   1129 			   serv->index,
   1130 			   hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
   1131 			   serv->port,
   1132 			   serv->round_trip_time,
   1133 			   serv->requests,
   1134 			   serv->retransmissions,
   1135 			   serv->responses,
   1136 			   serv->malformed_responses,
   1137 			   serv->bad_authenticators,
   1138 			   pending,
   1139 			   serv->timeouts,
   1140 			   serv->unknown_types,
   1141 			   serv->packets_dropped);
   1142 }
   1143 
   1144 
   1145 int radius_client_get_mib(struct radius_client_data *radius, char *buf,
   1146 			  size_t buflen)
   1147 {
   1148 	struct hostapd_radius_servers *conf = radius->conf;
   1149 	int i;
   1150 	struct hostapd_radius_server *serv;
   1151 	int count = 0;
   1152 
   1153 	if (conf->auth_servers) {
   1154 		for (i = 0; i < conf->num_auth_servers; i++) {
   1155 			serv = &conf->auth_servers[i];
   1156 			count += radius_client_dump_auth_server(
   1157 				buf + count, buflen - count, serv,
   1158 				serv == conf->auth_server ?
   1159 				radius : NULL);
   1160 		}
   1161 	}
   1162 
   1163 	if (conf->acct_servers) {
   1164 		for (i = 0; i < conf->num_acct_servers; i++) {
   1165 			serv = &conf->acct_servers[i];
   1166 			count += radius_client_dump_acct_server(
   1167 				buf + count, buflen - count, serv,
   1168 				serv == conf->acct_server ?
   1169 				radius : NULL);
   1170 		}
   1171 	}
   1172 
   1173 	return count;
   1174 }
   1175 
   1176 
   1177 static int radius_servers_diff(struct hostapd_radius_server *nserv,
   1178 			       struct hostapd_radius_server *oserv,
   1179 			       int num)
   1180 {
   1181 	int i;
   1182 
   1183 	for (i = 0; i < num; i++) {
   1184 		if (hostapd_ip_diff(&nserv[i].addr, &oserv[i].addr) ||
   1185 		    nserv[i].port != oserv[i].port ||
   1186 		    nserv[i].shared_secret_len != oserv[i].shared_secret_len ||
   1187 		    memcmp(nserv[i].shared_secret, oserv[i].shared_secret,
   1188 			   nserv[i].shared_secret_len) != 0)
   1189 			return 1;
   1190 	}
   1191 
   1192 	return 0;
   1193 }
   1194 
   1195 
   1196 struct radius_client_data *
   1197 radius_client_reconfig(struct radius_client_data *old, void *ctx,
   1198 		       struct hostapd_radius_servers *oldconf,
   1199 		       struct hostapd_radius_servers *newconf)
   1200 {
   1201 	radius_client_flush(old, 0);
   1202 
   1203 	if (newconf->retry_primary_interval !=
   1204 	    oldconf->retry_primary_interval ||
   1205 	    newconf->num_auth_servers != oldconf->num_auth_servers ||
   1206 	    newconf->num_acct_servers != oldconf->num_acct_servers ||
   1207 	    radius_servers_diff(newconf->auth_servers, oldconf->auth_servers,
   1208 				newconf->num_auth_servers) ||
   1209 	    radius_servers_diff(newconf->acct_servers, oldconf->acct_servers,
   1210 				newconf->num_acct_servers)) {
   1211 		hostapd_logger(ctx, NULL, HOSTAPD_MODULE_RADIUS,
   1212 			       HOSTAPD_LEVEL_DEBUG,
   1213 			       "Reconfiguring RADIUS client");
   1214 		radius_client_deinit(old);
   1215 		return radius_client_init(ctx, newconf);
   1216 	}
   1217 
   1218 	return old;
   1219 }
   1220