xref: /dflybsd-src/contrib/wpa_supplicant/src/ap/preauth_auth.c (revision bcf9aa4feb4a2fdf8ceac276d271a57f4b27e13d)
1*3ff40c12SJohn Marino /*
2*3ff40c12SJohn Marino  * hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
3*3ff40c12SJohn Marino  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
4*3ff40c12SJohn Marino  *
5*3ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
6*3ff40c12SJohn Marino  * See README for more details.
7*3ff40c12SJohn Marino  */
8*3ff40c12SJohn Marino 
9*3ff40c12SJohn Marino #include "utils/includes.h"
10*3ff40c12SJohn Marino 
11*3ff40c12SJohn Marino #ifdef CONFIG_RSN_PREAUTH
12*3ff40c12SJohn Marino 
13*3ff40c12SJohn Marino #include "utils/common.h"
14*3ff40c12SJohn Marino #include "utils/eloop.h"
15*3ff40c12SJohn Marino #include "l2_packet/l2_packet.h"
16*3ff40c12SJohn Marino #include "common/wpa_common.h"
17*3ff40c12SJohn Marino #include "eapol_auth/eapol_auth_sm.h"
18*3ff40c12SJohn Marino #include "eapol_auth/eapol_auth_sm_i.h"
19*3ff40c12SJohn Marino #include "hostapd.h"
20*3ff40c12SJohn Marino #include "ap_config.h"
21*3ff40c12SJohn Marino #include "ieee802_1x.h"
22*3ff40c12SJohn Marino #include "sta_info.h"
23*3ff40c12SJohn Marino #include "wpa_auth.h"
24*3ff40c12SJohn Marino #include "preauth_auth.h"
25*3ff40c12SJohn Marino 
26*3ff40c12SJohn Marino #ifndef ETH_P_PREAUTH
27*3ff40c12SJohn Marino #define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
28*3ff40c12SJohn Marino #endif /* ETH_P_PREAUTH */
29*3ff40c12SJohn Marino 
30*3ff40c12SJohn Marino static const int dot11RSNAConfigPMKLifetime = 43200;
31*3ff40c12SJohn Marino 
32*3ff40c12SJohn Marino struct rsn_preauth_interface {
33*3ff40c12SJohn Marino 	struct rsn_preauth_interface *next;
34*3ff40c12SJohn Marino 	struct hostapd_data *hapd;
35*3ff40c12SJohn Marino 	struct l2_packet_data *l2;
36*3ff40c12SJohn Marino 	char *ifname;
37*3ff40c12SJohn Marino 	int ifindex;
38*3ff40c12SJohn Marino };
39*3ff40c12SJohn Marino 
40*3ff40c12SJohn Marino 
rsn_preauth_receive(void * ctx,const u8 * src_addr,const u8 * buf,size_t len)41*3ff40c12SJohn Marino static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
42*3ff40c12SJohn Marino 				const u8 *buf, size_t len)
43*3ff40c12SJohn Marino {
44*3ff40c12SJohn Marino 	struct rsn_preauth_interface *piface = ctx;
45*3ff40c12SJohn Marino 	struct hostapd_data *hapd = piface->hapd;
46*3ff40c12SJohn Marino 	struct ieee802_1x_hdr *hdr;
47*3ff40c12SJohn Marino 	struct sta_info *sta;
48*3ff40c12SJohn Marino 	struct l2_ethhdr *ethhdr;
49*3ff40c12SJohn Marino 
50*3ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "RSN: receive pre-auth packet "
51*3ff40c12SJohn Marino 		   "from interface '%s'", piface->ifname);
52*3ff40c12SJohn Marino 	if (len < sizeof(*ethhdr) + sizeof(*hdr)) {
53*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "RSN: too short pre-auth packet "
54*3ff40c12SJohn Marino 			   "(len=%lu)", (unsigned long) len);
55*3ff40c12SJohn Marino 		return;
56*3ff40c12SJohn Marino 	}
57*3ff40c12SJohn Marino 
58*3ff40c12SJohn Marino 	ethhdr = (struct l2_ethhdr *) buf;
59*3ff40c12SJohn Marino 	hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
60*3ff40c12SJohn Marino 
61*3ff40c12SJohn Marino 	if (os_memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) {
62*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "RSN: pre-auth for foreign address "
63*3ff40c12SJohn Marino 			   MACSTR, MAC2STR(ethhdr->h_dest));
64*3ff40c12SJohn Marino 		return;
65*3ff40c12SJohn Marino 	}
66*3ff40c12SJohn Marino 
67*3ff40c12SJohn Marino 	sta = ap_get_sta(hapd, ethhdr->h_source);
68*3ff40c12SJohn Marino 	if (sta && (sta->flags & WLAN_STA_ASSOC)) {
69*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "RSN: pre-auth for already association "
70*3ff40c12SJohn Marino 			   "STA " MACSTR, MAC2STR(sta->addr));
71*3ff40c12SJohn Marino 		return;
72*3ff40c12SJohn Marino 	}
73*3ff40c12SJohn Marino 	if (!sta && hdr->type == IEEE802_1X_TYPE_EAPOL_START) {
74*3ff40c12SJohn Marino 		sta = ap_sta_add(hapd, ethhdr->h_source);
75*3ff40c12SJohn Marino 		if (sta == NULL)
76*3ff40c12SJohn Marino 			return;
77*3ff40c12SJohn Marino 		sta->flags = WLAN_STA_PREAUTH;
78*3ff40c12SJohn Marino 
79*3ff40c12SJohn Marino 		ieee802_1x_new_station(hapd, sta);
80*3ff40c12SJohn Marino 		if (sta->eapol_sm == NULL) {
81*3ff40c12SJohn Marino 			ap_free_sta(hapd, sta);
82*3ff40c12SJohn Marino 			sta = NULL;
83*3ff40c12SJohn Marino 		} else {
84*3ff40c12SJohn Marino 			sta->eapol_sm->radius_identifier = -1;
85*3ff40c12SJohn Marino 			sta->eapol_sm->portValid = TRUE;
86*3ff40c12SJohn Marino 			sta->eapol_sm->flags |= EAPOL_SM_PREAUTH;
87*3ff40c12SJohn Marino 		}
88*3ff40c12SJohn Marino 	}
89*3ff40c12SJohn Marino 	if (sta == NULL)
90*3ff40c12SJohn Marino 		return;
91*3ff40c12SJohn Marino 	sta->preauth_iface = piface;
92*3ff40c12SJohn Marino 	ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1),
93*3ff40c12SJohn Marino 			   len - sizeof(*ethhdr));
94*3ff40c12SJohn Marino }
95*3ff40c12SJohn Marino 
96*3ff40c12SJohn Marino 
rsn_preauth_iface_add(struct hostapd_data * hapd,const char * ifname)97*3ff40c12SJohn Marino static int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname)
98*3ff40c12SJohn Marino {
99*3ff40c12SJohn Marino 	struct rsn_preauth_interface *piface;
100*3ff40c12SJohn Marino 
101*3ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "RSN pre-auth interface '%s'", ifname);
102*3ff40c12SJohn Marino 
103*3ff40c12SJohn Marino 	piface = os_zalloc(sizeof(*piface));
104*3ff40c12SJohn Marino 	if (piface == NULL)
105*3ff40c12SJohn Marino 		return -1;
106*3ff40c12SJohn Marino 	piface->hapd = hapd;
107*3ff40c12SJohn Marino 
108*3ff40c12SJohn Marino 	piface->ifname = os_strdup(ifname);
109*3ff40c12SJohn Marino 	if (piface->ifname == NULL) {
110*3ff40c12SJohn Marino 		goto fail1;
111*3ff40c12SJohn Marino 	}
112*3ff40c12SJohn Marino 
113*3ff40c12SJohn Marino 	piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH,
114*3ff40c12SJohn Marino 				    rsn_preauth_receive, piface, 1);
115*3ff40c12SJohn Marino 	if (piface->l2 == NULL) {
116*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Failed to open register layer 2 access "
117*3ff40c12SJohn Marino 			   "to ETH_P_PREAUTH");
118*3ff40c12SJohn Marino 		goto fail2;
119*3ff40c12SJohn Marino 	}
120*3ff40c12SJohn Marino 
121*3ff40c12SJohn Marino 	piface->next = hapd->preauth_iface;
122*3ff40c12SJohn Marino 	hapd->preauth_iface = piface;
123*3ff40c12SJohn Marino 	return 0;
124*3ff40c12SJohn Marino 
125*3ff40c12SJohn Marino fail2:
126*3ff40c12SJohn Marino 	os_free(piface->ifname);
127*3ff40c12SJohn Marino fail1:
128*3ff40c12SJohn Marino 	os_free(piface);
129*3ff40c12SJohn Marino 	return -1;
130*3ff40c12SJohn Marino }
131*3ff40c12SJohn Marino 
132*3ff40c12SJohn Marino 
rsn_preauth_iface_deinit(struct hostapd_data * hapd)133*3ff40c12SJohn Marino void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
134*3ff40c12SJohn Marino {
135*3ff40c12SJohn Marino 	struct rsn_preauth_interface *piface, *prev;
136*3ff40c12SJohn Marino 
137*3ff40c12SJohn Marino 	piface = hapd->preauth_iface;
138*3ff40c12SJohn Marino 	hapd->preauth_iface = NULL;
139*3ff40c12SJohn Marino 	while (piface) {
140*3ff40c12SJohn Marino 		prev = piface;
141*3ff40c12SJohn Marino 		piface = piface->next;
142*3ff40c12SJohn Marino 		l2_packet_deinit(prev->l2);
143*3ff40c12SJohn Marino 		os_free(prev->ifname);
144*3ff40c12SJohn Marino 		os_free(prev);
145*3ff40c12SJohn Marino 	}
146*3ff40c12SJohn Marino }
147*3ff40c12SJohn Marino 
148*3ff40c12SJohn Marino 
rsn_preauth_iface_init(struct hostapd_data * hapd)149*3ff40c12SJohn Marino int rsn_preauth_iface_init(struct hostapd_data *hapd)
150*3ff40c12SJohn Marino {
151*3ff40c12SJohn Marino 	char *tmp, *start, *end;
152*3ff40c12SJohn Marino 
153*3ff40c12SJohn Marino 	if (hapd->conf->rsn_preauth_interfaces == NULL)
154*3ff40c12SJohn Marino 		return 0;
155*3ff40c12SJohn Marino 
156*3ff40c12SJohn Marino 	tmp = os_strdup(hapd->conf->rsn_preauth_interfaces);
157*3ff40c12SJohn Marino 	if (tmp == NULL)
158*3ff40c12SJohn Marino 		return -1;
159*3ff40c12SJohn Marino 	start = tmp;
160*3ff40c12SJohn Marino 	for (;;) {
161*3ff40c12SJohn Marino 		while (*start == ' ')
162*3ff40c12SJohn Marino 			start++;
163*3ff40c12SJohn Marino 		if (*start == '\0')
164*3ff40c12SJohn Marino 			break;
165*3ff40c12SJohn Marino 		end = os_strchr(start, ' ');
166*3ff40c12SJohn Marino 		if (end)
167*3ff40c12SJohn Marino 			*end = '\0';
168*3ff40c12SJohn Marino 
169*3ff40c12SJohn Marino 		if (rsn_preauth_iface_add(hapd, start)) {
170*3ff40c12SJohn Marino 			rsn_preauth_iface_deinit(hapd);
171*3ff40c12SJohn Marino 			os_free(tmp);
172*3ff40c12SJohn Marino 			return -1;
173*3ff40c12SJohn Marino 		}
174*3ff40c12SJohn Marino 
175*3ff40c12SJohn Marino 		if (end)
176*3ff40c12SJohn Marino 			start = end + 1;
177*3ff40c12SJohn Marino 		else
178*3ff40c12SJohn Marino 			break;
179*3ff40c12SJohn Marino 	}
180*3ff40c12SJohn Marino 	os_free(tmp);
181*3ff40c12SJohn Marino 	return 0;
182*3ff40c12SJohn Marino }
183*3ff40c12SJohn Marino 
184*3ff40c12SJohn Marino 
rsn_preauth_finished_cb(void * eloop_ctx,void * timeout_ctx)185*3ff40c12SJohn Marino static void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx)
186*3ff40c12SJohn Marino {
187*3ff40c12SJohn Marino 	struct hostapd_data *hapd = eloop_ctx;
188*3ff40c12SJohn Marino 	struct sta_info *sta = timeout_ctx;
189*3ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "RSN: Removing pre-authentication STA entry for "
190*3ff40c12SJohn Marino 		   MACSTR, MAC2STR(sta->addr));
191*3ff40c12SJohn Marino 	ap_free_sta(hapd, sta);
192*3ff40c12SJohn Marino }
193*3ff40c12SJohn Marino 
194*3ff40c12SJohn Marino 
rsn_preauth_finished(struct hostapd_data * hapd,struct sta_info * sta,int success)195*3ff40c12SJohn Marino void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
196*3ff40c12SJohn Marino 			  int success)
197*3ff40c12SJohn Marino {
198*3ff40c12SJohn Marino 	const u8 *key;
199*3ff40c12SJohn Marino 	size_t len;
200*3ff40c12SJohn Marino 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
201*3ff40c12SJohn Marino 		       HOSTAPD_LEVEL_INFO, "pre-authentication %s",
202*3ff40c12SJohn Marino 		       success ? "succeeded" : "failed");
203*3ff40c12SJohn Marino 
204*3ff40c12SJohn Marino 	key = ieee802_1x_get_key(sta->eapol_sm, &len);
205*3ff40c12SJohn Marino 	if (len > PMK_LEN)
206*3ff40c12SJohn Marino 		len = PMK_LEN;
207*3ff40c12SJohn Marino 	if (success && key) {
208*3ff40c12SJohn Marino 		if (wpa_auth_pmksa_add_preauth(hapd->wpa_auth, key, len,
209*3ff40c12SJohn Marino 					       sta->addr,
210*3ff40c12SJohn Marino 					       dot11RSNAConfigPMKLifetime,
211*3ff40c12SJohn Marino 					       sta->eapol_sm) == 0) {
212*3ff40c12SJohn Marino 			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
213*3ff40c12SJohn Marino 				       HOSTAPD_LEVEL_DEBUG,
214*3ff40c12SJohn Marino 				       "added PMKSA cache entry (pre-auth)");
215*3ff40c12SJohn Marino 		} else {
216*3ff40c12SJohn Marino 			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
217*3ff40c12SJohn Marino 				       HOSTAPD_LEVEL_DEBUG,
218*3ff40c12SJohn Marino 				       "failed to add PMKSA cache entry "
219*3ff40c12SJohn Marino 				       "(pre-auth)");
220*3ff40c12SJohn Marino 		}
221*3ff40c12SJohn Marino 	}
222*3ff40c12SJohn Marino 
223*3ff40c12SJohn Marino 	/*
224*3ff40c12SJohn Marino 	 * Finish STA entry removal from timeout in order to avoid freeing
225*3ff40c12SJohn Marino 	 * STA data before the caller has finished processing.
226*3ff40c12SJohn Marino 	 */
227*3ff40c12SJohn Marino 	eloop_register_timeout(0, 0, rsn_preauth_finished_cb, hapd, sta);
228*3ff40c12SJohn Marino }
229*3ff40c12SJohn Marino 
230*3ff40c12SJohn Marino 
rsn_preauth_send(struct hostapd_data * hapd,struct sta_info * sta,u8 * buf,size_t len)231*3ff40c12SJohn Marino void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
232*3ff40c12SJohn Marino 		      u8 *buf, size_t len)
233*3ff40c12SJohn Marino {
234*3ff40c12SJohn Marino 	struct rsn_preauth_interface *piface;
235*3ff40c12SJohn Marino 	struct l2_ethhdr *ethhdr;
236*3ff40c12SJohn Marino 
237*3ff40c12SJohn Marino 	piface = hapd->preauth_iface;
238*3ff40c12SJohn Marino 	while (piface) {
239*3ff40c12SJohn Marino 		if (piface == sta->preauth_iface)
240*3ff40c12SJohn Marino 			break;
241*3ff40c12SJohn Marino 		piface = piface->next;
242*3ff40c12SJohn Marino 	}
243*3ff40c12SJohn Marino 
244*3ff40c12SJohn Marino 	if (piface == NULL) {
245*3ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "RSN: Could not find pre-authentication "
246*3ff40c12SJohn Marino 			   "interface for " MACSTR, MAC2STR(sta->addr));
247*3ff40c12SJohn Marino 		return;
248*3ff40c12SJohn Marino 	}
249*3ff40c12SJohn Marino 
250*3ff40c12SJohn Marino 	ethhdr = os_malloc(sizeof(*ethhdr) + len);
251*3ff40c12SJohn Marino 	if (ethhdr == NULL)
252*3ff40c12SJohn Marino 		return;
253*3ff40c12SJohn Marino 
254*3ff40c12SJohn Marino 	os_memcpy(ethhdr->h_dest, sta->addr, ETH_ALEN);
255*3ff40c12SJohn Marino 	os_memcpy(ethhdr->h_source, hapd->own_addr, ETH_ALEN);
256*3ff40c12SJohn Marino 	ethhdr->h_proto = host_to_be16(ETH_P_PREAUTH);
257*3ff40c12SJohn Marino 	os_memcpy(ethhdr + 1, buf, len);
258*3ff40c12SJohn Marino 
259*3ff40c12SJohn Marino 	if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr,
260*3ff40c12SJohn Marino 			   sizeof(*ethhdr) + len) < 0) {
261*3ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Failed to send preauth packet using "
262*3ff40c12SJohn Marino 			   "l2_packet_send\n");
263*3ff40c12SJohn Marino 	}
264*3ff40c12SJohn Marino 	os_free(ethhdr);
265*3ff40c12SJohn Marino }
266*3ff40c12SJohn Marino 
267*3ff40c12SJohn Marino 
rsn_preauth_free_station(struct hostapd_data * hapd,struct sta_info * sta)268*3ff40c12SJohn Marino void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta)
269*3ff40c12SJohn Marino {
270*3ff40c12SJohn Marino 	eloop_cancel_timeout(rsn_preauth_finished_cb, hapd, sta);
271*3ff40c12SJohn Marino }
272*3ff40c12SJohn Marino 
273*3ff40c12SJohn Marino #endif /* CONFIG_RSN_PREAUTH */
274