]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
hostapd: Allow addition of arbitrary RADIUS attributes
authorJouni Malinen <j@w1.fi>
Sat, 5 May 2012 17:19:56 +0000 (20:19 +0300)
committerJouni Malinen <j@w1.fi>
Sat, 5 May 2012 17:19:56 +0000 (20:19 +0300)
New configuration parameters radius_auth_req_attr and
radius_acct_req_attr can now be used to add (or override) RADIUS
attributes in Access-Request and Accounting-Request packets.

Signed-hostap: Jouni Malinen <j@w1.fi>

hostapd/config_file.c
hostapd/hostapd.conf
src/ap/accounting.c
src/ap/ap_config.c
src/ap/ap_config.h
src/ap/ieee802_1x.c

index c8a628862626e383a64b3d1ff51558f66a8769ec..5c8824c54ccd4fc8d589db171cc5e4d362c66e99 100644 (file)
@@ -491,6 +491,76 @@ hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
 
        return ret;
 }
+
+
+static struct hostapd_radius_attr *
+hostapd_parse_radius_attr(const char *value)
+{
+       const char *pos;
+       char syntax;
+       struct hostapd_radius_attr *attr;
+       size_t len;
+
+       attr = os_zalloc(sizeof(*attr));
+       if (attr == NULL)
+               return NULL;
+
+       attr->type = atoi(value);
+
+       pos = os_strchr(value, ':');
+       if (pos == NULL) {
+               attr->val = wpabuf_alloc(1);
+               if (attr->val == NULL) {
+                       os_free(attr);
+                       return NULL;
+               }
+               wpabuf_put_u8(attr->val, 0);
+               return attr;
+       }
+
+       pos++;
+       if (pos[0] == '\0' || pos[1] != ':') {
+               os_free(attr);
+               return NULL;
+       }
+       syntax = *pos++;
+       pos++;
+
+       switch (syntax) {
+       case 's':
+               attr->val = wpabuf_alloc_copy(pos, os_strlen(pos));
+               break;
+       case 'x':
+               len = os_strlen(pos);
+               if (len & 1)
+                       break;
+               len /= 2;
+               attr->val = wpabuf_alloc(len);
+               if (attr->val == NULL)
+                       break;
+               if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) {
+                       wpabuf_free(attr->val);
+                       os_free(attr);
+                       return NULL;
+               }
+               break;
+       case 'd':
+               attr->val = wpabuf_alloc(4);
+               if (attr->val)
+                       wpabuf_put_be32(attr->val, atoi(pos));
+               break;
+       default:
+               os_free(attr);
+               return NULL;
+       }
+
+       if (attr->val == NULL) {
+               os_free(attr);
+               return NULL;
+       }
+
+       return attr;
+}
 #endif /* CONFIG_NO_RADIUS */
 
 
@@ -1557,6 +1627,36 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                        bss->acct_interim_interval = atoi(pos);
                } else if (os_strcmp(buf, "radius_request_cui") == 0) {
                        bss->radius_request_cui = atoi(pos);
+               } else if (os_strcmp(buf, "radius_auth_req_attr") == 0) {
+                       struct hostapd_radius_attr *attr, *a;
+                       attr = hostapd_parse_radius_attr(pos);
+                       if (attr == NULL) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "radius_auth_req_attr", line);
+                               errors++;
+                       } else if (bss->radius_auth_req_attr == NULL) {
+                               bss->radius_auth_req_attr = attr;
+                       } else {
+                               a = bss->radius_auth_req_attr;
+                               while (a->next)
+                                       a = a->next;
+                               a->next = attr;
+                       }
+               } else if (os_strcmp(buf, "radius_acct_req_attr") == 0) {
+                       struct hostapd_radius_attr *attr, *a;
+                       attr = hostapd_parse_radius_attr(pos);
+                       if (attr == NULL) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "radius_acct_req_attr", line);
+                               errors++;
+                       } else if (bss->radius_acct_req_attr == NULL) {
+                               bss->radius_acct_req_attr = attr;
+                       } else {
+                               a = bss->radius_acct_req_attr;
+                               while (a->next)
+                                       a = a->next;
+                               a->next = attr;
+                       }
 #endif /* CONFIG_NO_RADIUS */
                } else if (os_strcmp(buf, "auth_algs") == 0) {
                        bss->auth_algs = atoi(pos);
index e38a7aa02725df18583bcea966673bd2b0b5638f..8890cd27c813b0d5bd4fdaf91479a98aa22ed6eb 100644 (file)
@@ -665,6 +665,36 @@ own_ip_addr=127.0.0.1
 # to the bridge.
 #vlan_tagged_interface=eth0
 
+# Arbitrary RADIUS attributes can be added into Access-Request and
+# Accounting-Request packets by specifying the contents of the attributes with
+# the following configuration parameters. There can be multiple of these to
+# add multiple attributes. These parameters can also be used to override some
+# of the attributes added automatically by hostapd.
+# Format: <attr_id>[:<syntax:value>]
+# attr_id: RADIUS attribute type (e.g., 26 = Vendor-Specific)
+# syntax: s = string (UTF-8), d = integer, x = octet string
+# value: attribute value in format indicated by the syntax
+# If syntax and value parts are omitted, a null value (single 0x00 octet) is
+# used.
+#
+# Additional Access-Request attributes
+# radius_auth_req_attr=<attr_id>[:<syntax:value>]
+# Examples:
+# Operator-Name = "Operator"
+#radius_auth_req_attr=126:s:Operator
+# Service-Type = Framed (2)
+#radius_auth_req_attr=6:d:2
+# Connect-Info = "testing" (this overrides the automatically generated value)
+#radius_auth_req_attr=77:s:testing
+# Same Connect-Info value set as a hexdump
+#radius_auth_req_attr=77:x:74657374696e67
+
+#
+# Additional Accounting-Request attributes
+# radius_acct_req_attr=<attr_id>[:<syntax:value>]
+# Examples:
+# Operator-Name = "Operator"
+#radius_acct_req_attr=126:s:Operator
 
 ##### RADIUS authentication server configuration ##############################
 
index 82443a1f359e43a5d5d2a1d31897a3f18498e072..2c3a6d9f4c917851643e5f7ea271483f4f90e17b 100644 (file)
@@ -40,6 +40,7 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
        size_t len;
        int i;
        struct wpabuf *b;
+       struct hostapd_radius_attr *attr;
 
        msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
                             radius_client_get_id(hapd->radius));
