104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt/* 204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * RADIUS Dynamic Authorization Server (DAS) (RFC 5176) 304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * Copyright (c) 2012, 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 Shmidtextern int wpa_debug_level; 2004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 2104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 2204949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstruct radius_das_data { 2304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int sock; 2404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 *shared_secret; 2504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t shared_secret_len; 2604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct hostapd_ip_addr client_addr; 2704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt unsigned int time_window; 2804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int require_event_timestamp; 2904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt void *ctx; 3004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt enum radius_das_res (*disconnect)(void *ctx, 3104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_das_attrs *attr); 3204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}; 3304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 3404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 3504949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic struct radius_msg * radius_das_disconnect(struct radius_das_data *das, 3604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_msg *msg, 3704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt const char *abuf, 3804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int from_port) 3904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 4004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_hdr *hdr; 4104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_msg *reply; 4204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 allowed[] = { 4304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_ATTR_USER_NAME, 4404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_ATTR_CALLING_STATION_ID, 4504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_ATTR_ACCT_SESSION_ID, 4604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_ATTR_EVENT_TIMESTAMP, 4704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 4804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 4904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 0 5004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt }; 5104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int error = 405; 5204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 attr; 5304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt enum radius_das_res res; 5404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_das_attrs attrs; 5504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 *buf; 5604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt size_t len; 5704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt char tmp[100]; 5804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 sta_addr[ETH_ALEN]; 5904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 6004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hdr = radius_msg_get_hdr(msg); 6104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 6204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attr = radius_msg_find_unlisted_attr(msg, allowed); 6304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (attr) { 6404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_INFO, "DAS: Unsupported attribute %u in " 6504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "Disconnect-Request from %s:%d", attr, 6604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt abuf, from_port); 6704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt error = 401; 6804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto fail; 6904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 7004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 7104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(&attrs, 0, sizeof(attrs)); 7204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 7304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID, 7404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt &buf, &len, NULL) == 0) { 7504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (len >= sizeof(tmp)) 7604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len = sizeof(tmp) - 1; 7704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(tmp, buf, len); 7804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt tmp[len] = '\0'; 7904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (hwaddr_aton2(tmp, sta_addr) < 0) { 8004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_INFO, "DAS: Invalid Calling-Station-Id " 8104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "'%s' from %s:%d", tmp, abuf, from_port); 8204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt error = 407; 8304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto fail; 8404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 8504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.sta_addr = sta_addr; 8604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 8704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 8804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, 8904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt &buf, &len, NULL) == 0) { 9004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.user_name = buf; 9104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.user_name_len = len; 9204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 9304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 9404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_SESSION_ID, 9504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt &buf, &len, NULL) == 0) { 9604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.acct_session_id = buf; 9704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.acct_session_id_len = len; 9804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 9904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 10004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 10104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt &buf, &len, NULL) == 0) { 10204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.cui = buf; 10304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt attrs.cui_len = len; 10404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 10504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 10604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt res = das->disconnect(das->ctx, &attrs); 10704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt switch (res) { 10804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_DAS_NAS_MISMATCH: 10904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_INFO, "DAS: NAS mismatch from %s:%d", 11004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt abuf, from_port); 11104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt error = 403; 11204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 11304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_DAS_SESSION_NOT_FOUND: 11404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_INFO, "DAS: Session not found for request from " 11504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "%s:%d", abuf, from_port); 11604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt error = 503; 11704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 11804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_DAS_SUCCESS: 11904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt error = 0; 12004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 12104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 12204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 12304949598a23f501be6eec21697465fd46a28840aDmitry Shmidtfail: 12404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt reply = radius_msg_new(error ? RADIUS_CODE_DISCONNECT_NAK : 12504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_CODE_DISCONNECT_ACK, hdr->identifier); 12604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (reply == NULL) 12704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 12804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 12904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (error) { 13061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, 13161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt error)) { 13261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt radius_msg_free(reply); 13361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt return NULL; 13461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 13504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 13604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 13704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return reply; 13804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 13904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 14004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 14104949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx) 14204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 14304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_das_data *das = eloop_ctx; 14404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u8 buf[1500]; 14504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt union { 14604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct sockaddr_storage ss; 14704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct sockaddr_in sin; 14804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#ifdef CONFIG_IPV6 14904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct sockaddr_in6 sin6; 15004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#endif /* CONFIG_IPV6 */ 15104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } from; 15204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt char abuf[50]; 15304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int from_port = 0; 15404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt socklen_t fromlen; 15504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int len; 15604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_msg *msg, *reply = NULL; 15704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_hdr *hdr; 15804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct wpabuf *rbuf; 15904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u32 val; 16004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int res; 16104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct os_time now; 16204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 16304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt fromlen = sizeof(from); 16404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len = recvfrom(sock, buf, sizeof(buf), 0, 16504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (struct sockaddr *) &from.ss, &fromlen); 16604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (len < 0) { 16704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno)); 16804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 16904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 17004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 17104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf)); 17204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt from_port = ntohs(from.sin.sin_port); 17304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 17404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d", 17504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt len, abuf, from_port); 17604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) { 17704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client"); 17804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 17904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 18004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 18104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt msg = radius_msg_parse(buf, len); 18204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (msg == NULL) { 18304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet " 18404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "from %s:%d failed", abuf, from_port); 18504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 18604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 18704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 18804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (wpa_debug_level <= MSG_MSGDUMP) 18904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_msg_dump(msg); 19004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 19104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (radius_msg_verify_das_req(msg, das->shared_secret, 19204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->shared_secret_len)) { 19304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Invalid authenticator in packet " 19404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "from %s:%d - drop", abuf, from_port); 19504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto fail; 19604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 19704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 19804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_get_time(&now); 19904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt res = radius_msg_get_attr(msg, RADIUS_ATTR_EVENT_TIMESTAMP, 20004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (u8 *) &val, 4); 20104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (res == 4) { 20204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt u32 timestamp = ntohl(val); 20304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (abs(now.sec - timestamp) > das->time_window) { 20404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Unacceptable " 20504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "Event-Timestamp (%u; local time %u) in " 20604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "packet from %s:%d - drop", 20704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt timestamp, (unsigned int) now.sec, 20804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt abuf, from_port); 20904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto fail; 21004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 21104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } else if (das->require_event_timestamp) { 21204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Missing Event-Timestamp in packet " 21304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "from %s:%d - drop", abuf, from_port); 21404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt goto fail; 21504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 21604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 21704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hdr = radius_msg_get_hdr(msg); 21804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 21904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt switch (hdr->code) { 22004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_CODE_DISCONNECT_REQUEST: 22104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt reply = radius_das_disconnect(das, msg, abuf, from_port); 22204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 22304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt case RADIUS_CODE_COA_REQUEST: 22404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* TODO */ 22504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt reply = radius_msg_new(RADIUS_CODE_COA_NAK, 22604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hdr->identifier); 22704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (reply == NULL) 22804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 22904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 23004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt /* Unsupported Service */ 23161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, 23261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 405)) { 23361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt radius_msg_free(reply); 23461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt reply = NULL; 23561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt break; 23661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt } 23704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt break; 23804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt default: 23904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Unexpected RADIUS code %u in " 24004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "packet from %s:%d", 24104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt hdr->code, abuf, from_port); 24204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 24304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 24404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (reply) { 24504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Reply to %s:%d", abuf, from_port); 24604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 24704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (!radius_msg_add_attr_int32(reply, 24804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt RADIUS_ATTR_EVENT_TIMESTAMP, 24904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt now.sec)) { 25004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Failed to add " 25104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "Event-Timestamp attribute"); 25204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 25304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 25404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (radius_msg_finish_das_resp(reply, das->shared_secret, 25504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->shared_secret_len, hdr) < 25604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 0) { 25704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_DEBUG, "DAS: Failed to add " 25804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "Message-Authenticator attribute"); 25904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 26004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 26104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (wpa_debug_level <= MSG_MSGDUMP) 26204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_msg_dump(reply); 26304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 26404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt rbuf = radius_msg_get_buf(reply); 26504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt res = sendto(das->sock, wpabuf_head(rbuf), 26604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpabuf_len(rbuf), 0, 26704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt (struct sockaddr *) &from.ss, fromlen); 26804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (res < 0) { 26904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_ERROR, "DAS: sendto(to %s:%d): %s", 27004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt abuf, from_port, strerror(errno)); 27104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 27204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 27304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 27404949598a23f501be6eec21697465fd46a28840aDmitry Shmidtfail: 27504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_msg_free(msg); 27604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_msg_free(reply); 27704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 27804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 27904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 28004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic int radius_das_open_socket(int port) 28104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 28204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt int s; 28304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct sockaddr_in addr; 28404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 28504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt s = socket(PF_INET, SOCK_DGRAM, 0); 28604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (s < 0) { 28704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt perror("socket"); 28804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return -1; 28904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 29004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 29104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memset(&addr, 0, sizeof(addr)); 29204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr.sin_family = AF_INET; 29304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt addr.sin_port = htons(port); 29404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 29504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt perror("bind"); 29604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt close(s); 29704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return -1; 29804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 29904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 30004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return s; 30104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 30204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 30304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 30404949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstruct radius_das_data * 30504949598a23f501be6eec21697465fd46a28840aDmitry Shmidtradius_das_init(struct radius_das_conf *conf) 30604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 30704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt struct radius_das_data *das; 30804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 30904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (conf->port == 0 || conf->shared_secret == NULL || 31004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt conf->client_addr == NULL) 31104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 31204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 31304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das = os_zalloc(sizeof(*das)); 31404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (das == NULL) 31504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 31604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 31704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->time_window = conf->time_window; 31804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->require_event_timestamp = conf->require_event_timestamp; 31904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->ctx = conf->ctx; 32004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->disconnect = conf->disconnect; 32104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 32204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(&das->client_addr, conf->client_addr, 32304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt sizeof(das->client_addr)); 32404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 32504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->shared_secret = os_malloc(conf->shared_secret_len); 32604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (das->shared_secret == NULL) { 32704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_das_deinit(das); 32804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 32904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 33004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_memcpy(das->shared_secret, conf->shared_secret, 33104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt conf->shared_secret_len); 33204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->shared_secret_len = conf->shared_secret_len; 33304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 33404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt das->sock = radius_das_open_socket(conf->port); 33504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (das->sock < 0) { 33604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS " 33704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt "DAS"); 33804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_das_deinit(das); 33904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 34004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 34104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 34204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (eloop_register_read_sock(das->sock, radius_das_receive, das, NULL)) 34304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt { 34404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt radius_das_deinit(das); 34504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 34604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 34704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 34804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return das; 34904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 35004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 35104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 35204949598a23f501be6eec21697465fd46a28840aDmitry Shmidtvoid radius_das_deinit(struct radius_das_data *das) 35304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{ 35404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (das == NULL) 35504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return; 35604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 35704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (das->sock >= 0) { 35804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt eloop_unregister_read_sock(das->sock); 35904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt close(das->sock); 36004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 36104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 36204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_free(das->shared_secret); 36304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt os_free(das); 36404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt} 365