diff options
| author | Dmitry Shmidt <dimitrysh@google.com> | 2014-02-18 10:33:49 -0800 |
|---|---|---|
| committer | Dmitry Shmidt <dimitrysh@google.com> | 2014-02-18 10:33:49 -0800 |
| commit | bd14a57187b024f49f5b9ace55ef457d8d04650a (patch) | |
| tree | c9ae1052918a2718d01efc764a9f3577d3e96079 /src/radius | |
| parent | 96be6222df414a7dde5c5b1b72df22e67b1a77fc (diff) | |
| download | android_external_wpa_supplicant_8-bd14a57187b024f49f5b9ace55ef457d8d04650a.tar.gz android_external_wpa_supplicant_8-bd14a57187b024f49f5b9ace55ef457d8d04650a.tar.bz2 android_external_wpa_supplicant_8-bd14a57187b024f49f5b9ace55ef457d8d04650a.zip | |
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>
Diffstat (limited to 'src/radius')
| -rw-r--r-- | src/radius/radius.c | 102 | ||||
| -rw-r--r-- | src/radius/radius.h | 5 | ||||
| -rw-r--r-- | src/radius/radius_server.c | 208 | ||||
| -rw-r--r-- | src/radius/radius_server.h | 5 |
4 files changed, 271 insertions, 49 deletions
diff --git a/src/radius/radius.c b/src/radius/radius.c index 494f92d1..1070fc70 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 struct radius_attr_type *radius_get_attr_type(u8 type) } -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 @@ static void radius_msg_dump_attr(struct radius_attr_hdr *hdr) 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 @@ void radius_msg_dump(struct radius_msg *msg) { 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 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, 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(struct radius_msg *msg, const u8 *secret, } +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 *radius_msg_add_attr(struct radius_msg *msg, u8 type, 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 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret, 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 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret, } 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 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret, } 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 @@ int radius_msg_verify(struct radius_msg *msg, const u8 *secret, 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 @@ int radius_msg_verify(struct radius_msg *msg, const u8 *secret, 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 @@ static u8 * decrypt_ms_key(const u8 *key, size_t len, 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 @@ static u8 * decrypt_ms_key(const u8 *key, size_t len, } 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 2031054b..ad65b04b 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 @@ int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret, 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 1063d65a..2904b2f7 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 @@ struct radius_server_counters { 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 @@ struct radius_server_data { 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 @@ fail: } +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 @@ radius_server_init(struct radius_server_conf *conf) 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 @@ void radius_server_deinit(struct radius_server_data *data) 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 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf, "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 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf, 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 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf, "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 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf, 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 284bd59d..78f5fc23 100644 --- a/src/radius/radius_server.h +++ b/src/radius/radius_server.h @@ -22,6 +22,11 @@ struct radius_server_conf { 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 |