@@ -68,7 +69,9 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
                goto fail;
        }
 
-       if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+                                           RADIUS_ATTR_ACCT_AUTHENTIC) &&
+           !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
                                       hapd->conf->ieee802_1x ?
                                       RADIUS_ACCT_AUTHENTIC_RADIUS :
                                       RADIUS_ACCT_AUTHENTIC_LOCAL)) {
@@ -92,7 +95,9 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
                }
        }
 
-       if (hapd->conf->own_ip_addr.af == AF_INET &&
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+                                           RADIUS_ATTR_NAS_IP_ADDRESS) &&
+           hapd->conf->own_ip_addr.af == AF_INET &&
            !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
                                 (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
                printf("Could not add NAS-IP-Address\n");
@@ -100,7 +105,9 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
        }
 
 #ifdef CONFIG_IPV6
-       if (hapd->conf->own_ip_addr.af == AF_INET6 &&
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+                                           RADIUS_ATTR_NAS_IPV6_ADDRESS) &&
+           hapd->conf->own_ip_addr.af == AF_INET6 &&
            !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
                                 (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
                printf("Could not add NAS-IPv6-Address\n");
@@ -108,7 +115,9 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
        }
 #endif /* CONFIG_IPV6 */
 
-       if (hapd->conf->nas_identifier &&
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+                                           RADIUS_ATTR_NAS_IDENTIFIER) &&
+           hapd->conf->nas_identifier &&
            !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
                                 (u8 *) hapd->conf->nas_identifier,
                                 os_strlen(hapd->conf->nas_identifier))) {
@@ -116,7 +125,9 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
                goto fail;
        }
 
-       if (sta &&
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+                                           RADIUS_ATTR_NAS_PORT) &&
+           sta &&
            !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
                printf("Could not add NAS-Port\n");
                goto fail;
@@ -124,7 +135,9 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
 
        os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
                    MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
-       if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+                                           RADIUS_ATTR_CALLED_STATION_ID) &&
+           !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
                                 (u8 *) buf, os_strlen(buf))) {
                printf("Could not add Called-Station-Id\n");
                goto fail;
@@ -139,7 +152,10 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
                        goto fail;
                }
 
-               if (!radius_msg_add_attr_int32(
+               if (!hostapd_config_get_radius_attr(
+                           hapd->conf->radius_acct_req_attr,
+                           RADIUS_ATTR_NAS_PORT_TYPE) &&
+                   !radius_msg_add_attr_int32(
                            msg, RADIUS_ATTR_NAS_PORT_TYPE,
                            RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
                        printf("Could not add NAS-Port-Type\n");
@@ -150,7 +166,10 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
                            radius_sta_rate(hapd, sta) / 2,
                            (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
                            radius_mode_txt(hapd));
-               if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
+               if (!hostapd_config_get_radius_attr(
+                           hapd->conf->radius_acct_req_attr,
+                           RADIUS_ATTR_CONNECT_INFO) &&
+                   !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
                                         (u8 *) buf, os_strlen(buf))) {
                        printf("Could not add Connect-Info\n");
                        goto fail;
@@ -179,6 +198,17 @@ static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
                }
        }
 
+       for (attr = hapd->conf->radius_acct_req_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");
+                       goto fail;
+               }
+       }
+
        return msg;
 
  fail:
index 303448b215f94dc9e101c8218dbc7476faad239e..392b4fd40074d70b5ae6af0ce6e8133f56fefa74 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / Configuration helper functions
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -336,6 +336,30 @@ static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
 }
 
 
