aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hostapd/config_file.c5
-rw-r--r--hostapd/hostapd.eap_user_sqlite1
-rw-r--r--src/ap/ap_config.c1
-rw-r--r--src/ap/ap_config.h3
-rw-r--r--src/ap/authsrv.c5
-rw-r--r--src/ap/eap_user_db.c6
-rw-r--r--src/ap/ieee802_1x.c19
-rw-r--r--src/eap_server/eap.h1
-rw-r--r--src/eapol_auth/eapol_auth_sm.c16
-rw-r--r--src/eapol_auth/eapol_auth_sm.h3
-rw-r--r--src/eapol_auth/eapol_auth_sm_i.h2
-rw-r--r--src/radius/radius_server.c47
-rw-r--r--src/radius/radius_server.h3
13 files changed, 98 insertions, 14 deletions
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index ca95747..fa7d14a 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -3075,6 +3075,11 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "osu_service_desc") == 0) {
if (hs20_parse_osu_service_desc(bss, pos, line) < 0)
errors++;
+ } else if (os_strcmp(buf, "subscr_remediation_url") == 0) {
+ os_free(bss->subscr_remediation_url);
+ bss->subscr_remediation_url = os_strdup(pos);
+ } else if (os_strcmp(buf, "subscr_remediation_method") == 0) {
+ bss->subscr_remediation_method = atoi(pos);
#endif /* CONFIG_HS20 */
#ifdef CONFIG_TESTING_OPTIONS
#define PARSE_TEST_PROBABILITY(_val) \
diff --git a/hostapd/hostapd.eap_user_sqlite b/hostapd/hostapd.eap_user_sqlite
index f688327..2c1f130 100644
--- a/hostapd/hostapd.eap_user_sqlite
+++ b/hostapd/hostapd.eap_user_sqlite
@@ -2,6 +2,7 @@ CREATE TABLE users(
identity TEXT PRIMARY KEY,
methods TEXT,
password TEXT,
+ remediation TEXT,
phase2 INTEGER
);
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 07fd8c3..b995892 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -546,6 +546,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
}
os_free(conf->hs20_osu_providers);
}
+ os_free(conf->subscr_remediation_url);
#endif /* CONFIG_HS20 */
wpabuf_free(conf->vendor_elements);
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 7a40b3e..e1e34e2 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -126,6 +126,7 @@ struct hostapd_eap_user {
unsigned int wildcard_prefix:1;
unsigned int password_hash:1; /* whether password is hashed with
* nt_password_hash() */
+ unsigned int remediation:1;
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
};
@@ -489,6 +490,8 @@ struct hostapd_bss_config {
} *hs20_osu_providers, *last_osu;
size_t hs20_osu_providers_count;
unsigned int hs20_deauth_req_timeout;
+ char *subscr_remediation_url;
+ u8 subscr_remediation_method;
#endif /* CONFIG_HS20 */
u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 7183aba..7691012 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -80,6 +80,7 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
}
user->force_version = eap_user->force_version;
user->ttls_auth = eap_user->ttls_auth;
+ user->remediation = eap_user->remediation;
return 0;
}
@@ -116,6 +117,10 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
#ifdef CONFIG_RADIUS_TEST
srv.dump_msk_file = conf->dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
+#ifdef CONFIG_HS20
+ srv.subscr_remediation_url = conf->subscr_remediation_url;
+ srv.subscr_remediation_method = conf->subscr_remediation_method;
+#endif /* CONFIG_HS20 */
hapd->radius_srv = radius_server_init(&srv);
if (hapd->radius_srv == NULL) {
diff --git a/src/ap/eap_user_db.c b/src/ap/eap_user_db.c
index 79d50e5..371a73f 100644
--- a/src/ap/eap_user_db.c
+++ b/src/ap/eap_user_db.c
@@ -89,6 +89,8 @@ static int get_user_cb(void *ctx, int argc, char *argv[], char *col[])
user->next = (void *) 1;
} else if (os_strcmp(col[i], "methods") == 0 && argv[i]) {
set_user_methods(user, argv[i]);
+ } else if (os_strcmp(col[i], "remediation") == 0 && argv[i]) {
+ user->remediation = strlen(argv[i]) > 0;
}
}
@@ -173,8 +175,8 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
}
os_snprintf(cmd, sizeof(cmd),
- "SELECT password,methods FROM users WHERE "
- "identity='%s' AND phase2=%d;", id_str, phase2);
+ "SELECT * FROM users WHERE identity='%s' AND phase2=%d;",
+ id_str, phase2);
wpa_printf(MSG_DEBUG, "DB: %s", cmd);
if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
SQLITE_OK) {
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 1971908..b12c9d6 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -35,7 +35,8 @@
static void ieee802_1x_finished(struct hostapd_data *hapd,
- struct sta_info *sta, int success);
+ struct sta_info *sta, int success,
+ int remediation);
static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
@@ -1746,14 +1747,14 @@ static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx,
static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
- int preauth)
+ int preauth, int remediation)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
if (preauth)
rsn_preauth_finished(hapd, sta, success);
else
- ieee802_1x_finished(hapd, sta, success);
+ ieee802_1x_finished(hapd, sta, success, remediation);
}
@@ -1787,6 +1788,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
}
user->force_version = eap_user->force_version;
user->ttls_auth = eap_user->ttls_auth;
+ user->remediation = eap_user->remediation;
return 0;
}
@@ -2290,7 +2292,8 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
static void ieee802_1x_finished(struct hostapd_data *hapd,
- struct sta_info *sta, int success)
+ struct sta_info *sta, int success,
+ int remediation)
{
const u8 *key;
size_t len;
@@ -2298,6 +2301,14 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
static const int dot11RSNAConfigPMKLifetime = 43200;
#ifdef CONFIG_HS20
+ if (remediation && !sta->remediation) {
+ sta->remediation = 1;
+ os_free(sta->remediation_url);
+ sta->remediation_url =
+ os_strdup(hapd->conf->subscr_remediation_url);
+ sta->remediation_method = 1; /* SOAP-XML SPP */
+ }
+
if (success) {
if (sta->remediation) {
wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification "
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index 36b230b..197b232 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -32,6 +32,7 @@ struct eap_user {
* nt_password_hash() */
int phase2;
int force_version;
+ unsigned int remediation:1;
int ttls_auth; /* bitfield of
* EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */
};
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index a257781..525bdee 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -219,7 +219,8 @@ SM_STATE(AUTH_PAE, DISCONNECTED)
sm->eapolLogoff = FALSE;
if (!from_initialize) {
sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
- sm->flags & EAPOL_SM_PREAUTH);
+ sm->flags & EAPOL_SM_PREAUTH,
+ sm->remediation);
}
}
@@ -276,7 +277,7 @@ SM_STATE(AUTH_PAE, HELD)
eap_server_get_name(0, sm->eap_type_supp));
}
sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
- sm->flags & EAPOL_SM_PREAUTH);
+ sm->flags & EAPOL_SM_PREAUTH, sm->remediation);
}
@@ -302,7 +303,7 @@ SM_STATE(AUTH_PAE, AUTHENTICATED)
eap_server_get_name(0, sm->eap_type_authsrv),
extra);
sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1,
- sm->flags & EAPOL_SM_PREAUTH);
+ sm->flags & EAPOL_SM_PREAUTH, sm->remediation);
}
@@ -1001,8 +1002,13 @@ static int eapol_sm_get_eap_user(void *ctx, const u8 *identity,
struct eap_user *user)
{
struct eapol_state_machine *sm = ctx;
- return sm->eapol->cb.get_eap_user(sm->eapol->conf.ctx, identity,
- identity_len, phase2, user);
+ int ret;
+
+ ret = sm->eapol->cb.get_eap_user(sm->eapol->conf.ctx, identity,
+ identity_len, phase2, user);
+ if (user->remediation)
+ sm->remediation = 1;
+ return ret;
}
diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h
index f0ff464..320a0ad 100644
--- a/src/eapol_auth/eapol_auth_sm.h
+++ b/src/eapol_auth/eapol_auth_sm.h
@@ -60,7 +60,8 @@ struct eapol_auth_cb {
size_t datalen);
void (*aaa_send)(void *ctx, void *sta_ctx, const u8 *data,
size_t datalen);
- void (*finished)(void *ctx, void *sta_ctx, int success, int preauth);
+ void (*finished)(void *ctx, void *sta_ctx, int success, int preauth,
+ int remediation);
int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
int phase2, struct eap_user *user);
int (*sta_entry_alive)(void *ctx, const u8 *addr);
diff --git a/src/eapol_auth/eapol_auth_sm_i.h b/src/eapol_auth/eapol_auth_sm_i.h
index d7f893a..25baddb 100644
--- a/src/eapol_auth/eapol_auth_sm_i.h
+++ b/src/eapol_auth/eapol_auth_sm_i.h
@@ -173,6 +173,8 @@ struct eapol_state_machine {
struct eapol_authenticator *eapol;
void *sta; /* station context pointer to use in callbacks */
+
+ int remediation;
};
#endif /* EAPOL_AUTH_SM_I_H */
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 2904b2f..5074b60 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -77,6 +77,8 @@ struct radius_session {
u8 last_identifier;
struct radius_msg *last_reply;
u8 last_authenticator[16];
+
+ unsigned int remediation:1;
};
/**
@@ -307,6 +309,9 @@ struct radius_server_data {
#ifdef CONFIG_RADIUS_TEST
char *dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
+
+ char *subscr_remediation_url;
+ u8 subscr_remediation_method;
};
@@ -622,6 +627,34 @@ radius_server_encapsulate_eap(struct radius_server_data *data,
}
}
+#ifdef CONFIG_HS20
+ if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->remediation &&
+ data->subscr_remediation_url) {
+ u8 *buf;
+ size_t url_len = os_strlen(data->subscr_remediation_url);
+ buf = os_malloc(1 + url_len);
+ if (buf == NULL) {
+ radius_msg_free(msg);
+ return NULL;
+ }
+ buf[0] = data->subscr_remediation_method;
+ os_memcpy(&buf[1], data->subscr_remediation_url, url_len);
+ if (!radius_msg_add_wfa(
+ msg, RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION,
+ buf, 1 + url_len)) {
+ RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem");
+ }
+ os_free(buf);
+ } else if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->remediation) {
+ u8 buf[1];
+ if (!radius_msg_add_wfa(
+ msg, RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION,
+ buf, 0)) {
+ RADIUS_DEBUG("Failed to add WFA-HS20-SubscrRem");
+ }
+ }
+#endif /* CONFIG_HS20 */
+
if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
radius_msg_free(msg);
@@ -1444,6 +1477,11 @@ radius_server_init(struct radius_server_conf *conf)
}
}
+ if (conf->subscr_remediation_url) {
+ data->subscr_remediation_url =
+ os_strdup(conf->subscr_remediation_url);
+ }
+
#ifdef CONFIG_RADIUS_TEST
if (conf->dump_msk_file)
data->dump_msk_file = os_strdup(conf->dump_msk_file);
@@ -1530,6 +1568,7 @@ void radius_server_deinit(struct radius_server_data *data)
#ifdef CONFIG_RADIUS_TEST
os_free(data->dump_msk_file);
#endif /* CONFIG_RADIUS_TEST */
+ os_free(data->subscr_remediation_url);
os_free(data);
}
@@ -1682,9 +1721,13 @@ static int radius_server_get_eap_user(void *ctx, const u8 *identity,
{
struct radius_session *sess = ctx;
struct radius_server_data *data = sess->server;
+ int ret;
- return data->get_eap_user(data->conf_ctx, identity, identity_len,
- phase2, user);
+ ret = data->get_eap_user(data->conf_ctx, identity, identity_len,
+ phase2, user);
+ if (ret == 0 && user)
+ sess->remediation = user->remediation;
+ return ret;
}
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index 78f5fc2..e85d009 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -209,6 +209,9 @@ struct radius_server_conf {
#ifdef CONFIG_RADIUS_TEST
const char *dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
+
+ char *subscr_remediation_url;
+ u8 subscr_remediation_method;
};