diff --git a/hostapd/config_file.c b/hostapd/config_file.c index c8a628862..5c8824c54 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -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); diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index e38a7aa02..8890cd27c 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -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: 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=[:] +# 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=[:] +# Examples: +# Operator-Name = "Operator" +#radius_acct_req_attr=126:s:Operator ##### RADIUS authentication server configuration ############################## diff --git a/src/ap/accounting.c b/src/ap/accounting.c index 82443a1f3..2c3a6d9f4 100644 --- a/src/ap/accounting.c +++ b/src/ap/accounting.c @@ -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: diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 303448b21..392b4fd40 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -1,6 +1,6 @@ /* * hostapd / Configuration helper functions - * Copyright (c) 2003-2009, Jouni Malinen + * Copyright (c) 2003-2012, Jouni Malinen * * 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); diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 43047729e..5473be156 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -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 */ diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index 9bb63f538..dd0df1d38 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -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;