Cumulative patch from commit 39a5800f7c2a9de743c673a78929ac46a099b1a4

39a5800 wpa_supplicant: Allow disabling LDPC
7230040 Interworking: Read IMSI if not read at supplicant start
62f736d Interworking: Init scard when a credential requires SIM access
729897a Interworking: Fix incorrect compile PCSC flag
21611ea edit: Increase buffer size to 4096 bytes
0b2c59e OSU server: Add example scripts for Hotspot 2.0 PKI
0f27c20 HS 2.0R2: Add example OSU SPP server implementation
1e03c6c XML: Remove forgotten, unused definition of debug_print_func
5cfc87b Make hs20_wan_metrics parser error print more helpful
4be20bf Fix validation of anqp_3gpp_cell_net configuration parameter
23587e3 Remove duplicated vht_capab parser entry
18a8e55 Notify STA of disconnection based on ACL change
8943cc9 RADIUS server: Add support for MAC ACL
dc87541 Clean up debug print for PSK file search
bbbacbf DFS: Print CAC info in ctrl_iface STATUS command
ace0fbd P2P: Fix segfault when PBC overlap is detected
cf15b15 Add writing of network block ocsp parameter
5c9da16 nl80211: Set all BSS interfaces down when tearing down AP in MBSS mode
f1c4dbf wpa_supplicant: Remove pending sme-connect radio work
4f560cd wpa_supplicant: Override HT A-MPDU size if VHT A-MPDU was overridden
3ae8b7b hostapd: Add vendor command support
782e2f7 P2P: Do not initiate scan on P2P Device when enabled
74a1319 Fix issue with incorrect secondary_channel in HT40/HT80
96ecea5 Pass TDLS peer capability information in tdls_mgmt
78cd7e6 Sync with wireless-testing.git include/uapi/linux/nl80211.h
b36935b nl80211: Fix EAPOL frames not being delivered
6997f8b nl80211: Set interface address even if using old interface
9b4d9c8 nl80211: Print if_indices list in debug log
762c41a eloop: Add assert() on negative fd when using select() code path
978c673 Add a note on using 'iw list' to determine multi-BSS support

Change-Id: I89af7f8d92ed706c8909ed3cc9c49d6e1277a2b0
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index f2ea393..bd358ae 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -86,6 +86,7 @@
 	u8 last_authenticator[16];
 
 	unsigned int remediation:1;
+	unsigned int macacl:1;
 
 	struct hostapd_radius_attr *accept_attr;
 };
@@ -636,6 +637,7 @@
 		return NULL;
 	}
 	sess->accept_attr = tmp.accept_attr;
+	sess->macacl = tmp.macacl;
 
 	sess->username = os_malloc(user_len * 2 + 1);
 	if (sess->username == NULL) {
@@ -823,6 +825,87 @@
 }
 
 
+static struct radius_msg *
+radius_server_macacl(struct radius_server_data *data,
+		     struct radius_client *client,
+		     struct radius_session *sess,
+		     struct radius_msg *request)
+{
+	struct radius_msg *msg;
+	int code;
+	struct radius_hdr *hdr = radius_msg_get_hdr(request);
+	u8 *pw;
+	size_t pw_len;
+
+	code = RADIUS_CODE_ACCESS_ACCEPT;
+
+	if (radius_msg_get_attr_ptr(request, RADIUS_ATTR_USER_PASSWORD, &pw,
+				    &pw_len, NULL) < 0) {
+		RADIUS_DEBUG("Could not get User-Password");
+		code = RADIUS_CODE_ACCESS_REJECT;
+	} else {
+		int res;
+		struct eap_user tmp;
+
+		os_memset(&tmp, 0, sizeof(tmp));
+		res = data->get_eap_user(data->conf_ctx, (u8 *) sess->username,
+					 os_strlen(sess->username), 0, &tmp);
+		if (res || !tmp.macacl || tmp.password == NULL) {
+			RADIUS_DEBUG("No MAC ACL user entry");
+			os_free(tmp.password);
+			code = RADIUS_CODE_ACCESS_REJECT;
+		} else {
+			u8 buf[128];
+			res = radius_user_password_hide(
+				request, tmp.password, tmp.password_len,
+				(u8 *) client->shared_secret,
+				client->shared_secret_len,
+				buf, sizeof(buf));
+			os_free(tmp.password);
+
+			if (res < 0 || pw_len != (size_t) res ||
+			    os_memcmp(pw, buf, res) != 0) {
+				RADIUS_DEBUG("Incorrect User-Password");
+				code = RADIUS_CODE_ACCESS_REJECT;
+			}
+		}
+	}
+
+	msg = radius_msg_new(code, hdr->identifier);
+	if (msg == NULL) {
+		RADIUS_DEBUG("Failed to allocate reply message");
+		return NULL;
+	}
+
+	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);
+		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) {
+		RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
+	}
+
+	return msg;
+}
+
+
 static int radius_server_reject(struct radius_server_data *data,
 				struct radius_client *client,
 				struct radius_msg *request,
@@ -958,6 +1041,12 @@
 	}
 		      
 	eap = radius_msg_get_eap(msg);
+	if (eap == NULL && sess->macacl) {
+		reply = radius_server_macacl(data, client, sess, msg);
+		if (reply == NULL)
+			return -1;
+		goto send_reply;
+	}
 	if (eap == NULL) {
 		RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
 			     from_addr);
@@ -1015,6 +1104,7 @@
 
 	reply = radius_server_encapsulate_eap(data, client, sess, msg);
 
+send_reply:
 	if (reply) {
 		struct wpabuf *buf;
 		struct radius_hdr *hdr;
@@ -1904,6 +1994,7 @@
 	if (ret == 0 && user) {
 		sess->accept_attr = user->accept_attr;
 		sess->remediation = user->remediation;
+		sess->macacl = user->macacl;
 	}
 	return ret;
 }