]> git.ipfire.org Git - thirdparty/hostap.git/blob - hostapd/ieee802_11_auth.c
bbdf9f92d2c75cafd05a84793d3a724fd8c0c51f
[thirdparty/hostap.git] / hostapd / ieee802_11_auth.c
1 /*
2 * hostapd / IEEE 802.11 authentication (ACL)
3 * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
4 *
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.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15 #include "includes.h"
16
17 #ifndef CONFIG_NATIVE_WINDOWS
18
19 #include "hostapd.h"
20 #include "ieee802_11.h"
21 #include "ieee802_11_auth.h"
22 #include "radius/radius.h"
23 #include "radius/radius_client.h"
24 #include "eloop.h"
25
26 #define RADIUS_ACL_TIMEOUT 30
27
28
29 struct hostapd_cached_radius_acl {
30 time_t timestamp;
31 macaddr addr;
32 int accepted; /* HOSTAPD_ACL_* */
33 struct hostapd_cached_radius_acl *next;
34 u32 session_timeout;
35 u32 acct_interim_interval;
36 int vlan_id;
37 };
38
39
40 struct hostapd_acl_query_data {
41 time_t timestamp;
42 u8 radius_id;
43 macaddr addr;
44 u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
45 size_t auth_msg_len;
46 struct hostapd_acl_query_data *next;
47 };
48
49
50 static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
51 {
52 struct hostapd_cached_radius_acl *prev;
53
54 while (acl_cache) {
55 prev = acl_cache;
56 acl_cache = acl_cache->next;
57 os_free(prev);
58 }
59 }
60
61
62 static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
63 u32 *session_timeout,
64 u32 *acct_interim_interval, int *vlan_id)
65 {
66 struct hostapd_cached_radius_acl *entry;
67 time_t now;
68
69 time(&now);
70 entry = hapd->acl_cache;
71
72 while (entry) {
73 if (os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
74 if (now - entry->timestamp > RADIUS_ACL_TIMEOUT)
75 return -1; /* entry has expired */
76 if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
77 if (session_timeout)
78 *session_timeout =
79 entry->session_timeout;
80 if (acct_interim_interval)
81 *acct_interim_interval =
82 entry->acct_interim_interval;
83 if (vlan_id)
84 *vlan_id = entry->vlan_id;
85 return entry->accepted;
86 }
87
88 entry = entry->next;
89 }
90
91 return -1;
92 }
93
94
95 static void hostapd_acl_query_free(struct hostapd_acl_query_data *query)
96 {
97 if (query == NULL)
98 return;
99 os_free(query->auth_msg);
100 os_free(query);
101 }
102
103
104 static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
105 struct hostapd_acl_query_data *query)
106 {
107 struct radius_msg *msg;
108 char buf[128];
109
110 query->radius_id = radius_client_get_id(hapd->radius);
111 msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id);
112 if (msg == NULL)
113 return -1;
114
115 radius_msg_make_authenticator(msg, addr, ETH_ALEN);
116
117 os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
118 if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
119 os_strlen(buf))) {
120 wpa_printf(MSG_DEBUG, "Could not add User-Name");
121 goto fail;
122 }
123
124 if (!radius_msg_add_attr_user_password(
125 msg, (u8 *) buf, os_strlen(buf),
126 hapd->conf->radius->auth_server->shared_secret,
127 hapd->conf->radius->auth_server->shared_secret_len)) {
128 wpa_printf(MSG_DEBUG, "Could not add User-Password");
129 goto fail;
130 }
131
132 if (hapd->conf->own_ip_addr.af == AF_INET &&
133 !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
134 (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
135 wpa_printf(MSG_DEBUG, "Could not add NAS-IP-Address");
136 goto fail;
137 }
138
139 #ifdef CONFIG_IPV6
140 if (hapd->conf->own_ip_addr.af == AF_INET6 &&
141 !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
142 (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
143 wpa_printf(MSG_DEBUG, "Could not add NAS-IPv6-Address");
144 goto fail;
145 }
146 #endif /* CONFIG_IPV6 */
147
148 if (hapd->conf->nas_identifier &&
149 !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
150 (u8 *) hapd->conf->nas_identifier,
151 os_strlen(hapd->conf->nas_identifier))) {
152 wpa_printf(MSG_DEBUG, "Could not add NAS-Identifier");
153 goto fail;
154 }
155
156 os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
157 MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
158 if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
159 (u8 *) buf, os_strlen(buf))) {
160 wpa_printf(MSG_DEBUG, "Could not add Called-Station-Id");
161 goto fail;
162 }
163
164 os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
165 MAC2STR(addr));
166 if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
167 (u8 *) buf, os_strlen(buf))) {
168 wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id");
169 goto fail;
170 }
171
172 if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
173 RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
174 wpa_printf(MSG_DEBUG, "Could not add NAS-Port-Type");
175 goto fail;
176 }
177
178 os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
179 if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
180 (u8 *) buf, os_strlen(buf))) {
181 wpa_printf(MSG_DEBUG, "Could not add Connect-Info");
182 goto fail;
183 }
184
185 radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr);
186 return 0;
187
188 fail:
189 radius_msg_free(msg);
190 os_free(msg);
191 return -1;
192 }
193
194
195 int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
196 const u8 *msg, size_t len, u32 *session_timeout,
197 u32 *acct_interim_interval, int *vlan_id)
198 {
199 if (session_timeout)
200 *session_timeout = 0;
201 if (acct_interim_interval)
202 *acct_interim_interval = 0;
203 if (vlan_id)
204 *vlan_id = 0;
205
206 if (hostapd_maclist_found(hapd->conf->accept_mac,
207 hapd->conf->num_accept_mac, addr))
208 return HOSTAPD_ACL_ACCEPT;
209
210 if (hostapd_maclist_found(hapd->conf->deny_mac,
211 hapd->conf->num_deny_mac, addr))
212 return HOSTAPD_ACL_REJECT;
213
214 if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED)
215 return HOSTAPD_ACL_ACCEPT;
216 if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED)
217 return HOSTAPD_ACL_REJECT;
218
219 if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) {
220 struct hostapd_acl_query_data *query;
221
222 /* Check whether ACL cache has an entry for this station */
223 int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
224 acct_interim_interval,
225 vlan_id);
226 if (res == HOSTAPD_ACL_ACCEPT ||
227 res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
228 return res;
229 if (res == HOSTAPD_ACL_REJECT)
230 return HOSTAPD_ACL_REJECT;
231
232 query = hapd->acl_queries;
233 while (query) {
234 if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
235 /* pending query in RADIUS retransmit queue;
236 * do not generate a new one */
237 return HOSTAPD_ACL_PENDING;
238 }
239 query = query->next;
240 }
241
242 if (!hapd->conf->radius->auth_server)
243 return HOSTAPD_ACL_REJECT;
244
245 /* No entry in the cache - query external RADIUS server */
246 query = os_zalloc(sizeof(*query));
247 if (query == NULL) {
248 wpa_printf(MSG_ERROR, "malloc for query data failed");
249 return HOSTAPD_ACL_REJECT;
250 }
251 time(&query->timestamp);
252 os_memcpy(query->addr, addr, ETH_ALEN);
253 if (hostapd_radius_acl_query(hapd, addr, query)) {
254 wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
255 "for ACL query.");
256 hostapd_acl_query_free(query);
257 return HOSTAPD_ACL_REJECT;
258 }
259
260 query->auth_msg = os_malloc(len);
261 if (query->auth_msg == NULL) {
262 wpa_printf(MSG_ERROR, "Failed to allocate memory for "
263 "auth frame.");
264 hostapd_acl_query_free(query);
265 return HOSTAPD_ACL_REJECT;
266 }
267 os_memcpy(query->auth_msg, msg, len);
268 query->auth_msg_len = len;
269 query->next = hapd->acl_queries;
270 hapd->acl_queries = query;
271
272 /* Queued data will be processed in hostapd_acl_recv_radius()
273 * when RADIUS server replies to the sent Access-Request. */
274 return HOSTAPD_ACL_PENDING;
275 }
276
277 return HOSTAPD_ACL_REJECT;
278 }
279
280
281 static void hostapd_acl_expire_cache(struct hostapd_data *hapd, time_t now)
282 {
283 struct hostapd_cached_radius_acl *prev, *entry, *tmp;
284
285 prev = NULL;
286 entry = hapd->acl_cache;
287
288 while (entry) {
289 if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
290 wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR
291 " has expired.", MAC2STR(entry->addr));
292 if (prev)
293 prev->next = entry->next;
294 else
295 hapd->acl_cache = entry->next;
296
297 tmp = entry;
298 entry = entry->next;
299 os_free(tmp);
300 continue;
301 }
302
303 prev = entry;
304 entry = entry->next;
305 }
306 }
307
308
309 static void hostapd_acl_expire_queries(struct hostapd_data *hapd, time_t now)
310 {
311 struct hostapd_acl_query_data *prev, *entry, *tmp;
312
313 prev = NULL;
314 entry = hapd->acl_queries;
315
316 while (entry) {
317 if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
318 wpa_printf(MSG_DEBUG, "ACL query for " MACSTR
319 " has expired.", MAC2STR(entry->addr));
320 if (prev)
321 prev->next = entry->next;
322 else
323 hapd->acl_queries = entry->next;
324
325 tmp = entry;
326 entry = entry->next;
327 hostapd_acl_query_free(tmp);
328 continue;
329 }
330
331 prev = entry;
332 entry = entry->next;
333 }
334 }
335
336
337 static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
338 {
339 struct hostapd_data *hapd = eloop_ctx;
340 time_t now;
341
342 time(&now);
343 hostapd_acl_expire_cache(hapd, now);
344 hostapd_acl_expire_queries(hapd, now);
345
346 eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
347 }
348
349
350 /* Return 0 if RADIUS message was a reply to ACL query (and was processed here)
351 * or -1 if not. */
352 static RadiusRxResult
353 hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
354 u8 *shared_secret, size_t shared_secret_len,
355 void *data)
356 {
357 struct hostapd_data *hapd = data;
358 struct hostapd_acl_query_data *query, *prev;
359 struct hostapd_cached_radius_acl *cache;
360
361 query = hapd->acl_queries;
362 prev = NULL;
363 while (query) {
364 if (query->radius_id == msg->hdr->identifier)
365 break;
366 prev = query;
367 query = query->next;
368 }
369 if (query == NULL)
370 return RADIUS_RX_UNKNOWN;
371
372 wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS "
373 "message (id=%d)", query->radius_id);
374
375 if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
376 wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have "
377 "correct authenticator - dropped\n");
378 return RADIUS_RX_INVALID_AUTHENTICATOR;
379 }
380
381 if (msg->hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
382 msg->hdr->code != RADIUS_CODE_ACCESS_REJECT) {
383 wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL "
384 "query", msg->hdr->code);
385 return RADIUS_RX_UNKNOWN;
386 }
387
388 /* Insert Accept/Reject info into ACL cache */
389 cache = os_zalloc(sizeof(*cache));
390 if (cache == NULL) {
391 wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
392 goto done;
393 }
394 time(&cache->timestamp);
395 os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
396 if (msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
397 if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
398 &cache->session_timeout) == 0)
399 cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
400 else
401 cache->accepted = HOSTAPD_ACL_ACCEPT;
402
403 if (radius_msg_get_attr_int32(
404 msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
405 &cache->acct_interim_interval) == 0 &&
406 cache->acct_interim_interval < 60) {
407 wpa_printf(MSG_DEBUG, "Ignored too small "
408 "Acct-Interim-Interval %d for STA " MACSTR,
409 cache->acct_interim_interval,
410 MAC2STR(query->addr));
411 cache->acct_interim_interval = 0;
412 }
413
414 cache->vlan_id = radius_msg_get_vlanid(msg);
415 } else
416 cache->accepted = HOSTAPD_ACL_REJECT;
417 cache->next = hapd->acl_cache;
418 hapd->acl_cache = cache;
419
420 /* Re-send original authentication frame for 802.11 processing */
421 wpa_printf(MSG_DEBUG, "Re-sending authentication frame after "
422 "successful RADIUS ACL query");
423 ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len,
424 WLAN_FC_STYPE_AUTH, NULL);
425
426 done:
427 if (prev == NULL)
428 hapd->acl_queries = query->next;
429 else
430 prev->next = query->next;
431
432 hostapd_acl_query_free(query);
433
434 return RADIUS_RX_PROCESSED;
435 }
436
437
438 int hostapd_acl_init(struct hostapd_data *hapd)
439 {
440 if (radius_client_register(hapd->radius, RADIUS_AUTH,
441 hostapd_acl_recv_radius, hapd))
442 return -1;
443
444 eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
445
446 return 0;
447 }
448
449
450 void hostapd_acl_deinit(struct hostapd_data *hapd)
451 {
452 struct hostapd_acl_query_data *query, *prev;
453
454 eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL);
455
456 hostapd_acl_cache_free(hapd->acl_cache);
457
458 query = hapd->acl_queries;
459 while (query) {
460 prev = query;
461 query = query->next;
462 hostapd_acl_query_free(prev);
463 }
464 }
465
466
467 int hostapd_acl_reconfig(struct hostapd_data *hapd,
468 struct hostapd_config *oldconf)
469 {
470 if (!hapd->radius_client_reconfigured)
471 return 0;
472
473 hostapd_acl_deinit(hapd);
474 return hostapd_acl_init(hapd);
475 }
476
477 #endif /* CONFIG_NATIVE_WINDOWS */