Parcourir la source

Allow arbitrary RADIUS attributes to be added into Access-Accept

This extends the design already available for Access-Request packets to
the RADIUS server and Access-Accept messages. Each user entry can be
configured to add arbitrary RADIUS attributes.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
Jouni Malinen il y a 11 ans
Parent
commit
d0ee16edc8

+ 32 - 6
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;
 	}

+ 6 - 0
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=<value> line(s) following the main user entry
+# line.
 
 # Phase 1 users
 "user"		MD5	"password"

+ 2 - 1
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);

+ 2 - 0
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,

+ 1 - 0
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;
 }

+ 1 - 0
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 {

+ 24 - 2
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;
 }