diff --git a/hostapd/config_file.c b/hostapd/config_file.c index bd6647439..949a9d171 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -22,6 +22,14 @@ #include "config_file.h" +#ifndef CONFIG_NO_RADIUS +#ifdef EAP_SERVER +static struct hostapd_radius_attr * +hostapd_parse_radius_attr(const char *value); +#endif /* EAP_SERVER */ +#endif /* CONFIG_NO_RADIUS */ + + #ifndef CONFIG_NO_VLAN static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss, const char *fname) @@ -208,7 +216,7 @@ static int hostapd_config_read_eap_user(const char *fname, FILE *f; char buf[512], *pos, *start, *pos2; int line = 0, ret = 0, num_methods; - struct hostapd_eap_user *user, *tail = NULL; + struct hostapd_eap_user *user = NULL, *tail = NULL; if (!fname) return 0; @@ -242,6 +250,27 @@ static int hostapd_config_read_eap_user(const char *fname, if (buf[0] == '\0') continue; +#ifndef CONFIG_NO_RADIUS + if (user && os_strncmp(buf, "radius_accept_attr=", 19) == 0) { + struct hostapd_radius_attr *attr, *a; + attr = hostapd_parse_radius_attr(buf + 19); + if (attr == NULL) { + wpa_printf(MSG_ERROR, "Invalid radius_auth_req_attr: %s", + buf + 19); + goto failed; + } + if (user->accept_attr == NULL) { + user->accept_attr = attr; + } else { + a = user->accept_attr; + while (a->next) + a = a->next; + a->next = attr; + } + continue; + } +#endif /* CONFIG_NO_RADIUS */ + user = NULL; if (buf[0] != '"' && buf[0] != '*') { @@ -468,11 +497,8 @@ static int hostapd_config_read_eap_user(const char *fname, continue; failed: - if (user) { - os_free(user->password); - os_free(user->identity); - os_free(user); - } + if (user) + hostapd_config_free_eap_user(user); ret = -1; break; } diff --git a/hostapd/hostapd.eap_user b/hostapd/hostapd.eap_user index 12a2c6129..00edc95af 100644 --- a/hostapd/hostapd.eap_user +++ b/hostapd/hostapd.eap_user @@ -48,6 +48,12 @@ # TTLS-CHAP, TTLS-MSCHAP, TTLS-MSCHAPV2. TTLS-PAP and TTLS-CHAP require a # plaintext password while TTLS-MSCHAP and TTLS-MSCHAPV2 can use NT password # hash. +# +# Arbitrary RADIUS attributes can be added into Access-Accept packets similarly +# to the way radius_auth_req_attr is used for Access-Request packet in +# hostapd.conf. For EAP server, this is configured separately for each user +# entry with radius_accept_attr= line(s) following the main user entry +# line. # Phase 1 users "user" MD5 "password" diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index b995892cd..f744985a0 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -388,8 +388,9 @@ static void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr) } -static void hostapd_config_free_eap_user(struct hostapd_eap_user *user) +void hostapd_config_free_eap_user(struct hostapd_eap_user *user) { + hostapd_config_free_radius_attr(user->accept_attr); os_free(user->identity); os_free(user->password); os_free(user); diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index e1e34e2d5..f6ca8b1f9 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -128,6 +128,7 @@ struct hostapd_eap_user { * nt_password_hash() */ unsigned int remediation:1; int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */ + struct hostapd_radius_attr *accept_attr; }; struct hostapd_radius_attr { @@ -601,6 +602,7 @@ int hostapd_mac_comp(const void *a, const void *b); int hostapd_mac_comp_empty(const void *a); struct hostapd_config * hostapd_config_defaults(void); void hostapd_config_defaults_bss(struct hostapd_bss_config *bss); +void hostapd_config_free_eap_user(struct hostapd_eap_user *user); void hostapd_config_free_bss(struct hostapd_bss_config *conf); void hostapd_config_free(struct hostapd_config *conf); int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries, diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c index 7691012fe..8b922ec21 100644 --- a/src/ap/authsrv.c +++ b/src/ap/authsrv.c @@ -81,6 +81,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; + user->accept_attr = eap_user->accept_attr; return 0; } diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h index 197b232ff..25347baa4 100644 --- a/src/eap_server/eap.h +++ b/src/eap_server/eap.h @@ -35,6 +35,7 @@ struct eap_user { unsigned int remediation:1; int ttls_auth; /* bitfield of * EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */ + struct hostapd_radius_attr *accept_attr; }; struct eap_eapol_interface { diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c index 6b86932ac..dd96b592a 100644 --- a/src/radius/radius_server.c +++ b/src/radius/radius_server.c @@ -13,6 +13,7 @@ #include "radius.h" #include "eloop.h" #include "eap_server/eap.h" +#include "ap/ap_config.h" #include "radius_server.h" /** @@ -79,6 +80,8 @@ struct radius_session { u8 last_authenticator[16]; unsigned int remediation:1; + + struct hostapd_radius_attr *accept_attr; }; /** @@ -483,6 +486,7 @@ radius_server_get_new_session(struct radius_server_data *data, int res; struct radius_session *sess; struct eap_config eap_conf; + struct eap_user tmp; RADIUS_DEBUG("Creating a new session"); @@ -499,7 +503,9 @@ radius_server_get_new_session(struct radius_server_data *data, user_len = res; RADIUS_DUMP_ASCII("User-Name", user, user_len); - res = data->get_eap_user(data->conf_ctx, user, user_len, 0, NULL); + os_memset(&tmp, 0, sizeof(tmp)); + res = data->get_eap_user(data->conf_ctx, user, user_len, 0, &tmp); + os_free(tmp.password); os_free(user); if (res == 0) { @@ -509,6 +515,7 @@ radius_server_get_new_session(struct radius_server_data *data, RADIUS_DEBUG("Failed to create a new session"); return NULL; } + sess->accept_attr = tmp.accept_attr; } else { RADIUS_DEBUG("User-Name not found from user database"); return NULL; @@ -661,6 +668,19 @@ radius_server_encapsulate_eap(struct radius_server_data *data, return NULL; } + 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))) { + wpa_printf(MSG_ERROR, "Could not add RADIUS attribute"); + radius_msg_free(msg); + return NULL; + } + } + } + if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret, client->shared_secret_len, hdr->authenticator) < 0) { @@ -1725,8 +1745,10 @@ static int radius_server_get_eap_user(void *ctx, const u8 *identity, ret = data->get_eap_user(data->conf_ctx, identity, identity_len, phase2, user); - if (ret == 0 && user) + if (ret == 0 && user) { + sess->accept_attr = user->accept_attr; sess->remediation = user->remediation; + } return ret; }