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:
parent
81699e2e6e
commit
8943cc998a
8 changed files with 135 additions and 15 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue