1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
8 * Sun elects to license this software under the BSD license.
9 * See README for more details.
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdarg.h>
15 #include <unistd.h>
16 #include <string.h>
17 #include <syslog.h>
18 #include <sys/stat.h>
19 #include <errno.h>
20 #include <signal.h>
21 #include <fcntl.h>
22 #include <door.h>
23 #include <libscf.h>
24 #include <libdladm.h>
25 #include <libdllink.h>
26 #include <sys/ethernet.h>
27
28 #include "wpa_impl.h"
29 #include "wpa_enc.h"
30 #include "driver.h"
31 #include "eloop.h"
32 #include "l2_packet.h"
33
34 extern struct wpa_driver_ops wpa_driver_wifi_ops;
35 int wpa_debug_level = MSG_ERROR;
36
37 /*
38 * wpa_printf - conditional printf
39 * @level: priority level (MSG_*) of the message
40 * @fmt: printf format string, followed by optional arguments
41 *
42 * This function is used to print conditional debugging and error messages. The
43 * output may be directed to stdout, stderr, and/or syslog based on
44 * configuration.
45 */
46 void
wpa_printf(int level,char * fmt,...)47 wpa_printf(int level, char *fmt, ...)
48 {
49 va_list ap;
50 char buffer[MAX_LOGBUF];
51
52 if (level < wpa_debug_level)
53 return;
54
55 va_start(ap, fmt);
56
57 /* LINTED E_SEC_PRINTF_VAR_FMT */
58 (void) vsnprintf(buffer, sizeof (buffer), fmt, ap);
59
60 va_end(ap);
61
62 syslog(LOG_NOTICE | LOG_DAEMON, "%s", buffer);
63 }
64
65 /*
66 * wpa_hexdump - conditional hex dump
67 * @level: priority level (MSG_*) of the message
68 * @title: title of for the message
69 * @buf: data buffer to be dumped
70 * @len: length of the @buf
71 *
72 * This function is used to print conditional debugging and error messages. The
73 * output may be directed to stdout, stderr, and/or syslog based on
74 * configuration. The contents of @buf is printed out has hex dump.
75 */
76 void
wpa_hexdump(int level,const char * title,const uint8_t * buf,size_t len)77 wpa_hexdump(int level, const char *title, const uint8_t *buf, size_t len)
78 {
79 size_t i;
80 char buffer[MAX_LOGBUF], tmp[4];
81 int n;
82
83 if (level < wpa_debug_level)
84 return;
85
86 (void) snprintf(buffer, sizeof (buffer), "%s - hexdump(len=%d):",
87 title, len);
88 n = strlen(buffer);
89
90 for (i = 0; i < len; i++) {
91 (void) sprintf(tmp, " %02x", buf[i]);
92
93 n += strlen(tmp);
94 if (n >= MAX_LOGBUF) break;
95
96 (void) strlcat(buffer, tmp, sizeof (buffer));
97 }
98
99 syslog(LOG_NOTICE | LOG_DAEMON, "%s", buffer);
100 }
101
102 static const char *
wpa_ssid_txt(char * ssid,size_t ssid_len)103 wpa_ssid_txt(char *ssid, size_t ssid_len)
104 {
105 static char ssid_txt[MAX_ESSID_LENGTH + 1];
106 char *pos;
107
108 if (ssid_len > MAX_ESSID_LENGTH)
109 ssid_len = MAX_ESSID_LENGTH;
110 (void) memcpy(ssid_txt, ssid, ssid_len);
111 ssid_txt[ssid_len] = '\0';
112 for (pos = ssid_txt; *pos != '\0'; pos ++) {
113 if ((uint8_t)*pos < 32 || (uint8_t)*pos >= 127)
114 *pos = '_';
115 }
116 return (ssid_txt);
117 }
118
119 /* ARGSUSED */
120 void
wpa_supplicant_scan(void * eloop_ctx,void * timeout_ctx)121 wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
122 {
123 struct wpa_supplicant *wpa_s = eloop_ctx;
124 struct wpa_ssid *ssid;
125
126 if (wpa_s->conf == NULL)
127 return;
128
129 if (wpa_s->wpa_state == WPA_DISCONNECTED)
130 wpa_s->wpa_state = WPA_SCANNING;
131
132 ssid = wpa_s->conf->ssid;
133 wpa_printf(MSG_DEBUG, "Starting AP scan (%s SSID)",
134 ssid ? "specific": "broadcast");
135
136 if (ssid) {
137 wpa_printf(MSG_DEBUG, "Scan SSID: %s", ssid->ssid);
138 }
139
140 if (wpa_s->driver->scan(wpa_s->handle, wpa_s->linkid)) {
141 wpa_printf(MSG_WARNING, "Failed to initiate AP scan.");
142 }
143 }
144
145 void
wpa_supplicant_req_scan(struct wpa_supplicant * wpa_s,int sec,int usec)146 wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
147 {
148 wpa_printf(MSG_DEBUG, "Setting scan request: %d sec %d usec",
149 sec, usec);
150 (void) eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
151 (void) eloop_register_timeout(sec, usec, wpa_supplicant_scan,
152 wpa_s, NULL);
153 }
154
155 void
wpa_supplicant_cancel_scan(struct wpa_supplicant * wpa_s)156 wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s)
157 {
158 wpa_printf(MSG_DEBUG, "Cancelling scan request");
159 eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
160 }
161
162 /* ARGSUSED */
163 static void
wpa_supplicant_timeout(void * eloop_ctx,void * timeout_ctx)164 wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
165 {
166 struct wpa_supplicant *wpa_s = eloop_ctx;
167
168 wpa_printf(MSG_INFO, "Authentication with " MACSTR " timed out.",
169 MAC2STR(wpa_s->bssid));
170
171 wpa_s->reassociate = 1;
172 wpa_supplicant_req_scan(wpa_s, 0, 0);
173 }
174
175 void
wpa_supplicant_req_auth_timeout(struct wpa_supplicant * wpa_s,int sec,int usec)176 wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
177 int sec, int usec)
178 {
179 wpa_printf(MSG_DEBUG, "Setting authentication timeout: %d sec "
180 "%d usec", sec, usec);
181 eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
182 (void) eloop_register_timeout(sec, usec, wpa_supplicant_timeout,
183 wpa_s, NULL);
184 }
185
186 void
wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant * wpa_s)187 wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
188 {
189 wpa_printf(MSG_DEBUG, "Cancelling authentication timeout");
190 eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
191 }
192
193 static void
wpa_supplicant_cleanup(struct wpa_supplicant * wpa_s)194 wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
195 {
196 l2_packet_deinit(wpa_s->l2);
197 wpa_s->l2 = NULL;
198
199 if (wpa_s->conf != NULL) {
200 wpa_config_free(wpa_s->conf);
201 wpa_s->conf = NULL;
202 }
203
204 dladm_close(wpa_s->handle);
205 free(wpa_s->ap_wpa_ie);
206 pmksa_candidate_free(wpa_s);
207 pmksa_cache_free(wpa_s);
208 }
209
210 static void
wpa_clear_keys(struct wpa_supplicant * wpa_s,uint8_t * addr)211 wpa_clear_keys(struct wpa_supplicant *wpa_s, uint8_t *addr)
212 {
213 wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, WPA_ALG_NONE,
214 (uint8_t *)"\xff\xff\xff\xff\xff\xff", 0, 0, NULL, 0, NULL, 0);
215 wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, WPA_ALG_NONE,
216 (uint8_t *)"\xff\xff\xff\xff\xff\xff", 1, 0, NULL, 0, NULL, 0);
217 wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, WPA_ALG_NONE,
218 (uint8_t *)"\xff\xff\xff\xff\xff\xff", 2, 0, NULL, 0, NULL, 0);
219 wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, WPA_ALG_NONE,
220 (uint8_t *)"\xff\xff\xff\xff\xff\xff", 3, 0, NULL, 0, NULL, 0);
221 if (addr) {
222 wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid,
223 WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL, 0);
224 }
225 }
226
227 static void
wpa_supplicant_mark_disassoc(struct wpa_supplicant * wpa_s)228 wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
229 {
230 wpa_s->wpa_state = WPA_DISCONNECTED;
231 (void) memset(wpa_s->bssid, 0, IEEE80211_ADDR_LEN);
232 }
233
234 static int
wpa_supplicant_set_suites(struct wpa_supplicant * wpa_s,dladm_wlan_ess_t * bss,struct wpa_ssid * ssid,uint8_t * wpa_ie,int * wpa_ie_len)235 wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
236 dladm_wlan_ess_t *bss, struct wpa_ssid *ssid,
237 uint8_t *wpa_ie, int *wpa_ie_len)
238 {
239 struct wpa_ie_data ie;
240 int sel, proto;
241 uint8_t *ap_ie;
242 size_t ap_ie_len;
243
244 /* RSN or WPA */
245 if (bss->we_wpa_ie_len && bss->we_wpa_ie[0] == RSN_INFO_ELEM &&
246 (ssid->proto & WPA_PROTO_RSN)) {
247 wpa_printf(MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
248 proto = WPA_PROTO_RSN;
249 } else {
250 wpa_printf(MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
251 proto = WPA_PROTO_WPA;
252 }
253
254 ap_ie = bss->we_wpa_ie;
255 ap_ie_len = bss->we_wpa_ie_len;
256
257 if (wpa_parse_wpa_ie(wpa_s, ap_ie, ap_ie_len, &ie)) {
258 wpa_printf(MSG_WARNING, "WPA: Failed to parse WPA IE for "
259 "the selected BSS.");
260 return (-1);
261 }
262
263 wpa_s->proto = proto;
264 free(wpa_s->ap_wpa_ie);
265 wpa_s->ap_wpa_ie = malloc(ap_ie_len);
266 (void) memcpy(wpa_s->ap_wpa_ie, ap_ie, ap_ie_len);
267 wpa_s->ap_wpa_ie_len = ap_ie_len;
268
269 sel = ie.group_cipher & ssid->group_cipher;
270 if (sel & WPA_CIPHER_CCMP) {
271 wpa_s->group_cipher = WPA_CIPHER_CCMP;
272 } else if (sel & WPA_CIPHER_TKIP) {
273 wpa_s->group_cipher = WPA_CIPHER_TKIP;
274 } else if (sel & WPA_CIPHER_WEP104) {
275 wpa_s->group_cipher = WPA_CIPHER_WEP104;
276 } else if (sel & WPA_CIPHER_WEP40) {
277 wpa_s->group_cipher = WPA_CIPHER_WEP40;
278 } else {
279 wpa_printf(MSG_WARNING, "WPA: Failed to select group cipher.");
280 return (-1);
281 }
282
283 sel = ie.pairwise_cipher & ssid->pairwise_cipher;
284 if (sel & WPA_CIPHER_CCMP) {
285 wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
286 } else if (sel & WPA_CIPHER_TKIP) {
287 wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
288 } else if (sel & WPA_CIPHER_NONE) {
289 wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
290 } else {
291 wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise "
292 "cipher.");
293 return (-1);
294 }
295
296 sel = ie.key_mgmt & ssid->key_mgmt;
297 if (sel & WPA_KEY_MGMT_IEEE8021X) {
298 wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
299 } else if (sel & WPA_KEY_MGMT_PSK) {
300 wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
301 } else {
302 wpa_printf(MSG_WARNING, "WPA: Failed to select authenticated "
303 "key management type.");
304 return (-1);
305 }
306
307 *wpa_ie_len = wpa_gen_wpa_ie(wpa_s, wpa_ie);
308 if (*wpa_ie_len < 0) {
309 wpa_printf(MSG_WARNING, "WPA: Failed to generate WPA IE.");
310 return (-1);
311 }
312 wpa_hexdump(MSG_DEBUG, "WPA: Own WPA IE", wpa_ie, *wpa_ie_len);
313
314 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
315 (void) memcpy(wpa_s->pmk, ssid->psk, PMK_LEN);
316 else if (wpa_s->cur_pmksa)
317 (void) memcpy(wpa_s->pmk, wpa_s->cur_pmksa->pmk, PMK_LEN);
318 else {
319 (void) memset(wpa_s->pmk, 0, PMK_LEN);
320 }
321
322 return (0);
323 }
324
wpa_supplicant_associate(struct wpa_supplicant * wpa_s,dladm_wlan_ess_t * bss,struct wpa_ssid * ssid)325 static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
326 dladm_wlan_ess_t *bss, struct wpa_ssid *ssid)
327 {
328 uint8_t wpa_ie[IEEE80211_MAX_OPT_IE];
329 int wpa_ie_len;
330
331 wpa_s->reassociate = 0;
332 wpa_printf(MSG_DEBUG, "Trying to associate with " MACSTR
333 " (SSID='%s' freq=%d MHz)", MAC2STR(bss->we_bssid.wb_bytes),
334 wpa_ssid_txt((char *)ssid->ssid, ssid->ssid_len), bss->we_freq);
335 wpa_supplicant_cancel_scan(wpa_s);
336
337 if (bss->we_wpa_ie_len &&
338 (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK))) {
339 wpa_s->cur_pmksa = pmksa_cache_get(wpa_s,
340 bss->we_bssid.wb_bytes, NULL);
341 if (wpa_s->cur_pmksa) {
342 wpa_hexdump(MSG_DEBUG, "RSN: PMKID",
343 wpa_s->cur_pmksa->pmkid, PMKID_LEN);
344 }
345 if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
346 wpa_ie, &wpa_ie_len)) {
347 wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key "
348 "management and encryption suites");
349 return;
350 }
351 } else {
352 wpa_ie_len = 0;
353 }
354
355 wpa_clear_keys(wpa_s, bss->we_bssid.wb_bytes);
356 wpa_s->wpa_state = WPA_ASSOCIATING;
357 wpa_s->driver->associate(wpa_s->handle, wpa_s->linkid,
358 (const char *)bss->we_bssid.wb_bytes, wpa_ie, wpa_ie_len);
359
360 /* Timeout for IEEE 802.11 authentication and association */
361 wpa_supplicant_req_auth_timeout(wpa_s, 15, 0);
362 }
363
364 void
wpa_supplicant_disassociate(struct wpa_supplicant * wpa_s,int reason_code)365 wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s, int reason_code)
366 {
367 uint8_t *addr = NULL;
368 wpa_s->wpa_state = WPA_DISCONNECTED;
369 if (memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00",
370 IEEE80211_ADDR_LEN) != 0) {
371 wpa_s->driver->disassociate(wpa_s->handle, wpa_s->linkid,
372 reason_code);
373 addr = wpa_s->bssid;
374 }
375 wpa_clear_keys(wpa_s, addr);
376 }
377
378 static dladm_wlan_ess_t *
wpa_supplicant_select_bss(struct wpa_supplicant * wpa_s,struct wpa_ssid * group,dladm_wlan_ess_t * results,int num,struct wpa_ssid ** selected_ssid)379 wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
380 dladm_wlan_ess_t *results, int num, struct wpa_ssid **selected_ssid)
381 {
382 struct wpa_ssid *ssid;
383 dladm_wlan_ess_t *bss, *selected = NULL;
384 int i;
385
386 struct wpa_ie_data ie;
387
388 wpa_printf(MSG_DEBUG, "Selecting BSS from scan results (%d)", num);
389
390 bss = NULL;
391 ssid = NULL;
392
393 /* try to find matched AP */
394 for (i = 0; i < num && !selected; i++) {
395 bss = &results[i];
396 wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
397 "wpa_ie_len=%d",
398 i, MAC2STR(bss->we_bssid.wb_bytes),
399 wpa_ssid_txt(bss->we_ssid.we_bytes, bss->we_ssid_len),
400 bss->we_wpa_ie_len);
401 if (bss->we_wpa_ie_len == 0) {
402 wpa_printf(MSG_DEBUG, " skip - no WPA/RSN IE");
403 }
404
405 ssid = group;
406 if (bss->we_ssid_len != ssid->ssid_len ||
407 memcmp(bss->we_ssid.we_bytes, ssid->ssid,
408 bss->we_ssid_len) != 0) {
409 wpa_printf(MSG_DEBUG, " skip - SSID mismatch");
410 continue;
411 }
412 if (!((ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_WPA)) &&
413 wpa_parse_wpa_ie(wpa_s, bss->we_wpa_ie,
414 bss->we_wpa_ie_len, &ie) == 0)) {
415 wpa_printf(MSG_DEBUG, " skip - "
416 "could not parse WPA/RSN IE");
417 continue;
418 }
419 if (!(ie.proto & ssid->proto)) {
420 wpa_printf(MSG_DEBUG, " skip - proto mismatch");
421 continue;
422 }
423 if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
424 wpa_printf(MSG_DEBUG, " skip - PTK cipher mismatch");
425 continue;
426 }
427 if (!(ie.group_cipher & ssid->group_cipher)) {
428 wpa_printf(MSG_DEBUG, " skip - GTK cipher mismatch");
429 continue;
430 }
431 if (!(ie.key_mgmt & ssid->key_mgmt)) {
432 wpa_printf(MSG_DEBUG, " skip - key mgmt mismatch");
433 continue;
434 }
435
436 selected = bss;
437 *selected_ssid = ssid;
438 wpa_printf(MSG_DEBUG, " selected");
439 }
440
441 return (selected);
442 }
443
444
445 static void
wpa_supplicant_scan_results(struct wpa_supplicant * wpa_s)446 wpa_supplicant_scan_results(struct wpa_supplicant *wpa_s)
447 {
448 dladm_wlan_ess_t results[MAX_SCANRESULTS];
449 int num;
450 dladm_wlan_ess_t *selected = NULL;
451 struct wpa_ssid *ssid;
452
453 (void) memset(results, 0, sizeof (dladm_wlan_ess_t) * MAX_SCANRESULTS);
454 num = wpa_s->driver->get_scan_results(wpa_s->handle, wpa_s->linkid,
455 results, MAX_SCANRESULTS);
456 wpa_printf(MSG_DEBUG, "Scan results: %d", num);
457 if (num < 0)
458 return;
459 if (num > MAX_SCANRESULTS) {
460 wpa_printf(MSG_INFO, "Not enough room for all APs (%d < %d)",
461 num, MAX_SCANRESULTS);
462 num = MAX_SCANRESULTS;
463 }
464
465 selected = wpa_supplicant_select_bss(wpa_s,
466 wpa_s->conf->ssid, results, num, &ssid);
467
468 if (selected) {
469 if (wpa_s->reassociate ||
470 memcmp(selected->we_bssid.wb_bytes, wpa_s->bssid,
471 IEEE80211_ADDR_LEN) != 0) {
472 wpa_supplicant_associate(wpa_s, selected, ssid);
473 } else {
474 wpa_printf(MSG_DEBUG, "Already associated with the "
475 "selected AP.");
476 }
477 } else {
478 wpa_printf(MSG_DEBUG, "No suitable AP found.");
479 wpa_supplicant_req_scan(wpa_s, 5, 0); /* wait 5 seconds */
480 }
481 }
482
483 /*
484 * wpa_event_handler - report a driver event for wpa_supplicant
485 * @wpa_s: pointer to wpa_supplicant data; this is the @ctx variable registered
486 * with wpa_driver_events_init()
487 * @event: event type (defined above)
488 *
489 * Driver wrapper code should call this function whenever an event is received
490 * from the driver.
491 */
492 void
wpa_event_handler(void * cookie,wpa_event_type event)493 wpa_event_handler(void *cookie, wpa_event_type event)
494 {
495 struct wpa_supplicant *wpa_s = cookie;
496
497 switch (event) {
498 case EVENT_ASSOC:
499 wpa_printf(MSG_DEBUG, "\nAssociation event\n");
500 /* async event */
501 if (wpa_s->wpa_state < WPA_ASSOCIATED) {
502 wpa_s->wpa_state = WPA_ASSOCIATED;
503 if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
504 wpa_supplicant_cancel_auth_timeout(wpa_s);
505 } else {
506 /* Timeout for receiving first EAPOL packet */
507 wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
508 }
509 }
510 break;
511 case EVENT_DISASSOC:
512 if (wpa_s->wpa_state >= WPA_ASSOCIATED)
513 wpa_supplicant_req_scan(wpa_s, 0, 100000);
514 wpa_supplicant_mark_disassoc(wpa_s);
515 wpa_printf(MSG_DEBUG, "Disconnect event - remove keys");
516 if (wpa_s->key_mgmt != WPA_KEY_MGMT_NONE)
517 wpa_clear_keys(wpa_s, wpa_s->bssid);
518 break;
519 case EVENT_SCAN_RESULTS:
520 wpa_supplicant_scan_results(wpa_s);
521 /* reset vars */
522 (void) memset(wpa_s->rx_replay_counter, 0,
523 WPA_REPLAY_COUNTER_LEN);
524 wpa_s->rx_replay_counter_set = 0;
525 wpa_s->renew_snonce = 1;
526 wpa_s->eapol_received = 0;
527 break;
528 default:
529 wpa_printf(MSG_INFO, "Unknown event %d", event);
530 break;
531 }
532 }
533
534 /* ARGSUSED */
535 static void
wpa_supplicant_terminate(int sig,void * eloop_ctx,void * signal_ctx)536 wpa_supplicant_terminate(int sig, void *eloop_ctx, void *signal_ctx)
537 {
538 wpa_printf(MSG_INFO, "Signal %d received - terminating", sig);
539 eloop_terminate();
540 }
541
542 static int
wpa_supplicant_driver_init(const char * link,struct wpa_supplicant * wpa_s)543 wpa_supplicant_driver_init(const char *link, struct wpa_supplicant *wpa_s)
544 {
545 wpa_s->l2 = l2_packet_init(link, ETHERTYPE_EAPOL,
546 wpa_supplicant_rx_eapol, wpa_s);
547 if (wpa_s->l2 == NULL)
548 return (-1);
549
550 if (l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
551 (void) fprintf(stderr, "Failed to get own L2 address\n");
552 return (-1);
553 }
554
555 if (wpa_s->driver->set_wpa(wpa_s->handle, wpa_s->linkid, 1) < 0) {
556 wpa_printf(MSG_ERROR, "Failed to enable WPA in the driver.");
557 return (-1);
558 }
559
560 wpa_clear_keys(wpa_s, NULL);
561 wpa_supplicant_req_scan(wpa_s, 0, 100000);
562
563 return (0);
564 }
565
566 static int door_id = -1;
567
568 /* ARGSUSED */
569 static void
event_handler(void * cookie,char * argp,size_t asize,door_desc_t * dp,uint_t n_desc)570 event_handler(void *cookie, char *argp, size_t asize,
571 door_desc_t *dp, uint_t n_desc)
572 {
573 wpa_event_type event;
574
575 /* LINTED E_BAD_PTR_CAST_ALIGN */
576 event = ((wl_events_t *)argp)->event;
577 wpa_event_handler(cookie, event);
578
579 (void) door_return(NULL, 0, NULL, 0);
580 }
581
582 /*
583 * Create the driver to wpad door
584 */
585 int
wpa_supplicant_door_setup(void * cookie,char * doorname)586 wpa_supplicant_door_setup(void *cookie, char *doorname)
587 {
588 struct stat stbuf;
589 int error = 0;
590
591 wpa_printf(MSG_DEBUG, "wpa_supplicant_door_setup(%s)", doorname);
592 /*
593 * Create the door
594 */
595 door_id = door_create(event_handler, cookie,
596 DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
597
598 if (door_id < 0) {
599 error = -1;
600 goto out;
601 }
602
603 if (stat(doorname, &stbuf) < 0) {
604 int newfd;
605 if ((newfd = creat(doorname, 0666)) < 0) {
606 (void) door_revoke(door_id);
607 door_id = -1;
608 error = -1;
609
610 goto out;
611 }
612 (void) close(newfd);
613 }
614
615 if (fattach(door_id, doorname) < 0) {
616 if ((errno != EBUSY) || (fdetach(doorname) < 0) ||
617 (fattach(door_id, doorname) < 0)) {
618 (void) door_revoke(door_id);
619 door_id = -1;
620 error = -1;
621
622 goto out;
623 }
624 }
625
626 out:
627 return (error);
628 }
629
630 void
wpa_supplicant_door_destroy(char * doorname)631 wpa_supplicant_door_destroy(char *doorname)
632 {
633 wpa_printf(MSG_DEBUG, "wpa_supplicant_door_destroy(%s)\n", doorname);
634
635 if (door_id == -1)
636 return;
637
638 if (door_revoke(door_id) == -1) {
639 wpa_printf(MSG_ERROR, "failed to door_revoke(%d) %s, exiting.",
640 door_id, strerror(errno));
641 }
642
643 if (fdetach(doorname) == -1) {
644 wpa_printf(MSG_ERROR, "failed to fdetach %s: %s, exiting.",
645 doorname, strerror(errno));
646 }
647
648 (void) close(door_id);
649 }
650
651 static int
wpa_config_parse_ssid(struct wpa_ssid * ssid,int line,const char * value)652 wpa_config_parse_ssid(struct wpa_ssid *ssid, int line, const char *value)
653 {
654 free(ssid->ssid);
655
656 ssid->ssid = (uint8_t *)strdup(value);
657 ssid->ssid_len = strlen(value);
658
659 if (ssid->ssid == NULL) {
660 wpa_printf(MSG_ERROR, "Invalid SSID '%s'.", line, value);
661 return (-1);
662 }
663 if (ssid->ssid_len > MAX_ESSID_LENGTH) {
664 free(ssid->ssid);
665 wpa_printf(MSG_ERROR, "Too long SSID '%s'.", line, value);
666 return (-1);
667 }
668 wpa_printf(MSG_MSGDUMP, "SSID: %s", ssid->ssid);
669 return (0);
670 }
671
672 static struct wpa_ssid *
wpa_config_read_network(struct wpa_supplicant * wpa_s)673 wpa_config_read_network(struct wpa_supplicant *wpa_s)
674 {
675 struct wpa_ssid *ssid;
676 char buf[MAX_ESSID_LENGTH + 1];
677 dladm_secobj_class_t cl;
678 uint8_t psk[MAX_PSK_LENGTH + 1];
679 uint_t key_len;
680
681 wpa_printf(MSG_MSGDUMP, "Start of a new network configration");
682
683 ssid = (struct wpa_ssid *)malloc(sizeof (*ssid));
684 if (ssid == NULL)
685 return (NULL);
686 (void) memset(ssid, 0, sizeof (*ssid));
687
688 /*
689 * Set default supported values
690 */
691 ssid->proto = WPA_PROTO_WPA | WPA_PROTO_RSN;
692 ssid->pairwise_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
693 ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP |
694 WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40;
695 ssid->key_mgmt = WPA_KEY_MGMT_PSK; /* | WPA_KEY_MGMT_IEEE8021X; */
696
697 (void) memset(buf, 0, MAX_ESSID_LENGTH + 1);
698 wpa_s->driver->get_ssid(wpa_s->handle, wpa_s->linkid, (char *)buf);
699
700 (void) wpa_config_parse_ssid(ssid, 0, buf);
701
702 key_len = sizeof (psk);
703 (void) dladm_get_secobj(wpa_s->handle, (const char *)wpa_s->kname, &cl,
704 psk, &key_len, DLADM_OPT_ACTIVE);
705 psk[key_len] = '\0';
706 ssid->passphrase = strdup((const char *)psk);
707
708 if (ssid->passphrase) {
709 pbkdf2_sha1(ssid->passphrase, (char *)ssid->ssid,
710 ssid->ssid_len, 4096, ssid->psk, PMK_LEN);
711 wpa_hexdump(MSG_MSGDUMP, "PSK (from passphrase)",
712 ssid->psk, PMK_LEN);
713 ssid->psk_set = 1;
714 }
715
716 if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) {
717 wpa_printf(MSG_ERROR, "WPA-PSK accepted for key "
718 "management, but no PSK configured.");
719 free(ssid);
720 ssid = NULL;
721 }
722
723 return (ssid);
724 }
725
726 struct wpa_config *
wpa_config_read(void * arg)727 wpa_config_read(void *arg)
728 {
729 struct wpa_ssid *ssid;
730 struct wpa_config *config;
731 struct wpa_supplicant *wpa_s = arg;
732
733 config = malloc(sizeof (*config));
734 if (config == NULL)
735 return (NULL);
736 (void) memset(config, 0, sizeof (*config));
737 config->eapol_version = 1; /* fixed value */
738
739 wpa_printf(MSG_DEBUG, "Reading configuration parameters from driver\n");
740
741 ssid = wpa_config_read_network(wpa_s);
742 if (ssid == NULL) {
743 wpa_config_free(config);
744 config = NULL;
745 } else {
746 config->ssid = ssid;
747 }
748
749 return (config);
750 }
751
752 void
wpa_config_free(struct wpa_config * config)753 wpa_config_free(struct wpa_config *config)
754 {
755 struct wpa_ssid *ssid = config->ssid;
756
757 if (ssid != NULL) {
758 free(ssid->ssid);
759 free(ssid->passphrase);
760 free(ssid);
761 }
762 free(config);
763 }
764
765 /*
766 * make sure wpad is running under SMF context.
767 */
768 static boolean_t
is_smf_context(void)769 is_smf_context(void)
770 {
771 char *fmri;
772
773 return (((fmri = getenv("SMF_FMRI")) != NULL) &&
774 (strstr(fmri, SERVICE_NAME) != NULL));
775 }
776
777 int
main(int argc,char * argv[])778 main(int argc, char *argv[])
779 {
780 struct wpa_supplicant wpa_s;
781 char *link = NULL;
782 char *key = NULL;
783 dlpi_handle_t dh = NULL;
784 datalink_id_t linkid;
785 dladm_phys_attr_t dpa;
786 int c;
787 int exitcode;
788 char door_file[MAXPATHLEN];
789 dladm_handle_t handle;
790
791 if (!is_smf_context()) {
792 (void) fprintf(stderr,
793 "wpad is an smf(5) managed service and cannot be run from "
794 "the command line; please use dladm(1M).\n");
795 return (SMF_EXIT_ERR_NOSMF);
796 }
797
798 for (;;) {
799 c = getopt(argc, argv, "i:k:");
800 if (c < 0)
801 break;
802 switch (c) {
803 case 'i':
804 link = optarg;
805 break;
806 case 'k':
807 key = optarg;
808 break;
809 default:
810 return (SMF_EXIT_ERR_CONFIG);
811 }
812 }
813
814 /*
815 * key name is required to retrieve PSK value through libwdladm APIs.
816 * key is saved by dladm command by keyname
817 * see dladm.
818 */
819 if ((link == NULL) || (key == NULL)) {
820 wpa_printf(MSG_ERROR, "\nLink & key is required.");
821 return (-1);
822 }
823
824 if ((strlen(key) >= sizeof (wpa_s.kname))) {
825 wpa_printf(MSG_ERROR, "Too long key name '%s'.", key);
826 return (-1);
827 }
828
829 if (daemon(0, 0))
830 return (-1);
831
832 /*
833 * Hold this link open to prevent a link renaming operation.
834 */
835 if (dlpi_open(link, &dh, 0) != DLPI_SUCCESS) {
836 wpa_printf(MSG_ERROR, "Failed to open link '%s'.", link);
837 return (-1);
838 }
839
840 /* This handle is stored in wpa_s when that struct is filled. */
841 if (dladm_open(&handle) != DLADM_STATUS_OK) {
842 wpa_printf(MSG_ERROR, "Failed to open dladm handle");
843 dlpi_close(dh);
844 return (-1);
845 }
846
847 if (dladm_name2info(handle, link, &linkid, NULL, NULL, NULL) !=
848 DLADM_STATUS_OK) {
849 wpa_printf(MSG_ERROR, "Invalid link name '%s'.", link);
850 dladm_close(handle);
851 dlpi_close(dh);
852 return (-1);
853 }
854
855 /*
856 * Get the device name of the link, which will be used as the door
857 * file name used to communicate with the driver. Note that different
858 * links use different doors.
859 */
860 if (dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_ACTIVE) !=
861 DLADM_STATUS_OK) {
862 wpa_printf(MSG_ERROR,
863 "Failed to get device name of link '%s'.", link);
864 dladm_close(handle);
865 dlpi_close(dh);
866 return (-1);
867 }
868 (void) snprintf(door_file, MAXPATHLEN, "%s_%s", WPA_DOOR, dpa.dp_dev);
869
870 (void) memset(&wpa_s, 0, sizeof (wpa_s));
871 wpa_s.driver = &wpa_driver_wifi_ops;
872 wpa_s.handle = handle;
873 wpa_s.linkid = linkid;
874 (void) strlcpy(wpa_s.kname, key, sizeof (wpa_s.kname));
875 eloop_init(&wpa_s);
876
877 /*
878 * Setup default WPA/WPA2 configuration
879 * get ESSID and PSK value
880 */
881 wpa_s.conf = wpa_config_read(&wpa_s);
882 if (wpa_s.conf == NULL || wpa_s.conf->ssid == NULL) {
883 wpa_printf(MSG_ERROR, "\nNo networks (SSID) configured.\n");
884 exitcode = -1;
885 goto cleanup;
886 }
887
888 exitcode = 0;
889
890 /*
891 * Setup door file to communicate with driver
892 */
893 if (wpa_supplicant_door_setup(&wpa_s, door_file) != 0) {
894 wpa_printf(MSG_ERROR, "Failed to setup door(%s)", door_file);
895 exitcode = -1;
896 goto cleanup;
897 }
898
899 wpa_s.renew_snonce = 1;
900 if (wpa_supplicant_driver_init(link, &wpa_s) < 0) {
901 exitcode = -1;
902 goto cleanup;
903 }
904
905 /*
906 * This link is hold again in wpa_supplicant_driver_init(), so that
907 * we release the first reference.
908 */
909 dlpi_close(dh);
910 dh = NULL;
911
912 wpa_printf(MSG_DEBUG, "=> eloop_run");
913
914 (void) eloop_register_signal(SIGINT, wpa_supplicant_terminate, NULL);
915 (void) eloop_register_signal(SIGTERM, wpa_supplicant_terminate, NULL);
916 (void) eloop_register_signal(SIGKILL, wpa_supplicant_terminate, NULL);
917
918 eloop_run();
919
920 wpa_printf(MSG_DEBUG, "<= eloop_run()");
921 wpa_supplicant_disassociate(&wpa_s, REASON_DEAUTH_LEAVING);
922
923 if (wpa_s.driver->set_wpa(wpa_s.handle, wpa_s.linkid, 0) < 0) {
924 wpa_printf(MSG_ERROR, "Failed to disable WPA in the driver.\n");
925 }
926
927 cleanup:
928 wpa_supplicant_door_destroy(door_file);
929 /* The libdladm handle is closed in the following method */
930 wpa_supplicant_cleanup(&wpa_s);
931 eloop_destroy();
932
933 if (dh != NULL)
934 dlpi_close(dh);
935
936 return (exitcode);
937 }
938