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;
|
EAP_TTLS_AUTH_MSCHAPV2;
|
||||||
goto skip_eap;
|
goto skip_eap;
|
||||||
}
|
}
|
||||||
|
if (os_strcmp(start, "MACACL") == 0) {
|
||||||
|
user->macacl = 1;
|
||||||
|
goto skip_eap;
|
||||||
|
}
|
||||||
wpa_printf(MSG_ERROR, "Unsupported EAP type "
|
wpa_printf(MSG_ERROR, "Unsupported EAP type "
|
||||||
"'%s' on line %d in '%s'",
|
"'%s' on line %d in '%s'",
|
||||||
start, line, fname);
|
start, line, fname);
|
||||||
|
@ -380,7 +384,7 @@ static int hostapd_config_read_eap_user(const char *fname,
|
||||||
break;
|
break;
|
||||||
start = pos3;
|
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 "
|
wpa_printf(MSG_ERROR, "No EAP types configured on "
|
||||||
"line %d in '%s'", line, fname);
|
"line %d in '%s'", line, fname);
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
|
@ -127,6 +127,7 @@ struct hostapd_eap_user {
|
||||||
unsigned int password_hash:1; /* whether password is hashed with
|
unsigned int password_hash:1; /* whether password is hashed with
|
||||||
* nt_password_hash() */
|
* nt_password_hash() */
|
||||||
unsigned int remediation:1;
|
unsigned int remediation:1;
|
||||||
|
unsigned int macacl:1;
|
||||||
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
|
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
|
||||||
struct hostapd_radius_attr *accept_attr;
|
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->password_hash = eap_user->password_hash;
|
||||||
}
|
}
|
||||||
user->force_version = eap_user->force_version;
|
user->force_version = eap_user->force_version;
|
||||||
|
user->macacl = eap_user->macacl;
|
||||||
user->ttls_auth = eap_user->ttls_auth;
|
user->ttls_auth = eap_user->ttls_auth;
|
||||||
user->remediation = eap_user->remediation;
|
user->remediation = eap_user->remediation;
|
||||||
user->accept_attr = eap_user->accept_attr;
|
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->password_hash = eap_user->password_hash;
|
||||||
}
|
}
|
||||||
user->force_version = eap_user->force_version;
|
user->force_version = eap_user->force_version;
|
||||||
|
user->macacl = eap_user->macacl;
|
||||||
user->ttls_auth = eap_user->ttls_auth;
|
user->ttls_auth = eap_user->ttls_auth;
|
||||||
user->remediation = eap_user->remediation;
|
user->remediation = eap_user->remediation;
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ struct eap_user {
|
||||||
int phase2;
|
int phase2;
|
||||||
int force_version;
|
int force_version;
|
||||||
unsigned int remediation:1;
|
unsigned int remediation:1;
|
||||||
|
unsigned int macacl:1;
|
||||||
int ttls_auth; /* bitfield of
|
int ttls_auth; /* bitfield of
|
||||||
* EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */
|
* EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */
|
||||||
struct hostapd_radius_attr *accept_attr;
|
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
|
int radius_user_password_hide(struct radius_msg *msg,
|
||||||
* in RFC 2865, Chap. 5.2 */
|
const u8 *data, size_t data_len,
|
||||||
struct radius_attr_hdr *
|
const u8 *secret, size_t secret_len,
|
||||||
radius_msg_add_attr_user_password(struct radius_msg *msg,
|
u8 *buf, size_t buf_len)
|
||||||
const u8 *data, size_t data_len,
|
|
||||||
const u8 *secret, size_t secret_len)
|
|
||||||
{
|
{
|
||||||
u8 buf[128];
|
size_t padlen, i, pos;
|
||||||
size_t padlen, i, buf_len, pos;
|
|
||||||
const u8 *addr[2];
|
const u8 *addr[2];
|
||||||
size_t len[2];
|
size_t len[2];
|
||||||
u8 hash[16];
|
u8 hash[16];
|
||||||
|
|
||||||
if (data_len > 128)
|
if (data_len + 16 > buf_len)
|
||||||
return NULL;
|
return -1;
|
||||||
|
|
||||||
os_memcpy(buf, data, data_len);
|
os_memcpy(buf, data, data_len);
|
||||||
buf_len = data_len;
|
|
||||||
|
|
||||||
padlen = data_len % 16;
|
padlen = data_len % 16;
|
||||||
if (padlen && data_len < sizeof(buf)) {
|
if (padlen && data_len < buf_len) {
|
||||||
padlen = 16 - padlen;
|
padlen = 16 - padlen;
|
||||||
os_memset(buf + data_len, 0, padlen);
|
os_memset(buf + data_len, 0, padlen);
|
||||||
buf_len += padlen;
|
buf_len = data_len + padlen;
|
||||||
|
} else {
|
||||||
|
buf_len = data_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr[0] = secret;
|
addr[0] = secret;
|
||||||
|
@ -1296,8 +1294,27 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
|
||||||
pos += 16;
|
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,
|
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);
|
const u8 *recv_key, size_t recv_key_len);
|
||||||
int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data,
|
int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data,
|
||||||
size_t len);
|
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 *
|
struct radius_attr_hdr *
|
||||||
radius_msg_add_attr_user_password(struct radius_msg *msg,
|
radius_msg_add_attr_user_password(struct radius_msg *msg,
|
||||||
const u8 *data, size_t data_len,
|
const u8 *data, size_t data_len,
|
||||||
|
|
|
@ -86,6 +86,7 @@ struct radius_session {
|
||||||
u8 last_authenticator[16];
|
u8 last_authenticator[16];
|
||||||
|
|
||||||
unsigned int remediation:1;
|
unsigned int remediation:1;
|
||||||
|
unsigned int macacl:1;
|
||||||
|
|
||||||
struct hostapd_radius_attr *accept_attr;
|
struct hostapd_radius_attr *accept_attr;
|
||||||
};
|
};
|
||||||
|
@ -636,6 +637,7 @@ radius_server_get_new_session(struct radius_server_data *data,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
sess->accept_attr = tmp.accept_attr;
|
sess->accept_attr = tmp.accept_attr;
|
||||||
|
sess->macacl = tmp.macacl;
|
||||||
|
|
||||||
sess->username = os_malloc(user_len * 2 + 1);
|
sess->username = os_malloc(user_len * 2 + 1);
|
||||||
if (sess->username == NULL) {
|
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,
|
static int radius_server_reject(struct radius_server_data *data,
|
||||||
struct radius_client *client,
|
struct radius_client *client,
|
||||||
struct radius_msg *request,
|
struct radius_msg *request,
|
||||||
|
@ -958,6 +1041,12 @@ static int radius_server_request(struct radius_server_data *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
eap = radius_msg_get_eap(msg);
|
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) {
|
if (eap == NULL) {
|
||||||
RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
|
RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
|
||||||
from_addr);
|
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);
|
reply = radius_server_encapsulate_eap(data, client, sess, msg);
|
||||||
|
|
||||||
|
send_reply:
|
||||||
if (reply) {
|
if (reply) {
|
||||||
struct wpabuf *buf;
|
struct wpabuf *buf;
|
||||||
struct radius_hdr *hdr;
|
struct radius_hdr *hdr;
|
||||||
|
@ -1904,6 +1994,7 @@ static int radius_server_get_eap_user(void *ctx, const u8 *identity,
|
||||||
if (ret == 0 && user) {
|
if (ret == 0 && user) {
|
||||||
sess->accept_attr = user->accept_attr;
|
sess->accept_attr = user->accept_attr;
|
||||||
sess->remediation = user->remediation;
|
sess->remediation = user->remediation;
|
||||||
|
sess->macacl = user->macacl;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue