preauth_auth.c revision 214501
1214501Srpaulo/*
2214501Srpaulo * hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
3214501Srpaulo * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5214501Srpaulo * This program is free software; you can redistribute it and/or modify
6214501Srpaulo * it under the terms of the GNU General Public License version 2 as
7214501Srpaulo * published by the Free Software Foundation.
8214501Srpaulo *
9214501Srpaulo * Alternatively, this software may be distributed under the terms of BSD
10214501Srpaulo * license.
11214501Srpaulo *
12214501Srpaulo * See README and COPYING for more details.
13214501Srpaulo */
14214501Srpaulo
15214501Srpaulo#include "utils/includes.h"
16214501Srpaulo
17214501Srpaulo#ifdef CONFIG_RSN_PREAUTH
18214501Srpaulo
19214501Srpaulo#include "utils/common.h"
20214501Srpaulo#include "utils/eloop.h"
21214501Srpaulo#include "l2_packet/l2_packet.h"
22214501Srpaulo#include "common/wpa_common.h"
23214501Srpaulo#include "eapol_auth/eapol_auth_sm.h"
24214501Srpaulo#include "eapol_auth/eapol_auth_sm_i.h"
25214501Srpaulo#include "hostapd.h"
26214501Srpaulo#include "ap_config.h"
27214501Srpaulo#include "ieee802_1x.h"
28214501Srpaulo#include "sta_info.h"
29214501Srpaulo#include "wpa_auth.h"
30214501Srpaulo#include "preauth_auth.h"
31214501Srpaulo
32214501Srpaulo#ifndef ETH_P_PREAUTH
33214501Srpaulo#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
34214501Srpaulo#endif /* ETH_P_PREAUTH */
35214501Srpaulo
36214501Srpaulostatic const int dot11RSNAConfigPMKLifetime = 43200;
37214501Srpaulo
38214501Srpaulostruct rsn_preauth_interface {
39214501Srpaulo	struct rsn_preauth_interface *next;
40214501Srpaulo	struct hostapd_data *hapd;
41214501Srpaulo	struct l2_packet_data *l2;
42214501Srpaulo	char *ifname;
43214501Srpaulo	int ifindex;
44214501Srpaulo};
45214501Srpaulo
46214501Srpaulo
47214501Srpaulostatic void rsn_preauth_receive(void *ctx, const u8 *src_addr,
48214501Srpaulo				const u8 *buf, size_t len)
49214501Srpaulo{
50214501Srpaulo	struct rsn_preauth_interface *piface = ctx;
51214501Srpaulo	struct hostapd_data *hapd = piface->hapd;
52214501Srpaulo	struct ieee802_1x_hdr *hdr;
53214501Srpaulo	struct sta_info *sta;
54214501Srpaulo	struct l2_ethhdr *ethhdr;
55214501Srpaulo
56214501Srpaulo	wpa_printf(MSG_DEBUG, "RSN: receive pre-auth packet "
57214501Srpaulo		   "from interface '%s'", piface->ifname);
58214501Srpaulo	if (len < sizeof(*ethhdr) + sizeof(*hdr)) {
59214501Srpaulo		wpa_printf(MSG_DEBUG, "RSN: too short pre-auth packet "
60214501Srpaulo			   "(len=%lu)", (unsigned long) len);
61214501Srpaulo		return;
62214501Srpaulo	}
63214501Srpaulo
64214501Srpaulo	ethhdr = (struct l2_ethhdr *) buf;
65214501Srpaulo	hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
66214501Srpaulo
67214501Srpaulo	if (os_memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) {
68214501Srpaulo		wpa_printf(MSG_DEBUG, "RSN: pre-auth for foreign address "
69214501Srpaulo			   MACSTR, MAC2STR(ethhdr->h_dest));
70214501Srpaulo		return;
71214501Srpaulo	}
72214501Srpaulo
73214501Srpaulo	sta = ap_get_sta(hapd, ethhdr->h_source);
74214501Srpaulo	if (sta && (sta->flags & WLAN_STA_ASSOC)) {
75214501Srpaulo		wpa_printf(MSG_DEBUG, "RSN: pre-auth for already association "
76214501Srpaulo			   "STA " MACSTR, MAC2STR(sta->addr));
77214501Srpaulo		return;
78214501Srpaulo	}
79214501Srpaulo	if (!sta && hdr->type == IEEE802_1X_TYPE_EAPOL_START) {
80214501Srpaulo		sta = ap_sta_add(hapd, ethhdr->h_source);
81214501Srpaulo		if (sta == NULL)
82214501Srpaulo			return;
83214501Srpaulo		sta->flags = WLAN_STA_PREAUTH;
84214501Srpaulo
85214501Srpaulo		ieee802_1x_new_station(hapd, sta);
86214501Srpaulo		if (sta->eapol_sm == NULL) {
87214501Srpaulo			ap_free_sta(hapd, sta);
88214501Srpaulo			sta = NULL;
89214501Srpaulo		} else {
90214501Srpaulo			sta->eapol_sm->radius_identifier = -1;
91214501Srpaulo			sta->eapol_sm->portValid = TRUE;
92214501Srpaulo			sta->eapol_sm->flags |= EAPOL_SM_PREAUTH;
93214501Srpaulo		}
94214501Srpaulo	}
95214501Srpaulo	if (sta == NULL)
96214501Srpaulo		return;
97214501Srpaulo	sta->preauth_iface = piface;
98214501Srpaulo	ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1),
99214501Srpaulo			   len - sizeof(*ethhdr));
100214501Srpaulo}
101214501Srpaulo
102214501Srpaulo
103214501Srpaulostatic int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname)
104214501Srpaulo{
105214501Srpaulo	struct rsn_preauth_interface *piface;
106214501Srpaulo
107214501Srpaulo	wpa_printf(MSG_DEBUG, "RSN pre-auth interface '%s'", ifname);
108214501Srpaulo
109214501Srpaulo	piface = os_zalloc(sizeof(*piface));
110214501Srpaulo	if (piface == NULL)
111214501Srpaulo		return -1;
112214501Srpaulo	piface->hapd = hapd;
113214501Srpaulo
114214501Srpaulo	piface->ifname = os_strdup(ifname);
115214501Srpaulo	if (piface->ifname == NULL) {
116214501Srpaulo		goto fail1;
117214501Srpaulo	}
118214501Srpaulo
119214501Srpaulo	piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH,
120214501Srpaulo				    rsn_preauth_receive, piface, 1);
121214501Srpaulo	if (piface->l2 == NULL) {
122214501Srpaulo		wpa_printf(MSG_ERROR, "Failed to open register layer 2 access "
123214501Srpaulo			   "to ETH_P_PREAUTH");
124214501Srpaulo		goto fail2;
125214501Srpaulo	}
126214501Srpaulo
127214501Srpaulo	piface->next = hapd->preauth_iface;
128214501Srpaulo	hapd->preauth_iface = piface;
129214501Srpaulo	return 0;
130214501Srpaulo
131214501Srpaulofail2:
132214501Srpaulo	os_free(piface->ifname);
133214501Srpaulofail1:
134214501Srpaulo	os_free(piface);
135214501Srpaulo	return -1;
136214501Srpaulo}
137214501Srpaulo
138214501Srpaulo
139214501Srpaulovoid rsn_preauth_iface_deinit(struct hostapd_data *hapd)
140214501Srpaulo{
141214501Srpaulo	struct rsn_preauth_interface *piface, *prev;
142214501Srpaulo
143214501Srpaulo	piface = hapd->preauth_iface;
144214501Srpaulo	hapd->preauth_iface = NULL;
145214501Srpaulo	while (piface) {
146214501Srpaulo		prev = piface;
147214501Srpaulo		piface = piface->next;
148214501Srpaulo		l2_packet_deinit(prev->l2);
149214501Srpaulo		os_free(prev->ifname);
150214501Srpaulo		os_free(prev);
151214501Srpaulo	}
152214501Srpaulo}
153214501Srpaulo
154214501Srpaulo
155214501Srpauloint rsn_preauth_iface_init(struct hostapd_data *hapd)
156214501Srpaulo{
157214501Srpaulo	char *tmp, *start, *end;
158214501Srpaulo
159214501Srpaulo	if (hapd->conf->rsn_preauth_interfaces == NULL)
160214501Srpaulo		return 0;
161214501Srpaulo
162214501Srpaulo	tmp = os_strdup(hapd->conf->rsn_preauth_interfaces);
163214501Srpaulo	if (tmp == NULL)
164214501Srpaulo		return -1;
165214501Srpaulo	start = tmp;
166214501Srpaulo	for (;;) {
167214501Srpaulo		while (*start == ' ')
168214501Srpaulo			start++;
169214501Srpaulo		if (*start == '\0')
170214501Srpaulo			break;
171214501Srpaulo		end = os_strchr(start, ' ');
172214501Srpaulo		if (end)
173214501Srpaulo			*end = '\0';
174214501Srpaulo
175214501Srpaulo		if (rsn_preauth_iface_add(hapd, start)) {
176214501Srpaulo			rsn_preauth_iface_deinit(hapd);
177214501Srpaulo			os_free(tmp);
178214501Srpaulo			return -1;
179214501Srpaulo		}
180214501Srpaulo
181214501Srpaulo		if (end)
182214501Srpaulo			start = end + 1;
183214501Srpaulo		else
184214501Srpaulo			break;
185214501Srpaulo	}
186214501Srpaulo	os_free(tmp);
187214501Srpaulo	return 0;
188214501Srpaulo}
189214501Srpaulo
190214501Srpaulo
191214501Srpaulostatic void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx)
192214501Srpaulo{
193214501Srpaulo	struct hostapd_data *hapd = eloop_ctx;
194214501Srpaulo	struct sta_info *sta = timeout_ctx;
195214501Srpaulo	wpa_printf(MSG_DEBUG, "RSN: Removing pre-authentication STA entry for "
196214501Srpaulo		   MACSTR, MAC2STR(sta->addr));
197214501Srpaulo	ap_free_sta(hapd, sta);
198214501Srpaulo}
199214501Srpaulo
200214501Srpaulo
201214501Srpaulovoid rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
202214501Srpaulo			  int success)
203214501Srpaulo{
204214501Srpaulo	const u8 *key;
205214501Srpaulo	size_t len;
206214501Srpaulo	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
207214501Srpaulo		       HOSTAPD_LEVEL_INFO, "pre-authentication %s",
208214501Srpaulo		       success ? "succeeded" : "failed");
209214501Srpaulo
210214501Srpaulo	key = ieee802_1x_get_key(sta->eapol_sm, &len);
211214501Srpaulo	if (len > PMK_LEN)
212214501Srpaulo		len = PMK_LEN;
213214501Srpaulo	if (success && key) {
214214501Srpaulo		if (wpa_auth_pmksa_add_preauth(hapd->wpa_auth, key, len,
215214501Srpaulo					       sta->addr,
216214501Srpaulo					       dot11RSNAConfigPMKLifetime,
217214501Srpaulo					       sta->eapol_sm) == 0) {
218214501Srpaulo			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
219214501Srpaulo				       HOSTAPD_LEVEL_DEBUG,
220214501Srpaulo				       "added PMKSA cache entry (pre-auth)");
221214501Srpaulo		} else {
222214501Srpaulo			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
223214501Srpaulo				       HOSTAPD_LEVEL_DEBUG,
224214501Srpaulo				       "failed to add PMKSA cache entry "
225214501Srpaulo				       "(pre-auth)");
226214501Srpaulo		}
227214501Srpaulo	}
228214501Srpaulo
229214501Srpaulo	/*
230214501Srpaulo	 * Finish STA entry removal from timeout in order to avoid freeing
231214501Srpaulo	 * STA data before the caller has finished processing.
232214501Srpaulo	 */
233214501Srpaulo	eloop_register_timeout(0, 0, rsn_preauth_finished_cb, hapd, sta);
234214501Srpaulo}
235214501Srpaulo
236214501Srpaulo
237214501Srpaulovoid rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
238214501Srpaulo		      u8 *buf, size_t len)
239214501Srpaulo{
240214501Srpaulo	struct rsn_preauth_interface *piface;
241214501Srpaulo	struct l2_ethhdr *ethhdr;
242214501Srpaulo
243214501Srpaulo	piface = hapd->preauth_iface;
244214501Srpaulo	while (piface) {
245214501Srpaulo		if (piface == sta->preauth_iface)
246214501Srpaulo			break;
247214501Srpaulo		piface = piface->next;
248214501Srpaulo	}
249214501Srpaulo
250214501Srpaulo	if (piface == NULL) {
251214501Srpaulo		wpa_printf(MSG_DEBUG, "RSN: Could not find pre-authentication "
252214501Srpaulo			   "interface for " MACSTR, MAC2STR(sta->addr));
253214501Srpaulo		return;
254214501Srpaulo	}
255214501Srpaulo
256214501Srpaulo	ethhdr = os_malloc(sizeof(*ethhdr) + len);
257214501Srpaulo	if (ethhdr == NULL)
258214501Srpaulo		return;
259214501Srpaulo
260214501Srpaulo	os_memcpy(ethhdr->h_dest, sta->addr, ETH_ALEN);
261214501Srpaulo	os_memcpy(ethhdr->h_source, hapd->own_addr, ETH_ALEN);
262214501Srpaulo	ethhdr->h_proto = host_to_be16(ETH_P_PREAUTH);
263214501Srpaulo	os_memcpy(ethhdr + 1, buf, len);
264214501Srpaulo
265214501Srpaulo	if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr,
266214501Srpaulo			   sizeof(*ethhdr) + len) < 0) {
267214501Srpaulo		wpa_printf(MSG_ERROR, "Failed to send preauth packet using "
268214501Srpaulo			   "l2_packet_send\n");
269214501Srpaulo	}
270214501Srpaulo	os_free(ethhdr);
271214501Srpaulo}
272214501Srpaulo
273214501Srpaulo
274214501Srpaulovoid rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta)
275214501Srpaulo{
276214501Srpaulo	eloop_cancel_timeout(rsn_preauth_finished_cb, hapd, sta);
277214501Srpaulo}
278214501Srpaulo
279214501Srpaulo#endif /* CONFIG_RSN_PREAUTH */
280