2 * hostapd / IEEE 802.11 authentication (ACL)
3 * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
17 #ifndef CONFIG_NATIVE_WINDOWS
20 #include "ieee802_11.h"
21 #include "ieee802_11_auth.h"
23 #include "radius_client.h"
27 #define RADIUS_ACL_TIMEOUT 30
30 struct hostapd_cached_radius_acl
{
33 int accepted
; /* HOSTAPD_ACL_* */
34 struct hostapd_cached_radius_acl
*next
;
36 u32 acct_interim_interval
;
41 struct hostapd_acl_query_data
{
45 u8
*auth_msg
; /* IEEE 802.11 authentication frame from station */
47 struct hostapd_acl_query_data
*next
;
51 static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl
*acl_cache
)
53 struct hostapd_cached_radius_acl
*prev
;
57 acl_cache
= acl_cache
->next
;
63 static int hostapd_acl_cache_get(struct hostapd_data
*hapd
, const u8
*addr
,
65 u32
*acct_interim_interval
, int *vlan_id
)
67 struct hostapd_cached_radius_acl
*entry
;
71 entry
= hapd
->acl_cache
;
74 if (memcmp(entry
->addr
, addr
, ETH_ALEN
) == 0) {
75 if (now
- entry
->timestamp
> RADIUS_ACL_TIMEOUT
)
76 return -1; /* entry has expired */
77 if (entry
->accepted
== HOSTAPD_ACL_ACCEPT_TIMEOUT
)
79 *session_timeout
= entry
->session_timeout
;
80 if (acct_interim_interval
)
81 *acct_interim_interval
= entry
->acct_interim_interval
;
83 *vlan_id
= entry
->vlan_id
;
84 return entry
->accepted
;
94 static void hostapd_acl_query_free(struct hostapd_acl_query_data
*query
)
98 free(query
->auth_msg
);
103 static int hostapd_radius_acl_query(struct hostapd_data
*hapd
, const u8
*addr
,
104 struct hostapd_acl_query_data
*query
)
106 struct radius_msg
*msg
;
109 query
->radius_id
= radius_client_get_id(hapd
->radius
);
110 msg
= radius_msg_new(RADIUS_CODE_ACCESS_REQUEST
, query
->radius_id
);
114 radius_msg_make_authenticator(msg
, addr
, ETH_ALEN
);
116 snprintf(buf
, sizeof(buf
), RADIUS_ADDR_FORMAT
, MAC2STR(addr
));
117 if (!radius_msg_add_attr(msg
, RADIUS_ATTR_USER_NAME
, (u8
*) buf
,
119 printf("Could not add User-Name\n");
123 if (!radius_msg_add_attr_user_password(
124 msg
, (u8
*) buf
, strlen(buf
),
125 hapd
->conf
->radius
->auth_server
->shared_secret
,
126 hapd
->conf
->radius
->auth_server
->shared_secret_len
)) {
127 printf("Could not add User-Password\n");
131 if (hapd
->conf
->own_ip_addr
.af
== AF_INET
&&
132 !radius_msg_add_attr(msg
, RADIUS_ATTR_NAS_IP_ADDRESS
,
133 (u8
*) &hapd
->conf
->own_ip_addr
.u
.v4
, 4)) {
134 printf("Could not add NAS-IP-Address\n");
139 if (hapd
->conf
->own_ip_addr
.af
== AF_INET6
&&
140 !radius_msg_add_attr(msg
, RADIUS_ATTR_NAS_IPV6_ADDRESS
,
141 (u8
*) &hapd
->conf
->own_ip_addr
.u
.v6
, 16)) {
142 printf("Could not add NAS-IPv6-Address\n");
145 #endif /* CONFIG_IPV6 */
147 if (hapd
->conf
->nas_identifier
&&
148 !radius_msg_add_attr(msg
, RADIUS_ATTR_NAS_IDENTIFIER
,
149 (u8
*) hapd
->conf
->nas_identifier
,
150 strlen(hapd
->conf
->nas_identifier
))) {
151 printf("Could not add NAS-Identifier\n");
155 snprintf(buf
, sizeof(buf
), RADIUS_802_1X_ADDR_FORMAT
":%s",
156 MAC2STR(hapd
->own_addr
), hapd
->conf
->ssid
.ssid
);
157 if (!radius_msg_add_attr(msg
, RADIUS_ATTR_CALLED_STATION_ID
,
158 (u8
*) buf
, strlen(buf
))) {
159 printf("Could not add Called-Station-Id\n");
163 snprintf(buf
, sizeof(buf
), RADIUS_802_1X_ADDR_FORMAT
,
165 if (!radius_msg_add_attr(msg
, RADIUS_ATTR_CALLING_STATION_ID
,
166 (u8
*) buf
, strlen(buf
))) {
167 printf("Could not add Calling-Station-Id\n");
171 if (!radius_msg_add_attr_int32(msg
, RADIUS_ATTR_NAS_PORT_TYPE
,
172 RADIUS_NAS_PORT_TYPE_IEEE_802_11
)) {
173 printf("Could not add NAS-Port-Type\n");
177 snprintf(buf
, sizeof(buf
), "CONNECT 11Mbps 802.11b");
178 if (!radius_msg_add_attr(msg
, RADIUS_ATTR_CONNECT_INFO
,
179 (u8
*) buf
, strlen(buf
))) {
180 printf("Could not add Connect-Info\n");
184 radius_client_send(hapd
->radius
, msg
, RADIUS_AUTH
, addr
);
188 radius_msg_free(msg
);
194 int hostapd_allowed_address(struct hostapd_data
*hapd
, const u8
*addr
,
195 const u8
*msg
, size_t len
, u32
*session_timeout
,
196 u32
*acct_interim_interval
, int *vlan_id
)
199 *session_timeout
= 0;
200 if (acct_interim_interval
)
201 *acct_interim_interval
= 0;
205 if (hostapd_maclist_found(hapd
->conf
->accept_mac
,
206 hapd
->conf
->num_accept_mac
, addr
))
207 return HOSTAPD_ACL_ACCEPT
;
209 if (hostapd_maclist_found(hapd
->conf
->deny_mac
,
210 hapd
->conf
->num_deny_mac
, addr
))
211 return HOSTAPD_ACL_REJECT
;
213 if (hapd
->conf
->macaddr_acl
== ACCEPT_UNLESS_DENIED
)
214 return HOSTAPD_ACL_ACCEPT
;
215 if (hapd
->conf
->macaddr_acl
== DENY_UNLESS_ACCEPTED
)
216 return HOSTAPD_ACL_REJECT
;
218 if (hapd
->conf
->macaddr_acl
== USE_EXTERNAL_RADIUS_AUTH
) {
219 struct hostapd_acl_query_data
*query
;
221 /* Check whether ACL cache has an entry for this station */
222 int res
= hostapd_acl_cache_get(hapd
, addr
, session_timeout
,
223 acct_interim_interval
,
225 if (res
== HOSTAPD_ACL_ACCEPT
||
226 res
== HOSTAPD_ACL_ACCEPT_TIMEOUT
)
228 if (res
== HOSTAPD_ACL_REJECT
)
229 return HOSTAPD_ACL_REJECT
;
231 query
= hapd
->acl_queries
;
233 if (memcmp(query
->addr
, addr
, ETH_ALEN
) == 0) {
234 /* pending query in RADIUS retransmit queue;
235 * do not generate a new one */
236 return HOSTAPD_ACL_PENDING
;
241 if (!hapd
->conf
->radius
->auth_server
)
242 return HOSTAPD_ACL_REJECT
;
244 /* No entry in the cache - query external RADIUS server */
245 query
= wpa_zalloc(sizeof(*query
));
247 printf("malloc for query data failed\n");
248 return HOSTAPD_ACL_REJECT
;
250 time(&query
->timestamp
);
251 memcpy(query
->addr
, addr
, ETH_ALEN
);
252 if (hostapd_radius_acl_query(hapd
, addr
, query
)) {
253 printf("Failed to send Access-Request for ACL "
255 hostapd_acl_query_free(query
);
256 return HOSTAPD_ACL_REJECT
;
259 query
->auth_msg
= malloc(len
);
260 if (query
->auth_msg
== NULL
) {
261 printf("Failed to allocate memory for auth frame.\n");
262 hostapd_acl_query_free(query
);
263 return HOSTAPD_ACL_REJECT
;
265 memcpy(query
->auth_msg
, msg
, len
);
266 query
->auth_msg_len
= len
;
267 query
->next
= hapd
->acl_queries
;
268 hapd
->acl_queries
= query
;
270 /* Queued data will be processed in hostapd_acl_recv_radius()
271 * when RADIUS server replies to the sent Access-Request. */
272 return HOSTAPD_ACL_PENDING
;
275 return HOSTAPD_ACL_REJECT
;
279 static void hostapd_acl_expire_cache(struct hostapd_data
*hapd
, time_t now
)
281 struct hostapd_cached_radius_acl
*prev
, *entry
, *tmp
;
284 entry
= hapd
->acl_cache
;
287 if (now
- entry
->timestamp
> RADIUS_ACL_TIMEOUT
) {
288 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL
,
289 "Cached ACL entry for " MACSTR
290 " has expired.\n", MAC2STR(entry
->addr
));
292 prev
->next
= entry
->next
;
294 hapd
->acl_cache
= entry
->next
;
295 #ifdef CONFIG_DRIVER_RADIUS_ACL
296 hostapd_set_radius_acl_expire(hapd
, entry
->addr
);
310 static void hostapd_acl_expire_queries(struct hostapd_data
*hapd
, time_t now
)
312 struct hostapd_acl_query_data
*prev
, *entry
, *tmp
;
315 entry
= hapd
->acl_queries
;
318 if (now
- entry
->timestamp
> RADIUS_ACL_TIMEOUT
) {
319 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL
,
320 "ACL query for " MACSTR
321 " has expired.\n", MAC2STR(entry
->addr
));
323 prev
->next
= entry
->next
;
325 hapd
->acl_queries
= entry
->next
;
329 hostapd_acl_query_free(tmp
);
339 static void hostapd_acl_expire(void *eloop_ctx
, void *timeout_ctx
)
341 struct hostapd_data
*hapd
= eloop_ctx
;
345 hostapd_acl_expire_cache(hapd
, now
);
346 hostapd_acl_expire_queries(hapd
, now
);
348 eloop_register_timeout(10, 0, hostapd_acl_expire
, hapd
, NULL
);
352 /* Return 0 if RADIUS message was a reply to ACL query (and was processed here)
354 static RadiusRxResult
355 hostapd_acl_recv_radius(struct radius_msg
*msg
, struct radius_msg
*req
,
356 u8
*shared_secret
, size_t shared_secret_len
,
359 struct hostapd_data
*hapd
= data
;
360 struct hostapd_acl_query_data
*query
, *prev
;
361 struct hostapd_cached_radius_acl
*cache
;
363 query
= hapd
->acl_queries
;
366 if (query
->radius_id
== msg
->hdr
->identifier
)
372 return RADIUS_RX_UNKNOWN
;
374 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL
, "Found matching Access-Request "
375 "for RADIUS message (id=%d)\n", query
->radius_id
);
377 if (radius_msg_verify(msg
, shared_secret
, shared_secret_len
, req
, 0)) {
378 printf("Incoming RADIUS packet did not have correct "
379 "authenticator - dropped\n");
380 return RADIUS_RX_INVALID_AUTHENTICATOR
;
383 if (msg
->hdr
->code
!= RADIUS_CODE_ACCESS_ACCEPT
&&
384 msg
->hdr
->code
!= RADIUS_CODE_ACCESS_REJECT
) {
385 printf("Unknown RADIUS message code %d to ACL query\n",
387 return RADIUS_RX_UNKNOWN
;
390 /* Insert Accept/Reject info into ACL cache */
391 cache
= wpa_zalloc(sizeof(*cache
));
393 printf("Failed to add ACL cache entry\n");
396 time(&cache
->timestamp
);
397 memcpy(cache
->addr
, query
->addr
, sizeof(cache
->addr
));
398 if (msg
->hdr
->code
== RADIUS_CODE_ACCESS_ACCEPT
) {
399 if (radius_msg_get_attr_int32(msg
, RADIUS_ATTR_SESSION_TIMEOUT
,
400 &cache
->session_timeout
) == 0)
401 cache
->accepted
= HOSTAPD_ACL_ACCEPT_TIMEOUT
;
403 cache
->accepted
= HOSTAPD_ACL_ACCEPT
;
405 if (radius_msg_get_attr_int32(
406 msg
, RADIUS_ATTR_ACCT_INTERIM_INTERVAL
,
407 &cache
->acct_interim_interval
) == 0 &&
408 cache
->acct_interim_interval
< 60) {
409 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL
, "Ignored too "
410 "small Acct-Interim-Interval %d for "
412 cache
->acct_interim_interval
,
413 MAC2STR(query
->addr
));
414 cache
->acct_interim_interval
= 0;
417 cache
->vlan_id
= radius_msg_get_vlanid(msg
);
419 cache
->accepted
= HOSTAPD_ACL_REJECT
;
420 cache
->next
= hapd
->acl_cache
;
421 hapd
->acl_cache
= cache
;
423 #ifdef CONFIG_DRIVER_RADIUS_ACL
424 hostapd_set_radius_acl_auth(hapd
, query
->addr
, cache
->accepted
,
425 cache
->session_timeout
);
427 /* Re-send original authentication frame for 802.11 processing */
428 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL
, "Re-sending authentication frame "
429 "after successful RADIUS ACL query\n");
430 ieee802_11_mgmt(hapd
, query
->auth_msg
, query
->auth_msg_len
,
431 WLAN_FC_STYPE_AUTH
, NULL
);
436 hapd
->acl_queries
= query
->next
;
438 prev
->next
= query
->next
;
440 hostapd_acl_query_free(query
);
442 return RADIUS_RX_PROCESSED
;
446 int hostapd_acl_init(struct hostapd_data
*hapd
)
448 if (radius_client_register(hapd
->radius
, RADIUS_AUTH
,
449 hostapd_acl_recv_radius
, hapd
))
452 eloop_register_timeout(10, 0, hostapd_acl_expire
, hapd
, NULL
);
458 void hostapd_acl_deinit(struct hostapd_data
*hapd
)
460 struct hostapd_acl_query_data
*query
, *prev
;
462 eloop_cancel_timeout(hostapd_acl_expire
, hapd
, NULL
);
464 hostapd_acl_cache_free(hapd
->acl_cache
);
466 query
= hapd
->acl_queries
;
470 hostapd_acl_query_free(prev
);
475 int hostapd_acl_reconfig(struct hostapd_data
*hapd
,
476 struct hostapd_config
*oldconf
)
478 if (!hapd
->radius_client_reconfigured
)
481 hostapd_acl_deinit(hapd
);
482 return hostapd_acl_init(hapd
);
485 #endif /* CONFIG_NATIVE_WINDOWS */