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