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 <j@w1.fi>
This commit is contained in:
Jouni Malinen 2014-03-29 19:31:56 +02:00
parent 81699e2e6e
commit 8943cc998a
8 changed files with 135 additions and 15 deletions

View file

@ -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;
}