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