Cumulative patch from commit b3253ebb73d6d52ac636c5cc6d958955a5a98fca
b3253eb wpa_supplicant: Complete radio works on disable event
38ecb06 Convert RADIUS debug dumps to use wpa_printf()
a0ac572 EAP-SIM DB: Remove client socket file on connect() error
a1dd890 RADIUS: Add minimal accounting server support
22dd2d7 Fix MSCHAP UTF-8 to UCS-2 conversion for three-byte encoding
9aab811 Fix nt_password_hash build
a9b08ad Remove unused crypto_bignum_rshift()
2dff9e8 Remove unused NFC_RX_HANDOVER_REQ
be24917 nl80211: Use nl80211_set_iface_id() to get hw features data
8a45811 hostapd: Add Operating Mode Notification support
d9dd86b Enable IEEE 802.11w in defconfig
Change-Id: I6bf13cd0b7e3cb3c3550b87a77a035340e9d0a6b
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/radius/radius.c b/src/radius/radius.c
index 494f92d..1070fc7 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -1,6 +1,6 @@
/*
* RADIUS message processing
- * Copyright (c) 2002-2009, 2011-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2011-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -249,25 +249,17 @@
}
-static void print_char(char c)
-{
- if (c >= 32 && c < 127)
- printf("%c", c);
- else
- printf("<%02x>", c);
-}
-
-
static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
{
struct radius_attr_type *attr;
- int i, len;
+ int len;
unsigned char *pos;
+ char buf[1000];
attr = radius_get_attr_type(hdr->type);
- printf(" Attribute %d (%s) length=%d\n",
- hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
+ wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d",
+ hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr))
return;
@@ -277,47 +269,50 @@
switch (attr->data_type) {
case RADIUS_ATTR_TEXT:
- printf(" Value: '");
- for (i = 0; i < len; i++)
- print_char(pos[i]);
- printf("'\n");
+ printf_encode(buf, sizeof(buf), pos, len);
+ wpa_printf(MSG_INFO, " Value: '%s'", buf);
break;
case RADIUS_ATTR_IP:
if (len == 4) {
struct in_addr addr;
os_memcpy(&addr, pos, 4);
- printf(" Value: %s\n", inet_ntoa(addr));
- } else
- printf(" Invalid IP address length %d\n", len);
+ wpa_printf(MSG_INFO, " Value: %s",
+ inet_ntoa(addr));
+ } else {
+ wpa_printf(MSG_INFO, " Invalid IP address length %d",
+ len);
+ }
break;
#ifdef CONFIG_IPV6
case RADIUS_ATTR_IPV6:
if (len == 16) {
- char buf[128];
const char *atxt;
struct in6_addr *addr = (struct in6_addr *) pos;
atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf));
- printf(" Value: %s\n", atxt ? atxt : "?");
- } else
- printf(" Invalid IPv6 address length %d\n", len);
+ wpa_printf(MSG_INFO, " Value: %s",
+ atxt ? atxt : "?");
+ } else {
+ wpa_printf(MSG_INFO, " Invalid IPv6 address length %d",
+ len);
+ }
break;
#endif /* CONFIG_IPV6 */
case RADIUS_ATTR_HEXDUMP:
case RADIUS_ATTR_UNDIST:
- printf(" Value:");
- for (i = 0; i < len; i++)
- printf(" %02x", pos[i]);
- printf("\n");
+ wpa_snprintf_hex(buf, sizeof(buf), pos, len);
+ wpa_printf(MSG_INFO, " Value: %s", buf);
break;
case RADIUS_ATTR_INT32:
if (len == 4)
- printf(" Value: %u\n", WPA_GET_BE32(pos));
+ wpa_printf(MSG_INFO, " Value: %u",
+ WPA_GET_BE32(pos));
else
- printf(" Invalid INT32 length %d\n", len);
+ wpa_printf(MSG_INFO, " Invalid INT32 length %d",
+ len);
break;
default:
@@ -330,9 +325,9 @@
{
size_t i;
- printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n",
- msg->hdr->code, radius_code_string(msg->hdr->code),
- msg->hdr->identifier, be_to_host16(msg->hdr->length));
+ wpa_printf(MSG_INFO, "RADIUS message: code=%d (%s) identifier=%d length=%d",
+ msg->hdr->code, radius_code_string(msg->hdr->code),
+ msg->hdr->identifier, be_to_host16(msg->hdr->length));
for (i = 0; i < msg->attr_used; i++) {
struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
@@ -384,7 +379,7 @@
attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
auth, MD5_MAC_LEN);
if (attr == NULL) {
- printf("WARNING: Could not add Message-Authenticator\n");
+ wpa_printf(MSG_ERROR, "WARNING: Could not add Message-Authenticator");
return -1;
}
msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
@@ -473,6 +468,27 @@
}
+void radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len, const u8 *req_authenticator)
+{
+ const u8 *addr[2];
+ size_t len[2];
+
+ msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
+ os_memcpy(msg->hdr->authenticator, req_authenticator, MD5_MAC_LEN);
+ addr[0] = wpabuf_head(msg->buf);
+ len[0] = wpabuf_len(msg->buf);
+ addr[1] = secret;
+ len[1] = secret_len;
+ md5_vector(2, addr, len, msg->hdr->authenticator);
+
+ if (wpabuf_len(msg->buf) > 0xffff) {
+ wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
+ (unsigned long) wpabuf_len(msg->buf));
+ }
+}
+
+
int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
size_t secret_len)
{
@@ -585,7 +601,7 @@
struct radius_attr_hdr *attr;
if (data_len > RADIUS_MAX_ATTR_LEN) {
- printf("radius_msg_add_attr: too long attribute (%lu bytes)\n",
+ wpa_printf(MSG_ERROR, "radius_msg_add_attr: too long attribute (%lu bytes)",
(unsigned long) data_len);
return NULL;
}
@@ -756,8 +772,7 @@
tmp = radius_get_attr_hdr(msg, i);
if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
if (attr != NULL) {
- printf("Multiple Message-Authenticator "
- "attributes in RADIUS message\n");
+ wpa_printf(MSG_INFO, "Multiple Message-Authenticator attributes in RADIUS message");
return 1;
}
attr = tmp;
@@ -765,7 +780,7 @@
}
if (attr == NULL) {
- printf("No Message-Authenticator attribute found\n");
+ wpa_printf(MSG_INFO, "No Message-Authenticator attribute found");
return 1;
}
@@ -786,7 +801,7 @@
}
if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) {
- printf("Invalid Message-Authenticator!\n");
+ wpa_printf(MSG_INFO, "Invalid Message-Authenticator!");
return 1;
}
@@ -802,7 +817,7 @@
u8 hash[MD5_MAC_LEN];
if (sent_msg == NULL) {
- printf("No matching Access-Request message found\n");
+ wpa_printf(MSG_INFO, "No matching Access-Request message found");
return 1;
}
@@ -823,7 +838,7 @@
len[3] = secret_len;
md5_vector(4, addr, len, hash);
if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
- printf("Response Authenticator invalid!\n");
+ wpa_printf(MSG_INFO, "Response Authenticator invalid!");
return 1;
}
@@ -962,7 +977,8 @@
pos = key + 2;
left = len - 2;
if (left % 16) {
- printf("Invalid ms key len %lu\n", (unsigned long) left);
+ wpa_printf(MSG_INFO, "Invalid ms key len %lu",
+ (unsigned long) left);
return NULL;
}
@@ -996,7 +1012,7 @@
}
if (plain[0] == 0 || plain[0] > plen - 1) {
- printf("Failed to decrypt MPPE key\n");
+ wpa_printf(MSG_INFO, "Failed to decrypt MPPE key");
os_free(plain);
return NULL;
}
diff --git a/src/radius/radius.h b/src/radius/radius.h
index 2031054..ad65b04 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -1,6 +1,6 @@
/*
* RADIUS message processing
- * Copyright (c) 2002-2009, 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012, 2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -204,6 +204,9 @@
const struct radius_hdr *req_hdr);
void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
size_t secret_len);
+void radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len,
+ const u8 *req_authenticator);
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,
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 1063d65..2904b2f 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -1,6 +1,6 @@
/*
* RADIUS authentication server
- * Copyright (c) 2005-2009, 2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2009, 2011-2014, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -49,6 +49,13 @@
u32 bad_authenticators;
u32 packets_dropped;
u32 unknown_types;
+
+ u32 acct_requests;
+ u32 invalid_acct_requests;
+ u32 acct_responses;
+ u32 malformed_acct_requests;
+ u32 acct_bad_authenticators;
+ u32 unknown_acct_types;
};
/**
@@ -99,6 +106,11 @@
int auth_sock;
/**
+ * acct_sock - Socket for RADIUS accounting messages
+ */
+ int acct_sock;
+
+ /**
* clients - List of authorized RADIUS clients
*/
struct radius_client *clients;
@@ -979,6 +991,140 @@
}
+static void radius_server_receive_acct(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct radius_server_data *data = eloop_ctx;
+ u8 *buf = NULL;
+ union {
+ struct sockaddr_storage ss;
+ struct sockaddr_in sin;
+#ifdef CONFIG_IPV6
+ struct sockaddr_in6 sin6;
+#endif /* CONFIG_IPV6 */
+ } from;
+ socklen_t fromlen;
+ int len, res;
+ struct radius_client *client = NULL;
+ struct radius_msg *msg = NULL, *resp = NULL;
+ char abuf[50];
+ int from_port = 0;
+ struct radius_hdr *hdr;
+ struct wpabuf *rbuf;
+
+ buf = os_malloc(RADIUS_MAX_MSG_LEN);
+ if (buf == NULL) {
+ goto fail;
+ }
+
+ fromlen = sizeof(from);
+ len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
+ (struct sockaddr *) &from.ss, &fromlen);
+ if (len < 0) {
+ wpa_printf(MSG_INFO, "recvfrom[radius_server]: %s",
+ strerror(errno));
+ goto fail;
+ }
+
+#ifdef CONFIG_IPV6
+ if (data->ipv6) {
+ if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf,
+ sizeof(abuf)) == NULL)
+ abuf[0] = '\0';
+ from_port = ntohs(from.sin6.sin6_port);
+ RADIUS_DEBUG("Received %d bytes from %s:%d",
+ len, abuf, from_port);
+
+ client = radius_server_get_client(data,
+ (struct in_addr *)
+ &from.sin6.sin6_addr, 1);
+ }
+#endif /* CONFIG_IPV6 */
+
+ if (!data->ipv6) {
+ os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
+ from_port = ntohs(from.sin.sin_port);
+ RADIUS_DEBUG("Received %d bytes from %s:%d",
+ len, abuf, from_port);
+
+ client = radius_server_get_client(data, &from.sin.sin_addr, 0);
+ }
+
+ RADIUS_DUMP("Received data", buf, len);
+
+ if (client == NULL) {
+ RADIUS_DEBUG("Unknown client %s - packet ignored", abuf);
+ data->counters.invalid_acct_requests++;
+ goto fail;
+ }
+
+ msg = radius_msg_parse(buf, len);
+ if (msg == NULL) {
+ RADIUS_DEBUG("Parsing incoming RADIUS frame failed");
+ data->counters.malformed_acct_requests++;
+ client->counters.malformed_acct_requests++;
+ goto fail;
+ }
+
+ os_free(buf);
+ buf = NULL;
+
+ if (wpa_debug_level <= MSG_MSGDUMP) {
+ radius_msg_dump(msg);
+ }
+
+ if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_REQUEST) {
+ RADIUS_DEBUG("Unexpected RADIUS code %d",
+ radius_msg_get_hdr(msg)->code);
+ data->counters.unknown_acct_types++;
+ client->counters.unknown_acct_types++;
+ goto fail;
+ }
+
+ data->counters.acct_requests++;
+ client->counters.acct_requests++;
+
+ if (radius_msg_verify_acct_req(msg, (u8 *) client->shared_secret,
+ client->shared_secret_len)) {
+ RADIUS_DEBUG("Invalid Authenticator from %s", abuf);
+ data->counters.acct_bad_authenticators++;
+ client->counters.acct_bad_authenticators++;
+ goto fail;
+ }
+
+ /* TODO: Write accounting information to a file or database */
+
+ hdr = radius_msg_get_hdr(msg);
+
+ resp = radius_msg_new(RADIUS_CODE_ACCOUNTING_RESPONSE, hdr->identifier);
+ if (resp == NULL)
+ goto fail;
+
+ radius_msg_finish_acct_resp(resp, (u8 *) client->shared_secret,
+ client->shared_secret_len,
+ hdr->authenticator);
+
+ RADIUS_DEBUG("Reply to %s:%d", abuf, from_port);
+ if (wpa_debug_level <= MSG_MSGDUMP) {
+ radius_msg_dump(resp);
+ }
+ rbuf = radius_msg_get_buf(resp);
+ data->counters.acct_responses++;
+ client->counters.acct_responses++;
+ res = sendto(data->acct_sock, wpabuf_head(rbuf), wpabuf_len(rbuf), 0,
+ (struct sockaddr *) &from.ss, fromlen);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "sendto[RADIUS SRV]: %s",
+ strerror(errno));
+ }
+
+fail:
+ radius_msg_free(resp);
+ radius_msg_free(msg);
+ os_free(buf);
+}
+
+
static int radius_server_disable_pmtu_discovery(int s)
{
int r = -1;
@@ -1329,6 +1475,29 @@
return NULL;
}
+ if (conf->acct_port) {
+#ifdef CONFIG_IPV6
+ if (conf->ipv6)
+ data->acct_sock = radius_server_open_socket6(
+ conf->acct_port);
+ else
+#endif /* CONFIG_IPV6 */
+ data->acct_sock = radius_server_open_socket(conf->acct_port);
+ if (data->acct_sock < 0) {
+ wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS accounting server");
+ radius_server_deinit(data);
+ return NULL;
+ }
+ if (eloop_register_read_sock(data->acct_sock,
+ radius_server_receive_acct,
+ data, NULL)) {
+ radius_server_deinit(data);
+ return NULL;
+ }
+ } else {
+ data->acct_sock = -1;
+ }
+
return data;
}
@@ -1347,6 +1516,11 @@
close(data->auth_sock);
}
+ if (data->acct_sock >= 0) {
+ eloop_unregister_read_sock(data->acct_sock);
+ close(data->acct_sock);
+ }
+
radius_server_free_clients(data, data->clients);
os_free(data->pac_opaque_encr_key);
@@ -1410,7 +1584,13 @@
"radiusAuthServTotalMalformedAccessRequests=%u\n"
"radiusAuthServTotalBadAuthenticators=%u\n"
"radiusAuthServTotalPacketsDropped=%u\n"
- "radiusAuthServTotalUnknownTypes=%u\n",
+ "radiusAuthServTotalUnknownTypes=%u\n"
+ "radiusAccServTotalRequests=%u\n"
+ "radiusAccServTotalInvalidRequests=%u\n"
+ "radiusAccServTotalResponses=%u\n"
+ "radiusAccServTotalMalformedRequests=%u\n"
+ "radiusAccServTotalBadAuthenticators=%u\n"
+ "radiusAccServTotalUnknownTypes=%u\n",
data->counters.access_requests,
data->counters.invalid_requests,
data->counters.dup_access_requests,
@@ -1420,7 +1600,13 @@
data->counters.malformed_access_requests,
data->counters.bad_authenticators,
data->counters.packets_dropped,
- data->counters.unknown_types);
+ data->counters.unknown_types,
+ data->counters.acct_requests,
+ data->counters.invalid_acct_requests,
+ data->counters.acct_responses,
+ data->counters.malformed_acct_requests,
+ data->counters.acct_bad_authenticators,
+ data->counters.unknown_acct_types);
if (ret < 0 || ret >= end - pos) {
*pos = '\0';
return pos - buf;
@@ -1455,7 +1641,13 @@
"radiusAuthServMalformedAccessRequests=%u\n"
"radiusAuthServBadAuthenticators=%u\n"
"radiusAuthServPacketsDropped=%u\n"
- "radiusAuthServUnknownTypes=%u\n",
+ "radiusAuthServUnknownTypes=%u\n"
+ "radiusAccServTotalRequests=%u\n"
+ "radiusAccServTotalInvalidRequests=%u\n"
+ "radiusAccServTotalResponses=%u\n"
+ "radiusAccServTotalMalformedRequests=%u\n"
+ "radiusAccServTotalBadAuthenticators=%u\n"
+ "radiusAccServTotalUnknownTypes=%u\n",
idx,
abuf, mbuf,
cli->counters.access_requests,
@@ -1466,7 +1658,13 @@
cli->counters.malformed_access_requests,
cli->counters.bad_authenticators,
cli->counters.packets_dropped,
- cli->counters.unknown_types);
+ cli->counters.unknown_types,
+ cli->counters.acct_requests,
+ cli->counters.invalid_acct_requests,
+ cli->counters.acct_responses,
+ cli->counters.malformed_acct_requests,
+ cli->counters.acct_bad_authenticators,
+ cli->counters.unknown_acct_types);
if (ret < 0 || ret >= end - pos) {
*pos = '\0';
return pos - buf;
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index 284bd59..78f5fc2 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -22,6 +22,11 @@
int auth_port;
/**
+ * acct_port - UDP port to listen to as an accounting server
+ */
+ int acct_port;
+
+ /**
* client_file - RADIUS client configuration file
*
* This file contains the RADIUS clients and the shared secret to be