aboutsummaryrefslogtreecommitdiffstats
path: root/src/radius
diff options
context:
space:
mode:
Diffstat (limited to 'src/radius')
-rw-r--r--src/radius/radius.c45
-rw-r--r--src/radius/radius.h4
-rw-r--r--src/radius/radius_server.c91
3 files changed, 126 insertions, 14 deletions
diff --git a/src/radius/radius.c b/src/radius/radius.c
index 370b517f..47b4f8af 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 d8bf21eb..d388f717 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 f2ea3932..bd358ae9 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;
}