+struct hostapd_radius_attr *
+hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type)
+{
+       for (; attr; attr = attr->next) {
+               if (attr->type == type)
+                       return attr;
+       }
+       return NULL;
+}
+
+
+static void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
+{
+       struct hostapd_radius_attr *prev;
+
+       while (attr) {
+               prev = attr;
+               attr = attr->next;
+               wpabuf_free(prev->val);
+               os_free(prev);
+       }
+}
+
+
 static void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
 {
        os_free(user->identity);
@@ -392,6 +416,8 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
                                   conf->radius->num_auth_servers);
        hostapd_config_free_radius(conf->radius->acct_servers,
                                   conf->radius->num_acct_servers);
+       hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
+       hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
        os_free(conf->rsn_preauth_interfaces);
        os_free(conf->ctrl_interface);
        os_free(conf->ca_cert);
index 43047729e82eafb8052e524b8a81927ecec52db7..5473be156ee7e283cb5c26437c239a33ad272283 100644 (file)
@@ -116,6 +116,12 @@ struct hostapd_eap_user {
        int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
 };
 
+struct hostapd_radius_attr {
+       u8 type;
+       struct wpabuf *val;
+       struct hostapd_radius_attr *next;
+};
+
 
 #define NUM_TX_QUEUES 4
 
@@ -178,6 +184,8 @@ struct hostapd_bss_config {
        struct hostapd_radius_servers *radius;
        int acct_interim_interval;
        int radius_request_cui;
+       struct hostapd_radius_attr *radius_auth_req_attr;
+       struct hostapd_radius_attr *radius_acct_req_attr;
 
        struct hostapd_ssid ssid;
 
@@ -455,5 +463,7 @@ const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
 const struct hostapd_eap_user *
 hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
                     size_t identity_len, int phase2);
+struct hostapd_radius_attr *
+hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
 
 #endif /* HOSTAPD_CONFIG_H */
index 9bb63f538b84320f2cddbcafe93f9191f130b8d4..dd0df1d38e480d57f122b76eb9d173a8221a27d1 100644 (file)
@@ -416,6 +416,7 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
        struct radius_msg *msg;
        char buf[128];
        struct eapol_state_machine *sm = sta->eapol_sm;
+       struct hostapd_radius_attr *attr;
 
        if (sm == NULL)
                return;
@@ -442,7 +443,9 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
                goto fail;
        }
 
-       if (hapd->conf->own_ip_addr.af == AF_INET &&
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+                                           RADIUS_ATTR_NAS_IP_ADDRESS) &&
+           hapd->conf->own_ip_addr.af == AF_INET &&
            !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
                                 (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
                printf("Could not add NAS-IP-Address\n");
@@ -450,7 +453,9 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
        }
 
 #ifdef CONFIG_IPV6
-       if (hapd->conf->own_ip_addr.af == AF_INET6 &&
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+                                           RADIUS_ATTR_NAS_IPV6_ADDRESS) &&
+           hapd->conf->own_ip_addr.af == AF_INET6 &&
            !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
                                 (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
                printf("Could not add NAS-IPv6-Address\n");
@@ -458,7 +463,9 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
        }
 #endif /* CONFIG_IPV6 */
 
-       if (hapd->conf->nas_identifier &&
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+                                           RADIUS_ATTR_NAS_IDENTIFIER) &&
+           hapd->conf->nas_identifier &&
            !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
                                 (u8 *) hapd->conf->nas_identifier,
                                 os_strlen(hapd->conf->nas_identifier))) {
@@ -466,7 +473,9 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
                goto fail;
        }
 
-       if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+                                           RADIUS_ATTR_NAS_PORT) &&
+           !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
                printf("Could not add NAS-Port\n");
                goto fail;
        }
@@ -474,7 +483,9 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
        os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
                    MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
        buf[sizeof(buf) - 1] = '\0';
-       if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+                                           RADIUS_ATTR_CALLED_STATION_ID) &&
+           !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
                                 (u8 *) buf, os_strlen(buf))) {
                printf("Could not add Called-Station-Id\n");
                goto fail;
@@ -492,12 +503,16 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
        /* TODO: should probably check MTU from driver config; 2304 is max for
         * IEEE 802.11, but use 1400 to avoid problems with too large packets
         */
-       if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+                                           RADIUS_ATTR_FRAMED_MTU) &&
+           !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
                printf("Could not add Framed-MTU\n");
                goto fail;
        }
 
-       if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+                                           RADIUS_ATTR_NAS_PORT_TYPE) &&
+           !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
                                       RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
                printf("Could not add NAS-Port-Type\n");
                goto fail;
@@ -513,7 +528,9 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
                            radius_mode_txt(hapd));
                buf[sizeof(buf) - 1] = '\0';
        }
-       if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
+       if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+                                           RADIUS_ATTR_CONNECT_INFO) &&
+           !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
                                 (u8 *) buf, os_strlen(buf))) {
                printf("Could not add Connect-Info\n");
                goto fail;
@@ -560,6 +577,17 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
                }
        }
 
+       for (attr = hapd->conf->radius_auth_req_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");
+                       goto fail;
+               }
+       }
+
        if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0)
                goto fail;