1 /* 2 * WPA Supplicant / UNIX domain socket -based control interface 3 * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15 #include "includes.h" 16 #include <sys/un.h> 17 #include <sys/stat.h> 18 #include <grp.h> 19 20 #include "common.h" 21 #include "eloop.h" 22 #include "config.h" 23 #include "eapol_supp/eapol_supp_sm.h" 24 #include "wpa_supplicant_i.h" 25 #include "ctrl_iface.h" 26 27 /* Per-interface ctrl_iface */ 28 29 /** 30 * struct wpa_ctrl_dst - Internal data structure of control interface monitors 31 * 32 * This structure is used to store information about registered control 33 * interface monitors into struct wpa_supplicant. This data is private to 34 * ctrl_iface_unix.c and should not be touched directly from other files. 35 */ 36 struct wpa_ctrl_dst { 37 struct wpa_ctrl_dst *next; 38 struct sockaddr_un addr; 39 socklen_t addrlen; 40 int debug_level; 41 int errors; 42 }; 43 44 45 struct ctrl_iface_priv { 46 struct wpa_supplicant *wpa_s; 47 int sock; 48 struct wpa_ctrl_dst *ctrl_dst; 49 }; 50 51 52 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 53 int level, const char *buf, 54 size_t len); 55 56 57 static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv, 58 struct sockaddr_un *from, 59 socklen_t fromlen) 60 { 61 struct wpa_ctrl_dst *dst; 62 63 dst = os_zalloc(sizeof(*dst)); 64 if (dst == NULL) 65 return -1; 66 os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); 67 dst->addrlen = fromlen; 68 dst->debug_level = MSG_INFO; 69 dst->next = priv->ctrl_dst; 70 priv->ctrl_dst = dst; 71 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached", 72 (u8 *) from->sun_path, fromlen - sizeof(from->sun_family)); 73 return 0; 74 } 75 76 77 static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv, 78 struct sockaddr_un *from, 79 socklen_t fromlen) 80 { 81 struct wpa_ctrl_dst *dst, *prev = NULL; 82 83 dst = priv->ctrl_dst; 84 while (dst) { 85 if (fromlen == dst->addrlen && 86 os_memcmp(from->sun_path, dst->addr.sun_path, 87 fromlen - sizeof(from->sun_family)) == 0) { 88 if (prev == NULL) 89 priv->ctrl_dst = dst->next; 90 else 91 prev->next = dst->next; 92 os_free(dst); 93 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached", 94 (u8 *) from->sun_path, 95 fromlen - sizeof(from->sun_family)); 96 return 0; 97 } 98 prev = dst; 99 dst = dst->next; 100 } 101 return -1; 102 } 103 104 105 static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, 106 struct sockaddr_un *from, 107 socklen_t fromlen, 108 char *level) 109 { 110 struct wpa_ctrl_dst *dst; 111 112 wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); 113 114 dst = priv->ctrl_dst; 115 while (dst) { 116 if (fromlen == dst->addrlen && 117 os_memcmp(from->sun_path, dst->addr.sun_path, 118 fromlen - sizeof(from->sun_family)) == 0) { 119 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor " 120 "level", (u8 *) from->sun_path, 121 fromlen - sizeof(from->sun_family)); 122 dst->debug_level = atoi(level); 123 return 0; 124 } 125 dst = dst->next; 126 } 127 128 return -1; 129 } 130 131 132 static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, 133 void *sock_ctx) 134 { 135 struct wpa_supplicant *wpa_s = eloop_ctx; 136 struct ctrl_iface_priv *priv = sock_ctx; 137 char buf[256]; 138 int res; 139 struct sockaddr_un from; 140 socklen_t fromlen = sizeof(from); 141 char *reply = NULL; 142 size_t reply_len = 0; 143 int new_attached = 0; 144 145 res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 146 (struct sockaddr *) &from, &fromlen); 147 if (res < 0) { 148 perror("recvfrom(ctrl_iface)"); 149 return; 150 } 151 buf[res] = '\0'; 152 153 if (os_strcmp(buf, "ATTACH") == 0) { 154 if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen)) 155 reply_len = 1; 156 else { 157 new_attached = 1; 158 reply_len = 2; 159 } 160 } else if (os_strcmp(buf, "DETACH") == 0) { 161 if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen)) 162 reply_len = 1; 163 else 164 reply_len = 2; 165 } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { 166 if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen, 167 buf + 6)) 168 reply_len = 1; 169 else 170 reply_len = 2; 171 } else { 172 reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf, 173 &reply_len); 174 } 175 176 if (reply) { 177 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, 178 fromlen); 179 os_free(reply); 180 } else if (reply_len == 1) { 181 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, 182 fromlen); 183 } else if (reply_len == 2) { 184 sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, 185 fromlen); 186 } 187 188 if (new_attached) 189 eapol_sm_notify_ctrl_attached(wpa_s->eapol); 190 } 191 192 193 static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s) 194 { 195 char *buf; 196 size_t len; 197 char *pbuf, *dir = NULL, *gid_str = NULL; 198 int res; 199 200 if (wpa_s->conf->ctrl_interface == NULL) 201 return NULL; 202 203 pbuf = os_strdup(wpa_s->conf->ctrl_interface); 204 if (pbuf == NULL) 205 return NULL; 206 if (os_strncmp(pbuf, "DIR=", 4) == 0) { 207 dir = pbuf + 4; 208 gid_str = os_strstr(dir, " GROUP="); 209 if (gid_str) { 210 *gid_str = '\0'; 211 gid_str += 7; 212 } 213 } else 214 dir = pbuf; 215 216 len = os_strlen(dir) + os_strlen(wpa_s->ifname) + 2; 217 buf = os_malloc(len); 218 if (buf == NULL) { 219 os_free(pbuf); 220 return NULL; 221 } 222 223 res = os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname); 224 if (res < 0 || (size_t) res >= len) { 225 os_free(pbuf); 226 os_free(buf); 227 return NULL; 228 } 229 #ifdef __CYGWIN__ 230 { 231 /* Windows/WinPcap uses interface names that are not suitable 232 * as a file name - convert invalid chars to underscores */ 233 char *pos = buf; 234 while (*pos) { 235 if (*pos == '\\') 236 *pos = '_'; 237 pos++; 238 } 239 } 240 #endif /* __CYGWIN__ */ 241 os_free(pbuf); 242 return buf; 243 } 244 245 246 static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, 247 const char *txt, size_t len) 248 { 249 struct wpa_supplicant *wpa_s = ctx; 250 if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) 251 return; 252 wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); 253 } 254 255 256 struct ctrl_iface_priv * 257 wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) 258 { 259 struct ctrl_iface_priv *priv; 260 struct sockaddr_un addr; 261 char *fname = NULL; 262 gid_t gid = 0; 263 int gid_set = 0; 264 char *buf, *dir = NULL, *gid_str = NULL; 265 struct group *grp; 266 char *endp; 267 268 priv = os_zalloc(sizeof(*priv)); 269 if (priv == NULL) 270 return NULL; 271 priv->wpa_s = wpa_s; 272 priv->sock = -1; 273 274 if (wpa_s->conf->ctrl_interface == NULL) 275 return priv; 276 277 buf = os_strdup(wpa_s->conf->ctrl_interface); 278 if (buf == NULL) 279 goto fail; 280 if (os_strncmp(buf, "DIR=", 4) == 0) { 281 dir = buf + 4; 282 gid_str = os_strstr(dir, " GROUP="); 283 if (gid_str) { 284 *gid_str = '\0'; 285 gid_str += 7; 286 } 287 } else { 288 dir = buf; 289 gid_str = wpa_s->conf->ctrl_interface_group; 290 } 291 292 if (mkdir(dir, S_IRWXU | S_IRWXG) < 0) { 293 if (errno == EEXIST) { 294 wpa_printf(MSG_DEBUG, "Using existing control " 295 "interface directory."); 296 } else { 297 perror("mkdir[ctrl_interface]"); 298 goto fail; 299 } 300 } 301 302 if (gid_str) { 303 grp = getgrnam(gid_str); 304 if (grp) { 305 gid = grp->gr_gid; 306 gid_set = 1; 307 wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d" 308 " (from group name '%s')", 309 (int) gid, gid_str); 310 } else { 311 /* Group name not found - try to parse this as gid */ 312 gid = strtol(gid_str, &endp, 10); 313 if (*gid_str == '\0' || *endp != '\0') { 314 wpa_printf(MSG_ERROR, "CTRL: Invalid group " 315 "'%s'", gid_str); 316 goto fail; 317 } 318 gid_set = 1; 319 wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", 320 (int) gid); 321 } 322 } 323 324 if (gid_set && chown(dir, -1, gid) < 0) { 325 perror("chown[ctrl_interface]"); 326 goto fail; 327 } 328 329 if (os_strlen(dir) + 1 + os_strlen(wpa_s->ifname) >= 330 sizeof(addr.sun_path)) { 331 wpa_printf(MSG_ERROR, "ctrl_iface path limit exceeded"); 332 goto fail; 333 } 334 335 priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); 336 if (priv->sock < 0) { 337 perror("socket(PF_UNIX)"); 338 goto fail; 339 } 340 341 os_memset(&addr, 0, sizeof(addr)); 342 addr.sun_family = AF_UNIX; 343 fname = wpa_supplicant_ctrl_iface_path(wpa_s); 344 if (fname == NULL) 345 goto fail; 346 os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); 347 if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 348 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", 349 strerror(errno)); 350 if (connect(priv->sock, (struct sockaddr *) &addr, 351 sizeof(addr)) < 0) { 352 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" 353 " allow connections - assuming it was left" 354 "over from forced program termination"); 355 if (unlink(fname) < 0) { 356 perror("unlink[ctrl_iface]"); 357 wpa_printf(MSG_ERROR, "Could not unlink " 358 "existing ctrl_iface socket '%s'", 359 fname); 360 goto fail; 361 } 362 if (bind(priv->sock, (struct sockaddr *) &addr, 363 sizeof(addr)) < 0) { 364 perror("bind(PF_UNIX)"); 365 goto fail; 366 } 367 wpa_printf(MSG_DEBUG, "Successfully replaced leftover " 368 "ctrl_iface socket '%s'", fname); 369 } else { 370 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " 371 "be in use - cannot override it"); 372 wpa_printf(MSG_INFO, "Delete '%s' manually if it is " 373 "not used anymore", fname); 374 os_free(fname); 375 fname = NULL; 376 goto fail; 377 } 378 } 379 380 if (gid_set && chown(fname, -1, gid) < 0) { 381 perror("chown[ctrl_interface/ifname]"); 382 goto fail; 383 } 384 385 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { 386 perror("chmod[ctrl_interface/ifname]"); 387 goto fail; 388 } 389 os_free(fname); 390 391 eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, 392 wpa_s, priv); 393 wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); 394 395 os_free(buf); 396 return priv; 397 398 fail: 399 if (priv->sock >= 0) 400 close(priv->sock); 401 os_free(priv); 402 if (fname) { 403 unlink(fname); 404 os_free(fname); 405 } 406 os_free(buf); 407 return NULL; 408 } 409 410 411 void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) 412 { 413 struct wpa_ctrl_dst *dst, *prev; 414 415 if (priv->sock > -1) { 416 char *fname; 417 char *buf, *dir = NULL, *gid_str = NULL; 418 eloop_unregister_read_sock(priv->sock); 419 if (priv->ctrl_dst) { 420 /* 421 * Wait a second before closing the control socket if 422 * there are any attached monitors in order to allow 423 * them to receive any pending messages. 424 */ 425 wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached " 426 "monitors to receive messages"); 427 os_sleep(1, 0); 428 } 429 close(priv->sock); 430 priv->sock = -1; 431 fname = wpa_supplicant_ctrl_iface_path(priv->wpa_s); 432 if (fname) { 433 unlink(fname); 434 os_free(fname); 435 } 436 437 buf = os_strdup(priv->wpa_s->conf->ctrl_interface); 438 if (buf == NULL) 439 goto free_dst; 440 if (os_strncmp(buf, "DIR=", 4) == 0) { 441 dir = buf + 4; 442 gid_str = os_strstr(dir, " GROUP="); 443 if (gid_str) { 444 *gid_str = '\0'; 445 gid_str += 7; 446 } 447 } else 448 dir = buf; 449 450 if (rmdir(dir) < 0) { 451 if (errno == ENOTEMPTY) { 452 wpa_printf(MSG_DEBUG, "Control interface " 453 "directory not empty - leaving it " 454 "behind"); 455 } else { 456 perror("rmdir[ctrl_interface]"); 457 } 458 } 459 os_free(buf); 460 } 461 462 free_dst: 463 dst = priv->ctrl_dst; 464 while (dst) { 465 prev = dst; 466 dst = dst->next; 467 os_free(prev); 468 } 469 os_free(priv); 470 } 471 472 473 /** 474 * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors 475 * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init() 476 * @level: Priority level of the message 477 * @buf: Message data 478 * @len: Message length 479 * 480 * Send a packet to all monitor programs attached to the control interface. 481 */ 482 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 483 int level, const char *buf, 484 size_t len) 485 { 486 struct wpa_ctrl_dst *dst, *next; 487 char levelstr[10]; 488 int idx, res; 489 struct msghdr msg; 490 struct iovec io[2]; 491 492 dst = priv->ctrl_dst; 493 if (priv->sock < 0 || dst == NULL) 494 return; 495 496 res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); 497 if (res < 0 || (size_t) res >= sizeof(levelstr)) 498 return; 499 io[0].iov_base = levelstr; 500 io[0].iov_len = os_strlen(levelstr); 501 io[1].iov_base = (char *) buf; 502 io[1].iov_len = len; 503 os_memset(&msg, 0, sizeof(msg)); 504 msg.msg_iov = io; 505 msg.msg_iovlen = 2; 506 507 idx = 0; 508 while (dst) { 509 next = dst->next; 510 if (level >= dst->debug_level) { 511 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send", 512 (u8 *) dst->addr.sun_path, dst->addrlen - 513 sizeof(dst->addr.sun_family)); 514 msg.msg_name = (void *) &dst->addr; 515 msg.msg_namelen = dst->addrlen; 516 if (sendmsg(priv->sock, &msg, 0) < 0) { 517 perror("sendmsg(CTRL_IFACE monitor)"); 518 dst->errors++; 519 if (dst->errors > 10) { 520 wpa_supplicant_ctrl_iface_detach( 521 priv, &dst->addr, 522 dst->addrlen); 523 } 524 } else 525 dst->errors = 0; 526 } 527 idx++; 528 dst = next; 529 } 530 } 531 532 533 void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) 534 { 535 char buf[256]; 536 int res; 537 struct sockaddr_un from; 538 socklen_t fromlen = sizeof(from); 539 540 for (;;) { 541 wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to " 542 "attach", priv->wpa_s->ifname); 543 eloop_wait_for_read_sock(priv->sock); 544 545 res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0, 546 (struct sockaddr *) &from, &fromlen); 547 if (res < 0) { 548 perror("recvfrom(ctrl_iface)"); 549 continue; 550 } 551 buf[res] = '\0'; 552 553 if (os_strcmp(buf, "ATTACH") == 0) { 554 /* handle ATTACH signal of first monitor interface */ 555 if (!wpa_supplicant_ctrl_iface_attach(priv, &from, 556 fromlen)) { 557 sendto(priv->sock, "OK\n", 3, 0, 558 (struct sockaddr *) &from, fromlen); 559 /* OK to continue */ 560 return; 561 } else { 562 sendto(priv->sock, "FAIL\n", 5, 0, 563 (struct sockaddr *) &from, fromlen); 564 } 565 } else { 566 /* return FAIL for all other signals */ 567 sendto(priv->sock, "FAIL\n", 5, 0, 568 (struct sockaddr *) &from, fromlen); 569 } 570 } 571 } 572 573 574 /* Global ctrl_iface */ 575 576 struct ctrl_iface_global_priv { 577 struct wpa_global *global; 578 int sock; 579 }; 580 581 582 static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, 583 void *sock_ctx) 584 { 585 struct wpa_global *global = eloop_ctx; 586 char buf[256]; 587 int res; 588 struct sockaddr_un from; 589 socklen_t fromlen = sizeof(from); 590 char *reply; 591 size_t reply_len; 592 593 res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 594 (struct sockaddr *) &from, &fromlen); 595 if (res < 0) { 596 perror("recvfrom(ctrl_iface)"); 597 return; 598 } 599 buf[res] = '\0'; 600 601 reply = wpa_supplicant_global_ctrl_iface_process(global, buf, 602 &reply_len); 603 604 if (reply) { 605 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, 606 fromlen); 607 os_free(reply); 608 } else if (reply_len) { 609 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, 610 fromlen); 611 } 612 } 613 614 615 struct ctrl_iface_global_priv * 616 wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) 617 { 618 struct ctrl_iface_global_priv *priv; 619 struct sockaddr_un addr; 620 621 priv = os_zalloc(sizeof(*priv)); 622 if (priv == NULL) 623 return NULL; 624 priv->global = global; 625 priv->sock = -1; 626 627 if (global->params.ctrl_interface == NULL) 628 return priv; 629 630 wpa_printf(MSG_DEBUG, "Global control interface '%s'", 631 global->params.ctrl_interface); 632 633 priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); 634 if (priv->sock < 0) { 635 perror("socket(PF_UNIX)"); 636 goto fail; 637 } 638 639 os_memset(&addr, 0, sizeof(addr)); 640 addr.sun_family = AF_UNIX; 641 os_strlcpy(addr.sun_path, global->params.ctrl_interface, 642 sizeof(addr.sun_path)); 643 if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 644 perror("bind(PF_UNIX)"); 645 if (connect(priv->sock, (struct sockaddr *) &addr, 646 sizeof(addr)) < 0) { 647 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" 648 " allow connections - assuming it was left" 649 "over from forced program termination"); 650 if (unlink(global->params.ctrl_interface) < 0) { 651 perror("unlink[ctrl_iface]"); 652 wpa_printf(MSG_ERROR, "Could not unlink " 653 "existing ctrl_iface socket '%s'", 654 global->params.ctrl_interface); 655 goto fail; 656 } 657 if (bind(priv->sock, (struct sockaddr *) &addr, 658 sizeof(addr)) < 0) { 659 perror("bind(PF_UNIX)"); 660 goto fail; 661 } 662 wpa_printf(MSG_DEBUG, "Successfully replaced leftover " 663 "ctrl_iface socket '%s'", 664 global->params.ctrl_interface); 665 } else { 666 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " 667 "be in use - cannot override it"); 668 wpa_printf(MSG_INFO, "Delete '%s' manually if it is " 669 "not used anymore", 670 global->params.ctrl_interface); 671 goto fail; 672 } 673 } 674 675 eloop_register_read_sock(priv->sock, 676 wpa_supplicant_global_ctrl_iface_receive, 677 global, NULL); 678 679 return priv; 680 681 fail: 682 if (priv->sock >= 0) 683 close(priv->sock); 684 os_free(priv); 685 return NULL; 686 } 687 688 689 void 690 wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) 691 { 692 if (priv->sock >= 0) { 693 eloop_unregister_read_sock(priv->sock); 694 close(priv->sock); 695 } 696 if (priv->global->params.ctrl_interface) 697 unlink(priv->global->params.ctrl_interface); 698 os_free(priv); 699 } 700