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, 4504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_ATTR_EVENT_TIMESTAMP, 4604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 4704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 4813ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt#ifdef CONFIG_IPV6 4913ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt RADIUS_ATTR_NAS_IPV6_ADDRESS, 5013ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt#endif /* CONFIG_IPV6 */ 5104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 0 5204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt }; 5304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int error = 405; 5404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 attr; 5504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt enum radius_das_res res; 5604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_das_attrs attrs; 5704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 *buf; 5804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t len; 5904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt char tmp[100]; 6004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 sta_addr[ETH_ALEN]; 6104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 6204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hdr = radius_msg_get_hdr(msg); 6304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 6404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attr = radius_msg_find_unlisted_attr(msg, allowed); 6504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (attr) { 6604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_INFO, "DAS: Unsupported attribute %u in " 6704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "Disconnect-Request from %s:%d", attr, 6804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt abuf, from_port); 6904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt error = 401; 7004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto fail; 7104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 7204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 7304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(&attrs, 0, sizeof(attrs)); 7404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 7513ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, 7613ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt &buf, &len, NULL) == 0) { 7713ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt if (len != 4) { 7813ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt wpa_printf(MSG_INFO, "DAS: Invalid NAS-IP-Address from %s:%d", 7913ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt abuf, from_port); 8013ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt error = 407; 8113ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt goto fail; 8213ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt } 8313ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt attrs.nas_ip_addr = buf; 8413ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt } 8513ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt 8613ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt#ifdef CONFIG_IPV6 8713ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, 8813ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt &buf, &len, NULL) == 0) { 8913ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt if (len != 16) { 9013ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt wpa_printf(MSG_INFO, "DAS: Invalid NAS-IPv6-Address from %s:%d", 9113ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt abuf, from_port); 9213ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt error = 407; 9313ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt goto fail; 9413ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt } 9513ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt attrs.nas_ipv6_addr = buf; 9613ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt } 9713ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt#endif /* CONFIG_IPV6 */ 9813ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt 9913ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IDENTIFIER, 10013ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt &buf, &len, NULL) == 0) { 10113ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt attrs.nas_identifier = buf; 10213ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt attrs.nas_identifier_len = len; 10313ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt } 10413ca8d8ea51a1aa5e24c6c956473a11b0c7daed4Dmitry Shmidt 10504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID, 10604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt &buf, &len, NULL) == 0) { 10704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (len >= sizeof(tmp)) 10804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len = sizeof(tmp) - 1; 10904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(tmp, buf, len); 11004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tmp[len] = '\0'; 11104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (hwaddr_aton2(tmp, sta_addr) < 0) { 11204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_INFO, "DAS: Invalid Calling-Station-Id " 11304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "'%s' from %s:%d", tmp, abuf, from_port); 11404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt error = 407; 11504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto fail; 11604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 11704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.sta_addr = sta_addr; 11804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 11904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 12004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, 12104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt &buf, &len, NULL) == 0) { 12204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.user_name = buf; 12304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.user_name_len = len; 12404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 12504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 12604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_SESSION_ID, 12704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt &buf, &len, NULL) == 0) { 12804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.acct_session_id = buf; 12904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.acct_session_id_len = len; 13004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 13104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 13204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 13304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt &buf, &len, NULL) == 0) { 13404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.cui = buf; 13504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.cui_len = len; 13604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 13704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 13804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt res = das->disconnect(das->ctx, &attrs); 13904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt switch (res) { 14004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_DAS_NAS_MISMATCH: 14104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_INFO, "DAS: NAS mismatch from %s:%d", 14204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt abuf, from_port); 14304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt error = 403; 14404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 14504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_DAS_SESSION_NOT_FOUND: 14604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_INFO, "DAS: Session not found for request from " 14704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "%s:%d", abuf, from_port); 14804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt error = 503; 14904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 15004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_DAS_SUCCESS: 15104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt error = 0; 15204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 15304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 15404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 15504949598a23f501be6eec21697465fd46a28840aDmitry Shmidtfail: 15604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt reply = radius_msg_new(error ? RADIUS_CODE_DISCONNECT_NAK : 15704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_CODE_DISCONNECT_ACK, hdr->identifier); 15804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (reply == NULL) 15904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 16004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 16104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (error) { 16261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, 16361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt error)) { 16461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt radius_msg_free(reply); 16561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return NULL; 16661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 16704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 16804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 16904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return reply; 17004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 17104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 17204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 17304949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx) 17404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 17504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_das_data *das = eloop_ctx; 17604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 buf[1500]; 17704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt union { 17804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct sockaddr_storage ss; 17904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct sockaddr_in sin; 18004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#ifdef CONFIG_IPV6 18104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct sockaddr_in6 sin6; 18204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#endif /* CONFIG_IPV6 */ 18304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } from; 18404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt char abuf[50]; 18504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int from_port = 0; 18604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt socklen_t fromlen; 18704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int len; 18804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_msg *msg, *reply = NULL; 18904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_hdr *hdr; 19004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpabuf *rbuf; 19104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u32 val; 19204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int res; 19304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct os_time now; 19404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 19504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt fromlen = sizeof(from); 19604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len = recvfrom(sock, buf, sizeof(buf), 0, 19704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (struct sockaddr *) &from.ss, &fromlen); 19804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (len < 0) { 19904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno)); 20004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 20104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 20204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 20304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf)); 20404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt from_port = ntohs(from.sin.sin_port); 20504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 20604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d", 20704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len, abuf, from_port); 20804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) { 20904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client"); 21004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 21104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 21204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 21304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt msg = radius_msg_parse(buf, len); 21404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (msg == NULL) { 21504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet " 21604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "from %s:%d failed", abuf, from_port); 21704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 21804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 21904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 22004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (wpa_debug_level <= MSG_MSGDUMP) 22104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_msg_dump(msg); 22204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 22304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (radius_msg_verify_das_req(msg, das->shared_secret, 22404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->shared_secret_len)) { 22504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Invalid authenticator in packet " 22604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "from %s:%d - drop", abuf, from_port); 22704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto fail; 22804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 22904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 23004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_get_time(&now); 23104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt res = radius_msg_get_attr(msg, RADIUS_ATTR_EVENT_TIMESTAMP, 23204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (u8 *) &val, 4); 23304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (res == 4) { 23404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u32 timestamp = ntohl(val); 2355460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt if ((unsigned int) abs(now.sec - timestamp) > 2365460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt das->time_window) { 23704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Unacceptable " 23804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "Event-Timestamp (%u; local time %u) in " 23904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "packet from %s:%d - drop", 24004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt timestamp, (unsigned int) now.sec, 24104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt abuf, from_port); 24204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto fail; 24304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 24404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } else if (das->require_event_timestamp) { 24504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Missing Event-Timestamp in packet " 24604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "from %s:%d - drop", abuf, from_port); 24704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto fail; 24804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 24904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 25004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hdr = radius_msg_get_hdr(msg); 25104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 25204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt switch (hdr->code) { 25304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_CODE_DISCONNECT_REQUEST: 25404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt reply = radius_das_disconnect(das, msg, abuf, from_port); 25504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 25604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_CODE_COA_REQUEST: 25704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* TODO */ 25804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt reply = radius_msg_new(RADIUS_CODE_COA_NAK, 25904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hdr->identifier); 26004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (reply == NULL) 26104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 26204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 26304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* Unsupported Service */ 26461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, 26561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 405)) { 26661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt radius_msg_free(reply); 26761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt reply = NULL; 26861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 26961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 27004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 27104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt default: 27204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Unexpected RADIUS code %u in " 27304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "packet from %s:%d", 27404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hdr->code, abuf, from_port); 27504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 27604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 27704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (reply) { 27804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Reply to %s:%d", abuf, from_port); 27904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 28004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!radius_msg_add_attr_int32(reply, 28104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_ATTR_EVENT_TIMESTAMP, 28204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt now.sec)) { 28304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Failed to add " 28404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "Event-Timestamp attribute"); 28504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 28604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 28704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (radius_msg_finish_das_resp(reply, das->shared_secret, 28804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->shared_secret_len, hdr) < 28904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 0) { 29004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Failed to add " 29104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "Message-Authenticator attribute"); 29204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 29304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 29404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (wpa_debug_level <= MSG_MSGDUMP) 29504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_msg_dump(reply); 29604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 29704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt rbuf = radius_msg_get_buf(reply); 29804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt res = sendto(das->sock, wpabuf_head(rbuf), 29904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_len(rbuf), 0, 30004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (struct sockaddr *) &from.ss, fromlen); 30104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (res < 0) { 30204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_ERROR, "DAS: sendto(to %s:%d): %s", 30304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt abuf, from_port, strerror(errno)); 30404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 30504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 30604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 30704949598a23f501be6eec21697465fd46a28840aDmitry Shmidtfail: 30804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_msg_free(msg); 30904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_msg_free(reply); 31004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 31104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 31204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 31304949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic int radius_das_open_socket(int port) 31404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 31504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int s; 31604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct sockaddr_in addr; 31704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 31804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt s = socket(PF_INET, SOCK_DGRAM, 0); 31904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (s < 0) { 320cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_printf(MSG_INFO, "RADIUS DAS: socket: %s", strerror(errno)); 32104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return -1; 32204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 32304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 32404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(&addr, 0, sizeof(addr)); 32504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr.sin_family = AF_INET; 32604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr.sin_port = htons(port); 32704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 328cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt wpa_printf(MSG_INFO, "RADIUS DAS: bind: %s", strerror(errno)); 32904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt close(s); 33004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return -1; 33104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 33204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 33304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return s; 33404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 33504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 33604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 33704949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstruct radius_das_data * 33804949598a23f501be6eec21697465fd46a28840aDmitry Shmidtradius_das_init(struct radius_das_conf *conf) 33904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 34004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_das_data *das; 34104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 34204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (conf->port == 0 || conf->shared_secret == NULL || 34304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt conf->client_addr == NULL) 34404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 34504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 34604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das = os_zalloc(sizeof(*das)); 34704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (das == NULL) 34804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 34904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 35004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->time_window = conf->time_window; 35104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->require_event_timestamp = conf->require_event_timestamp; 35204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->ctx = conf->ctx; 35304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->disconnect = conf->disconnect; 35404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 35504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(&das->client_addr, conf->client_addr, 35604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sizeof(das->client_addr)); 35704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 35804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->shared_secret = os_malloc(conf->shared_secret_len); 35904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (das->shared_secret == NULL) { 36004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_das_deinit(das); 36104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 36204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 36304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(das->shared_secret, conf->shared_secret, 36404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt conf->shared_secret_len); 36504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->shared_secret_len = conf->shared_secret_len; 36604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 36704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->sock = radius_das_open_socket(conf->port); 36804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (das->sock < 0) { 36904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS " 37004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "DAS"); 37104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_das_deinit(das); 37204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 37304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 37404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 37504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (eloop_register_read_sock(das->sock, radius_das_receive, das, NULL)) 37604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt { 37704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_das_deinit(das); 37804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 37904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 38004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 38104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return das; 38204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 38304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 38404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 38504949598a23f501be6eec21697465fd46a28840aDmitry Shmidtvoid radius_das_deinit(struct radius_das_data *das) 38604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 38704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (das == NULL) 38804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 38904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 39004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (das->sock >= 0) { 39104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt eloop_unregister_read_sock(das->sock); 39204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt close(das->sock); 39304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 39404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 39504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_free(das->shared_secret); 39604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_free(das); 39704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 398