summaryrefslogtreecommitdiff
path: root/src/radius
diff options
context:
space:
mode:
Diffstat (limited to 'src/radius')
-rw-r--r--src/radius/radius.c124
-rw-r--r--src/radius/radius.h19
-rw-r--r--src/radius/radius_client.c150
-rw-r--r--src/radius/radius_client.h3
-rw-r--r--src/radius/radius_das.c11
-rw-r--r--src/radius/radius_das.h1
6 files changed, 219 insertions, 89 deletions
diff --git a/src/radius/radius.c b/src/radius/radius.c
index 1ebfd11f3b9a2..407e4f8b96149 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -1,6 +1,6 @@
/*
* RADIUS message processing
- * Copyright (c) 2002-2009, 2011-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2011-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -173,6 +173,8 @@ static const struct radius_attr_type radius_attrs[] =
{ RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST },
{ RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP },
{ RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_SERVICE_TYPE, "Service-Type", RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_FRAMED_IP_ADDRESS, "Framed-IP-Address", RADIUS_ATTR_IP },
{ RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 },
{ RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT },
{ RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST },
@@ -214,6 +216,7 @@ static const struct radius_attr_type radius_attrs[] =
RADIUS_ATTR_INT32 },
{ RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp",
RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_EGRESS_VLANID, "EGRESS-VLANID", RADIUS_ATTR_HEXDUMP },
{ RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 },
{ RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
{ RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
@@ -535,7 +538,8 @@ int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
- size_t secret_len)
+ size_t secret_len,
+ int require_message_authenticator)
{
const u8 *addr[4];
size_t len[4];
@@ -574,7 +578,11 @@ int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
}
if (attr == NULL) {
- /* Message-Authenticator is MAY; not required */
+ if (require_message_authenticator) {
+ wpa_printf(MSG_WARNING,
+ "Missing Message-Authenticator attribute in RADIUS message");
+ return 1;
+ }
return 0;
}
@@ -703,7 +711,7 @@ struct radius_msg * radius_msg_parse(const u8 *data, size_t len)
attr = (struct radius_attr_hdr *) pos;
- if (pos + attr->length > end || attr->length < sizeof(*attr))
+ if (attr->length > end - pos || attr->length < sizeof(*attr))
goto fail;
/* TODO: check that attr->length is suitable for attr->type */
@@ -815,8 +823,9 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
os_memcpy(msg->hdr->authenticator, req_auth,
sizeof(msg->hdr->authenticator));
}
- hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
- wpabuf_len(msg->buf), auth);
+ if (hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+ wpabuf_len(msg->buf), auth) < 0)
+ return 1;
os_memcpy(attr + 1, orig, MD5_MAC_LEN);
if (req_auth) {
os_memcpy(msg->hdr->authenticator, orig_authenticator,
@@ -859,8 +868,8 @@ int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
addr[3] = secret;
len[3] = secret_len;
- md5_vector(4, addr, len, hash);
- if (os_memcmp_const(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
+ if (md5_vector(4, addr, len, hash) < 0 ||
+ os_memcmp_const(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
wpa_printf(MSG_INFO, "Response Authenticator invalid!");
return 1;
}
@@ -892,25 +901,11 @@ int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
/* Create Request Authenticator. The value should be unique over the lifetime
* of the shared secret between authenticator and authentication server.
- * Use one-way MD5 hash calculated from current timestamp and some data given
- * by the caller. */
-void radius_msg_make_authenticator(struct radius_msg *msg,
- const u8 *data, size_t len)
+ */
+int radius_msg_make_authenticator(struct radius_msg *msg)
{
- struct os_time tv;
- long int l;
- const u8 *addr[3];
- size_t elen[3];
-
- os_get_time(&tv);
- l = os_random();
- addr[0] = (u8 *) &tv;
- elen[0] = sizeof(tv);
- addr[1] = data;
- elen[1] = len;
- addr[2] = (u8 *) &l;
- elen[2] = sizeof(l);
- md5_vector(3, addr, elen, msg->hdr->authenticator);
+ return os_get_random((u8 *) &msg->hdr->authenticator,
+ sizeof(msg->hdr->authenticator));
}
@@ -1028,7 +1023,10 @@ static u8 * decrypt_ms_key(const u8 *key, size_t len,
addr[1] = pos - MD5_MAC_LEN;
elen[1] = MD5_MAC_LEN;
}
- md5_vector(first ? 3 : 2, addr, elen, hash);
+ if (md5_vector(first ? 3 : 2, addr, elen, hash) < 0) {
+ os_free(plain);
+ return NULL;
+ }
first = 0;
for (i = 0; i < MD5_MAC_LEN; i++)
@@ -1210,7 +1208,11 @@ int radius_msg_add_mppe_keys(struct radius_msg *msg,
vhdr = (struct radius_attr_vendor *) pos;
vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY;
pos = (u8 *) (vhdr + 1);
- salt = os_random() | 0x8000;
+ if (os_get_random((u8 *) &salt, sizeof(salt)) < 0) {
+ os_free(buf);
+ return 0;
+ }
+ salt |= 0x8000;
WPA_PUT_BE16(pos, salt);
pos += 2;
encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret,
@@ -1422,12 +1424,30 @@ struct radius_tunnel_attrs {
};
+static int cmp_int(const void *a, const void *b)
+{
+ int x, y;
+
+ x = *((int *) a);
+ y = *((int *) b);
+ return (x - y);
+}
+
+
/**
* radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
+ * The k tagged vlans found are sorted by vlan_id and stored in the first k
+ * items of tagged.
+ *
* @msg: RADIUS message
- * Returns: VLAN ID for the first tunnel configuration or 0 if none is found
+ * @untagged: Pointer to store untagged vid
+ * @numtagged: Size of tagged
+ * @tagged: Pointer to store tagged list
+ *
+ * Returns: 0 if neither tagged nor untagged configuration is found, 1 otherwise
*/
-int radius_msg_get_vlanid(struct radius_msg *msg)
+int radius_msg_get_vlanid(struct radius_msg *msg, int *untagged, int numtagged,
+ int *tagged)
{
struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun;
size_t i;
@@ -1435,8 +1455,12 @@ int radius_msg_get_vlanid(struct radius_msg *msg)
const u8 *data;
char buf[10];
size_t dlen;
+ int j, taggedidx = 0, vlan_id;
os_memset(&tunnel, 0, sizeof(tunnel));
+ for (j = 0; j < numtagged; j++)
+ tagged[j] = 0;
+ *untagged = 0;
for (i = 0; i < msg->attr_used; i++) {
attr = radius_get_attr_hdr(msg, i);
@@ -1473,21 +1497,44 @@ int radius_msg_get_vlanid(struct radius_msg *msg)
break;
os_memcpy(buf, data, dlen);
buf[dlen] = '\0';
+ vlan_id = atoi(buf);
+ if (vlan_id <= 0)
+ break;
tun->tag_used++;
- tun->vlanid = atoi(buf);
+ tun->vlanid = vlan_id;
+ break;
+ case RADIUS_ATTR_EGRESS_VLANID: /* RFC 4675 */
+ if (attr->length != 6)
+ break;
+ vlan_id = WPA_GET_BE24(data + 1);
+ if (vlan_id <= 0)
+ break;
+ if (data[0] == 0x32)
+ *untagged = vlan_id;
+ else if (data[0] == 0x31 && tagged &&
+ taggedidx < numtagged)
+ tagged[taggedidx++] = vlan_id;
break;
}
}
+ /* Use tunnel with the lowest tag for untagged VLAN id */
for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) {
tun = &tunnel[i];
if (tun->tag_used &&
tun->type == RADIUS_TUNNEL_TYPE_VLAN &&
tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 &&
- tun->vlanid > 0)
- return tun->vlanid;
+ tun->vlanid > 0) {
+ *untagged = tun->vlanid;
+ break;
+ }
}
+ if (taggedidx)
+ qsort(tagged, taggedidx, sizeof(int), cmp_int);
+
+ if (*untagged > 0 || taggedidx)
+ return 1;
return 0;
}
@@ -1669,3 +1716,14 @@ u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs)
return 0;
}
+
+
+int radius_gen_session_id(u8 *id, size_t len)
+{
+ /*
+ * Acct-Session-Id and Acct-Multi-Session-Id should be globally and
+ * temporarily unique. A high quality random number is required
+ * therefore. This could be be improved by switching to a GUID.
+ */
+ return os_get_random(id, len);
+}
diff --git a/src/radius/radius.h b/src/radius/radius.h
index 5977339e08d2b..cd510d2c88e22 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -1,6 +1,6 @@
/*
* RADIUS message processing
- * Copyright (c) 2002-2009, 2012, 2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012, 2014-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -52,6 +52,8 @@ enum { RADIUS_ATTR_USER_NAME = 1,
RADIUS_ATTR_USER_PASSWORD = 2,
RADIUS_ATTR_NAS_IP_ADDRESS = 4,
RADIUS_ATTR_NAS_PORT = 5,
+ RADIUS_ATTR_SERVICE_TYPE = 6,
+ RADIUS_ATTR_FRAMED_IP_ADDRESS = 8,
RADIUS_ATTR_FRAMED_MTU = 12,
RADIUS_ATTR_REPLY_MESSAGE = 18,
RADIUS_ATTR_STATE = 24,
@@ -79,6 +81,7 @@ enum { RADIUS_ATTR_USER_NAME = 1,
RADIUS_ATTR_ACCT_INPUT_GIGAWORDS = 52,
RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS = 53,
RADIUS_ATTR_EVENT_TIMESTAMP = 55,
+ RADIUS_ATTR_EGRESS_VLANID = 56,
RADIUS_ATTR_NAS_PORT_TYPE = 61,
RADIUS_ATTR_TUNNEL_TYPE = 64,
RADIUS_ATTR_TUNNEL_MEDIUM_TYPE = 65,
@@ -108,6 +111,9 @@ enum { RADIUS_ATTR_USER_NAME = 1,
};
+/* Service-Type values (RFC 2865, 5.6) */
+#define RADIUS_SERVICE_TYPE_FRAMED 2
+
/* Termination-Action */
#define RADIUS_TERMINATION_ACTION_DEFAULT 0
#define RADIUS_TERMINATION_ACTION_RADIUS_REQUEST 1
@@ -236,7 +242,8 @@ void radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret,
int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
size_t secret_len);
int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
- size_t secret_len);
+ size_t secret_len,
+ int require_message_authenticator);
struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u8 type,
const u8 *data, size_t data_len);
struct radius_msg * radius_msg_parse(const u8 *data, size_t len);
@@ -250,8 +257,7 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
size_t secret_len, const u8 *req_auth);
int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
u8 type);
-void radius_msg_make_authenticator(struct radius_msg *msg,
- const u8 *data, size_t len);
+int radius_msg_make_authenticator(struct radius_msg *msg);
struct radius_ms_mppe_keys *
radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
const u8 *secret, size_t secret_len);
@@ -274,7 +280,8 @@ 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_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len);
-int radius_msg_get_vlanid(struct radius_msg *msg);
+int radius_msg_get_vlanid(struct radius_msg *msg, int *untagged, int numtagged,
+ int *tagged);
char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
const u8 *secret, size_t secret_len,
struct radius_msg *sent_msg, size_t n);
@@ -319,4 +326,6 @@ int radius_copy_class(struct radius_class_data *dst,
u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs);
+int radius_gen_session_id(u8 *id, size_t len);
+
#endif /* RADIUS_H */
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 693f61ea04552..06c804d132fd5 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -226,6 +226,16 @@ struct radius_client_data {
* next_radius_identifier - Next RADIUS message identifier to use
*/
u8 next_radius_identifier;
+
+ /**
+ * interim_error_cb - Interim accounting error callback
+ */
+ void (*interim_error_cb)(const u8 *addr, void *ctx);
+
+ /**
+ * interim_error_cb_ctx - interim_error_cb() context data
+ */
+ void *interim_error_cb_ctx;
};
@@ -297,6 +307,25 @@ int radius_client_register(struct radius_client_data *radius,
}
+/**
+ * radius_client_set_interim_erro_cb - Register an interim acct error callback
+ * @radius: RADIUS client context from radius_client_init()
+ * @addr: Station address from the failed message
+ * @cb: Handler for interim accounting errors
+ * @ctx: Context pointer for handler callbacks
+ *
+ * This function is used to register a handler for processing failed
+ * transmission attempts of interim accounting update messages.
+ */
+void radius_client_set_interim_error_cb(struct radius_client_data *radius,
+ void (*cb)(const u8 *addr, void *ctx),
+ void *ctx)
+{
+ radius->interim_error_cb = cb;
+ radius->interim_error_cb_ctx = ctx;
+}
+
+
/*
* Returns >0 if message queue was flushed (i.e., the message that triggered
* the error is not available anymore)
@@ -308,7 +337,7 @@ static int radius_client_handle_send_error(struct radius_client_data *radius,
int _errno = errno;
wpa_printf(MSG_INFO, "send[RADIUS,s=%d]: %s", s, strerror(errno));
if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
- _errno == EBADF || _errno == ENETUNREACH) {
+ _errno == EBADF || _errno == ENETUNREACH || _errno == EACCES) {
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"Send failed - maybe interface status changed -"
@@ -336,6 +365,8 @@ static int radius_client_retransmit(struct radius_client_data *radius,
int s;
struct wpabuf *buf;
size_t prev_num_msgs;
+ u8 *acct_delay_time;
+ size_t acct_delay_time_len;
if (entry->msg_type == RADIUS_ACCT ||
entry->msg_type == RADIUS_ACCT_INTERIM) {
@@ -371,12 +402,52 @@ static int radius_client_retransmit(struct radius_client_data *radius,
conf->auth_server->retransmissions++;
}
}
+
+ if (entry->msg_type == RADIUS_ACCT_INTERIM) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: Failed to transmit interim accounting update to "
+ MACSTR " - drop message and request a new update",
+ MAC2STR(entry->addr));
+ if (radius->interim_error_cb)
+ radius->interim_error_cb(entry->addr,
+ radius->interim_error_cb_ctx);
+ return 1;
+ }
+
if (s < 0) {
wpa_printf(MSG_INFO,
"RADIUS: No valid socket for retransmission");
return 1;
}
+ if (entry->msg_type == RADIUS_ACCT &&
+ radius_msg_get_attr_ptr(entry->msg, RADIUS_ATTR_ACCT_DELAY_TIME,
+ &acct_delay_time, &acct_delay_time_len,
+ NULL) == 0 &&
+ acct_delay_time_len == 4) {
+ struct radius_hdr *hdr;
+ u32 delay_time;
+
+ /*
+ * Need to assign a new identifier since attribute contents
+ * changes.
+ */
+ hdr = radius_msg_get_hdr(entry->msg);
+ hdr->identifier = radius_client_get_id(radius);
+
+ /* Update Acct-Delay-Time to show wait time in queue */
+ delay_time = now - entry->first_try;
+ WPA_PUT_BE32(acct_delay_time, delay_time);
+
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: Updated Acct-Delay-Time to %u for retransmission",
+ delay_time);
+ radius_msg_finish_acct(entry->msg, entry->shared_secret,
+ entry->shared_secret_len);
+ if (radius->conf->msg_dumps)
+ radius_msg_dump(entry->msg);
+ }
+
/* retransmit; remove entry if too many attempts */
entry->attempts++;
hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
@@ -407,7 +478,6 @@ static int radius_client_retransmit(struct radius_client_data *radius,
static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
{
struct radius_client_data *radius = eloop_ctx;
- struct hostapd_radius_servers *conf = radius->conf;
struct os_reltime now;
os_time_t first;
struct radius_msg_list *entry, *prev, *tmp;
@@ -476,10 +546,10 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
(long int) (first - now.sec));
}
- if (auth_failover && conf->num_auth_servers > 1)
+ if (auth_failover)
radius_client_auth_failover(radius);
- if (acct_failover && conf->num_acct_servers > 1)
+ if (acct_failover)
radius_client_acct_failover(radius);
}
@@ -625,39 +695,6 @@ static void radius_client_list_add(struct radius_client_data *radius,
}
-static void radius_client_list_del(struct radius_client_data *radius,
- RadiusType msg_type, const u8 *addr)
-{
- struct radius_msg_list *entry, *prev, *tmp;
-
- if (addr == NULL)
- return;
-
- entry = radius->msgs;
- prev = NULL;
- while (entry) {
- if (entry->msg_type == msg_type &&
- os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
- if (prev)
- prev->next = entry->next;
- else
- radius->msgs = entry->next;
- tmp = entry;
- entry = entry->next;
- hostapd_logger(radius->ctx, addr,
- HOSTAPD_MODULE_RADIUS,
- HOSTAPD_LEVEL_DEBUG,
- "Removing matching RADIUS message");
- radius_client_msg_free(tmp);
- radius->num_msgs--;
- continue;
- }
- prev = entry;
- entry = entry->next;
- }
-}
-
-
/**
* radius_client_send - Send a RADIUS request
* @radius: RADIUS client context from radius_client_init()
@@ -669,16 +706,19 @@ static void radius_client_list_del(struct radius_client_data *radius,
* This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or
* accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference
* between accounting and interim accounting messages is that the interim
- * message will override any pending interim accounting updates while a new
- * accounting message does not remove any pending messages.
+ * message will not be retransmitted. Instead, a callback is used to indicate
+ * that the transmission failed for the specific station @addr so that a new
+ * interim accounting update message can be generated with up-to-date session
+ * data instead of trying to resend old information.
*
* The message is added on the retransmission queue and will be retransmitted
* automatically until a response is received or maximum number of retries
- * (RADIUS_CLIENT_MAX_RETRIES) is reached.
+ * (RADIUS_CLIENT_MAX_RETRIES) is reached. No such retries are used with
+ * RADIUS_ACCT_INTERIM, i.e., such a pending message is removed from the queue
+ * automatically on transmission failure.
*
* The related device MAC address can be used to identify pending messages that
- * can be removed with radius_client_flush_auth() or with interim accounting
- * updates.
+ * can be removed with radius_client_flush_auth().
*/
int radius_client_send(struct radius_client_data *radius,
struct radius_msg *msg, RadiusType msg_type,
@@ -691,11 +731,6 @@ int radius_client_send(struct radius_client_data *radius,
int s, res;
struct wpabuf *buf;
- if (msg_type == RADIUS_ACCT_INTERIM) {
- /* Remove any pending interim acct update for the same STA. */
- radius_client_list_del(radius, msg_type, addr);
- }
-
if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
if (conf->acct_server && radius->acct_sock < 0)
radius_client_init_acct(radius);
@@ -1015,6 +1050,9 @@ radius_change_server(struct radius_client_data *radius,
int sel_sock;
struct radius_msg_list *entry;
struct hostapd_radius_servers *conf = radius->conf;
+ struct sockaddr_in disconnect_addr = {
+ .sin_family = AF_UNSPEC,
+ };
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
@@ -1023,6 +1061,12 @@ radius_change_server(struct radius_client_data *radius,
hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
nserv->port);
+ if (oserv && oserv == nserv) {
+ /* Reconnect to same server, flush */
+ if (auth)
+ radius_client_flush(radius, 1);
+ }
+
if (oserv && oserv != nserv &&
(nserv->shared_secret_len != oserv->shared_secret_len ||
os_memcmp(nserv->shared_secret, oserv->shared_secret,
@@ -1125,6 +1169,11 @@ radius_change_server(struct radius_client_data *radius,
}
}
+ /* Force a reconnect by disconnecting the socket first */
+ if (connect(sel_sock, (struct sockaddr *) &disconnect_addr,
+ sizeof(disconnect_addr)) < 0)
+ wpa_printf(MSG_INFO, "disconnect[radius]: %s", strerror(errno));
+
if (connect(sel_sock, addr, addrlen) < 0) {
wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno));
return -1;
@@ -1587,11 +1636,16 @@ static int radius_client_dump_acct_server(char *buf, size_t buflen,
int radius_client_get_mib(struct radius_client_data *radius, char *buf,
size_t buflen)
{
- struct hostapd_radius_servers *conf = radius->conf;
+ struct hostapd_radius_servers *conf;
int i;
struct hostapd_radius_server *serv;
int count = 0;
+ if (!radius)
+ return 0;
+
+ conf = radius->conf;
+
if (conf->auth_servers) {
for (i = 0; i < conf->num_auth_servers; i++) {
serv = &conf->auth_servers[i];
diff --git a/src/radius/radius_client.h b/src/radius/radius_client.h
index 3db16aa282ba7..8ca0874db498a 100644
--- a/src/radius/radius_client.h
+++ b/src/radius/radius_client.h
@@ -241,6 +241,9 @@ int radius_client_register(struct radius_client_data *radius,
const u8 *shared_secret, size_t shared_secret_len,
void *data),
void *data);
+void radius_client_set_interim_error_cb(struct radius_client_data *radius,
+ void (*cb)(const u8 *addr, void *ctx),
+ void *ctx);
int radius_client_send(struct radius_client_data *radius,
struct radius_msg *msg,
RadiusType msg_type, const u8 *addr);
diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c
index b7d991bbd0979..8a3d7e0324bc2 100644
--- a/src/radius/radius_das.c
+++ b/src/radius/radius_das.c
@@ -23,6 +23,7 @@ struct radius_das_data {
struct hostapd_ip_addr client_addr;
unsigned int time_window;
int require_event_timestamp;
+ int require_message_authenticator;
void *ctx;
enum radius_das_res (*disconnect)(void *ctx,
struct radius_das_attrs *attr);
@@ -234,9 +235,11 @@ static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
radius_msg_dump(msg);
if (radius_msg_verify_das_req(msg, das->shared_secret,
- das->shared_secret_len)) {
- wpa_printf(MSG_DEBUG, "DAS: Invalid authenticator in packet "
- "from %s:%d - drop", abuf, from_port);
+ das->shared_secret_len,
+ das->require_message_authenticator)) {
+ wpa_printf(MSG_DEBUG,
+ "DAS: Invalid authenticator or Message-Authenticator in packet from %s:%d - drop",
+ abuf, from_port);
goto fail;
}
@@ -362,6 +365,8 @@ radius_das_init(struct radius_das_conf *conf)
das->time_window = conf->time_window;
das->require_event_timestamp = conf->require_event_timestamp;
+ das->require_message_authenticator =
+ conf->require_message_authenticator;
das->ctx = conf->ctx;
das->disconnect = conf->disconnect;
diff --git a/src/radius/radius_das.h b/src/radius/radius_das.h
index ce731d46a9ace..9863fdc1eaca0 100644
--- a/src/radius/radius_das.h
+++ b/src/radius/radius_das.h
@@ -44,6 +44,7 @@ struct radius_das_conf {
const struct hostapd_ip_addr *client_addr;
unsigned int time_window;
int require_event_timestamp;
+ int require_message_authenticator;
void *ctx;
enum radius_das_res (*disconnect)(void *ctx,
struct radius_das_attrs *attr);