mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-11-01 19:07:47 +00:00
hostapd: add internal radius server
Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
@@ -167,7 +167,7 @@ define Package/hostapd-openssl
|
||||
$(call Package/hostapd/Default,$(1))
|
||||
TITLE+= (OpenSSL full)
|
||||
VARIANT:=full-openssl
|
||||
DEPENDS+=+libopenssl
|
||||
DEPENDS+=+libopenssl +libopenssl-legacy
|
||||
endef
|
||||
|
||||
Package/hostapd-openssl/description = $(Package/hostapd/description)
|
||||
@@ -253,7 +253,7 @@ define Package/wpad-openssl
|
||||
$(call Package/wpad/Default,$(1))
|
||||
TITLE+= (OpenSSL full)
|
||||
VARIANT:=wpad-full-openssl
|
||||
DEPENDS+=+libopenssl
|
||||
DEPENDS+=+libopenssl +libopenssl-legacy
|
||||
endef
|
||||
|
||||
Package/wpad-openssl/description = $(Package/wpad/description)
|
||||
@@ -506,7 +506,7 @@ TARGET_CPPFLAGS := \
|
||||
$(if $(CONFIG_WPA_MSG_MIN_PRIORITY),-DCONFIG_MSG_MIN_PRIORITY=$(CONFIG_WPA_MSG_MIN_PRIORITY))
|
||||
|
||||
TARGET_CFLAGS += -ffunction-sections -fdata-sections -flto
|
||||
TARGET_LDFLAGS += -Wl,--gc-sections -flto=jobserver -fuse-linker-plugin -lubox -lubus -lucode
|
||||
TARGET_LDFLAGS += -Wl,--gc-sections -flto=jobserver -fuse-linker-plugin -lubox -lubus -lucode -lblobmsg_json
|
||||
|
||||
ifdef CONFIG_PACKAGE_kmod-cfg80211
|
||||
TARGET_LDFLAGS += -lm -lnl-tiny
|
||||
@@ -592,6 +592,12 @@ endef
|
||||
define Install/hostapd
|
||||
$(INSTALL_DIR) $(1)/usr/sbin $(1)/usr/share/hostap
|
||||
$(INSTALL_DATA) ./files/hostapd.uc $(1)/usr/share/hostap/
|
||||
$(INSTALL_DIR) $(1)/etc/init.d $(1)/etc/config $(1)/etc/radius
|
||||
ln -sf hostapd $(1)/usr/sbin/hostapd-radius
|
||||
$(INSTALL_BIN) ./files/radius.init $(1)/etc/init.d/radius
|
||||
$(INSTALL_DATA) ./files/radius.config $(1)/etc/config/radius
|
||||
$(INSTALL_DATA) ./files/radius.clients $(1)/etc/radius/clients
|
||||
$(INSTALL_DATA) ./files/radius.users $(1)/etc/radius/users
|
||||
endef
|
||||
|
||||
define Install/supplicant
|
||||
@@ -613,6 +619,7 @@ endef
|
||||
define Package/hostapd/install
|
||||
$(call Install/hostapd,$(1))
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/hostapd/hostapd $(1)/usr/sbin/
|
||||
$(Install/hostapd/full)
|
||||
endef
|
||||
Package/hostapd-basic/install = $(Package/hostapd/install)
|
||||
Package/hostapd-basic-openssl/install = $(Package/hostapd/install)
|
||||
|
||||
@@ -142,7 +142,7 @@ CONFIG_PKCS12=y
|
||||
|
||||
# RADIUS authentication server. This provides access to the integrated EAP
|
||||
# server from external hosts using RADIUS.
|
||||
#CONFIG_RADIUS_SERVER=y
|
||||
CONFIG_RADIUS_SERVER=y
|
||||
|
||||
# Build IPv6 support for RADIUS operations
|
||||
CONFIG_IPV6=y
|
||||
|
||||
1
feeds/ipq807x_v5.4/hostapd/files/radius.clients
Normal file
1
feeds/ipq807x_v5.4/hostapd/files/radius.clients
Normal file
@@ -0,0 +1 @@
|
||||
0.0.0.0/0 radius
|
||||
9
feeds/ipq807x_v5.4/hostapd/files/radius.config
Normal file
9
feeds/ipq807x_v5.4/hostapd/files/radius.config
Normal file
@@ -0,0 +1,9 @@
|
||||
config radius
|
||||
option disabled '1'
|
||||
option ca_cert '/etc/radius/ca.pem'
|
||||
option cert '/etc/radius/cert.pem'
|
||||
option key '/etc/radius/key.pem'
|
||||
option users '/etc/radius/users'
|
||||
option clients '/etc/radius/clients'
|
||||
option auth_port '1812'
|
||||
option acct_port '1813'
|
||||
42
feeds/ipq807x_v5.4/hostapd/files/radius.init
Normal file
42
feeds/ipq807x_v5.4/hostapd/files/radius.init
Normal file
@@ -0,0 +1,42 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=30
|
||||
|
||||
USE_PROCD=1
|
||||
NAME=radius
|
||||
|
||||
radius_start() {
|
||||
local cfg="$1"
|
||||
|
||||
config_get_bool disabled "$cfg" disabled 0
|
||||
|
||||
[ "$disabled" -gt 0 ] && return
|
||||
|
||||
config_get ca "$cfg" ca_cert
|
||||
config_get key "$cfg" key
|
||||
config_get cert "$cfg" cert
|
||||
config_get users "$cfg" users
|
||||
config_get clients "$cfg" clients
|
||||
config_get auth_port "$cfg" auth_port 1812
|
||||
config_get acct_port "$cfg" acct_port 1813
|
||||
config_get identity "$cfg" identity "$(cat /proc/sys/kernel/hostname)"
|
||||
|
||||
procd_open_instance $cfg
|
||||
procd_set_param command /usr/sbin/hostapd-radius \
|
||||
-C "$ca" \
|
||||
-c "$cert" -k "$key" \
|
||||
-s "$clients" -u "$users" \
|
||||
-p "$auth_port" -P "$acct_port" \
|
||||
-i "$identity"
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
start_service() {
|
||||
config_load radius
|
||||
config_foreach radius_start radius
|
||||
}
|
||||
|
||||
service_triggers()
|
||||
{
|
||||
procd_add_reload_trigger "radius"
|
||||
}
|
||||
14
feeds/ipq807x_v5.4/hostapd/files/radius.users
Normal file
14
feeds/ipq807x_v5.4/hostapd/files/radius.users
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"phase1": {
|
||||
"wildcard": [
|
||||
{
|
||||
"name": "*",
|
||||
"methods": [ "PEAP" ]
|
||||
}
|
||||
]
|
||||
},
|
||||
"phase2": {
|
||||
"users": {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
From a561d12d24c2c8bb0f825d4a3a55a5e47e845853 Mon Sep 17 00:00:00 2001
|
||||
From: Jouni Malinen <quic_jouni@quicinc.com>
|
||||
Date: Wed, 4 May 2022 23:55:38 +0300
|
||||
Subject: [PATCH] EAP peer status notification for server not supporting RFC
|
||||
5746
|
||||
|
||||
Add a notification message to indicate reason for TLS handshake failure
|
||||
due to the server not supporting safe renegotiation (RFC 5746).
|
||||
|
||||
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
|
||||
---
|
||||
src/ap/authsrv.c | 3 +++
|
||||
src/crypto/tls.h | 3 ++-
|
||||
src/crypto/tls_openssl.c | 15 +++++++++++++--
|
||||
src/eap_peer/eap.c | 5 +++++
|
||||
4 files changed, 23 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
|
||||
index 516c1da74..fd9c96fad 100644
|
||||
--- a/src/ap/authsrv.c
|
||||
+++ b/src/ap/authsrv.c
|
||||
@@ -169,6 +169,9 @@ static void authsrv_tls_event(void *ctx, enum tls_event ev,
|
||||
wpa_printf(MSG_DEBUG, "authsrv: remote TLS alert: %s",
|
||||
data->alert.description);
|
||||
break;
|
||||
+ case TLS_UNSAFE_RENEGOTIATION_DISABLED:
|
||||
+ /* Not applicable to TLS server */
|
||||
+ break;
|
||||
}
|
||||
}
|
||||
#endif /* EAP_TLS_FUNCS */
|
||||
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
|
||||
index 7ea32ee4a..7a2ee32df 100644
|
||||
--- a/src/crypto/tls.h
|
||||
+++ b/src/crypto/tls.h
|
||||
@@ -22,7 +22,8 @@ enum tls_event {
|
||||
TLS_CERT_CHAIN_SUCCESS,
|
||||
TLS_CERT_CHAIN_FAILURE,
|
||||
TLS_PEER_CERTIFICATE,
|
||||
- TLS_ALERT
|
||||
+ TLS_ALERT,
|
||||
+ TLS_UNSAFE_RENEGOTIATION_DISABLED,
|
||||
};
|
||||
|
||||
/*
|
||||
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
|
||||
index 0d23f44ad..912471ba2 100644
|
||||
--- a/src/crypto/tls_openssl.c
|
||||
+++ b/src/crypto/tls_openssl.c
|
||||
@@ -4443,6 +4443,7 @@ int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
|
||||
static struct wpabuf *
|
||||
openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data)
|
||||
{
|
||||
+ struct tls_context *context = conn->context;
|
||||
int res;
|
||||
struct wpabuf *out_data;
|
||||
|
||||
@@ -4472,7 +4473,19 @@ openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data)
|
||||
wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to "
|
||||
"write");
|
||||
else {
|
||||
+ unsigned long error = ERR_peek_last_error();
|
||||
+
|
||||
tls_show_errors(MSG_INFO, __func__, "SSL_connect");
|
||||
+
|
||||
+ if (context->event_cb &&
|
||||
+ ERR_GET_LIB(error) == ERR_LIB_SSL &&
|
||||
+ ERR_GET_REASON(error) ==
|
||||
+ SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED) {
|
||||
+ context->event_cb(
|
||||
+ context->cb_ctx,
|
||||
+ TLS_UNSAFE_RENEGOTIATION_DISABLED,
|
||||
+ NULL);
|
||||
+ }
|
||||
conn->failed++;
|
||||
if (!conn->server && !conn->client_hello_generated) {
|
||||
/* The server would not understand TLS Alert
|
||||
@@ -4495,8 +4508,6 @@ openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data)
|
||||
if ((conn->flags & TLS_CONN_SUITEB) && !conn->server &&
|
||||
os_strncmp(SSL_get_cipher(conn->ssl), "DHE-", 4) == 0 &&
|
||||
conn->server_dh_prime_len < 3072) {
|
||||
- struct tls_context *context = conn->context;
|
||||
-
|
||||
/*
|
||||
* This should not be reached since earlier cert_cb should have
|
||||
* terminated the handshake. Keep this check here for extra
|
||||
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
|
||||
index 429b20d3a..729388f4f 100644
|
||||
--- a/src/eap_peer/eap.c
|
||||
+++ b/src/eap_peer/eap.c
|
||||
@@ -2172,6 +2172,11 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
|
||||
eap_notify_status(sm, "remote TLS alert",
|
||||
data->alert.description);
|
||||
break;
|
||||
+ case TLS_UNSAFE_RENEGOTIATION_DISABLED:
|
||||
+ wpa_printf(MSG_INFO,
|
||||
+ "TLS handshake failed due to the server not supporting safe renegotiation (RFC 5746); phase1 parameter allow_unsafe_renegotiation=1 can be used to work around this");
|
||||
+ eap_notify_status(sm, "unsafe server renegotiation", "failure");
|
||||
+ break;
|
||||
}
|
||||
|
||||
os_free(hash_hex);
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
From ff2eccbdf9541fc3491e8a5a302eb661208bb827 Mon Sep 17 00:00:00 2001
|
||||
From: Jouni Malinen <quic_jouni@quicinc.com>
|
||||
Date: Tue, 11 Jan 2022 12:43:19 +0200
|
||||
Subject: [PATCH] OpenSSL: Load legacy provider when needed for OpenSSL 3.0
|
||||
|
||||
Number of the older algorithms have now been moved into a separate
|
||||
provider in OpenSSL 3.0 and they are not available by default.
|
||||
Explicitly load the legacy provider when such an algorithm is needed for
|
||||
the first time.
|
||||
|
||||
In addition, at least for now, load the legacy providers when initiating
|
||||
TLS context to maintain existing functionality for various private key
|
||||
formats.
|
||||
|
||||
Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
|
||||
---
|
||||
src/crypto/crypto_openssl.c | 28 ++++++++++++++++++++++++++++
|
||||
src/crypto/tls_openssl.c | 4 ++++
|
||||
2 files changed, 32 insertions(+)
|
||||
|
||||
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
|
||||
index bac260e11..0372fc3f7 100644
|
||||
--- a/src/crypto/crypto_openssl.c
|
||||
+++ b/src/crypto/crypto_openssl.c
|
||||
@@ -24,6 +24,9 @@
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
#endif /* CONFIG_ECC */
|
||||
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
+#include <openssl/provider.h>
|
||||
+#endif /* OpenSSL version >= 3.0 */
|
||||
|
||||
#include "common.h"
|
||||
#include "utils/const_time.h"
|
||||
@@ -117,6 +120,26 @@ static const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
|
||||
}
|
||||
#endif /* OpenSSL version < 1.1.0 */
|
||||
|
||||
+
|
||||
+void openssl_load_legacy_provider(void)
|
||||
+{
|
||||
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
+ static bool loaded = false;
|
||||
+ OSSL_PROVIDER *legacy;
|
||||
+
|
||||
+ if (loaded)
|
||||
+ return;
|
||||
+
|
||||
+ legacy = OSSL_PROVIDER_load(NULL, "legacy");
|
||||
+
|
||||
+ if (legacy) {
|
||||
+ OSSL_PROVIDER_load(NULL, "default");
|
||||
+ loaded = true;
|
||||
+ }
|
||||
+#endif /* OpenSSL version >= 3.0 */
|
||||
+}
|
||||
+
|
||||
+
|
||||
static BIGNUM * get_group5_prime(void)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
|
||||
@@ -223,6 +246,7 @@ static int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
|
||||
#ifndef CONFIG_FIPS
|
||||
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
|
||||
{
|
||||
+ openssl_load_legacy_provider();
|
||||
return openssl_digest_vector(EVP_md4(), num_elem, addr, len, mac);
|
||||
}
|
||||
#endif /* CONFIG_FIPS */
|
||||
@@ -234,6 +258,8 @@ int des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
|
||||
int i, plen, ret = -1;
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
|
||||
+ openssl_load_legacy_provider();
|
||||
+
|
||||
/* Add parity bits to the key */
|
||||
next = 0;
|
||||
for (i = 0; i < 7; i++) {
|
||||
@@ -271,6 +297,8 @@ int rc4_skip(const u8 *key, size_t keylen, size_t skip,
|
||||
int res = -1;
|
||||
unsigned char skip_buf[16];
|
||||
|
||||
+ openssl_load_legacy_provider();
|
||||
+
|
||||
ctx = EVP_CIPHER_CTX_new();
|
||||
if (!ctx ||
|
||||
!EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, NULL, NULL, 1) ||
|
||||
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
|
||||
index 203b0f781..ad651bdc8 100644
|
||||
--- a/src/crypto/tls_openssl.c
|
||||
+++ b/src/crypto/tls_openssl.c
|
||||
@@ -957,6 +957,10 @@ void * tls_init(const struct tls_config *conf)
|
||||
const char *ciphers;
|
||||
|
||||
if (tls_openssl_ref_count == 0) {
|
||||
+ void openssl_load_legacy_provider(void);
|
||||
+
|
||||
+ openssl_load_legacy_provider();
|
||||
+
|
||||
tls_global = context = tls_context_new(conf);
|
||||
if (context == NULL)
|
||||
return NULL;
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
From 097ca6bf0b6f3de92eb4e938c8ebf5dddef8b79e Mon Sep 17 00:00:00 2001
|
||||
From: Jouni Malinen <j@w1.fi>
|
||||
Date: Sun, 10 Apr 2022 00:19:02 +0300
|
||||
Subject: [PATCH] OpenSSL: Unload providers on deinit
|
||||
|
||||
This frees up the allocated resources and makes memory leak detection
|
||||
more convenient without the known allocations being left behind.
|
||||
|
||||
Signed-off-by: Jouni Malinen <j@w1.fi>
|
||||
---
|
||||
src/crypto/crypto_openssl.c | 30 ++++++++++++++++++++++--------
|
||||
src/crypto/tls_openssl.c | 3 +++
|
||||
2 files changed, 25 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
|
||||
index 42c501363..4fdac0afe 100644
|
||||
--- a/src/crypto/crypto_openssl.c
|
||||
+++ b/src/crypto/crypto_openssl.c
|
||||
@@ -130,20 +130,34 @@ static int EC_GROUP_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a,
|
||||
#endif /* OpenSSL version < 1.1.1 */
|
||||
|
||||
|
||||
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
+static OSSL_PROVIDER *openssl_default_provider = NULL;
|
||||
+static OSSL_PROVIDER *openssl_legacy_provider = NULL;
|
||||
+#endif /* OpenSSL version >= 3.0 */
|
||||
+
|
||||
void openssl_load_legacy_provider(void)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
- static bool loaded = false;
|
||||
- OSSL_PROVIDER *legacy;
|
||||
-
|
||||
- if (loaded)
|
||||
+ if (openssl_legacy_provider)
|
||||
return;
|
||||
|
||||
- legacy = OSSL_PROVIDER_load(NULL, "legacy");
|
||||
+ openssl_legacy_provider = OSSL_PROVIDER_load(NULL, "legacy");
|
||||
+ if (openssl_legacy_provider && !openssl_default_provider)
|
||||
+ openssl_default_provider = OSSL_PROVIDER_load(NULL, "default");
|
||||
+#endif /* OpenSSL version >= 3.0 */
|
||||
+}
|
||||
+
|
||||
|
||||
- if (legacy) {
|
||||
- OSSL_PROVIDER_load(NULL, "default");
|
||||
- loaded = true;
|
||||
+void openssl_unload_legacy_provider(void)
|
||||
+{
|
||||
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
+ if (openssl_legacy_provider) {
|
||||
+ OSSL_PROVIDER_unload(openssl_legacy_provider);
|
||||
+ openssl_legacy_provider = NULL;
|
||||
+ }
|
||||
+ if (openssl_default_provider) {
|
||||
+ OSSL_PROVIDER_unload(openssl_default_provider);
|
||||
+ openssl_default_provider = NULL;
|
||||
}
|
||||
#endif /* OpenSSL version >= 3.0 */
|
||||
}
|
||||
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
|
||||
index 3eca7b17c..e6b7d411d 100644
|
||||
--- a/src/crypto/tls_openssl.c
|
||||
+++ b/src/crypto/tls_openssl.c
|
||||
@@ -1130,6 +1130,8 @@ void tls_deinit(void *ssl_ctx)
|
||||
|
||||
tls_openssl_ref_count--;
|
||||
if (tls_openssl_ref_count == 0) {
|
||||
+ void openssl_unload_legacy_provider(void);
|
||||
+
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
|
||||
(defined(LIBRESSL_VERSION_NUMBER) && \
|
||||
LIBRESSL_VERSION_NUMBER < 0x20700000L)
|
||||
@@ -1145,6 +1147,7 @@ void tls_deinit(void *ssl_ctx)
|
||||
tls_global->ocsp_stapling_response = NULL;
|
||||
os_free(tls_global);
|
||||
tls_global = NULL;
|
||||
+ openssl_unload_legacy_provider();
|
||||
}
|
||||
|
||||
os_free(data->check_cert_subject);
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
From 0143dc1cb6404f13f6fee6da192a486038e79a9f Mon Sep 17 00:00:00 2001
|
||||
From: Norman Hamer <NHamer@absolute.com>
|
||||
Date: Mon, 31 Oct 2022 23:06:22 +0000
|
||||
Subject: [PATCH] OpenSSL: Load OpenSSL 3.0 legacy provider but let default be
|
||||
loaded
|
||||
|
||||
The default provider is being loaded here explicitly only because
|
||||
OSSL_PROVIDER_load() disables the fallback provider loading (on either
|
||||
success or failure). If the legacy provider fails to load, which it may
|
||||
in some configurations, it will never load the default provider.
|
||||
|
||||
Just use the formulation which attempts to load without changing the
|
||||
fallback behavior.
|
||||
|
||||
"default" will still be/only be loaded if no other provider (notably
|
||||
FIPS) is loaded to provide algorithms.
|
||||
|
||||
Signed-off-by: Norman Hamer <nhamer@absolute.com>
|
||||
---
|
||||
src/crypto/crypto_openssl.c | 9 +--------
|
||||
1 file changed, 1 insertion(+), 8 deletions(-)
|
||||
|
||||
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
|
||||
index c8013a892..8f220bb1a 100644
|
||||
--- a/src/crypto/crypto_openssl.c
|
||||
+++ b/src/crypto/crypto_openssl.c
|
||||
@@ -182,7 +182,6 @@ static int EC_GROUP_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a,
|
||||
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
-static OSSL_PROVIDER *openssl_default_provider = NULL;
|
||||
static OSSL_PROVIDER *openssl_legacy_provider = NULL;
|
||||
#endif /* OpenSSL version >= 3.0 */
|
||||
|
||||
@@ -192,9 +191,7 @@ void openssl_load_legacy_provider(void)
|
||||
if (openssl_legacy_provider)
|
||||
return;
|
||||
|
||||
- openssl_legacy_provider = OSSL_PROVIDER_load(NULL, "legacy");
|
||||
- if (openssl_legacy_provider && !openssl_default_provider)
|
||||
- openssl_default_provider = OSSL_PROVIDER_load(NULL, "default");
|
||||
+ openssl_legacy_provider = OSSL_PROVIDER_try_load(NULL, "legacy", 1);
|
||||
#endif /* OpenSSL version >= 3.0 */
|
||||
}
|
||||
|
||||
@@ -206,10 +203,6 @@ static void openssl_unload_legacy_provider(void)
|
||||
OSSL_PROVIDER_unload(openssl_legacy_provider);
|
||||
openssl_legacy_provider = NULL;
|
||||
}
|
||||
- if (openssl_default_provider) {
|
||||
- OSSL_PROVIDER_unload(openssl_default_provider);
|
||||
- openssl_default_provider = NULL;
|
||||
- }
|
||||
#endif /* OpenSSL version >= 3.0 */
|
||||
}
|
||||
|
||||
--
|
||||
2.34.1
|
||||
|
||||
154
feeds/ipq807x_v5.4/hostapd/patches/770-radius_server.patch
Normal file
154
feeds/ipq807x_v5.4/hostapd/patches/770-radius_server.patch
Normal file
@@ -0,0 +1,154 @@
|
||||
--- a/hostapd/Makefile
|
||||
+++ b/hostapd/Makefile
|
||||
@@ -63,6 +63,10 @@ endif
|
||||
OBJS += main.o
|
||||
OBJS += config_file.o
|
||||
|
||||
+ifdef CONFIG_RADIUS_SERVER
|
||||
+OBJS += radius.o
|
||||
+endif
|
||||
+
|
||||
OBJS += ../src/ap/hostapd.o
|
||||
OBJS += ../src/ap/wpa_auth_glue.o
|
||||
OBJS += ../src/ap/drv_callbacks.o
|
||||
--- a/hostapd/main.c
|
||||
+++ b/hostapd/main.c
|
||||
@@ -42,6 +42,7 @@ static struct hapd_global global;
|
||||
static int daemonize = 0;
|
||||
static char *pid_file = NULL;
|
||||
|
||||
+extern int radius_main(int argc, char **argv);
|
||||
|
||||
#ifndef CONFIG_NO_HOSTAPD_LOGGER
|
||||
static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
|
||||
@@ -665,6 +666,11 @@ int main(int argc, char *argv[])
|
||||
if (os_program_init())
|
||||
return -1;
|
||||
|
||||
+#ifdef RADIUS_SERVER
|
||||
+ if (strstr(argv[0], "radius"))
|
||||
+ return radius_main(argc, argv);
|
||||
+#endif
|
||||
+
|
||||
os_memset(&interfaces, 0, sizeof(interfaces));
|
||||
interfaces.reload_config = hostapd_reload_config;
|
||||
interfaces.config_read_cb = hostapd_config_read;
|
||||
--- a/src/radius/radius_server.c
|
||||
+++ b/src/radius/radius_server.c
|
||||
@@ -63,6 +63,12 @@ struct radius_server_counters {
|
||||
u32 unknown_acct_types;
|
||||
};
|
||||
|
||||
+struct radius_accept_attr {
|
||||
+ u8 type;
|
||||
+ u16 len;
|
||||
+ void *data;
|
||||
+};
|
||||
+
|
||||
/**
|
||||
* struct radius_session - Internal RADIUS server data for a session
|
||||
*/
|
||||
@@ -90,7 +96,7 @@ struct radius_session {
|
||||
unsigned int macacl:1;
|
||||
unsigned int t_c_filtering:1;
|
||||
|
||||
- struct hostapd_radius_attr *accept_attr;
|
||||
+ struct radius_accept_attr *accept_attr;
|
||||
|
||||
u32 t_c_timestamp; /* Last read T&C timestamp from user DB */
|
||||
};
|
||||
@@ -394,6 +400,7 @@ static void radius_server_session_free(s
|
||||
radius_msg_free(sess->last_reply);
|
||||
os_free(sess->username);
|
||||
os_free(sess->nas_ip);
|
||||
+ os_free(sess->accept_attr);
|
||||
os_free(sess);
|
||||
data->num_sess--;
|
||||
}
|
||||
@@ -554,6 +561,36 @@ radius_server_erp_find_key(struct radius
|
||||
}
|
||||
#endif /* CONFIG_ERP */
|
||||
|
||||
+static struct radius_accept_attr *
|
||||
+radius_server_copy_attr(const struct hostapd_radius_attr *data)
|
||||
+{
|
||||
+ const struct hostapd_radius_attr *attr;
|
||||
+ struct radius_accept_attr *attr_new;
|
||||
+ size_t data_size = 0;
|
||||
+ void *data_buf;
|
||||
+ int n_attr = 1;
|
||||
+
|
||||
+ for (attr = data; attr; attr = attr->next) {
|
||||
+ n_attr++;
|
||||
+ data_size += wpabuf_len(attr->val);
|
||||
+ }
|
||||
+
|
||||
+ attr_new = os_zalloc(n_attr * sizeof(*attr) + data_size);
|
||||
+ if (!attr_new)
|
||||
+ return NULL;
|
||||
+
|
||||
+ data_buf = &attr_new[n_attr];
|
||||
+ for (n_attr = 0, attr = data; attr; attr = attr->next) {
|
||||
+ struct radius_accept_attr *cur = &attr_new[n_attr++];
|
||||
+
|
||||
+ cur->type = attr->type;
|
||||
+ cur->len = wpabuf_len(attr->val);
|
||||
+ cur->data = memcpy(data_buf, wpabuf_head(attr->val), cur->len);
|
||||
+ data_buf += cur->len;
|
||||
+ }
|
||||
+
|
||||
+ return attr_new;
|
||||
+}
|
||||
|
||||
static struct radius_session *
|
||||
radius_server_get_new_session(struct radius_server_data *data,
|
||||
@@ -607,7 +644,7 @@ radius_server_get_new_session(struct rad
|
||||
eap_user_free(tmp);
|
||||
return NULL;
|
||||
}
|
||||
- sess->accept_attr = tmp->accept_attr;
|
||||
+ sess->accept_attr = radius_server_copy_attr(tmp->accept_attr);
|
||||
sess->macacl = tmp->macacl;
|
||||
eap_user_free(tmp);
|
||||
|
||||
@@ -1118,11 +1155,10 @@ radius_server_encapsulate_eap(struct rad
|
||||
}
|
||||
|
||||
if (code == RADIUS_CODE_ACCESS_ACCEPT) {
|
||||
- struct hostapd_radius_attr *attr;
|
||||
- for (attr = sess->accept_attr; attr; attr = attr->next) {
|
||||
- if (!radius_msg_add_attr(msg, attr->type,
|
||||
- wpabuf_head(attr->val),
|
||||
- wpabuf_len(attr->val))) {
|
||||
+ struct radius_accept_attr *attr;
|
||||
+ for (attr = sess->accept_attr; attr->data; attr++) {
|
||||
+ if (!radius_msg_add_attr(msg, attr->type, attr->data,
|
||||
+ attr->len)) {
|
||||
wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
|
||||
radius_msg_free(msg);
|
||||
return NULL;
|
||||
@@ -1211,11 +1247,10 @@ radius_server_macacl(struct radius_serve
|
||||
}
|
||||
|
||||
if (code == RADIUS_CODE_ACCESS_ACCEPT) {
|
||||
- struct hostapd_radius_attr *attr;
|
||||
- for (attr = sess->accept_attr; attr; attr = attr->next) {
|
||||
- if (!radius_msg_add_attr(msg, attr->type,
|
||||
- wpabuf_head(attr->val),
|
||||
- wpabuf_len(attr->val))) {
|
||||
+ struct radius_accept_attr *attr;
|
||||
+ for (attr = sess->accept_attr; attr->data; attr++) {
|
||||
+ if (!radius_msg_add_attr(msg, attr->type, attr->data,
|
||||
+ attr->len)) {
|
||||
wpa_printf(MSG_ERROR, "Could not add RADIUS attribute");
|
||||
radius_msg_free(msg);
|
||||
return NULL;
|
||||
@@ -2512,7 +2547,7 @@ static int radius_server_get_eap_user(vo
|
||||
ret = data->get_eap_user(data->conf_ctx, identity, identity_len,
|
||||
phase2, user);
|
||||
if (ret == 0 && user) {
|
||||
- sess->accept_attr = user->accept_attr;
|
||||
+ sess->accept_attr = radius_server_copy_attr(user->accept_attr);
|
||||
sess->remediation = user->remediation;
|
||||
sess->macacl = user->macacl;
|
||||
sess->t_c_timestamp = user->t_c_timestamp;
|
||||
715
feeds/ipq807x_v5.4/hostapd/src/hostapd/radius.c
Normal file
715
feeds/ipq807x_v5.4/hostapd/src/hostapd/radius.c
Normal file
@@ -0,0 +1,715 @@
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
#include "utils/eloop.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/tls.h"
|
||||
|
||||
#include "ap/ap_config.h"
|
||||
#include "eap_server/eap.h"
|
||||
#include "radius/radius.h"
|
||||
#include "radius/radius_server.h"
|
||||
#include "eap_register.h"
|
||||
|
||||
#include <libubox/blobmsg_json.h>
|
||||
#include <libubox/blobmsg.h>
|
||||
#include <libubox/avl.h>
|
||||
#include <libubox/avl-cmp.h>
|
||||
#include <libubox/kvlist.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fnmatch.h>
|
||||
|
||||
#define VENDOR_ID_WISPR 14122
|
||||
#define VENDOR_ATTR_SIZE 6
|
||||
|
||||
struct radius_parse_attr_data {
|
||||
unsigned int vendor;
|
||||
u8 type;
|
||||
int size;
|
||||
char format;
|
||||
const char *data;
|
||||
};
|
||||
|
||||
struct radius_parse_attr_state {
|
||||
struct hostapd_radius_attr *prev;
|
||||
struct hostapd_radius_attr *attr;
|
||||
struct wpabuf *buf;
|
||||
void *attrdata;
|
||||
};
|
||||
|
||||
struct radius_user_state {
|
||||
struct avl_node node;
|
||||
struct eap_user data;
|
||||
};
|
||||
|
||||
struct radius_user_data {
|
||||
struct kvlist users;
|
||||
struct avl_tree user_state;
|
||||
struct blob_attr *wildcard;
|
||||
};
|
||||
|
||||
struct radius_state {
|
||||
struct radius_server_data *radius;
|
||||
struct eap_config eap;
|
||||
|
||||
struct radius_user_data phase1, phase2;
|
||||
const char *user_file;
|
||||
time_t user_file_ts;
|
||||
|
||||
int n_attrs;
|
||||
struct hostapd_radius_attr *attrs;
|
||||
};
|
||||
|
||||
struct radius_config {
|
||||
struct tls_connection_params tls;
|
||||
struct radius_server_conf radius;
|
||||
};
|
||||
|
||||
enum {
|
||||
USER_ATTR_PASSWORD,
|
||||
USER_ATTR_HASH,
|
||||
USER_ATTR_SALT,
|
||||
USER_ATTR_METHODS,
|
||||
USER_ATTR_RADIUS,
|
||||
USER_ATTR_VLAN,
|
||||
USER_ATTR_MAX_RATE_UP,
|
||||
USER_ATTR_MAX_RATE_DOWN,
|
||||
__USER_ATTR_MAX
|
||||
};
|
||||
|
||||
static void radius_tls_event(void *ctx, enum tls_event ev,
|
||||
union tls_event_data *data)
|
||||
{
|
||||
switch (ev) {
|
||||
case TLS_CERT_CHAIN_SUCCESS:
|
||||
wpa_printf(MSG_DEBUG, "radius: remote certificate verification success");
|
||||
break;
|
||||
case TLS_CERT_CHAIN_FAILURE:
|
||||
wpa_printf(MSG_INFO, "radius: certificate chain failure: reason=%d depth=%d subject='%s' err='%s'",
|
||||
data->cert_fail.reason,
|
||||
data->cert_fail.depth,
|
||||
data->cert_fail.subject,
|
||||
data->cert_fail.reason_txt);
|
||||
break;
|
||||
case TLS_PEER_CERTIFICATE:
|
||||
wpa_printf(MSG_DEBUG, "radius: peer certificate: depth=%d serial_num=%s subject=%s",
|
||||
data->peer_cert.depth,
|
||||
data->peer_cert.serial_num ? data->peer_cert.serial_num : "N/A",
|
||||
data->peer_cert.subject);
|
||||
break;
|
||||
case TLS_ALERT:
|
||||
if (data->alert.is_local)
|
||||
wpa_printf(MSG_DEBUG, "radius: local TLS alert: %s",
|
||||
data->alert.description);
|
||||
else
|
||||
wpa_printf(MSG_DEBUG, "radius: remote TLS alert: %s",
|
||||
data->alert.description);
|
||||
break;
|
||||
case TLS_UNSAFE_RENEGOTIATION_DISABLED:
|
||||
/* Not applicable to TLS server */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void radius_userdata_init(struct radius_user_data *u)
|
||||
{
|
||||
kvlist_init(&u->users, kvlist_blob_len);
|
||||
avl_init(&u->user_state, avl_strcmp, false, NULL);
|
||||
}
|
||||
|
||||
static void radius_userdata_free(struct radius_user_data *u)
|
||||
{
|
||||
struct radius_user_state *s, *tmp;
|
||||
|
||||
kvlist_free(&u->users);
|
||||
free(u->wildcard);
|
||||
u->wildcard = NULL;
|
||||
avl_remove_all_elements(&u->user_state, s, node, tmp)
|
||||
free(s);
|
||||
}
|
||||
|
||||
static void
|
||||
radius_userdata_load(struct radius_user_data *u, struct blob_attr *data)
|
||||
{
|
||||
enum {
|
||||
USERSTATE_USERS,
|
||||
USERSTATE_WILDCARD,
|
||||
__USERSTATE_MAX,
|
||||
};
|
||||
static const struct blobmsg_policy policy[__USERSTATE_MAX] = {
|
||||
[USERSTATE_USERS] = { "users", BLOBMSG_TYPE_TABLE },
|
||||
[USERSTATE_WILDCARD] = { "wildcard", BLOBMSG_TYPE_ARRAY },
|
||||
};
|
||||
struct blob_attr *tb[__USERSTATE_MAX], *cur;
|
||||
int rem;
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
blobmsg_parse(policy, __USERSTATE_MAX, tb, blobmsg_data(data), blobmsg_len(data));
|
||||
|
||||
blobmsg_for_each_attr(cur, tb[USERSTATE_USERS], rem)
|
||||
kvlist_set(&u->users, blobmsg_name(cur), cur);
|
||||
|
||||
if (tb[USERSTATE_WILDCARD])
|
||||
u->wildcard = blob_memdup(tb[USERSTATE_WILDCARD]);
|
||||
}
|
||||
|
||||
static void
|
||||
load_userfile(struct radius_state *s)
|
||||
{
|
||||
enum {
|
||||
USERDATA_PHASE1,
|
||||
USERDATA_PHASE2,
|
||||
__USERDATA_MAX
|
||||
};
|
||||
static const struct blobmsg_policy policy[__USERDATA_MAX] = {
|
||||
[USERDATA_PHASE1] = { "phase1", BLOBMSG_TYPE_TABLE },
|
||||
[USERDATA_PHASE2] = { "phase2", BLOBMSG_TYPE_TABLE },
|
||||
};
|
||||
struct blob_attr *tb[__USERDATA_MAX], *cur;
|
||||
static struct blob_buf b;
|
||||
struct stat st;
|
||||
int rem;
|
||||
|
||||
if (stat(s->user_file, &st))
|
||||
return;
|
||||
|
||||
if (s->user_file_ts == st.st_mtime)
|
||||
return;
|
||||
|
||||
s->user_file_ts = st.st_mtime;
|
||||
radius_userdata_free(&s->phase1);
|
||||
radius_userdata_free(&s->phase2);
|
||||
|
||||
blob_buf_init(&b, 0);
|
||||
blobmsg_add_json_from_file(&b, s->user_file);
|
||||
blobmsg_parse(policy, __USERDATA_MAX, tb, blob_data(b.head), blob_len(b.head));
|
||||
radius_userdata_load(&s->phase1, tb[USERDATA_PHASE1]);
|
||||
radius_userdata_load(&s->phase2, tb[USERDATA_PHASE2]);
|
||||
|
||||
blob_buf_free(&b);
|
||||
}
|
||||
|
||||
static struct blob_attr *
|
||||
radius_user_get(struct radius_user_data *s, const char *name)
|
||||
{
|
||||
struct blob_attr *cur;
|
||||
int rem;
|
||||
|
||||
cur = kvlist_get(&s->users, name);
|
||||
if (cur)
|
||||
return cur;
|
||||
|
||||
blobmsg_for_each_attr(cur, s->wildcard, rem) {
|
||||
static const struct blobmsg_policy policy = {
|
||||
"name", BLOBMSG_TYPE_STRING
|
||||
};
|
||||
struct blob_attr *pattern;
|
||||
|
||||
if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE)
|
||||
continue;
|
||||
|
||||
blobmsg_parse(&policy, 1, &pattern, blobmsg_data(cur), blobmsg_len(cur));
|
||||
if (!name)
|
||||
continue;
|
||||
|
||||
if (!fnmatch(blobmsg_get_string(pattern), name, 0))
|
||||
return cur;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct radius_parse_attr_data *
|
||||
radius_parse_attr(struct blob_attr *attr)
|
||||
{
|
||||
static const struct blobmsg_policy policy[4] = {
|
||||
{ .type = BLOBMSG_TYPE_INT32 },
|
||||
{ .type = BLOBMSG_TYPE_INT32 },
|
||||
{ .type = BLOBMSG_TYPE_STRING },
|
||||
{ .type = BLOBMSG_TYPE_STRING },
|
||||
};
|
||||
static struct radius_parse_attr_data data;
|
||||
struct blob_attr *tb[4];
|
||||
const char *format;
|
||||
|
||||
blobmsg_parse_array(policy, ARRAY_SIZE(policy), tb, blobmsg_data(attr), blobmsg_len(attr));
|
||||
|
||||
if (!tb[0] || !tb[1] || !tb[2] || !tb[3])
|
||||
return NULL;
|
||||
|
||||
format = blobmsg_get_string(tb[2]);
|
||||
if (strlen(format) != 1)
|
||||
return NULL;
|
||||
|
||||
data.vendor = blobmsg_get_u32(tb[0]);
|
||||
data.type = blobmsg_get_u32(tb[1]);
|
||||
data.format = format[0];
|
||||
data.data = blobmsg_get_string(tb[3]);
|
||||
data.size = strlen(data.data);
|
||||
|
||||
switch (data.format) {
|
||||
case 's':
|
||||
break;
|
||||
case 'x':
|
||||
if (data.size & 1)
|
||||
return NULL;
|
||||
data.size /= 2;
|
||||
break;
|
||||
case 'd':
|
||||
data.size = 4;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &data;
|
||||
}
|
||||
|
||||
static void
|
||||
radius_count_attrs(struct blob_attr **tb, int *n_attr, size_t *attr_size)
|
||||
{
|
||||
struct blob_attr *data = tb[USER_ATTR_RADIUS];
|
||||
struct blob_attr *cur;
|
||||
int rem;
|
||||
|
||||
blobmsg_for_each_attr(cur, data, rem) {
|
||||
struct radius_parse_attr_data *data;
|
||||
size_t prev = *attr_size;
|
||||
|
||||
data = radius_parse_attr(cur);
|
||||
if (!data)
|
||||
continue;
|
||||
|
||||
*attr_size += data->size;
|
||||
if (data->vendor)
|
||||
*attr_size += VENDOR_ATTR_SIZE;
|
||||
|
||||
(*n_attr)++;
|
||||
}
|
||||
|
||||
*n_attr += !!tb[USER_ATTR_VLAN] * 3 +
|
||||
!!tb[USER_ATTR_MAX_RATE_UP] +
|
||||
!!tb[USER_ATTR_MAX_RATE_DOWN];
|
||||
*attr_size += !!tb[USER_ATTR_VLAN] * (4 + 4 + 5) +
|
||||
!!tb[USER_ATTR_MAX_RATE_UP] * (4 + VENDOR_ATTR_SIZE) +
|
||||
!!tb[USER_ATTR_MAX_RATE_DOWN] * (4 + VENDOR_ATTR_SIZE);
|
||||
}
|
||||
|
||||
static void *
|
||||
radius_add_attr(struct radius_parse_attr_state *state,
|
||||
u32 vendor, u8 type, u8 len)
|
||||
{
|
||||
struct hostapd_radius_attr *attr;
|
||||
struct wpabuf *buf;
|
||||
void *val;
|
||||
|
||||
val = state->attrdata;
|
||||
|
||||
buf = state->buf++;
|
||||
buf->buf = val;
|
||||
|
||||
attr = state->attr++;
|
||||
attr->val = buf;
|
||||
attr->type = type;
|
||||
|
||||
if (state->prev)
|
||||
state->prev->next = attr;
|
||||
state->prev = attr;
|
||||
|
||||
if (vendor) {
|
||||
u8 *vendor_hdr = val + 4;
|
||||
|
||||
WPA_PUT_BE32(val, vendor);
|
||||
vendor_hdr[0] = type;
|
||||
vendor_hdr[1] = len + 2;
|
||||
|
||||
len += VENDOR_ATTR_SIZE;
|
||||
val += VENDOR_ATTR_SIZE;
|
||||
attr->type = RADIUS_ATTR_VENDOR_SPECIFIC;
|
||||
}
|
||||
|
||||
buf->size = buf->used = len;
|
||||
state->attrdata += len;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void
|
||||
radius_parse_attrs(struct blob_attr **tb, struct radius_parse_attr_state *state)
|
||||
{
|
||||
struct blob_attr *data = tb[USER_ATTR_RADIUS];
|
||||
struct hostapd_radius_attr *prev = NULL;
|
||||
struct blob_attr *cur;
|
||||
int len, rem;
|
||||
void *val;
|
||||
|
||||
if ((cur = tb[USER_ATTR_VLAN]) != NULL && blobmsg_get_u32(cur) < 4096) {
|
||||
char buf[5];
|
||||
|
||||
val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_TYPE, 4);
|
||||
WPA_PUT_BE32(val, RADIUS_TUNNEL_TYPE_VLAN);
|
||||
|
||||
val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, 4);
|
||||
WPA_PUT_BE32(val, RADIUS_TUNNEL_MEDIUM_TYPE_802);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%d", blobmsg_get_u32(cur));
|
||||
val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, len);
|
||||
memcpy(val, buf, len);
|
||||
}
|
||||
|
||||
if ((cur = tb[USER_ATTR_MAX_RATE_UP]) != NULL) {
|
||||
val = radius_add_attr(state, VENDOR_ID_WISPR, 7, 4);
|
||||
WPA_PUT_BE32(val, blobmsg_get_u32(cur));
|
||||
}
|
||||
|
||||
if ((cur = tb[USER_ATTR_MAX_RATE_DOWN]) != NULL) {
|
||||
val = radius_add_attr(state, VENDOR_ID_WISPR, 8, 4);
|
||||
WPA_PUT_BE32(val, blobmsg_get_u32(cur));
|
||||
}
|
||||
|
||||
blobmsg_for_each_attr(cur, data, rem) {
|
||||
struct radius_parse_attr_data *data;
|
||||
void *val;
|
||||
int size;
|
||||
|
||||
data = radius_parse_attr(cur);
|
||||
if (!data)
|
||||
continue;
|
||||
|
||||
val = radius_add_attr(state, data->vendor, data->type, data->size);
|
||||
switch (data->format) {
|
||||
case 's':
|
||||
memcpy(val, data->data, data->size);
|
||||
break;
|
||||
case 'x':
|
||||
hexstr2bin(data->data, val, data->size);
|
||||
break;
|
||||
case 'd':
|
||||
WPA_PUT_BE32(val, atoi(data->data));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
radius_user_parse_methods(struct eap_user *eap, struct blob_attr *data)
|
||||
{
|
||||
struct blob_attr *cur;
|
||||
int rem, n = 0;
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
blobmsg_for_each_attr(cur, data, rem) {
|
||||
const char *method;
|
||||
|
||||
if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
|
||||
continue;
|
||||
|
||||
if (n == EAP_MAX_METHODS)
|
||||
break;
|
||||
|
||||
method = blobmsg_get_string(cur);
|
||||
eap->methods[n].method = eap_server_get_type(method, &eap->methods[n].vendor);
|
||||
if (eap->methods[n].vendor == EAP_VENDOR_IETF &&
|
||||
eap->methods[n].method == EAP_TYPE_NONE) {
|
||||
if (!strcmp(method, "TTLS-PAP")) {
|
||||
eap->ttls_auth |= EAP_TTLS_AUTH_PAP;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(method, "TTLS-CHAP")) {
|
||||
eap->ttls_auth |= EAP_TTLS_AUTH_CHAP;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(method, "TTLS-MSCHAP")) {
|
||||
eap->ttls_auth |= EAP_TTLS_AUTH_MSCHAP;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(method, "TTLS-MSCHAPV2")) {
|
||||
eap->ttls_auth |= EAP_TTLS_AUTH_MSCHAPV2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
static struct eap_user *
|
||||
radius_user_get_state(struct radius_user_data *u, struct blob_attr *data,
|
||||
const char *id)
|
||||
{
|
||||
static const struct blobmsg_policy policy[__USER_ATTR_MAX] = {
|
||||
[USER_ATTR_PASSWORD] = { "password", BLOBMSG_TYPE_STRING },
|
||||
[USER_ATTR_HASH] = { "hash", BLOBMSG_TYPE_STRING },
|
||||
[USER_ATTR_SALT] = { "salt", BLOBMSG_TYPE_STRING },
|
||||
[USER_ATTR_METHODS] = { "methods", BLOBMSG_TYPE_ARRAY },
|
||||
[USER_ATTR_RADIUS] = { "radius", BLOBMSG_TYPE_ARRAY },
|
||||
[USER_ATTR_VLAN] = { "vlan-id", BLOBMSG_TYPE_INT32 },
|
||||
[USER_ATTR_MAX_RATE_UP] = { "max-rate-up", BLOBMSG_TYPE_INT32 },
|
||||
[USER_ATTR_MAX_RATE_DOWN] = { "max-rate-down", BLOBMSG_TYPE_INT32 },
|
||||
};
|
||||
struct blob_attr *tb[__USER_ATTR_MAX], *cur;
|
||||
char *password_buf, *salt_buf, *name_buf;
|
||||
struct radius_parse_attr_state astate = {};
|
||||
struct hostapd_radius_attr *attr;
|
||||
struct radius_user_state *state;
|
||||
int pw_len = 0, salt_len = 0;
|
||||
struct eap_user *eap;
|
||||
struct wpabuf *val;
|
||||
size_t attrsize = 0;
|
||||
void *attrdata;
|
||||
int n_attr = 0;
|
||||
|
||||
state = avl_find_element(&u->user_state, id, state, node);
|
||||
if (state)
|
||||
return &state->data;
|
||||
|
||||
blobmsg_parse(policy, __USER_ATTR_MAX, tb, blobmsg_data(data), blobmsg_len(data));
|
||||
|
||||
if ((cur = tb[USER_ATTR_SALT]) != NULL)
|
||||
salt_len = strlen(blobmsg_get_string(cur)) / 2;
|
||||
if ((cur = tb[USER_ATTR_HASH]) != NULL)
|
||||
pw_len = strlen(blobmsg_get_string(cur)) / 2;
|
||||
else if ((cur = tb[USER_ATTR_PASSWORD]) != NULL)
|
||||
pw_len = blobmsg_len(cur) - 1;
|
||||
radius_count_attrs(tb, &n_attr, &attrsize);
|
||||
|
||||
state = calloc_a(sizeof(*state), &name_buf, strlen(id) + 1,
|
||||
&password_buf, pw_len,
|
||||
&salt_buf, salt_len,
|
||||
&astate.attr, n_attr * sizeof(*astate.attr),
|
||||
&astate.buf, n_attr * sizeof(*astate.buf),
|
||||
&astate.attrdata, attrsize);
|
||||
eap = &state->data;
|
||||
eap->salt = salt_len ? salt_buf : NULL;
|
||||
eap->salt_len = salt_len;
|
||||
eap->password = pw_len ? password_buf : NULL;
|
||||
eap->password_len = pw_len;
|
||||
eap->force_version = -1;
|
||||
|
||||
if ((cur = tb[USER_ATTR_SALT]) != NULL)
|
||||
hexstr2bin(blobmsg_get_string(cur), salt_buf, salt_len);
|
||||
if ((cur = tb[USER_ATTR_PASSWORD]) != NULL)
|
||||
memcpy(password_buf, blobmsg_get_string(cur), pw_len);
|
||||
else if ((cur = tb[USER_ATTR_HASH]) != NULL) {
|
||||
hexstr2bin(blobmsg_get_string(cur), password_buf, pw_len);
|
||||
eap->password_hash = 1;
|
||||
}
|
||||
radius_user_parse_methods(eap, tb[USER_ATTR_METHODS]);
|
||||
|
||||
if (n_attr > 0) {
|
||||
cur = tb[USER_ATTR_RADIUS];
|
||||
eap->accept_attr = astate.attr;
|
||||
radius_parse_attrs(tb, &astate);
|
||||
}
|
||||
|
||||
state->node.key = strcpy(name_buf, id);
|
||||
avl_insert(&u->user_state, &state->node);
|
||||
|
||||
return &state->data;
|
||||
|
||||
free:
|
||||
free(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int radius_get_eap_user(void *ctx, const u8 *identity,
|
||||
size_t identity_len, int phase2,
|
||||
struct eap_user *user)
|
||||
{
|
||||
struct radius_state *s = ctx;
|
||||
struct radius_user_data *u = phase2 ? &s->phase2 : &s->phase1;
|
||||
struct blob_attr *entry;
|
||||
struct eap_user *data;
|
||||
char *id;
|
||||
|
||||
if (identity_len > 512)
|
||||
return -1;
|
||||
|
||||
load_userfile(s);
|
||||
|
||||
id = alloca(identity_len + 1);
|
||||
memcpy(id, identity, identity_len);
|
||||
id[identity_len] = 0;
|
||||
|
||||
entry = radius_user_get(u, id);
|
||||
if (!entry)
|
||||
return -1;
|
||||
|
||||
if (!user)
|
||||
return 0;
|
||||
|
||||
data = radius_user_get_state(u, entry, id);
|
||||
if (!data)
|
||||
return -1;
|
||||
|
||||
*user = *data;
|
||||
if (user->password_len > 0)
|
||||
user->password = os_memdup(user->password, user->password_len);
|
||||
if (user->salt_len > 0)
|
||||
user->salt = os_memdup(user->salt, user->salt_len);
|
||||
user->phase2 = phase2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int radius_setup(struct radius_state *s, struct radius_config *c)
|
||||
{
|
||||
struct eap_config *eap = &s->eap;
|
||||
struct tls_config conf = {
|
||||
.event_cb = radius_tls_event,
|
||||
.tls_flags = TLS_CONN_DISABLE_TLSv1_3,
|
||||
.cb_ctx = s,
|
||||
};
|
||||
|
||||
eap->eap_server = 1;
|
||||
eap->max_auth_rounds = 100;
|
||||
eap->max_auth_rounds_short = 50;
|
||||
eap->ssl_ctx = tls_init(&conf);
|
||||
if (!eap->ssl_ctx) {
|
||||
wpa_printf(MSG_INFO, "TLS init failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (tls_global_set_params(eap->ssl_ctx, &c->tls)) {
|
||||
wpa_printf(MSG_INFO, "failed to set TLS parameters\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
c->radius.eap_cfg = eap;
|
||||
c->radius.conf_ctx = s;
|
||||
c->radius.get_eap_user = radius_get_eap_user;
|
||||
s->radius = radius_server_init(&c->radius);
|
||||
if (!s->radius) {
|
||||
wpa_printf(MSG_INFO, "failed to initialize radius server\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int radius_init(struct radius_state *s)
|
||||
{
|
||||
memset(s, 0, sizeof(*s));
|
||||
radius_userdata_init(&s->phase1);
|
||||
radius_userdata_init(&s->phase2);
|
||||
}
|
||||
|
||||
static void radius_deinit(struct radius_state *s)
|
||||
{
|
||||
if (s->radius)
|
||||
radius_server_deinit(s->radius);
|
||||
|
||||
if (s->eap.ssl_ctx)
|
||||
tls_deinit(s->eap.ssl_ctx);
|
||||
|
||||
radius_userdata_free(&s->phase1);
|
||||
radius_userdata_free(&s->phase2);
|
||||
}
|
||||
|
||||
static int usage(const char *progname)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s <options>\n",
|
||||
progname);
|
||||
}
|
||||
|
||||
int radius_main(int argc, char **argv)
|
||||
{
|
||||
static struct radius_state state = {};
|
||||
static struct radius_config config = {};
|
||||
const char *progname = argv[0];
|
||||
int ret = 0;
|
||||
int ch;
|
||||
|
||||
wpa_debug_setup_stdout();
|
||||
wpa_debug_level = 0;
|
||||
|
||||
if (eloop_init()) {
|
||||
wpa_printf(MSG_ERROR, "Failed to initialize event loop");
|
||||
return 1;
|
||||
}
|
||||
|
||||
eap_server_register_methods();
|
||||
radius_init(&state);
|
||||
|
||||
while ((ch = getopt(argc, argv, "6C:c:d:i:k:K:p:P:s:u:")) != -1) {
|
||||
switch (ch) {
|
||||
case '6':
|
||||
config.radius.ipv6 = 1;
|
||||
break;
|
||||
case 'C':
|
||||
config.tls.ca_cert = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
if (config.tls.client_cert2)
|
||||
return usage(progname);
|
||||
|
||||
if (config.tls.client_cert)
|
||||
config.tls.client_cert2 = optarg;
|
||||
else
|
||||
config.tls.client_cert = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
config.tls.dh_file = optarg;
|
||||
break;
|
||||
case 'i':
|
||||
state.eap.server_id = optarg;
|
||||
state.eap.server_id_len = strlen(optarg);
|
||||
break;
|
||||
case 'k':
|
||||
if (config.tls.private_key2)
|
||||
return usage(progname);
|
||||
|
||||
if (config.tls.private_key)
|
||||
config.tls.private_key2 = optarg;
|
||||
else
|
||||
config.tls.private_key = optarg;
|
||||
break;
|
||||
case 'K':
|
||||
if (config.tls.private_key_passwd2)
|
||||
return usage(progname);
|
||||
|
||||
if (config.tls.private_key_passwd)
|
||||
config.tls.private_key_passwd2 = optarg;
|
||||
else
|
||||
config.tls.private_key_passwd = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
config.radius.auth_port = atoi(optarg);
|
||||
break;
|
||||
case 'P':
|
||||
config.radius.acct_port = atoi(optarg);
|
||||
break;
|
||||
case 's':
|
||||
config.radius.client_file = optarg;
|
||||
break;
|
||||
case 'u':
|
||||
state.user_file = optarg;
|
||||
break;
|
||||
default:
|
||||
return usage(progname);
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.tls.client_cert || !config.tls.private_key ||
|
||||
!config.radius.client_file || !state.eap.server_id ||
|
||||
!state.user_file) {
|
||||
wpa_printf(MSG_INFO, "missing options\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = radius_setup(&state, &config);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
load_userfile(&state);
|
||||
eloop_run();
|
||||
|
||||
out:
|
||||
radius_deinit(&state);
|
||||
os_program_deinit();
|
||||
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user