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 event = ((wl_events_t *)argp)->event; 584 wpa_event_handler(cookie, event); 585 586 (void) door_return(NULL, 0, NULL, 0); 587 } 588 589 /* 590 * Create the driver to wpad door 591 */ 592 int 593 wpa_supplicant_door_setup(void *cookie, char *doorname) 594 { 595 struct stat stbuf; 596 int error = 0; 597 598 wpa_printf(MSG_DEBUG, "wpa_supplicant_door_setup(%s)", doorname); 599 /* 600 * Create the door 601 */ 602 door_id = door_create(event_handler, cookie, 603 DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL); 604 605 if (door_id < 0) { 606 error = -1; 607 goto out; 608 } 609 610 if (stat(doorname, &stbuf) < 0) { 611 int newfd; 612 if ((newfd = creat(doorname, 0666)) < 0) { 613 (void) door_revoke(door_id); 614 door_id = -1; 615 error = -1; 616 617 goto out; 618 } 619 (void) close(newfd); 620 } 621 622 if (fattach(door_id, doorname) < 0) { 623 if ((errno != EBUSY) || (fdetach(doorname) < 0) || 624 (fattach(door_id, doorname) < 0)) { 625 (void) door_revoke(door_id); 626 door_id = -1; 627 error = -1; 628 629 goto out; 630 } 631 } 632 633 out: 634 return (error); 635 } 636 637 void 638 wpa_supplicant_door_destroy(char *doorname) 639 { 640 wpa_printf(MSG_DEBUG, "wpa_supplicant_door_destroy(%s)\n", doorname); 641 642 if (door_id == -1) 643 return; 644 645 if (door_revoke(door_id) == -1) { 646 wpa_printf(MSG_ERROR, "failed to door_revoke(%d) %s, exiting.", 647 door_id, strerror(errno)); 648 } 649 650 if (fdetach(doorname) == -1) { 651 wpa_printf(MSG_ERROR, "failed to fdetach %s: %s, exiting.", 652 doorname, strerror(errno)); 653 } 654 655 (void) close(door_id); 656 } 657 658 static int 659 wpa_config_parse_ssid(struct wpa_ssid *ssid, int line, const char *value) 660 { 661 free(ssid->ssid); 662 663 ssid->ssid = (uint8_t *)strdup(value); 664 ssid->ssid_len = strlen(value); 665 666 if (ssid->ssid == NULL) { 667 wpa_printf(MSG_ERROR, "Invalid SSID '%s'.", line, value); 668 return (-1); 669 } 670 if (ssid->ssid_len > MAX_ESSID_LENGTH) { 671 free(ssid->ssid); 672 wpa_printf(MSG_ERROR, "Too long SSID '%s'.", line, value); 673 return (-1); 674 } 675 wpa_printf(MSG_MSGDUMP, "SSID: %s", ssid->ssid); 676 return (0); 677 } 678 679 static struct wpa_ssid * 680 wpa_config_read_network(struct wpa_supplicant *wpa_s) 681 { 682 struct wpa_ssid *ssid; 683 char buf[MAX_ESSID_LENGTH + 1]; 684 dladm_secobj_class_t cl; 685 uint8_t psk[MAX_PSK_LENGTH + 1]; 686 uint_t key_len; 687 688 wpa_printf(MSG_MSGDUMP, "Start of a new network configration"); 689 690 ssid = (struct wpa_ssid *)malloc(sizeof (*ssid)); 691 if (ssid == NULL) 692 return (NULL); 693 (void) memset(ssid, 0, sizeof (*ssid)); 694 695 /* 696 * Set default supported values 697 */ 698 ssid->proto = WPA_PROTO_WPA | WPA_PROTO_RSN; 699 ssid->pairwise_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP; 700 ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | 701 WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40; 702 ssid->key_mgmt = WPA_KEY_MGMT_PSK; /* | WPA_KEY_MGMT_IEEE8021X; */ 703 704 (void) memset(buf, 0, MAX_ESSID_LENGTH + 1); 705 wpa_s->driver->get_ssid(wpa_s->linkid, (char *)buf); 706 707 (void) wpa_config_parse_ssid(ssid, 0, buf); 708 709 key_len = sizeof (psk); 710 (void) dladm_get_secobj((const char *)wpa_s->kname, &cl, psk, &key_len, 711 DLADM_OPT_ACTIVE); 712 psk[key_len] = '\0'; 713 ssid->passphrase = strdup((const char *)psk); 714 715 if (ssid->passphrase) { 716 pbkdf2_sha1(ssid->passphrase, (char *)ssid->ssid, 717 ssid->ssid_len, 4096, ssid->psk, PMK_LEN); 718 wpa_hexdump(MSG_MSGDUMP, "PSK (from passphrase)", 719 ssid->psk, PMK_LEN); 720 ssid->psk_set = 1; 721 } 722 723 if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) { 724 wpa_printf(MSG_ERROR, "WPA-PSK accepted for key " 725 "management, but no PSK configured."); 726 free(ssid); 727 ssid = NULL; 728 } 729 730 return (ssid); 731 } 732 733 struct wpa_config * 734 wpa_config_read(void *arg) 735 { 736 struct wpa_ssid *ssid; 737 struct wpa_config *config; 738 struct wpa_supplicant *wpa_s = arg; 739 740 config = malloc(sizeof (*config)); 741 if (config == NULL) 742 return (NULL); 743 (void) memset(config, 0, sizeof (*config)); 744 config->eapol_version = 1; /* fixed value */ 745 746 wpa_printf(MSG_DEBUG, "Reading configuration parameters from driver\n"); 747 748 ssid = wpa_config_read_network(wpa_s); 749 if (ssid == NULL) { 750 wpa_config_free(config); 751 config = NULL; 752 } else { 753 config->ssid = ssid; 754 } 755 756 return (config); 757 } 758 759 void 760 wpa_config_free(struct wpa_config *config) 761 { 762 struct wpa_ssid *ssid = config->ssid; 763 764 if (ssid != NULL) { 765 free(ssid->ssid); 766 free(ssid->passphrase); 767 free(ssid); 768 } 769 free(config); 770 } 771 772 static int 773 daemon(boolean_t nochdir, boolean_t noclose) 774 { 775 int retv; 776 777 if ((retv = fork()) == -1) 778 return (-1); 779 if (retv != 0) 780 _exit(EXIT_SUCCESS); 781 if (setsid() == -1) 782 return (-1); 783 784 if (!nochdir && chdir("/") == -1) 785 return (-1); 786 787 if (!noclose) { 788 (void) close(0); 789 (void) close(1); 790 (void) close(2); 791 if ((retv = open("/dev/null", O_RDWR)) != -1) { 792 (void) dup2(retv, 1); 793 (void) dup2(retv, 2); 794 } 795 } 796 797 return (0); 798 } 799 800 /* 801 * make sure wpad is running under SMF context. 802 */ 803 static boolean_t 804 is_smf_context(void) 805 { 806 char *fmri; 807 808 return (((fmri = getenv("SMF_FMRI")) != NULL) && 809 (strstr(fmri, SERVICE_NAME) != NULL)); 810 } 811 812 int 813 main(int argc, char *argv[]) 814 { 815 struct wpa_supplicant wpa_s; 816 char *link = NULL; 817 char *key = NULL; 818 dlpi_handle_t dh = NULL; 819 datalink_id_t linkid; 820 dladm_phys_attr_t dpa; 821 int c; 822 int exitcode; 823 char door_file[MAXPATHLEN]; 824 825 if (!is_smf_context()) { 826 (void) fprintf(stderr, 827 "wpad is an smf(5) managed service and cannot be run from " 828 "the command line; please use dladm(1M).\n"); 829 return (SMF_EXIT_ERR_NOSMF); 830 } 831 832 for (;;) { 833 c = getopt(argc, argv, "i:k:"); 834 if (c < 0) 835 break; 836 switch (c) { 837 case 'i': 838 link = optarg; 839 break; 840 case 'k': 841 key = optarg; 842 break; 843 default: 844 return (SMF_EXIT_ERR_CONFIG); 845 } 846 } 847 848 /* 849 * key name is required to retrieve PSK value through libwdladm APIs. 850 * key is saved by dladm command by keyname 851 * see dladm. 852 */ 853 if ((link == NULL) || (key == NULL)) { 854 wpa_printf(MSG_ERROR, "\nLink & key is required."); 855 return (-1); 856 } 857 858 if ((strlen(key) >= sizeof (wpa_s.kname))) { 859 wpa_printf(MSG_ERROR, "Too long key name '%s'.", key); 860 return (-1); 861 } 862 863 if (daemon(0, 0)) 864 return (-1); 865 866 /* 867 * Hold this link open to prevent a link renaming operation. 868 */ 869 if (dlpi_open(link, &dh, 0) != DLPI_SUCCESS) { 870 wpa_printf(MSG_ERROR, "Failed to open link '%s'.", link); 871 return (-1); 872 } 873 874 if (dladm_name2info(link, &linkid, NULL, NULL, NULL) != 875 DLADM_STATUS_OK) { 876 wpa_printf(MSG_ERROR, "Invalid link name '%s'.", link); 877 dlpi_close(dh); 878 return (-1); 879 } 880 881 /* 882 * Get the device name of the link, which will be used as the door 883 * file name used to communicate with the driver. Note that different 884 * links use different doors. 885 */ 886 if (dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE) != 887 DLADM_STATUS_OK) { 888 wpa_printf(MSG_ERROR, 889 "Failed to get device name of link '%s'.", link); 890 dlpi_close(dh); 891 return (-1); 892 } 893 (void) snprintf(door_file, MAXPATHLEN, "%s_%s", WPA_DOOR, dpa.dp_dev); 894 895 (void) memset(&wpa_s, 0, sizeof (wpa_s)); 896 wpa_s.driver = &wpa_driver_wifi_ops; 897 wpa_s.linkid = linkid; 898 (void) strlcpy(wpa_s.kname, key, sizeof (wpa_s.kname)); 899 eloop_init(&wpa_s); 900 901 /* 902 * Setup default WPA/WPA2 configuration 903 * get ESSID and PSK value 904 */ 905 wpa_s.conf = wpa_config_read(&wpa_s); 906 if (wpa_s.conf == NULL || wpa_s.conf->ssid == NULL) { 907 wpa_printf(MSG_ERROR, "\nNo networks (SSID) configured.\n"); 908 exitcode = -1; 909 goto cleanup; 910 } 911 912 exitcode = 0; 913 914 /* 915 * Setup door file to communicate with driver 916 */ 917 if (wpa_supplicant_door_setup(&wpa_s, door_file) != 0) { 918 wpa_printf(MSG_ERROR, "Failed to setup door(%s)", door_file); 919 exitcode = -1; 920 goto cleanup; 921 } 922 923 wpa_s.renew_snonce = 1; 924 if (wpa_supplicant_driver_init(link, &wpa_s) < 0) { 925 exitcode = -1; 926 goto cleanup; 927 } 928 929 /* 930 * This link is hold again in wpa_supplicant_driver_init(), so that 931 * we release the first reference. 932 */ 933 dlpi_close(dh); 934 dh = NULL; 935 936 wpa_printf(MSG_DEBUG, "=> eloop_run"); 937 938 (void) eloop_register_signal(SIGINT, wpa_supplicant_terminate, NULL); 939 (void) eloop_register_signal(SIGTERM, wpa_supplicant_terminate, NULL); 940 (void) eloop_register_signal(SIGKILL, wpa_supplicant_terminate, NULL); 941 942 eloop_run(); 943 944 wpa_printf(MSG_DEBUG, "<= eloop_run()"); 945 wpa_supplicant_disassociate(&wpa_s, REASON_DEAUTH_LEAVING); 946 947 if (wpa_s.driver->set_wpa(wpa_s.linkid, 0) < 0) { 948 wpa_printf(MSG_ERROR, "Failed to disable WPA in the driver.\n"); 949 } 950 951 cleanup: 952 wpa_supplicant_door_destroy(door_file); 953 wpa_supplicant_cleanup(&wpa_s); 954 eloop_destroy(); 955 956 if (dh != NULL) 957 dlpi_close(dh); 958 959 return (exitcode); 960 } 961