Revert "Revert "[wpa_supplicant] cumilative patch from commit 4b..."
Revert submission 28102966-revert-26533062-Supplicant_merge_June24-CUATTSRBBR
Fixed the regression issue (ag/28389573)
Bug: 329004037
Reverted changes: /q/submissionid:28102966-revert-26533062-Supplicant_merge_June24-CUATTSRBBR
Test: Turn ON/OFF SoftAp
Change-Id: Ie7ea1ee7f8b1311fce280907d37a2e321542f547
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 18aaec1..2a7f361 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -1,18 +1,20 @@
/*
* RADIUS client
- * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2024, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
+#include <fcntl.h>
#include <net/if.h>
#include "common.h"
+#include "eloop.h"
+#include "crypto/tls.h"
#include "radius.h"
#include "radius_client.h"
-#include "eloop.h"
/* Defaults for RADIUS retransmit values (exponential backoff) */
@@ -169,36 +171,36 @@
struct hostapd_radius_servers *conf;
/**
- * auth_serv_sock - IPv4 socket for RADIUS authentication messages
- */
- int auth_serv_sock;
-
- /**
- * acct_serv_sock - IPv4 socket for RADIUS accounting messages
- */
- int acct_serv_sock;
-
- /**
- * auth_serv_sock6 - IPv6 socket for RADIUS authentication messages
- */
- int auth_serv_sock6;
-
- /**
- * acct_serv_sock6 - IPv6 socket for RADIUS accounting messages
- */
- int acct_serv_sock6;
-
- /**
* auth_sock - Currently used socket for RADIUS authentication server
*/
int auth_sock;
/**
+ * auth_tls - Whether current authentication connection uses TLS
+ */
+ bool auth_tls;
+
+ /**
+ * auth_tls_ready - Whether authentication TLS is ready
+ */
+ bool auth_tls_ready;
+
+ /**
* acct_sock - Currently used socket for RADIUS accounting server
*/
int acct_sock;
/**
+ * acct_tls - Whether current accounting connection uses TLS
+ */
+ bool acct_tls;
+
+ /**
+ * acct_tls_ready - Whether accounting TLS is ready
+ */
+ bool acct_tls_ready;
+
+ /**
* auth_handlers - Authentication message handlers
*/
struct radius_rx_handler *auth_handlers;
@@ -242,6 +244,12 @@
* interim_error_cb_ctx - interim_error_cb() context data
*/
void *interim_error_cb_ctx;
+
+#ifdef CONFIG_RADIUS_TLS
+ void *tls_ctx;
+ struct tls_connection *auth_tls_conn;
+ struct tls_connection *acct_tls_conn;
+#endif /* CONFIG_RADIUS_TLS */
};
@@ -249,7 +257,7 @@
radius_change_server(struct radius_client_data *radius,
struct hostapd_radius_server *nserv,
struct hostapd_radius_server *oserv,
- int sock, int sock6, int auth);
+ int auth);
static int radius_client_init_acct(struct radius_client_data *radius);
static int radius_client_init_auth(struct radius_client_data *radius);
static void radius_client_auth_failover(struct radius_client_data *radius);
@@ -374,9 +382,19 @@
u8 *acct_delay_time;
size_t acct_delay_time_len;
int num_servers;
+#ifdef CONFIG_RADIUS_TLS
+ struct wpabuf *out = NULL;
+ struct tls_connection *conn = NULL;
+ bool acct = false;
+#endif /* CONFIG_RADIUS_TLS */
if (entry->msg_type == RADIUS_ACCT ||
entry->msg_type == RADIUS_ACCT_INTERIM) {
+#ifdef CONFIG_RADIUS_TLS
+ acct = true;
+ if (radius->acct_tls)
+ conn = radius->acct_tls_conn;
+#endif /* CONFIG_RADIUS_TLS */
num_servers = conf->num_acct_servers;
if (radius->acct_sock < 0)
radius_client_init_acct(radius);
@@ -394,6 +412,10 @@
conf->acct_server->retransmissions++;
}
} else {
+#ifdef CONFIG_RADIUS_TLS
+ if (radius->auth_tls)
+ conn = radius->auth_tls_conn;
+#endif /* CONFIG_RADIUS_TLS */
num_servers = conf->num_auth_servers;
if (radius->auth_sock < 0)
radius_client_init_auth(radius);
@@ -429,6 +451,15 @@
return 1;
}
+#ifdef CONFIG_RADIUS_TLS
+ if ((acct && radius->acct_tls && !radius->acct_tls_ready) ||
+ (!acct && radius->auth_tls && !radius->auth_tls_ready)) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: TLS connection not yet ready for TX");
+ goto not_ready;
+ }
+#endif /* CONFIG_RADIUS_TLS */
+
if (entry->msg_type == RADIUS_ACCT &&
radius_msg_get_attr_ptr(entry->msg, RADIUS_ATTR_ACCT_DELAY_TIME,
&acct_delay_time, &acct_delay_time_len,
@@ -473,11 +504,37 @@
os_get_reltime(&entry->last_attempt);
buf = radius_msg_get_buf(entry->msg);
+#ifdef CONFIG_RADIUS_TLS
+ if (conn) {
+ out = tls_connection_encrypt(radius->tls_ctx, conn, buf);
+ if (!out) {
+ wpa_printf(MSG_INFO,
+ "RADIUS: Failed to encrypt RADIUS message (TLS)");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: TLS encryption of %zu bytes of plaintext to %zu bytes of ciphertext",
+ wpabuf_len(buf), wpabuf_len(out));
+ buf = out;
+ }
+#endif /* CONFIG_RADIUS_TLS */
+
+ wpa_printf(MSG_DEBUG, "RADIUS: Send %zu bytes to the server",
+ wpabuf_len(buf));
if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
if (radius_client_handle_send_error(radius, s, entry->msg_type)
- > 0)
+ > 0) {
+#ifdef CONFIG_RADIUS_TLS
+ wpabuf_free(out);
+#endif /* CONFIG_RADIUS_TLS */
return 0;
+ }
}
+#ifdef CONFIG_RADIUS_TLS
+ wpabuf_free(out);
+
+not_ready:
+#endif /* CONFIG_RADIUS_TLS */
entry->next_try = now + entry->next_wait;
entry->next_wait *= 2;
@@ -598,9 +655,7 @@
if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
next = conf->auth_servers;
conf->auth_server = next;
- radius_change_server(radius, next, old,
- radius->auth_serv_sock,
- radius->auth_serv_sock6, 1);
+ radius_change_server(radius, next, old, 1);
}
@@ -628,9 +683,7 @@
if (next > &conf->acct_servers[conf->num_acct_servers - 1])
next = conf->acct_servers;
conf->acct_server = next;
- radius_change_server(radius, next, old,
- radius->acct_serv_sock,
- radius->acct_serv_sock6, 0);
+ radius_change_server(radius, next, old, 0);
}
@@ -719,6 +772,52 @@
}
+static int radius_client_disable_pmtu_discovery(int s)
+{
+ int r = -1;
+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
+ /* Turn off Path MTU discovery on IPv4/UDP sockets. */
+ int action = IP_PMTUDISC_DONT;
+ r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
+ sizeof(action));
+ if (r == -1)
+ wpa_printf(MSG_ERROR, "RADIUS: Failed to set IP_MTU_DISCOVER: %s",
+ strerror(errno));
+#endif
+ return r;
+}
+
+
+static void radius_close_auth_socket(struct radius_client_data *radius)
+{
+ if (radius->auth_sock >= 0) {
+#ifdef CONFIG_RADIUS_TLS
+ if (radius->conf->auth_server->tls)
+ eloop_unregister_sock(radius->auth_sock,
+ EVENT_TYPE_WRITE);
+#endif /* CONFIG_RADIUS_TLS */
+ eloop_unregister_read_sock(radius->auth_sock);
+ close(radius->auth_sock);
+ radius->auth_sock = -1;
+ }
+}
+
+
+static void radius_close_acct_socket(struct radius_client_data *radius)
+{
+ if (radius->acct_sock >= 0) {
+#ifdef CONFIG_RADIUS_TLS
+ if (radius->conf->acct_server->tls)
+ eloop_unregister_sock(radius->acct_sock,
+ EVENT_TYPE_WRITE);
+#endif /* CONFIG_RADIUS_TLS */
+ eloop_unregister_read_sock(radius->acct_sock);
+ close(radius->acct_sock);
+ radius->acct_sock = -1;
+ }
+}
+
+
/**
* radius_client_send - Send a RADIUS request
* @radius: RADIUS client context from radius_client_init()
@@ -754,8 +853,18 @@
char *name;
int s, res;
struct wpabuf *buf;
+#ifdef CONFIG_RADIUS_TLS
+ struct wpabuf *out = NULL;
+ struct tls_connection *conn = NULL;
+ bool acct = false;
+#endif /* CONFIG_RADIUS_TLS */
if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
+#ifdef CONFIG_RADIUS_TLS
+ acct = true;
+ if (radius->acct_tls)
+ conn = radius->acct_tls_conn;
+#endif /* CONFIG_RADIUS_TLS */
if (conf->acct_server && radius->acct_sock < 0)
radius_client_init_acct(radius);
@@ -774,6 +883,10 @@
s = radius->acct_sock;
conf->acct_server->requests++;
} else {
+#ifdef CONFIG_RADIUS_TLS
+ if (radius->auth_tls)
+ conn = radius->auth_tls_conn;
+#endif /* CONFIG_RADIUS_TLS */
if (conf->auth_server && radius->auth_sock < 0)
radius_client_init_auth(radius);
@@ -799,11 +912,42 @@
if (conf->msg_dumps)
radius_msg_dump(msg);
+#ifdef CONFIG_RADIUS_TLS
+ if ((acct && radius->acct_tls && !radius->acct_tls_ready) ||
+ (!acct && radius->auth_tls && !radius->auth_tls_ready)) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: TLS connection not yet ready for TX");
+ goto skip_send;
+ }
+#endif /* CONFIG_RADIUS_TLS */
+
buf = radius_msg_get_buf(msg);
+#ifdef CONFIG_RADIUS_TLS
+ if (conn) {
+ out = tls_connection_encrypt(radius->tls_ctx, conn, buf);
+ if (!out) {
+ wpa_printf(MSG_INFO,
+ "RADIUS: Failed to encrypt RADIUS message (TLS)");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: TLS encryption of %zu bytes of plaintext to %zu bytes of ciphertext",
+ wpabuf_len(buf), wpabuf_len(out));
+ buf = out;
+ }
+#endif /* CONFIG_RADIUS_TLS */
+ wpa_printf(MSG_DEBUG, "RADIUS: Send %zu bytes to the server",
+ wpabuf_len(buf));
res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0);
+#ifdef CONFIG_RADIUS_TLS
+ wpabuf_free(out);
+#endif /* CONFIG_RADIUS_TLS */
if (res < 0)
radius_client_handle_send_error(radius, s, msg_type);
+#ifdef CONFIG_RADIUS_TLS
+skip_send:
+#endif /* CONFIG_RADIUS_TLS */
radius_client_list_add(radius, msg, msg_type, shared_secret,
shared_secret_len, addr);
@@ -811,6 +955,137 @@
}
+#ifdef CONFIG_RADIUS_TLS
+
+static void radius_client_close_tcp(struct radius_client_data *radius,
+ int sock, RadiusType msg_type)
+{
+ wpa_printf(MSG_DEBUG, "RADIUS: Closing TCP connection (sock %d)",
+ sock);
+ if (msg_type == RADIUS_ACCT) {
+ radius->acct_tls_ready = false;
+ radius_close_acct_socket(radius);
+ } else {
+ radius->auth_tls_ready = false;
+ radius_close_auth_socket(radius);
+ }
+}
+
+
+static void
+radius_client_process_tls_handshake(struct radius_client_data *radius,
+ int sock, RadiusType msg_type,
+ u8 *buf, size_t len)
+{
+ struct wpabuf *in, *out = NULL, *appl;
+ struct tls_connection *conn;
+ int res;
+ bool ready = false;
+
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: Process %zu bytes of received TLS handshake message",
+ len);
+
+ if (msg_type == RADIUS_ACCT)
+ conn = radius->acct_tls_conn;
+ else
+ conn = radius->auth_tls_conn;
+
+ in = wpabuf_alloc_copy(buf, len);
+ if (!in)
+ return;
+
+ appl = NULL;
+ out = tls_connection_handshake(radius->tls_ctx, conn, in, &appl);
+ wpabuf_free(in);
+ if (!out) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: Could not generate TLS handshake data");
+ goto fail;
+ }
+
+ if (tls_connection_get_failed(radius->tls_ctx, conn)) {
+ wpa_printf(MSG_INFO, "RADIUS: TLS handshake failed");
+ goto fail;
+ }
+
+ if (tls_connection_established(radius->tls_ctx, conn)) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: TLS connection established (sock=%d)",
+ sock);
+ if (msg_type == RADIUS_ACCT)
+ radius->acct_tls_ready = true;
+ else
+ radius->auth_tls_ready = true;
+ ready = true;
+ }
+
+ wpa_printf(MSG_DEBUG, "RADIUS: Sending %zu bytes of TLS handshake",
+ wpabuf_len(out));
+ res = send(sock, wpabuf_head(out), wpabuf_len(out), 0);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "RADIUS: send: %s", strerror(errno));
+ goto fail;
+ }
+ if ((size_t) res != wpabuf_len(out)) {
+ wpa_printf(MSG_INFO,
+ "RADIUS: Could not send all data for TLS handshake: only %d bytes sent",
+ res);
+ goto fail;
+ }
+ wpabuf_free(out);
+
+ if (ready) {
+ struct radius_msg_list *entry, *prev, *tmp;
+ struct os_reltime now;
+
+ /* Send all pending message of matching type since the TLS
+ * tunnel has now been established. */
+
+ os_get_reltime(&now);
+
+ entry = radius->msgs;
+ prev = NULL;
+ while (entry) {
+ if (entry->msg_type != msg_type) {
+ prev = entry;
+ entry = entry->next;
+ continue;
+ }
+
+ if (radius_client_retransmit(radius, entry, now.sec)) {
+ if (prev)
+ prev->next = entry->next;
+ else
+ radius->msgs = entry->next;
+
+ tmp = entry;
+ entry = entry->next;
+ radius_client_msg_free(tmp);
+ radius->num_msgs--;
+ continue;
+ }
+
+ prev = entry;
+ entry = entry->next;
+ }
+ }
+
+ return;
+
+fail:
+ wpabuf_free(out);
+ tls_connection_deinit(radius->tls_ctx, conn);
+ if (msg_type == RADIUS_ACCT)
+ radius->acct_tls_conn = NULL;
+ else
+ radius->auth_tls_conn = NULL;
+ radius_client_close_tcp(radius, sock, msg_type);
+}
+
+#endif /* CONFIG_RADIUS_TLS */
+
+
static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
struct radius_client_data *radius = eloop_ctx;
@@ -828,12 +1103,28 @@
struct os_reltime now;
struct hostapd_radius_server *rconf;
int invalid_authenticator = 0;
+#ifdef CONFIG_RADIUS_TLS
+ struct tls_connection *conn = NULL;
+ bool tls, tls_ready;
+#endif /* CONFIG_RADIUS_TLS */
if (msg_type == RADIUS_ACCT) {
+#ifdef CONFIG_RADIUS_TLS
+ if (radius->acct_tls)
+ conn = radius->acct_tls_conn;
+ tls = radius->acct_tls;
+ tls_ready = radius->acct_tls_ready;
+#endif /* CONFIG_RADIUS_TLS */
handlers = radius->acct_handlers;
num_handlers = radius->num_acct_handlers;
rconf = conf->acct_server;
} else {
+#ifdef CONFIG_RADIUS_TLS
+ if (radius->auth_tls)
+ conn = radius->auth_tls_conn;
+ tls = radius->auth_tls;
+ tls_ready = radius->auth_tls_ready;
+#endif /* CONFIG_RADIUS_TLS */
handlers = radius->auth_handlers;
num_handlers = radius->num_auth_handlers;
rconf = conf->auth_server;
@@ -849,6 +1140,52 @@
wpa_printf(MSG_INFO, "recvmsg[RADIUS]: %s", strerror(errno));
return;
}
+#ifdef CONFIG_RADIUS_TLS
+ if (tls && len == 0) {
+ wpa_printf(MSG_DEBUG, "RADIUS: No TCP data available");
+ goto close_tcp;
+ }
+
+ if (tls && !tls_ready) {
+ radius_client_process_tls_handshake(radius, sock, msg_type,
+ buf, len);
+ return;
+ }
+
+ if (conn) {
+ struct wpabuf *out, *in;
+
+ in = wpabuf_alloc_copy(buf, len);
+ if (!in)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: Process %d bytes of encrypted TLS data",
+ len);
+ out = tls_connection_decrypt(radius->tls_ctx, conn, in);
+ wpabuf_free(in);
+ if (!out) {
+ wpa_printf(MSG_INFO,
+ "RADIUS: Failed to decrypt TLS data");
+ goto close_tcp;
+ }
+ if (wpabuf_len(out) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: Full message not yet received - continue waiting for additional TLS data");
+ wpabuf_free(out);
+ return;
+ }
+ if (wpabuf_len(out) > RADIUS_MAX_MSG_LEN) {
+ wpa_printf(MSG_INFO,
+ "RADIUS: Too long RADIUS message from TLS: %zu",
+ wpabuf_len(out));
+ wpabuf_free(out);
+ goto close_tcp;
+ }
+ os_memcpy(buf, wpabuf_head(out), wpabuf_len(out));
+ len = wpabuf_len(out);
+ wpabuf_free(out);
+ }
+#endif /* CONFIG_RADIUS_TLS */
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
@@ -964,9 +1301,121 @@
fail:
radius_msg_free(msg);
+ return;
+
+#ifdef CONFIG_RADIUS_TLS
+close_tcp:
+ radius_client_close_tcp(radius, sock, msg_type);
+#endif /* CONFIG_RADIUS_TLS */
}
+#ifdef CONFIG_RADIUS_TLS
+static void radius_client_write_ready(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct radius_client_data *radius = eloop_ctx;
+ RadiusType msg_type = (uintptr_t) sock_ctx;
+ struct tls_connection *conn = NULL;
+ struct wpabuf *in, *out = NULL, *appl;
+ int res = -1;
+ struct tls_connection_params params;
+ struct hostapd_radius_server *server;
+
+ wpa_printf(MSG_DEBUG, "RADIUS: TCP connection established - start TLS handshake (sock=%d)",
+ sock);
+
+ if (msg_type == RADIUS_ACCT) {
+ eloop_unregister_sock(sock, EVENT_TYPE_WRITE);
+ eloop_register_read_sock(sock, radius_client_receive, radius,
+ (void *) RADIUS_ACCT);
+ if (radius->acct_tls_conn) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: Deinit previously used TLS connection");
+ tls_connection_deinit(radius->tls_ctx,
+ radius->acct_tls_conn);
+ radius->acct_tls_conn = NULL;
+ }
+ server = radius->conf->acct_server;
+ } else {
+ eloop_unregister_sock(sock, EVENT_TYPE_WRITE);
+ eloop_register_read_sock(sock, radius_client_receive, radius,
+ (void *) RADIUS_AUTH);
+ if (radius->auth_tls_conn) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: Deinit previously used TLS connection");
+ tls_connection_deinit(radius->tls_ctx,
+ radius->auth_tls_conn);
+ radius->auth_tls_conn = NULL;
+ }
+ server = radius->conf->auth_server;
+ }
+
+ if (!server)
+ goto fail;
+
+ conn = tls_connection_init(radius->tls_ctx);
+ if (!conn) {
+ wpa_printf(MSG_INFO,
+ "RADIUS: Failed to initiate TLS connection");
+ goto fail;
+ }
+
+ os_memset(¶ms, 0, sizeof(params));
+ params.ca_cert = server->ca_cert;
+ params.client_cert = server->client_cert;
+ params.private_key = server->private_key;
+ params.private_key_passwd = server->private_key_passwd;
+ params.flags = TLS_CONN_DISABLE_TLSv1_0 | TLS_CONN_DISABLE_TLSv1_1;
+ if (tls_connection_set_params(radius->tls_ctx, conn, ¶ms)) {
+ wpa_printf(MSG_INFO,
+ "RADIUS: Failed to set TLS connection parameters");
+ goto fail;
+ }
+
+ in = NULL;
+ appl = NULL;
+ out = tls_connection_handshake(radius->tls_ctx, conn, in, &appl);
+ if (!out) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: Could not generate TLS handshake data");
+ goto fail;
+ }
+
+ if (tls_connection_get_failed(radius->tls_ctx, conn)) {
+ wpa_printf(MSG_INFO, "RADIUS: TLS handshake failed");
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "RADIUS: Sending %zu bytes of TLS handshake",
+ wpabuf_len(out));
+ res = send(sock, wpabuf_head(out), wpabuf_len(out), 0);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "RADIUS: send: %s", strerror(errno));
+ goto fail;
+ }
+ if ((size_t) res != wpabuf_len(out)) {
+ wpa_printf(MSG_INFO,
+ "RADIUS: Could not send all data for TLS handshake: only %d bytes sent",
+ res);
+ goto fail;
+ }
+ wpabuf_free(out);
+
+ if (msg_type == RADIUS_ACCT)
+ radius->acct_tls_conn = conn;
+ else
+ radius->auth_tls_conn = conn;
+ return;
+
+fail:
+ wpa_printf(MSG_INFO, "RADIUS: Failed to perform TLS handshake");
+ tls_connection_deinit(radius->tls_ctx, conn);
+ wpabuf_free(out);
+ radius_client_close_tcp(radius, sock, msg_type);
+}
+#endif /* CONFIG_RADIUS_TLS */
+
+
/**
* radius_client_get_id - Get an identifier for a new RADIUS message
* @radius: RADIUS client context from radius_client_init()
@@ -1071,7 +1520,7 @@
radius_change_server(struct radius_client_data *radius,
struct hostapd_radius_server *nserv,
struct hostapd_radius_server *oserv,
- int sock, int sock6, int auth)
+ int auth)
{
struct sockaddr_in serv, claddr;
#ifdef CONFIG_IPV6
@@ -1083,9 +1532,17 @@
int sel_sock;
struct radius_msg_list *entry;
struct hostapd_radius_servers *conf = radius->conf;
- struct sockaddr_in disconnect_addr = {
- .sin_family = AF_UNSPEC,
- };
+ int type = SOCK_DGRAM;
+ bool tls = nserv->tls;
+
+ if (tls) {
+#ifdef CONFIG_RADIUS_TLS
+ type = SOCK_STREAM;
+#else /* CONFIG_RADIUS_TLS */
+ wpa_printf(MSG_ERROR, "RADIUS: TLS not supported");
+ return -1;
+#endif /* CONFIG_RADIUS_TLS */
+ }
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
@@ -1144,7 +1601,9 @@
serv.sin_port = htons(nserv->port);
addr = (struct sockaddr *) &serv;
addrlen = sizeof(serv);
- sel_sock = sock;
+ sel_sock = socket(PF_INET, type, 0);
+ if (sel_sock >= 0)
+ radius_client_disable_pmtu_discovery(sel_sock);
break;
#ifdef CONFIG_IPV6
case AF_INET6:
@@ -1155,7 +1614,7 @@
serv6.sin6_port = htons(nserv->port);
addr = (struct sockaddr *) &serv6;
addrlen = sizeof(serv6);
- sel_sock = sock6;
+ sel_sock = socket(PF_INET6, type, 0);
break;
#endif /* CONFIG_IPV6 */
default:
@@ -1164,15 +1623,19 @@
if (sel_sock < 0) {
wpa_printf(MSG_INFO,
- "RADIUS: No server socket available (af=%d sock=%d sock6=%d auth=%d",
- nserv->addr.af, sock, sock6, auth);
+ "RADIUS: Failed to open server socket (af=%d auth=%d)",
+ nserv->addr.af, auth);
return -1;
}
- /* Force a reconnect by disconnecting the socket first */
- if (connect(sel_sock, (struct sockaddr *) &disconnect_addr,
- sizeof(disconnect_addr)) < 0)
- wpa_printf(MSG_INFO, "disconnect[radius]: %s", strerror(errno));
+#ifdef CONFIG_RADIUS_TLS
+ if (tls && fcntl(sel_sock, F_SETFL, O_NONBLOCK) != 0) {
+ wpa_printf(MSG_DEBUG, "RADIUS: fnctl(O_NONBLOCK) failed: %s",
+ strerror(errno));
+ close(sel_sock);
+ return -1;
+ }
+#endif /* CONFIG_RADIUS_TLS */
#ifdef __linux__
if (conf->force_client_dev && conf->force_client_dev[0]) {
@@ -1214,19 +1677,29 @@
break;
#endif /* CONFIG_IPV6 */
default:
+ close(sel_sock);
return -1;
}
if (bind(sel_sock, cl_addr, claddrlen) < 0) {
wpa_printf(MSG_INFO, "bind[radius]: %s",
strerror(errno));
- return -1;
+ close(sel_sock);
+ return -2;
}
}
if (connect(sel_sock, addr, addrlen) < 0) {
- wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno));
- return -1;
+ if (nserv->tls && errno == EINPROGRESS) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: TCP connection establishment in progress (sock %d)",
+ sel_sock);
+ } else {
+ wpa_printf(MSG_INFO, "connect[radius]: %s",
+ strerror(errno));
+ close(sel_sock);
+ return -2;
+ }
}
#ifndef CONFIG_NATIVE_WINDOWS
@@ -1256,10 +1729,34 @@
}
#endif /* CONFIG_NATIVE_WINDOWS */
- if (auth)
+ if (auth) {
+ radius_close_auth_socket(radius);
radius->auth_sock = sel_sock;
- else
+ } else {
+ radius_close_acct_socket(radius);
radius->acct_sock = sel_sock;
+ }
+
+ if (!tls)
+ eloop_register_read_sock(sel_sock, radius_client_receive,
+ radius,
+ auth ? (void *) RADIUS_AUTH :
+ (void *) RADIUS_ACCT);
+#ifdef CONFIG_RADIUS_TLS
+ if (tls)
+ eloop_register_sock(sel_sock, EVENT_TYPE_WRITE,
+ radius_client_write_ready, radius,
+ auth ? (void *) RADIUS_AUTH :
+ (void *) RADIUS_ACCT);
+#endif /* CONFIG_RADIUS_TLS */
+
+ if (auth) {
+ radius->auth_tls = nserv->tls;
+ radius->auth_tls_ready = false;
+ } else {
+ radius->acct_tls = nserv->tls;
+ radius->acct_tls_ready = false;
+ }
return 0;
}
@@ -1276,12 +1773,10 @@
oserv = conf->auth_server;
conf->auth_server = conf->auth_servers;
if (radius_change_server(radius, conf->auth_server, oserv,
- radius->auth_serv_sock,
- radius->auth_serv_sock6, 1) < 0) {
+ 1) < 0) {
conf->auth_server = oserv;
radius_change_server(radius, oserv, conf->auth_server,
- radius->auth_serv_sock,
- radius->auth_serv_sock6, 1);
+ 1);
}
}
@@ -1290,12 +1785,10 @@
oserv = conf->acct_server;
conf->acct_server = conf->acct_servers;
if (radius_change_server(radius, conf->acct_server, oserv,
- radius->acct_serv_sock,
- radius->acct_serv_sock6, 0) < 0) {
+ 0) < 0) {
conf->acct_server = oserv;
radius_change_server(radius, oserv, conf->acct_server,
- radius->acct_serv_sock,
- radius->acct_serv_sock6, 0);
+ 0);
}
}
@@ -1306,172 +1799,29 @@
}
-static int radius_client_disable_pmtu_discovery(int s)
-{
- int r = -1;
-#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
- /* Turn off Path MTU discovery on IPv4/UDP sockets. */
- int action = IP_PMTUDISC_DONT;
- r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
- sizeof(action));
- if (r == -1)
- wpa_printf(MSG_ERROR, "RADIUS: Failed to set IP_MTU_DISCOVER: %s",
- strerror(errno));
-#endif
- return r;
-}
-
-
-static void radius_close_auth_sockets(struct radius_client_data *radius)
-{
- radius->auth_sock = -1;
-
- if (radius->auth_serv_sock >= 0) {
- eloop_unregister_read_sock(radius->auth_serv_sock);
- close(radius->auth_serv_sock);
- radius->auth_serv_sock = -1;
- }
-#ifdef CONFIG_IPV6
- if (radius->auth_serv_sock6 >= 0) {
- eloop_unregister_read_sock(radius->auth_serv_sock6);
- close(radius->auth_serv_sock6);
- radius->auth_serv_sock6 = -1;
- }
-#endif /* CONFIG_IPV6 */
-}
-
-
-static void radius_close_acct_sockets(struct radius_client_data *radius)
-{
- radius->acct_sock = -1;
-
- if (radius->acct_serv_sock >= 0) {
- eloop_unregister_read_sock(radius->acct_serv_sock);
- close(radius->acct_serv_sock);
- radius->acct_serv_sock = -1;
- }
-#ifdef CONFIG_IPV6
- if (radius->acct_serv_sock6 >= 0) {
- eloop_unregister_read_sock(radius->acct_serv_sock6);
- close(radius->acct_serv_sock6);
- radius->acct_serv_sock6 = -1;
- }
-#endif /* CONFIG_IPV6 */
-}
-
-
static int radius_client_init_auth(struct radius_client_data *radius)
{
- struct hostapd_radius_servers *conf = radius->conf;
- int ok = 0;
-
- radius_close_auth_sockets(radius);
-
- radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
- if (radius->auth_serv_sock < 0)
- wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
- strerror(errno));
- else {
- radius_client_disable_pmtu_discovery(radius->auth_serv_sock);
- ok++;
- }
-
-#ifdef CONFIG_IPV6
- radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
- if (radius->auth_serv_sock6 < 0)
- wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
- strerror(errno));
- else
- ok++;
-#endif /* CONFIG_IPV6 */
-
- if (ok == 0)
- return -1;
-
- radius_change_server(radius, conf->auth_server, NULL,
- radius->auth_serv_sock, radius->auth_serv_sock6,
- 1);
-
- if (radius->auth_serv_sock >= 0 &&
- eloop_register_read_sock(radius->auth_serv_sock,
- radius_client_receive, radius,
- (void *) RADIUS_AUTH)) {
- wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
- radius_close_auth_sockets(radius);
- return -1;
- }
-
-#ifdef CONFIG_IPV6
- if (radius->auth_serv_sock6 >= 0 &&
- eloop_register_read_sock(radius->auth_serv_sock6,
- radius_client_receive, radius,
- (void *) RADIUS_AUTH)) {
- wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
- radius_close_auth_sockets(radius);
- return -1;
- }
-#endif /* CONFIG_IPV6 */
-
- return 0;
+ radius_close_auth_socket(radius);
+ return radius_change_server(radius, radius->conf->auth_server, NULL, 1);
}
static int radius_client_init_acct(struct radius_client_data *radius)
{
- struct hostapd_radius_servers *conf = radius->conf;
- int ok = 0;
-
- radius_close_acct_sockets(radius);
-
- radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
- if (radius->acct_serv_sock < 0)
- wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
- strerror(errno));
- else {
- radius_client_disable_pmtu_discovery(radius->acct_serv_sock);
- ok++;
- }
-
-#ifdef CONFIG_IPV6
- radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
- if (radius->acct_serv_sock6 < 0)
- wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
- strerror(errno));
- else
- ok++;
-#endif /* CONFIG_IPV6 */
-
- if (ok == 0)
- return -1;
-
- radius_change_server(radius, conf->acct_server, NULL,
- radius->acct_serv_sock, radius->acct_serv_sock6,
- 0);
-
- if (radius->acct_serv_sock >= 0 &&
- eloop_register_read_sock(radius->acct_serv_sock,
- radius_client_receive, radius,
- (void *) RADIUS_ACCT)) {
- wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
- radius_close_acct_sockets(radius);
- return -1;
- }
-
-#ifdef CONFIG_IPV6
- if (radius->acct_serv_sock6 >= 0 &&
- eloop_register_read_sock(radius->acct_serv_sock6,
- radius_client_receive, radius,
- (void *) RADIUS_ACCT)) {
- wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
- radius_close_acct_sockets(radius);
- return -1;
- }
-#endif /* CONFIG_IPV6 */
-
- return 0;
+ radius_close_acct_socket(radius);
+ return radius_change_server(radius, radius->conf->acct_server, NULL, 0);
}
+#ifdef CONFIG_RADIUS_TLS
+static void radius_tls_event_cb(void *ctx, enum tls_event ev,
+ union tls_event_data *data)
+{
+ wpa_printf(MSG_DEBUG, "RADIUS: TLS event %d", ev);
+}
+#endif /* CONFIG_RADIUS_TLS */
+
+
/**
* radius_client_init - Initialize RADIUS client
* @ctx: Callback context to be used in hostapd_logger() calls
@@ -1493,16 +1843,14 @@
radius->ctx = ctx;
radius->conf = conf;
- radius->auth_serv_sock = radius->acct_serv_sock =
- radius->auth_serv_sock6 = radius->acct_serv_sock6 =
- radius->auth_sock = radius->acct_sock = -1;
+ radius->auth_sock = radius->acct_sock = -1;
- if (conf->auth_server && radius_client_init_auth(radius)) {
+ if (conf->auth_server && radius_client_init_auth(radius) == -1) {
radius_client_deinit(radius);
return NULL;
}
- if (conf->acct_server && radius_client_init_acct(radius)) {
+ if (conf->acct_server && radius_client_init_acct(radius) == -1) {
radius_client_deinit(radius);
return NULL;
}
@@ -1512,6 +1860,22 @@
radius_retry_primary_timer, radius,
NULL);
+#ifdef CONFIG_RADIUS_TLS
+ if ((conf->auth_server && conf->auth_server->tls) ||
+ (conf->acct_server && conf->acct_server->tls)) {
+ struct tls_config tls_conf;
+
+ os_memset(&tls_conf, 0, sizeof(tls_conf));
+ tls_conf.event_cb = radius_tls_event_cb;
+ radius->tls_ctx = tls_init(&tls_conf);
+ if (!radius->tls_ctx) {
+ radius_client_deinit(radius);
+ return NULL;
+ }
+ }
+#endif /* CONFIG_RADIUS_TLS */
+
+
return radius;
}
@@ -1525,14 +1889,21 @@
if (!radius)
return;
- radius_close_auth_sockets(radius);
- radius_close_acct_sockets(radius);
+ radius_close_auth_socket(radius);
+ radius_close_acct_socket(radius);
eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
radius_client_flush(radius, 0);
os_free(radius->auth_handlers);
os_free(radius->acct_handlers);
+#ifdef CONFIG_RADIUS_TLS
+ if (radius->tls_ctx) {
+ tls_connection_deinit(radius->tls_ctx, radius->auth_tls_conn);
+ tls_connection_deinit(radius->tls_ctx, radius->acct_tls_conn);
+ tls_deinit(radius->tls_ctx);
+ }
+#endif /* CONFIG_RADIUS_TLS */
os_free(radius);
}