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