1214501Srpaulo/*
2214501Srpaulo * hostapd / IEEE 802.11 authentication (ACL)
3252726Srpaulo * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7214501Srpaulo *
8214501Srpaulo * Access control list for IEEE 802.11 authentication can uses statically
9214501Srpaulo * configured ACL from configuration files or an external RADIUS server.
10214501Srpaulo * Results from external RADIUS queries are cached to allow faster
11214501Srpaulo * authentication frame processing.
12214501Srpaulo */
13214501Srpaulo
14214501Srpaulo#include "utils/includes.h"
15214501Srpaulo
16214501Srpaulo#include "utils/common.h"
17214501Srpaulo#include "utils/eloop.h"
18252726Srpaulo#include "crypto/sha1.h"
19214501Srpaulo#include "radius/radius.h"
20214501Srpaulo#include "radius/radius_client.h"
21214501Srpaulo#include "hostapd.h"
22214501Srpaulo#include "ap_config.h"
23252726Srpaulo#include "ap_drv_ops.h"
24214501Srpaulo#include "ieee802_11.h"
25252726Srpaulo#include "ieee802_1x.h"
26214501Srpaulo#include "ieee802_11_auth.h"
27214501Srpaulo
28214501Srpaulo#define RADIUS_ACL_TIMEOUT 30
29214501Srpaulo
30214501Srpaulo
31214501Srpaulostruct hostapd_cached_radius_acl {
32252726Srpaulo	os_time_t timestamp;
33214501Srpaulo	macaddr addr;
34214501Srpaulo	int accepted; /* HOSTAPD_ACL_* */
35214501Srpaulo	struct hostapd_cached_radius_acl *next;
36214501Srpaulo	u32 session_timeout;
37214501Srpaulo	u32 acct_interim_interval;
38214501Srpaulo	int vlan_id;
39252726Srpaulo	struct hostapd_sta_wpa_psk_short *psk;
40252726Srpaulo	char *identity;
41252726Srpaulo	char *radius_cui;
42214501Srpaulo};
43214501Srpaulo
44214501Srpaulo
45214501Srpaulostruct hostapd_acl_query_data {
46252726Srpaulo	os_time_t timestamp;
47214501Srpaulo	u8 radius_id;
48214501Srpaulo	macaddr addr;
49214501Srpaulo	u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
50214501Srpaulo	size_t auth_msg_len;
51214501Srpaulo	struct hostapd_acl_query_data *next;
52214501Srpaulo};
53214501Srpaulo
54214501Srpaulo
55214501Srpaulo#ifndef CONFIG_NO_RADIUS
56252726Srpaulostatic void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
57252726Srpaulo{
58252726Srpaulo	os_free(e->identity);
59252726Srpaulo	os_free(e->radius_cui);
60252726Srpaulo	hostapd_free_psk_list(e->psk);
61252726Srpaulo	os_free(e);
62252726Srpaulo}
63252726Srpaulo
64252726Srpaulo
65214501Srpaulostatic void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
66214501Srpaulo{
67214501Srpaulo	struct hostapd_cached_radius_acl *prev;
68214501Srpaulo
69214501Srpaulo	while (acl_cache) {
70214501Srpaulo		prev = acl_cache;
71214501Srpaulo		acl_cache = acl_cache->next;
72252726Srpaulo		hostapd_acl_cache_free_entry(prev);
73214501Srpaulo	}
74214501Srpaulo}
75214501Srpaulo
76214501Srpaulo
77252726Srpaulostatic void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
78252726Srpaulo			  struct hostapd_sta_wpa_psk_short *src)
79252726Srpaulo{
80252726Srpaulo	struct hostapd_sta_wpa_psk_short **copy_to;
81252726Srpaulo	struct hostapd_sta_wpa_psk_short *copy_from;
82252726Srpaulo
83252726Srpaulo	/* Copy PSK linked list */
84252726Srpaulo	copy_to = psk;
85252726Srpaulo	copy_from = src;
86252726Srpaulo	while (copy_from && copy_to) {
87252726Srpaulo		*copy_to = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
88252726Srpaulo		if (*copy_to == NULL)
89252726Srpaulo			break;
90252726Srpaulo		os_memcpy(*copy_to, copy_from,
91252726Srpaulo			  sizeof(struct hostapd_sta_wpa_psk_short));
92252726Srpaulo		copy_from = copy_from->next;
93252726Srpaulo		copy_to = &((*copy_to)->next);
94252726Srpaulo	}
95252726Srpaulo	if (copy_to)
96252726Srpaulo		*copy_to = NULL;
97252726Srpaulo}
98252726Srpaulo
99252726Srpaulo
100214501Srpaulostatic int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
101214501Srpaulo				 u32 *session_timeout,
102252726Srpaulo				 u32 *acct_interim_interval, int *vlan_id,
103252726Srpaulo				 struct hostapd_sta_wpa_psk_short **psk,
104252726Srpaulo				 char **identity, char **radius_cui)
105214501Srpaulo{
106214501Srpaulo	struct hostapd_cached_radius_acl *entry;
107252726Srpaulo	struct os_time now;
108214501Srpaulo
109252726Srpaulo	os_get_time(&now);
110214501Srpaulo
111252726Srpaulo	for (entry = hapd->acl_cache; entry; entry = entry->next) {
112252726Srpaulo		if (os_memcmp(entry->addr, addr, ETH_ALEN) != 0)
113252726Srpaulo			continue;
114252726Srpaulo
115252726Srpaulo		if (now.sec - entry->timestamp > RADIUS_ACL_TIMEOUT)
116252726Srpaulo			return -1; /* entry has expired */
117252726Srpaulo		if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
118252726Srpaulo			if (session_timeout)
119252726Srpaulo				*session_timeout = entry->session_timeout;
120252726Srpaulo		if (acct_interim_interval)
121252726Srpaulo			*acct_interim_interval =
122252726Srpaulo				entry->acct_interim_interval;
123252726Srpaulo		if (vlan_id)
124252726Srpaulo			*vlan_id = entry->vlan_id;
125252726Srpaulo		copy_psk_list(psk, entry->psk);
126252726Srpaulo		if (identity) {
127252726Srpaulo			if (entry->identity)
128252726Srpaulo				*identity = os_strdup(entry->identity);
129252726Srpaulo			else
130252726Srpaulo				*identity = NULL;
131214501Srpaulo		}
132252726Srpaulo		if (radius_cui) {
133252726Srpaulo			if (entry->radius_cui)
134252726Srpaulo				*radius_cui = os_strdup(entry->radius_cui);
135252726Srpaulo			else
136252726Srpaulo				*radius_cui = NULL;
137252726Srpaulo		}
138252726Srpaulo		return entry->accepted;
139214501Srpaulo	}
140214501Srpaulo
141214501Srpaulo	return -1;
142214501Srpaulo}
143214501Srpaulo#endif /* CONFIG_NO_RADIUS */
144214501Srpaulo
145214501Srpaulo
146214501Srpaulostatic void hostapd_acl_query_free(struct hostapd_acl_query_data *query)
147214501Srpaulo{
148214501Srpaulo	if (query == NULL)
149214501Srpaulo		return;
150214501Srpaulo	os_free(query->auth_msg);
151214501Srpaulo	os_free(query);
152214501Srpaulo}
153214501Srpaulo
154214501Srpaulo
155214501Srpaulo#ifndef CONFIG_NO_RADIUS
156214501Srpaulostatic int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
157214501Srpaulo				    struct hostapd_acl_query_data *query)
158214501Srpaulo{
159214501Srpaulo	struct radius_msg *msg;
160214501Srpaulo	char buf[128];
161214501Srpaulo
162214501Srpaulo	query->radius_id = radius_client_get_id(hapd->radius);
163214501Srpaulo	msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id);
164214501Srpaulo	if (msg == NULL)
165214501Srpaulo		return -1;
166214501Srpaulo
167214501Srpaulo	radius_msg_make_authenticator(msg, addr, ETH_ALEN);
168214501Srpaulo
169214501Srpaulo	os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
170214501Srpaulo	if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
171214501Srpaulo				 os_strlen(buf))) {
172214501Srpaulo		wpa_printf(MSG_DEBUG, "Could not add User-Name");
173214501Srpaulo		goto fail;
174214501Srpaulo	}
175214501Srpaulo
176214501Srpaulo	if (!radius_msg_add_attr_user_password(
177214501Srpaulo		    msg, (u8 *) buf, os_strlen(buf),
178214501Srpaulo		    hapd->conf->radius->auth_server->shared_secret,
179214501Srpaulo		    hapd->conf->radius->auth_server->shared_secret_len)) {
180214501Srpaulo		wpa_printf(MSG_DEBUG, "Could not add User-Password");
181214501Srpaulo		goto fail;
182214501Srpaulo	}
183214501Srpaulo
184252726Srpaulo	if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr,
185252726Srpaulo				   NULL, msg) < 0)
186214501Srpaulo		goto fail;
187214501Srpaulo
188214501Srpaulo	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
189214501Srpaulo		    MAC2STR(addr));
190214501Srpaulo	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
191214501Srpaulo				 (u8 *) buf, os_strlen(buf))) {
192214501Srpaulo		wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id");
193214501Srpaulo		goto fail;
194214501Srpaulo	}
195214501Srpaulo
196214501Srpaulo	os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
197214501Srpaulo	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
198214501Srpaulo				 (u8 *) buf, os_strlen(buf))) {
199214501Srpaulo		wpa_printf(MSG_DEBUG, "Could not add Connect-Info");
200214501Srpaulo		goto fail;
201214501Srpaulo	}
202214501Srpaulo
203252726Srpaulo	if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0)
204252726Srpaulo		goto fail;
205214501Srpaulo	return 0;
206214501Srpaulo
207214501Srpaulo fail:
208214501Srpaulo	radius_msg_free(msg);
209214501Srpaulo	return -1;
210214501Srpaulo}
211214501Srpaulo#endif /* CONFIG_NO_RADIUS */
212214501Srpaulo
213214501Srpaulo
214214501Srpaulo/**
215214501Srpaulo * hostapd_allowed_address - Check whether a specified STA can be authenticated
216214501Srpaulo * @hapd: hostapd BSS data
217214501Srpaulo * @addr: MAC address of the STA
218214501Srpaulo * @msg: Authentication message
219214501Srpaulo * @len: Length of msg in octets
220214501Srpaulo * @session_timeout: Buffer for returning session timeout (from RADIUS)
221214501Srpaulo * @acct_interim_interval: Buffer for returning account interval (from RADIUS)
222214501Srpaulo * @vlan_id: Buffer for returning VLAN ID
223252726Srpaulo * @psk: Linked list buffer for returning WPA PSK
224252726Srpaulo * @identity: Buffer for returning identity (from RADIUS)
225252726Srpaulo * @radius_cui: Buffer for returning CUI (from RADIUS)
226214501Srpaulo * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
227252726Srpaulo *
228252726Srpaulo * The caller is responsible for freeing the returned *identity and *radius_cui
229252726Srpaulo * values with os_free().
230214501Srpaulo */
231214501Srpauloint hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
232214501Srpaulo			    const u8 *msg, size_t len, u32 *session_timeout,
233252726Srpaulo			    u32 *acct_interim_interval, int *vlan_id,
234252726Srpaulo			    struct hostapd_sta_wpa_psk_short **psk,
235252726Srpaulo			    char **identity, char **radius_cui)
236214501Srpaulo{
237214501Srpaulo	if (session_timeout)
238214501Srpaulo		*session_timeout = 0;
239214501Srpaulo	if (acct_interim_interval)
240214501Srpaulo		*acct_interim_interval = 0;
241214501Srpaulo	if (vlan_id)
242214501Srpaulo		*vlan_id = 0;
243252726Srpaulo	if (psk)
244252726Srpaulo		*psk = NULL;
245252726Srpaulo	if (identity)
246252726Srpaulo		*identity = NULL;
247252726Srpaulo	if (radius_cui)
248252726Srpaulo		*radius_cui = NULL;
249214501Srpaulo
250214501Srpaulo	if (hostapd_maclist_found(hapd->conf->accept_mac,
251214501Srpaulo				  hapd->conf->num_accept_mac, addr, vlan_id))
252214501Srpaulo		return HOSTAPD_ACL_ACCEPT;
253214501Srpaulo
254214501Srpaulo	if (hostapd_maclist_found(hapd->conf->deny_mac,
255214501Srpaulo				  hapd->conf->num_deny_mac, addr, vlan_id))
256214501Srpaulo		return HOSTAPD_ACL_REJECT;
257214501Srpaulo
258214501Srpaulo	if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED)
259214501Srpaulo		return HOSTAPD_ACL_ACCEPT;
260214501Srpaulo	if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED)
261214501Srpaulo		return HOSTAPD_ACL_REJECT;
262214501Srpaulo
263214501Srpaulo	if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) {
264214501Srpaulo#ifdef CONFIG_NO_RADIUS
265214501Srpaulo		return HOSTAPD_ACL_REJECT;
266214501Srpaulo#else /* CONFIG_NO_RADIUS */
267214501Srpaulo		struct hostapd_acl_query_data *query;
268252726Srpaulo		struct os_time t;
269214501Srpaulo
270214501Srpaulo		/* Check whether ACL cache has an entry for this station */
271214501Srpaulo		int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
272214501Srpaulo						acct_interim_interval,
273252726Srpaulo						vlan_id, psk,
274252726Srpaulo						identity, radius_cui);
275214501Srpaulo		if (res == HOSTAPD_ACL_ACCEPT ||
276214501Srpaulo		    res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
277214501Srpaulo			return res;
278214501Srpaulo		if (res == HOSTAPD_ACL_REJECT)
279214501Srpaulo			return HOSTAPD_ACL_REJECT;
280214501Srpaulo
281214501Srpaulo		query = hapd->acl_queries;
282214501Srpaulo		while (query) {
283214501Srpaulo			if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
284214501Srpaulo				/* pending query in RADIUS retransmit queue;
285214501Srpaulo				 * do not generate a new one */
286252726Srpaulo				if (identity) {
287252726Srpaulo					os_free(*identity);
288252726Srpaulo					*identity = NULL;
289252726Srpaulo				}
290252726Srpaulo				if (radius_cui) {
291252726Srpaulo					os_free(*radius_cui);
292252726Srpaulo					*radius_cui = NULL;
293252726Srpaulo				}
294214501Srpaulo				return HOSTAPD_ACL_PENDING;
295214501Srpaulo			}
296214501Srpaulo			query = query->next;
297214501Srpaulo		}
298214501Srpaulo
299214501Srpaulo		if (!hapd->conf->radius->auth_server)
300214501Srpaulo			return HOSTAPD_ACL_REJECT;
301214501Srpaulo
302214501Srpaulo		/* No entry in the cache - query external RADIUS server */
303214501Srpaulo		query = os_zalloc(sizeof(*query));
304214501Srpaulo		if (query == NULL) {
305214501Srpaulo			wpa_printf(MSG_ERROR, "malloc for query data failed");
306214501Srpaulo			return HOSTAPD_ACL_REJECT;
307214501Srpaulo		}
308252726Srpaulo		os_get_time(&t);
309252726Srpaulo		query->timestamp = t.sec;
310214501Srpaulo		os_memcpy(query->addr, addr, ETH_ALEN);
311214501Srpaulo		if (hostapd_radius_acl_query(hapd, addr, query)) {
312214501Srpaulo			wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
313214501Srpaulo				   "for ACL query.");
314214501Srpaulo			hostapd_acl_query_free(query);
315214501Srpaulo			return HOSTAPD_ACL_REJECT;
316214501Srpaulo		}
317214501Srpaulo
318214501Srpaulo		query->auth_msg = os_malloc(len);
319214501Srpaulo		if (query->auth_msg == NULL) {
320214501Srpaulo			wpa_printf(MSG_ERROR, "Failed to allocate memory for "
321214501Srpaulo				   "auth frame.");
322214501Srpaulo			hostapd_acl_query_free(query);
323214501Srpaulo			return HOSTAPD_ACL_REJECT;
324214501Srpaulo		}
325214501Srpaulo		os_memcpy(query->auth_msg, msg, len);
326214501Srpaulo		query->auth_msg_len = len;
327214501Srpaulo		query->next = hapd->acl_queries;
328214501Srpaulo		hapd->acl_queries = query;
329214501Srpaulo
330214501Srpaulo		/* Queued data will be processed in hostapd_acl_recv_radius()
331214501Srpaulo		 * when RADIUS server replies to the sent Access-Request. */
332214501Srpaulo		return HOSTAPD_ACL_PENDING;
333214501Srpaulo#endif /* CONFIG_NO_RADIUS */
334214501Srpaulo	}
335214501Srpaulo
336214501Srpaulo	return HOSTAPD_ACL_REJECT;
337214501Srpaulo}
338214501Srpaulo
339214501Srpaulo
340214501Srpaulo#ifndef CONFIG_NO_RADIUS
341252726Srpaulostatic void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now)
342214501Srpaulo{
343214501Srpaulo	struct hostapd_cached_radius_acl *prev, *entry, *tmp;
344214501Srpaulo
345214501Srpaulo	prev = NULL;
346214501Srpaulo	entry = hapd->acl_cache;
347214501Srpaulo
348214501Srpaulo	while (entry) {
349214501Srpaulo		if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
350214501Srpaulo			wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR
351214501Srpaulo				   " has expired.", MAC2STR(entry->addr));
352214501Srpaulo			if (prev)
353214501Srpaulo				prev->next = entry->next;
354214501Srpaulo			else
355214501Srpaulo				hapd->acl_cache = entry->next;
356252726Srpaulo			hostapd_drv_set_radius_acl_expire(hapd, entry->addr);
357214501Srpaulo			tmp = entry;
358214501Srpaulo			entry = entry->next;
359252726Srpaulo			hostapd_acl_cache_free_entry(tmp);
360214501Srpaulo			continue;
361214501Srpaulo		}
362214501Srpaulo
363214501Srpaulo		prev = entry;
364214501Srpaulo		entry = entry->next;
365214501Srpaulo	}
366214501Srpaulo}
367214501Srpaulo
368214501Srpaulo
369252726Srpaulostatic void hostapd_acl_expire_queries(struct hostapd_data *hapd,
370252726Srpaulo				       os_time_t now)
371214501Srpaulo{
372214501Srpaulo	struct hostapd_acl_query_data *prev, *entry, *tmp;
373214501Srpaulo
374214501Srpaulo	prev = NULL;
375214501Srpaulo	entry = hapd->acl_queries;
376214501Srpaulo
377214501Srpaulo	while (entry) {
378214501Srpaulo		if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
379214501Srpaulo			wpa_printf(MSG_DEBUG, "ACL query for " MACSTR
380214501Srpaulo				   " has expired.", MAC2STR(entry->addr));
381214501Srpaulo			if (prev)
382214501Srpaulo				prev->next = entry->next;
383214501Srpaulo			else
384214501Srpaulo				hapd->acl_queries = entry->next;
385214501Srpaulo
386214501Srpaulo			tmp = entry;
387214501Srpaulo			entry = entry->next;
388214501Srpaulo			hostapd_acl_query_free(tmp);
389214501Srpaulo			continue;
390214501Srpaulo		}
391214501Srpaulo
392214501Srpaulo		prev = entry;
393214501Srpaulo		entry = entry->next;
394214501Srpaulo	}
395214501Srpaulo}
396214501Srpaulo
397214501Srpaulo
398214501Srpaulo/**
399214501Srpaulo * hostapd_acl_expire - ACL cache expiration callback
400214501Srpaulo * @eloop_ctx: struct hostapd_data *
401214501Srpaulo * @timeout_ctx: Not used
402214501Srpaulo */
403214501Srpaulostatic void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
404214501Srpaulo{
405214501Srpaulo	struct hostapd_data *hapd = eloop_ctx;
406252726Srpaulo	struct os_time now;
407214501Srpaulo
408252726Srpaulo	os_get_time(&now);
409252726Srpaulo	hostapd_acl_expire_cache(hapd, now.sec);
410252726Srpaulo	hostapd_acl_expire_queries(hapd, now.sec);
411214501Srpaulo
412214501Srpaulo	eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
413214501Srpaulo}
414214501Srpaulo
415214501Srpaulo
416252726Srpaulostatic void decode_tunnel_passwords(struct hostapd_data *hapd,
417252726Srpaulo				    const u8 *shared_secret,
418252726Srpaulo				    size_t shared_secret_len,
419252726Srpaulo				    struct radius_msg *msg,
420252726Srpaulo				    struct radius_msg *req,
421252726Srpaulo				    struct hostapd_cached_radius_acl *cache)
422252726Srpaulo{
423252726Srpaulo	int passphraselen;
424252726Srpaulo	char *passphrase, *strpassphrase;
425252726Srpaulo	size_t i;
426252726Srpaulo	struct hostapd_sta_wpa_psk_short *psk;
427252726Srpaulo
428252726Srpaulo	/*
429252726Srpaulo	 * Decode all tunnel passwords as PSK and save them into a linked list.
430252726Srpaulo	 */
431252726Srpaulo	for (i = 0; ; i++) {
432252726Srpaulo		passphrase = radius_msg_get_tunnel_password(
433252726Srpaulo			msg, &passphraselen, shared_secret, shared_secret_len,
434252726Srpaulo			req, i);
435252726Srpaulo		/*
436252726Srpaulo		 * Passphrase is NULL iff there is no i-th Tunnel-Password
437252726Srpaulo		 * attribute in msg.
438252726Srpaulo		 */
439252726Srpaulo		if (passphrase == NULL)
440252726Srpaulo			break;
441252726Srpaulo		/*
442252726Srpaulo		 * passphrase does not contain the NULL termination.
443252726Srpaulo		 * Add it here as pbkdf2_sha1() requires it.
444252726Srpaulo		 */
445252726Srpaulo		strpassphrase = os_zalloc(passphraselen + 1);
446252726Srpaulo		psk = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
447252726Srpaulo		if (strpassphrase && psk) {
448252726Srpaulo			os_memcpy(strpassphrase, passphrase, passphraselen);
449252726Srpaulo			pbkdf2_sha1(strpassphrase,
450252726Srpaulo				    hapd->conf->ssid.ssid,
451252726Srpaulo				    hapd->conf->ssid.ssid_len, 4096,
452252726Srpaulo				    psk->psk, PMK_LEN);
453252726Srpaulo			psk->next = cache->psk;
454252726Srpaulo			cache->psk = psk;
455252726Srpaulo			psk = NULL;
456252726Srpaulo		}
457252726Srpaulo		os_free(strpassphrase);
458252726Srpaulo		os_free(psk);
459252726Srpaulo		os_free(passphrase);
460252726Srpaulo	}
461252726Srpaulo}
462252726Srpaulo
463252726Srpaulo
464214501Srpaulo/**
465214501Srpaulo * hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages
466214501Srpaulo * @msg: RADIUS response message
467214501Srpaulo * @req: RADIUS request message
468214501Srpaulo * @shared_secret: RADIUS shared secret
469214501Srpaulo * @shared_secret_len: Length of shared_secret in octets
470214501Srpaulo * @data: Context data (struct hostapd_data *)
471214501Srpaulo * Returns: RADIUS_RX_PROCESSED if RADIUS message was a reply to ACL query (and
472214501Srpaulo * was processed here) or RADIUS_RX_UNKNOWN if not.
473214501Srpaulo */
474214501Srpaulostatic RadiusRxResult
475214501Srpaulohostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
476214501Srpaulo			const u8 *shared_secret, size_t shared_secret_len,
477214501Srpaulo			void *data)
478214501Srpaulo{
479214501Srpaulo	struct hostapd_data *hapd = data;
480214501Srpaulo	struct hostapd_acl_query_data *query, *prev;
481214501Srpaulo	struct hostapd_cached_radius_acl *cache;
482214501Srpaulo	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
483252726Srpaulo	struct os_time t;
484214501Srpaulo
485214501Srpaulo	query = hapd->acl_queries;
486214501Srpaulo	prev = NULL;
487214501Srpaulo	while (query) {
488214501Srpaulo		if (query->radius_id == hdr->identifier)
489214501Srpaulo			break;
490214501Srpaulo		prev = query;
491214501Srpaulo		query = query->next;
492214501Srpaulo	}
493214501Srpaulo	if (query == NULL)
494214501Srpaulo		return RADIUS_RX_UNKNOWN;
495214501Srpaulo
496214501Srpaulo	wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS "
497214501Srpaulo		   "message (id=%d)", query->radius_id);
498214501Srpaulo
499214501Srpaulo	if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
500214501Srpaulo		wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have "
501214501Srpaulo			   "correct authenticator - dropped\n");
502214501Srpaulo		return RADIUS_RX_INVALID_AUTHENTICATOR;
503214501Srpaulo	}
504214501Srpaulo
505214501Srpaulo	if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
506214501Srpaulo	    hdr->code != RADIUS_CODE_ACCESS_REJECT) {
507214501Srpaulo		wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL "
508214501Srpaulo			   "query", hdr->code);
509214501Srpaulo		return RADIUS_RX_UNKNOWN;
510214501Srpaulo	}
511214501Srpaulo
512214501Srpaulo	/* Insert Accept/Reject info into ACL cache */
513214501Srpaulo	cache = os_zalloc(sizeof(*cache));
514214501Srpaulo	if (cache == NULL) {
515214501Srpaulo		wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
516214501Srpaulo		goto done;
517214501Srpaulo	}
518252726Srpaulo	os_get_time(&t);
519252726Srpaulo	cache->timestamp = t.sec;
520214501Srpaulo	os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
521214501Srpaulo	if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
522252726Srpaulo		u8 *buf;
523252726Srpaulo		size_t len;
524252726Srpaulo
525214501Srpaulo		if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
526214501Srpaulo					      &cache->session_timeout) == 0)
527214501Srpaulo			cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
528214501Srpaulo		else
529214501Srpaulo			cache->accepted = HOSTAPD_ACL_ACCEPT;
530214501Srpaulo
531214501Srpaulo		if (radius_msg_get_attr_int32(
532214501Srpaulo			    msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
533214501Srpaulo			    &cache->acct_interim_interval) == 0 &&
534214501Srpaulo		    cache->acct_interim_interval < 60) {
535214501Srpaulo			wpa_printf(MSG_DEBUG, "Ignored too small "
536214501Srpaulo				   "Acct-Interim-Interval %d for STA " MACSTR,
537214501Srpaulo				   cache->acct_interim_interval,
538214501Srpaulo				   MAC2STR(query->addr));
539214501Srpaulo			cache->acct_interim_interval = 0;
540214501Srpaulo		}
541214501Srpaulo
542214501Srpaulo		cache->vlan_id = radius_msg_get_vlanid(msg);
543252726Srpaulo
544252726Srpaulo		decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
545252726Srpaulo					msg, req, cache);
546252726Srpaulo
547252726Srpaulo		if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
548252726Srpaulo					    &buf, &len, NULL) == 0) {
549252726Srpaulo			cache->identity = os_zalloc(len + 1);
550252726Srpaulo			if (cache->identity)
551252726Srpaulo				os_memcpy(cache->identity, buf, len);
552252726Srpaulo		}
553252726Srpaulo		if (radius_msg_get_attr_ptr(
554252726Srpaulo			    msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
555252726Srpaulo			    &buf, &len, NULL) == 0) {
556252726Srpaulo			cache->radius_cui = os_zalloc(len + 1);
557252726Srpaulo			if (cache->radius_cui)
558252726Srpaulo				os_memcpy(cache->radius_cui, buf, len);
559252726Srpaulo		}
560252726Srpaulo
561252726Srpaulo		if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
562252726Srpaulo		    !cache->psk)
563252726Srpaulo			cache->accepted = HOSTAPD_ACL_REJECT;
564214501Srpaulo	} else
565214501Srpaulo		cache->accepted = HOSTAPD_ACL_REJECT;
566214501Srpaulo	cache->next = hapd->acl_cache;
567214501Srpaulo	hapd->acl_cache = cache;
568214501Srpaulo
569214501Srpaulo#ifdef CONFIG_DRIVER_RADIUS_ACL
570252726Srpaulo	hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted,
571252726Srpaulo					cache->session_timeout);
572214501Srpaulo#else /* CONFIG_DRIVER_RADIUS_ACL */
573214501Srpaulo#ifdef NEED_AP_MLME
574214501Srpaulo	/* Re-send original authentication frame for 802.11 processing */
575214501Srpaulo	wpa_printf(MSG_DEBUG, "Re-sending authentication frame after "
576214501Srpaulo		   "successful RADIUS ACL query");
577214501Srpaulo	ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL);
578214501Srpaulo#endif /* NEED_AP_MLME */
579214501Srpaulo#endif /* CONFIG_DRIVER_RADIUS_ACL */
580214501Srpaulo
581214501Srpaulo done:
582214501Srpaulo	if (prev == NULL)
583214501Srpaulo		hapd->acl_queries = query->next;
584214501Srpaulo	else
585214501Srpaulo		prev->next = query->next;
586214501Srpaulo
587214501Srpaulo	hostapd_acl_query_free(query);
588214501Srpaulo
589214501Srpaulo	return RADIUS_RX_PROCESSED;
590214501Srpaulo}
591214501Srpaulo#endif /* CONFIG_NO_RADIUS */
592214501Srpaulo
593214501Srpaulo
594214501Srpaulo/**
595214501Srpaulo * hostapd_acl_init: Initialize IEEE 802.11 ACL
596214501Srpaulo * @hapd: hostapd BSS data
597214501Srpaulo * Returns: 0 on success, -1 on failure
598214501Srpaulo */
599214501Srpauloint hostapd_acl_init(struct hostapd_data *hapd)
600214501Srpaulo{
601214501Srpaulo#ifndef CONFIG_NO_RADIUS
602214501Srpaulo	if (radius_client_register(hapd->radius, RADIUS_AUTH,
603214501Srpaulo				   hostapd_acl_recv_radius, hapd))
604214501Srpaulo		return -1;
605214501Srpaulo
606214501Srpaulo	eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
607214501Srpaulo#endif /* CONFIG_NO_RADIUS */
608214501Srpaulo
609214501Srpaulo	return 0;
610214501Srpaulo}
611214501Srpaulo
612214501Srpaulo
613214501Srpaulo/**
614214501Srpaulo * hostapd_acl_deinit - Deinitialize IEEE 802.11 ACL
615214501Srpaulo * @hapd: hostapd BSS data
616214501Srpaulo */
617214501Srpaulovoid hostapd_acl_deinit(struct hostapd_data *hapd)
618214501Srpaulo{
619214501Srpaulo	struct hostapd_acl_query_data *query, *prev;
620214501Srpaulo
621214501Srpaulo#ifndef CONFIG_NO_RADIUS
622214501Srpaulo	eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL);
623214501Srpaulo
624214501Srpaulo	hostapd_acl_cache_free(hapd->acl_cache);
625214501Srpaulo#endif /* CONFIG_NO_RADIUS */
626214501Srpaulo
627214501Srpaulo	query = hapd->acl_queries;
628214501Srpaulo	while (query) {
629214501Srpaulo		prev = query;
630214501Srpaulo		query = query->next;
631214501Srpaulo		hostapd_acl_query_free(prev);
632214501Srpaulo	}
633214501Srpaulo}
634252726Srpaulo
635252726Srpaulo
636252726Srpaulovoid hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
637252726Srpaulo{
638252726Srpaulo	while (psk) {
639252726Srpaulo		struct hostapd_sta_wpa_psk_short *prev = psk;
640252726Srpaulo		psk = psk->next;
641252726Srpaulo		os_free(prev);
642252726Srpaulo	}
643252726Srpaulo}
644