2 * RADIUS Dynamic Authorization Server (DAS) (RFC 5176)
3 * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
12 #include "utils/common.h"
13 #include "utils/eloop.h"
14 #include "utils/ip_addr.h"
16 #include "radius_das.h"
19 extern int wpa_debug_level
;
22 struct radius_das_data
{
25 size_t shared_secret_len
;
26 struct hostapd_ip_addr client_addr
;
27 unsigned int time_window
;
28 int require_event_timestamp
;
32 static void radius_das_receive(int sock
, void *eloop_ctx
, void *sock_ctx
)
34 struct radius_das_data
*das
= eloop_ctx
;
37 struct sockaddr_storage ss
;
38 struct sockaddr_in sin
;
40 struct sockaddr_in6 sin6
;
41 #endif /* CONFIG_IPV6 */
47 struct radius_msg
*msg
, *reply
= NULL
;
48 struct radius_hdr
*hdr
;
53 fromlen
= sizeof(from
);
54 len
= recvfrom(sock
, buf
, sizeof(buf
), 0,
55 (struct sockaddr
*) &from
.ss
, &fromlen
);
57 wpa_printf(MSG_ERROR
, "DAS: recvfrom: %s", strerror(errno
));
61 os_strlcpy(abuf
, inet_ntoa(from
.sin
.sin_addr
), sizeof(abuf
));
62 from_port
= ntohs(from
.sin
.sin_port
);
64 wpa_printf(MSG_DEBUG
, "DAS: Received %d bytes from %s:%d",
65 len
, abuf
, from_port
);
66 if (das
->client_addr
.u
.v4
.s_addr
!= from
.sin
.sin_addr
.s_addr
) {
67 wpa_printf(MSG_DEBUG
, "DAS: Drop message from unknown client");
71 msg
= radius_msg_parse(buf
, len
);
73 wpa_printf(MSG_DEBUG
, "DAS: Parsing incoming RADIUS packet "
74 "from %s:%d failed", abuf
, from_port
);
78 if (wpa_debug_level
<= MSG_MSGDUMP
)
81 if (radius_msg_verify_das_req(msg
, das
->shared_secret
,
82 das
->shared_secret_len
)) {
83 wpa_printf(MSG_DEBUG
, "DAS: Invalid authenticator in packet "
84 "from %s:%d - drop", abuf
, from_port
);
88 res
= radius_msg_get_attr(msg
, RADIUS_ATTR_EVENT_TIMESTAMP
,
91 u32 timestamp
= ntohl(val
);
95 if (abs(now
.sec
- timestamp
) > das
->time_window
) {
96 wpa_printf(MSG_DEBUG
, "DAS: Unacceptable "
97 "Event-Timestamp (%u; local time %u) in "
98 "packet from %s:%d - drop",
99 timestamp
, (unsigned int) now
.sec
,
103 } else if (das
->require_event_timestamp
) {
104 wpa_printf(MSG_DEBUG
, "DAS: Missing Event-Timestamp in packet "
105 "from %s:%d - drop", abuf
, from_port
);
109 hdr
= radius_msg_get_hdr(msg
);
112 case RADIUS_CODE_DISCONNECT_REQUEST
:
114 reply
= radius_msg_new(RADIUS_CODE_DISCONNECT_NAK
,
119 radius_msg_add_attr_int32(reply
, RADIUS_ATTR_ERROR_CAUSE
, 405);
121 case RADIUS_CODE_COA_REQUEST
:
123 reply
= radius_msg_new(RADIUS_CODE_COA_NAK
,
128 /* Unsupported Service */
129 radius_msg_add_attr_int32(reply
, RADIUS_ATTR_ERROR_CAUSE
, 405);
132 wpa_printf(MSG_DEBUG
, "DAS: Unexpected RADIUS code %u in "
134 hdr
->code
, abuf
, from_port
);
138 wpa_printf(MSG_DEBUG
, "DAS: Reply to %s:%d", abuf
, from_port
);
140 if (radius_msg_finish_das_resp(reply
, das
->shared_secret
,
141 das
->shared_secret_len
, hdr
) <
143 wpa_printf(MSG_DEBUG
, "DAS: Failed to add "
144 "Message-Authenticator attribute");
147 if (wpa_debug_level
<= MSG_MSGDUMP
)
148 radius_msg_dump(reply
);
150 rbuf
= radius_msg_get_buf(reply
);
151 res
= sendto(das
->sock
, wpabuf_head(rbuf
),
153 (struct sockaddr
*) &from
.ss
, fromlen
);
155 wpa_printf(MSG_ERROR
, "DAS: sendto(to %s:%d): %s",
156 abuf
, from_port
, strerror(errno
));
161 radius_msg_free(msg
);
162 radius_msg_free(reply
);
166 static int radius_das_open_socket(int port
)
169 struct sockaddr_in addr
;
171 s
= socket(PF_INET
, SOCK_DGRAM
, 0);
177 os_memset(&addr
, 0, sizeof(addr
));
178 addr
.sin_family
= AF_INET
;
179 addr
.sin_port
= htons(port
);
180 if (bind(s
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
190 struct radius_das_data
*
191 radius_das_init(struct radius_das_conf
*conf
)
193 struct radius_das_data
*das
;
195 if (conf
->port
== 0 || conf
->shared_secret
== NULL
||
196 conf
->client_addr
== NULL
)
199 das
= os_zalloc(sizeof(*das
));
203 das
->time_window
= conf
->time_window
;
204 das
->require_event_timestamp
= conf
->require_event_timestamp
;
206 os_memcpy(&das
->client_addr
, conf
->client_addr
,
207 sizeof(das
->client_addr
));
209 das
->shared_secret
= os_malloc(conf
->shared_secret_len
);
210 if (das
->shared_secret
== NULL
) {
211 radius_das_deinit(das
);
214 os_memcpy(das
->shared_secret
, conf
->shared_secret
,
215 conf
->shared_secret_len
);
216 das
->shared_secret_len
= conf
->shared_secret_len
;
218 das
->sock
= radius_das_open_socket(conf
->port
);
220 wpa_printf(MSG_ERROR
, "Failed to open UDP socket for RADIUS "
222 radius_das_deinit(das
);
226 if (eloop_register_read_sock(das
->sock
, radius_das_receive
, das
, NULL
))
228 radius_das_deinit(das
);
236 void radius_das_deinit(struct radius_das_data
*das
)
241 if (das
->sock
>= 0) {
242 eloop_unregister_read_sock(das
->sock
);
246 os_free(das
->shared_secret
);