104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt/* 204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * RADIUS Dynamic Authorization Server (DAS) (RFC 5176) 3cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt * Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi> 404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * 504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * This software may be distributed under the terms of the BSD license. 604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * See README for more details. 704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt */ 804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "includes.h" 1004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include <net/if.h> 1104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 1204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "utils/common.h" 1304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "utils/eloop.h" 1404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "utils/ip_addr.h" 1504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "radius.h" 1604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "radius_das.h" 1704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 1804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 1904949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstruct radius_das_data { 2004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int sock; 2104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 *shared_secret; 2204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t shared_secret_len; 2304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct hostapd_ip_addr client_addr; 2404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt unsigned int time_window; 2504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int require_event_timestamp; 2604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt void *ctx; 2704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt enum radius_das_res (*disconnect)(void *ctx, 2804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_das_attrs *attr); 2904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}; 3004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 3104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 3204949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic struct radius_msg * radius_das_disconnect(struct radius_das_data *das, 3304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_msg *msg, 3404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const char *abuf, 3504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int from_port) 3604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 3704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_hdr *hdr; 3804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_msg *reply; 3904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 allowed[] = { 4004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_ATTR_USER_NAME, 4113ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt RADIUS_ATTR_NAS_IP_ADDRESS, 4204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_ATTR_CALLING_STATION_ID, 4313ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt RADIUS_ATTR_NAS_IDENTIFIER, 4404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_ATTR_ACCT_SESSION_ID, 45432d603c922e970f55866c63212d29c997438977Dmitry Shmidt RADIUS_ATTR_ACCT_MULTI_SESSION_ID, 4604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_ATTR_EVENT_TIMESTAMP, 4704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 4804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 4913ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt#ifdef CONFIG_IPV6 5013ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt RADIUS_ATTR_NAS_IPV6_ADDRESS, 5113ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt#endif /* CONFIG_IPV6 */ 5204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 0 5304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt }; 5404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int error = 405; 5504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 attr; 5604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt enum radius_das_res res; 5704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_das_attrs attrs; 5804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 *buf; 5904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t len; 6004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt char tmp[100]; 6104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 sta_addr[ETH_ALEN]; 6204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 6304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hdr = radius_msg_get_hdr(msg); 6404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 6504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attr = radius_msg_find_unlisted_attr(msg, allowed); 6604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (attr) { 6704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_INFO, "DAS: Unsupported attribute %u in " 6804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "Disconnect-Request from %s:%d", attr, 6904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt abuf, from_port); 7004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt error = 401; 7104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto fail; 7204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 7304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 7404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(&attrs, 0, sizeof(attrs)); 7504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 7613ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, 7713ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt &buf, &len, NULL) == 0) { 7813ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt if (len != 4) { 7913ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt wpa_printf(MSG_INFO, "DAS: Invalid NAS-IP-Address from %s:%d", 8013ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt abuf, from_port); 8113ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt error = 407; 8213ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt goto fail; 8313ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt } 8413ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt attrs.nas_ip_addr = buf; 8513ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt } 8613ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt 8713ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt#ifdef CONFIG_IPV6 8813ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, 8913ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt &buf, &len, NULL) == 0) { 9013ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt if (len != 16) { 9113ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt wpa_printf(MSG_INFO, "DAS: Invalid NAS-IPv6-Address from %s:%d", 9213ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt abuf, from_port); 9313ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt error = 407; 9413ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt goto fail; 9513ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt } 9613ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt attrs.nas_ipv6_addr = buf; 9713ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt } 9813ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt#endif /* CONFIG_IPV6 */ 9913ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt 10013ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IDENTIFIER, 10113ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt &buf, &len, NULL) == 0) { 10213ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt attrs.nas_identifier = buf; 10313ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt attrs.nas_identifier_len = len; 10413ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt } 10513ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt 10604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID, 10704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt &buf, &len, NULL) == 0) { 10804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (len >= sizeof(tmp)) 10904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len = sizeof(tmp) - 1; 11004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(tmp, buf, len); 11104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tmp[len] = '\0'; 11204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (hwaddr_aton2(tmp, sta_addr) < 0) { 11304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_INFO, "DAS: Invalid Calling-Station-Id " 11404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "'%s' from %s:%d", tmp, abuf, from_port); 11504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt error = 407; 11604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto fail; 11704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 11804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.sta_addr = sta_addr; 11904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 12004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 12104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, 12204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt &buf, &len, NULL) == 0) { 12304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.user_name = buf; 12404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.user_name_len = len; 12504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 12604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 12704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_SESSION_ID, 12804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt &buf, &len, NULL) == 0) { 12904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.acct_session_id = buf; 13004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.acct_session_id_len = len; 13104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 13204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 133432d603c922e970f55866c63212d29c997438977Dmitry Shmidt if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID, 134432d603c922e970f55866c63212d29c997438977Dmitry Shmidt &buf, &len, NULL) == 0) { 135432d603c922e970f55866c63212d29c997438977Dmitry Shmidt attrs.acct_multi_session_id = buf; 136432d603c922e970f55866c63212d29c997438977Dmitry Shmidt attrs.acct_multi_session_id_len = len; 137432d603c922e970f55866c63212d29c997438977Dmitry Shmidt } 138432d603c922e970f55866c63212d29c997438977Dmitry Shmidt 13904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 14004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt &buf, &len, NULL) == 0) { 14104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.cui = buf; 14204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.cui_len = len; 14304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 14404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 14504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt res = das->disconnect(das->ctx, &attrs); 14604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt switch (res) { 14704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_DAS_NAS_MISMATCH: 14804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_INFO, "DAS: NAS mismatch from %s:%d", 14904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt abuf, from_port); 15004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt error = 403; 15104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 15204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_DAS_SESSION_NOT_FOUND: 15304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_INFO, "DAS: Session not found for request from " 15404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "%s:%d", abuf, from_port); 15504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt error = 503; 15604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 157432d603c922e970f55866c63212d29c997438977Dmitry Shmidt case RADIUS_DAS_MULTI_SESSION_MATCH: 158432d603c922e970f55866c63212d29c997438977Dmitry Shmidt wpa_printf(MSG_INFO, 159432d603c922e970f55866c63212d29c997438977Dmitry Shmidt "DAS: Multiple sessions match for request from %s:%d", 160432d603c922e970f55866c63212d29c997438977Dmitry Shmidt abuf, from_port); 161432d603c922e970f55866c63212d29c997438977Dmitry Shmidt error = 508; 162432d603c922e970f55866c63212d29c997438977Dmitry Shmidt break; 16304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_DAS_SUCCESS: 16404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt error = 0; 16504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 16604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 16704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 16804949598a23f501be6eec21697465fd46a28840aDmitry Shmidtfail: 16904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt reply = radius_msg_new(error ? RADIUS_CODE_DISCONNECT_NAK : 17004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_CODE_DISCONNECT_ACK, hdr->identifier); 17104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (reply == NULL) 17204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 17304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 17404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (error) { 17561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, 17661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt error)) { 17761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt radius_msg_free(reply); 17861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return NULL; 17961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 18004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 18104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 18204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return reply; 18304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 18404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 18504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 18604949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx) 18704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 18804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_das_data *das = eloop_ctx; 18904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 buf[1500]; 19004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt union { 19104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct sockaddr_storage ss; 19204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct sockaddr_in sin; 19304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#ifdef CONFIG_IPV6 19404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct sockaddr_in6 sin6; 19504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#endif /* CONFIG_IPV6 */ 19604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } from; 19704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt char abuf[50]; 19804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int from_port = 0; 19904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt socklen_t fromlen; 20004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int len; 20104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_msg *msg, *reply = NULL; 20204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_hdr *hdr; 20304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpabuf *rbuf; 20404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u32 val; 20504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int res; 20604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct os_time now; 20704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 20804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt fromlen = sizeof(from); 20904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len = recvfrom(sock, buf, sizeof(buf), 0, 21004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (struct sockaddr *) &from.ss, &fromlen); 21104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (len < 0) { 21204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno)); 21304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 21404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 21504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 21604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf)); 21704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt from_port = ntohs(from.sin.sin_port); 21804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 21904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d", 22004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len, abuf, from_port); 22104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) { 22204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client"); 22304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 22404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 22504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 22604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt msg = radius_msg_parse(buf, len); 22704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (msg == NULL) { 22804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet " 22904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "from %s:%d failed", abuf, from_port); 23004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 23104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 23204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 23304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (wpa_debug_level <= MSG_MSGDUMP) 23404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_msg_dump(msg); 23504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 23604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (radius_msg_verify_das_req(msg, das->shared_secret, 23704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->shared_secret_len)) { 23804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Invalid authenticator in packet " 23904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "from %s:%d - drop", abuf, from_port); 24004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto fail; 24104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 24204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 24304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_get_time(&now); 24404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt res = radius_msg_get_attr(msg, RADIUS_ATTR_EVENT_TIMESTAMP, 24504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (u8 *) &val, 4); 24604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (res == 4) { 24704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u32 timestamp = ntohl(val); 2485460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt if ((unsigned int) abs(now.sec - timestamp) > 2495460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt das->time_window) { 25004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Unacceptable " 25104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "Event-Timestamp (%u; local time %u) in " 25204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "packet from %s:%d - drop", 25304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt timestamp, (unsigned int) now.sec, 25404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt abuf, from_port); 25504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto fail; 25604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 25704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } else if (das->require_event_timestamp) { 25804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Missing Event-Timestamp in packet " 25904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "from %s:%d - drop", abuf, from_port); 26004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto fail; 26104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 26204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 26304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hdr = radius_msg_get_hdr(msg); 26404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 26504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt switch (hdr->code) { 26604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_CODE_DISCONNECT_REQUEST: 26704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt reply = radius_das_disconnect(das, msg, abuf, from_port); 26804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 26904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_CODE_COA_REQUEST: 27004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* TODO */ 27104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt reply = radius_msg_new(RADIUS_CODE_COA_NAK, 27204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hdr->identifier); 27304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (reply == NULL) 27404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 27504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 27604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* Unsupported Service */ 27761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, 27861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 405)) { 27961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt radius_msg_free(reply); 28061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt reply = NULL; 28161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 28261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 28304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 28404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt default: 28504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Unexpected RADIUS code %u in " 28604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "packet from %s:%d", 28704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hdr->code, abuf, from_port); 28804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 28904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 29004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (reply) { 29104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Reply to %s:%d", abuf, from_port); 29204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 29304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!radius_msg_add_attr_int32(reply, 29404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_ATTR_EVENT_TIMESTAMP, 29504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt now.sec)) { 29604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Failed to add " 29704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "Event-Timestamp attribute"); 29804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 29904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 30004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (radius_msg_finish_das_resp(reply, das->shared_secret, 30104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->shared_secret_len, hdr) < 30204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 0) { 30304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Failed to add " 30404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "Message-Authenticator attribute"); 30504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 30604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 30704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (wpa_debug_level <= MSG_MSGDUMP) 30804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_msg_dump(reply); 30904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 31004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt rbuf = radius_msg_get_buf(reply); 31104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt res = sendto(das->sock, wpabuf_head(rbuf), 31204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_len(rbuf), 0, 31304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (struct sockaddr *) &from.ss, fromlen); 31404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (res < 0) { 31504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_ERROR, "DAS: sendto(to %s:%d): %s", 31604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt abuf, from_port, strerror(errno)); 31704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 31804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 31904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 32004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtfail: 32104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_msg_free(msg); 32204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_msg_free(reply); 32304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 32404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 32504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 32604949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic int radius_das_open_socket(int port) 32704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 32804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int s; 32904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct sockaddr_in addr; 33004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 33104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt s = socket(PF_INET, SOCK_DGRAM, 0); 33204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (s < 0) { 333cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_printf(MSG_INFO, "RADIUS DAS: socket: %s", strerror(errno)); 33404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return -1; 33504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 33604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 33704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(&addr, 0, sizeof(addr)); 33804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr.sin_family = AF_INET; 33904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr.sin_port = htons(port); 34004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 341cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_printf(MSG_INFO, "RADIUS DAS: bind: %s", strerror(errno)); 34204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt close(s); 34304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return -1; 34404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 34504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 34604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return s; 34704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 34804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 34904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 35004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstruct radius_das_data * 35104949598a23f501be6eec21697465fd46a28840aDmitry Shmidtradius_das_init(struct radius_das_conf *conf) 35204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 35304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_das_data *das; 35404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 35504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (conf->port == 0 || conf->shared_secret == NULL || 35604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt conf->client_addr == NULL) 35704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 35804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 35904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das = os_zalloc(sizeof(*das)); 36004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (das == NULL) 36104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 36204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 36304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->time_window = conf->time_window; 36404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->require_event_timestamp = conf->require_event_timestamp; 36504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->ctx = conf->ctx; 36604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->disconnect = conf->disconnect; 36704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 36804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(&das->client_addr, conf->client_addr, 36904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sizeof(das->client_addr)); 37004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 37104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->shared_secret = os_malloc(conf->shared_secret_len); 37204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (das->shared_secret == NULL) { 37304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_das_deinit(das); 37404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 37504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 37604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(das->shared_secret, conf->shared_secret, 37704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt conf->shared_secret_len); 37804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->shared_secret_len = conf->shared_secret_len; 37904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 38004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->sock = radius_das_open_socket(conf->port); 38104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (das->sock < 0) { 38204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS " 38304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "DAS"); 38404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_das_deinit(das); 38504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 38604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 38704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 38804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (eloop_register_read_sock(das->sock, radius_das_receive, das, NULL)) 38904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt { 39004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_das_deinit(das); 39104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 39204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 39304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 39404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return das; 39504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 39604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 39704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 39804949598a23f501be6eec21697465fd46a28840aDmitry Shmidtvoid radius_das_deinit(struct radius_das_data *das) 39904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 40004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (das == NULL) 40104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 40204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 40304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (das->sock >= 0) { 40404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt eloop_unregister_read_sock(das->sock); 40504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt close(das->sock); 40604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 40704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 40804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_free(das->shared_secret); 40904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_free(das); 41004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 411