From 8943cc998a395734aa2ab7afeafe6fe3ec97b348 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 29 Mar 2014 19:31:56 +0200 Subject: [PATCH] RADIUS server: Add support for MAC ACL "user" MACACL "password" style lines in the eap_user file can now be used to configured user entries for RADIUS-based MAC ACL. Signed-off-by: Jouni Malinen --- hostapd/config_file.c | 6 ++- src/ap/ap_config.h | 1 + src/ap/authsrv.c | 1 + src/ap/ieee802_1x.c | 1 + src/eap_server/eap.h | 1 + src/radius/radius.c | 45 +++++++++++++------ src/radius/radius.h | 4 ++ src/radius/radius_server.c | 91 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 135 insertions(+), 15 deletions(-) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index e1f8b20dc..8ce62aa3c 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -366,6 +366,10 @@ static int hostapd_config_read_eap_user(const char *fname, EAP_TTLS_AUTH_MSCHAPV2; goto skip_eap; } + if (os_strcmp(start, "MACACL") == 0) { + user->macacl = 1; + goto skip_eap; + } wpa_printf(MSG_ERROR, "Unsupported EAP type " "'%s' on line %d in '%s'", start, line, fname); @@ -380,7 +384,7 @@ static int hostapd_config_read_eap_user(const char *fname, break; start = pos3; } - if (num_methods == 0 && user->ttls_auth == 0) { + if (num_methods == 0 && user->ttls_auth == 0 && !user->macacl) { wpa_printf(MSG_ERROR, "No EAP types configured on " "line %d in '%s'", line, fname); goto failed; diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 25eb4903b..dfbe62602 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -127,6 +127,7 @@ struct hostapd_eap_user { unsigned int password_hash:1; /* whether password is hashed with * nt_password_hash() */ unsigned int remediation:1; + unsigned int macacl:1; int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */ struct hostapd_radius_attr *accept_attr; }; diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c index 6e3decd85..86f1cbe1f 100644 --- a/src/ap/authsrv.c +++ b/src/ap/authsrv.c @@ -79,6 +79,7 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity, user->password_hash = eap_user->password_hash; } user->force_version = eap_user->force_version; + user->macacl = eap_user->macacl; user->ttls_auth = eap_user->ttls_auth; user->remediation = eap_user->remediation; user->accept_attr = eap_user->accept_attr; diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index b12c9d6c7..035415f24 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -1787,6 +1787,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, user->password_hash = eap_user->password_hash; } user->force_version = eap_user->force_version; + user->macacl = eap_user->macacl; user->ttls_auth = eap_user->ttls_auth; user->remediation = eap_user->remediation; diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h index 698a5ac0b..1253bd6e4 100644 --- a/src/eap_server/eap.h +++ b/src/eap_server/eap.h @@ -33,6 +33,7 @@ struct eap_user { int phase2; int force_version; unsigned int remediation:1; + unsigned int macacl:1; int ttls_auth; /* bitfield of * EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */ struct hostapd_radius_attr *accept_attr; diff --git a/src/radius/radius.c b/src/radius/radius.c index 370b517fd..47b4f8af4 100644 --- a/src/radius/radius.c +++ b/src/radius/radius.c @@ -1247,30 +1247,28 @@ int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data, } -/* Add User-Password attribute to a RADIUS message and encrypt it as specified - * in RFC 2865, Chap. 5.2 */ -struct radius_attr_hdr * -radius_msg_add_attr_user_password(struct radius_msg *msg, - const u8 *data, size_t data_len, - const u8 *secret, size_t secret_len) +int radius_user_password_hide(struct radius_msg *msg, + const u8 *data, size_t data_len, + const u8 *secret, size_t secret_len, + u8 *buf, size_t buf_len) { - u8 buf[128]; - size_t padlen, i, buf_len, pos; + size_t padlen, i, pos; const u8 *addr[2]; size_t len[2]; u8 hash[16]; - if (data_len > 128) - return NULL; + if (data_len + 16 > buf_len) + return -1; os_memcpy(buf, data, data_len); - buf_len = data_len; padlen = data_len % 16; - if (padlen && data_len < sizeof(buf)) { + if (padlen && data_len < buf_len) { padlen = 16 - padlen; os_memset(buf + data_len, 0, padlen); - buf_len += padlen; + buf_len = data_len + padlen; + } else { + buf_len = data_len; } addr[0] = secret; @@ -1296,8 +1294,27 @@ radius_msg_add_attr_user_password(struct radius_msg *msg, pos += 16; } + return buf_len; +} + + +/* Add User-Password attribute to a RADIUS message and encrypt it as specified + * in RFC 2865, Chap. 5.2 */ +struct radius_attr_hdr * +radius_msg_add_attr_user_password(struct radius_msg *msg, + const u8 *data, size_t data_len, + const u8 *secret, size_t secret_len) +{ + u8 buf[128]; + int res; + + res = radius_user_password_hide(msg, data, data_len, + secret, secret_len, buf, sizeof(buf)); + if (res < 0) + return NULL; + return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD, - buf, buf_len); + buf, res); } diff --git a/src/radius/radius.h b/src/radius/radius.h index d8bf21eb1..d388f717a 100644 --- a/src/radius/radius.h +++ b/src/radius/radius.h @@ -251,6 +251,10 @@ int radius_msg_add_mppe_keys(struct radius_msg *msg, const u8 *recv_key, size_t recv_key_len); int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data, size_t len); +int radius_user_password_hide(struct radius_msg *msg, + const u8 *data, size_t data_len, + const u8 *secret, size_t secret_len, + u8 *buf, size_t buf_len); struct radius_attr_hdr * radius_msg_add_attr_user_password(struct radius_msg *msg, const u8 *data, size_t data_len, diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c index f2ea39324..bd358ae9e 100644 --- a/src/radius/radius_server.c +++ b/src/radius/radius_server.c @@ -86,6 +86,7 @@ struct radius_session { u8 last_authenticator[16]; unsigned int remediation:1; + unsigned int macacl:1; struct hostapd_radius_attr *accept_attr; }; @@ -636,6 +637,7 @@ radius_server_get_new_session(struct radius_server_data *data, 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 @@ radius_server_encapsulate_eap(struct radius_server_data *data, } +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 @@ static int radius_server_request(struct radius_server_data *data, } 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 @@ static int radius_server_request(struct radius_server_data *data, reply = radius_server_encapsulate_eap(data, client, sess, msg); +send_reply: if (reply) { struct wpabuf *buf; struct radius_hdr *hdr; @@ -1904,6 +1994,7 @@ static int radius_server_get_eap_user(void *ctx, const u8 *identity, if (ret == 0 && user) { sess->accept_attr = user->accept_attr; sess->remediation = user->remediation; + sess->macacl = user->macacl; } return ret; }