mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2024-11-25 00:38:24 -05:00
HS 2.0R2: RADIUS server support to request Subscr Remediation
The new hostapd.conf parameter subscr_remediation_url can be used to define the URL of the Subscription Remediation Server that will be added in a WFA VSA to Access-Accept message if the SQLite user database indicates that the user need subscription remediation. Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
ae6d15c722
commit
8d2a9921af
@ -3075,6 +3075,11 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
|||||||
} else if (os_strcmp(buf, "osu_service_desc") == 0) {
|
} else if (os_strcmp(buf, "osu_service_desc") == 0) {
|
||||||
if (hs20_parse_osu_service_desc(bss, pos, line) < 0)
|
if (hs20_parse_osu_service_desc(bss, pos, line) < 0)
|
||||||
errors++;
|
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 */
|
#endif /* CONFIG_HS20 */
|
||||||
#ifdef CONFIG_TESTING_OPTIONS
|
#ifdef CONFIG_TESTING_OPTIONS
|
||||||
#define PARSE_TEST_PROBABILITY(_val) \
|
#define PARSE_TEST_PROBABILITY(_val) \
|
||||||
|
@ -2,6 +2,7 @@ CREATE TABLE users(
|
|||||||
identity TEXT PRIMARY KEY,
|
identity TEXT PRIMARY KEY,
|
||||||
methods TEXT,
|
methods TEXT,
|
||||||
password TEXT,
|
password TEXT,
|
||||||
|
remediation TEXT,
|
||||||
phase2 INTEGER
|
phase2 INTEGER
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -546,6 +546,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
|
|||||||
}
|
}
|
||||||
os_free(conf->hs20_osu_providers);
|
os_free(conf->hs20_osu_providers);
|
||||||
}
|
}
|
||||||
|
os_free(conf->subscr_remediation_url);
|
||||||
#endif /* CONFIG_HS20 */
|
#endif /* CONFIG_HS20 */
|
||||||
|
|
||||||
wpabuf_free(conf->vendor_elements);
|
wpabuf_free(conf->vendor_elements);
|
||||||
|
@ -126,6 +126,7 @@ struct hostapd_eap_user {
|
|||||||
unsigned int wildcard_prefix:1;
|
unsigned int wildcard_prefix:1;
|
||||||
unsigned int password_hash:1; /* whether password is hashed with
|
unsigned int password_hash:1; /* whether password is hashed with
|
||||||
* nt_password_hash() */
|
* nt_password_hash() */
|
||||||
|
unsigned int remediation:1;
|
||||||
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
|
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -489,6 +490,8 @@ struct hostapd_bss_config {
|
|||||||
} *hs20_osu_providers, *last_osu;
|
} *hs20_osu_providers, *last_osu;
|
||||||
size_t hs20_osu_providers_count;
|
size_t hs20_osu_providers_count;
|
||||||
unsigned int hs20_deauth_req_timeout;
|
unsigned int hs20_deauth_req_timeout;
|
||||||
|
char *subscr_remediation_url;
|
||||||
|
u8 subscr_remediation_method;
|
||||||
#endif /* CONFIG_HS20 */
|
#endif /* CONFIG_HS20 */
|
||||||
|
|
||||||
u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
|
u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
|
||||||
|
@ -80,6 +80,7 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
|
|||||||
}
|
}
|
||||||
user->force_version = eap_user->force_version;
|
user->force_version = eap_user->force_version;
|
||||||
user->ttls_auth = eap_user->ttls_auth;
|
user->ttls_auth = eap_user->ttls_auth;
|
||||||
|
user->remediation = eap_user->remediation;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -116,6 +117,10 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
|
|||||||
#ifdef CONFIG_RADIUS_TEST
|
#ifdef CONFIG_RADIUS_TEST
|
||||||
srv.dump_msk_file = conf->dump_msk_file;
|
srv.dump_msk_file = conf->dump_msk_file;
|
||||||
#endif /* CONFIG_RADIUS_TEST */
|
#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);
|
hapd->radius_srv = radius_server_init(&srv);
|
||||||
if (hapd->radius_srv == NULL) {
|
if (hapd->radius_srv == NULL) {
|
||||||
|
@ -89,6 +89,8 @@ static int get_user_cb(void *ctx, int argc, char *argv[], char *col[])
|
|||||||
user->next = (void *) 1;
|
user->next = (void *) 1;
|
||||||
} else if (os_strcmp(col[i], "methods") == 0 && argv[i]) {
|
} else if (os_strcmp(col[i], "methods") == 0 && argv[i]) {
|
||||||
set_user_methods(user, 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),
|
os_snprintf(cmd, sizeof(cmd),
|
||||||
"SELECT password,methods FROM users WHERE "
|
"SELECT * FROM users WHERE identity='%s' AND phase2=%d;",
|
||||||
"identity='%s' AND phase2=%d;", id_str, phase2);
|
id_str, phase2);
|
||||||
wpa_printf(MSG_DEBUG, "DB: %s", cmd);
|
wpa_printf(MSG_DEBUG, "DB: %s", cmd);
|
||||||
if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
|
if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
|
||||||
SQLITE_OK) {
|
SQLITE_OK) {
|
||||||
|
@ -35,7 +35,8 @@
|
|||||||
|
|
||||||
|
|
||||||
static void ieee802_1x_finished(struct hostapd_data *hapd,
|
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,
|
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,
|
static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
|
||||||
int preauth)
|
int preauth, int remediation)
|
||||||
{
|
{
|
||||||
struct hostapd_data *hapd = ctx;
|
struct hostapd_data *hapd = ctx;
|
||||||
struct sta_info *sta = sta_ctx;
|
struct sta_info *sta = sta_ctx;
|
||||||
if (preauth)
|
if (preauth)
|
||||||
rsn_preauth_finished(hapd, sta, success);
|
rsn_preauth_finished(hapd, sta, success);
|
||||||
else
|
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->force_version = eap_user->force_version;
|
||||||
user->ttls_auth = eap_user->ttls_auth;
|
user->ttls_auth = eap_user->ttls_auth;
|
||||||
|
user->remediation = eap_user->remediation;
|
||||||
|
|
||||||
return 0;
|
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,
|
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;
|
const u8 *key;
|
||||||
size_t len;
|
size_t len;
|
||||||
@ -2298,6 +2301,14 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
|
|||||||
static const int dot11RSNAConfigPMKLifetime = 43200;
|
static const int dot11RSNAConfigPMKLifetime = 43200;
|
||||||
|
|
||||||
#ifdef CONFIG_HS20
|
#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 (success) {
|
||||||
if (sta->remediation) {
|
if (sta->remediation) {
|
||||||
wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification "
|
wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification "
|
||||||
|
@ -32,6 +32,7 @@ struct eap_user {
|
|||||||
* nt_password_hash() */
|
* nt_password_hash() */
|
||||||
int phase2;
|
int phase2;
|
||||||
int force_version;
|
int force_version;
|
||||||
|
unsigned int remediation:1;
|
||||||
int ttls_auth; /* bitfield of
|
int ttls_auth; /* bitfield of
|
||||||
* EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */
|
* EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */
|
||||||
};
|
};
|
||||||
|
@ -219,7 +219,8 @@ SM_STATE(AUTH_PAE, DISCONNECTED)
|
|||||||
sm->eapolLogoff = FALSE;
|
sm->eapolLogoff = FALSE;
|
||||||
if (!from_initialize) {
|
if (!from_initialize) {
|
||||||
sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
|
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));
|
eap_server_get_name(0, sm->eap_type_supp));
|
||||||
}
|
}
|
||||||
sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
|
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),
|
eap_server_get_name(0, sm->eap_type_authsrv),
|
||||||
extra);
|
extra);
|
||||||
sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1,
|
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 eap_user *user)
|
||||||
{
|
{
|
||||||
struct eapol_state_machine *sm = ctx;
|
struct eapol_state_machine *sm = ctx;
|
||||||
return sm->eapol->cb.get_eap_user(sm->eapol->conf.ctx, identity,
|
int ret;
|
||||||
|
|
||||||
|
ret = sm->eapol->cb.get_eap_user(sm->eapol->conf.ctx, identity,
|
||||||
identity_len, phase2, user);
|
identity_len, phase2, user);
|
||||||
|
if (user->remediation)
|
||||||
|
sm->remediation = 1;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,7 +60,8 @@ struct eapol_auth_cb {
|
|||||||
size_t datalen);
|
size_t datalen);
|
||||||
void (*aaa_send)(void *ctx, void *sta_ctx, const u8 *data,
|
void (*aaa_send)(void *ctx, void *sta_ctx, const u8 *data,
|
||||||
size_t datalen);
|
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 (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
|
||||||
int phase2, struct eap_user *user);
|
int phase2, struct eap_user *user);
|
||||||
int (*sta_entry_alive)(void *ctx, const u8 *addr);
|
int (*sta_entry_alive)(void *ctx, const u8 *addr);
|
||||||
|
@ -173,6 +173,8 @@ struct eapol_state_machine {
|
|||||||
struct eapol_authenticator *eapol;
|
struct eapol_authenticator *eapol;
|
||||||
|
|
||||||
void *sta; /* station context pointer to use in callbacks */
|
void *sta; /* station context pointer to use in callbacks */
|
||||||
|
|
||||||
|
int remediation;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* EAPOL_AUTH_SM_I_H */
|
#endif /* EAPOL_AUTH_SM_I_H */
|
||||||
|
@ -77,6 +77,8 @@ struct radius_session {
|
|||||||
u8 last_identifier;
|
u8 last_identifier;
|
||||||
struct radius_msg *last_reply;
|
struct radius_msg *last_reply;
|
||||||
u8 last_authenticator[16];
|
u8 last_authenticator[16];
|
||||||
|
|
||||||
|
unsigned int remediation:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -307,6 +309,9 @@ struct radius_server_data {
|
|||||||
#ifdef CONFIG_RADIUS_TEST
|
#ifdef CONFIG_RADIUS_TEST
|
||||||
char *dump_msk_file;
|
char *dump_msk_file;
|
||||||
#endif /* CONFIG_RADIUS_TEST */
|
#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) {
|
if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
|
||||||
RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
|
RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
|
||||||
radius_msg_free(msg);
|
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
|
#ifdef CONFIG_RADIUS_TEST
|
||||||
if (conf->dump_msk_file)
|
if (conf->dump_msk_file)
|
||||||
data->dump_msk_file = os_strdup(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
|
#ifdef CONFIG_RADIUS_TEST
|
||||||
os_free(data->dump_msk_file);
|
os_free(data->dump_msk_file);
|
||||||
#endif /* CONFIG_RADIUS_TEST */
|
#endif /* CONFIG_RADIUS_TEST */
|
||||||
|
os_free(data->subscr_remediation_url);
|
||||||
os_free(data);
|
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_session *sess = ctx;
|
||||||
struct radius_server_data *data = sess->server;
|
struct radius_server_data *data = sess->server;
|
||||||
|
int ret;
|
||||||
|
|
||||||
return data->get_eap_user(data->conf_ctx, identity, identity_len,
|
ret = data->get_eap_user(data->conf_ctx, identity, identity_len,
|
||||||
phase2, user);
|
phase2, user);
|
||||||
|
if (ret == 0 && user)
|
||||||
|
sess->remediation = user->remediation;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -209,6 +209,9 @@ struct radius_server_conf {
|
|||||||
#ifdef CONFIG_RADIUS_TEST
|
#ifdef CONFIG_RADIUS_TEST
|
||||||
const char *dump_msk_file;
|
const char *dump_msk_file;
|
||||||
#endif /* CONFIG_RADIUS_TEST */
|
#endif /* CONFIG_RADIUS_TEST */
|
||||||
|
|
||||||
|
char *subscr_remediation_url;
|
||||||
|
u8 subscr_remediation_method;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user