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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 * 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 * 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 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 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 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(7) managed service and cannot be run from " 794 "the command line; please use dladm(8).\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