]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
RADIUS server: Add support for MAC ACL
authorJouni Malinen <j@w1.fi>
Sat, 29 Mar 2014 17:31:56 +0000 (19:31 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 29 Mar 2014 17:31:56 +0000 (19:31 +0200)
"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>
hostapd/config_file.c
src/ap/ap_config.h
src/ap/authsrv.c
src/ap/ieee802_1x.c
src/eap_server/eap.h
src/radius/radius.c
src/radius/radius.h
src/radius/radius_server.c

index e1f8b20dc8a420fc576bfc6e23e0f0aeb431ef30..8ce62aa3c1ee873921663a1ca9d80987597c27e8 100644 (file)
@@ -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;
index 25eb4903b26e12e072563300e056d6828424f6c0..dfbe626028d397b04dd6961653881f6420a767e4 100644 (file)
@@ -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;
 };
index 6e3decd85822d938103aeab88a41f345f287869d..86f1cbe1fdd809e649d298d72f8997f796428cb1 100644 (file)
@@ -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;
index b12c9d6c72df38ab715229dbeb8bf345d3937ce2..035415f24209f2870b83333f1b4ecc49ef8c64c6 100644 (file)
@@ -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;
 
index 698a5ac0b289a2ee3693243d9d9eaf4255cd558b..1253bd6e4e6810456b6ee8260e363f41acbe1686 100644 (file)
@@ -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;
index 370b517fda31141e5ec687ec7477a65442c94c01..47b4f8af4479e36866c5e67df133700ed2b8433d 100644 (file)
@@ -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);
 }
 
 
index d8bf21eb1cdf1e9d0bb8a20732fb7e1f19a1d83b..d388f717aa4238cb5590111b6462c766ff1f3e7c 100644 (file)
@@ -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,
index f2ea3932462646163ecd8f2f790fff358e156d41..bd358ae9e9147176bfd89ee84b0717dde9cb5e1b 100644 (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;
 }