00001
00016 #include "includes.h"
00017 #include <sys/un.h>
00018 #include <sys/stat.h>
00019 #include <grp.h>
00020
00021 #include "common.h"
00022 #include "eloop.h"
00023 #include "config.h"
00024 #include "eapol_sm.h"
00025 #include "wpa_supplicant_i.h"
00026 #include "ctrl_iface.h"
00027
00028
00029
00038 struct wpa_ctrl_dst {
00039 struct wpa_ctrl_dst *next;
00040 struct sockaddr_un addr;
00041 socklen_t addrlen;
00042 int debug_level;
00043 int errors;
00044 };
00045
00046
00047 struct ctrl_iface_priv {
00048 struct wpa_supplicant *wpa_s;
00049 int sock;
00050 struct wpa_ctrl_dst *ctrl_dst;
00051 };
00052
00053
00054 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
00055 int level, const char *buf,
00056 size_t len);
00057
00058
00059 static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
00060 struct sockaddr_un *from,
00061 socklen_t fromlen)
00062 {
00063 struct wpa_ctrl_dst *dst;
00064
00065 dst = os_zalloc(sizeof(*dst));
00066 if (dst == NULL)
00067 return -1;
00068 os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
00069 dst->addrlen = fromlen;
00070 dst->debug_level = MSG_INFO;
00071 dst->next = priv->ctrl_dst;
00072 priv->ctrl_dst = dst;
00073 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
00074 (u8 *) from->sun_path, fromlen - sizeof(from->sun_family));
00075 return 0;
00076 }
00077
00078
00079 static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
00080 struct sockaddr_un *from,
00081 socklen_t fromlen)
00082 {
00083 struct wpa_ctrl_dst *dst, *prev = NULL;
00084
00085 dst = priv->ctrl_dst;
00086 while (dst) {
00087 if (fromlen == dst->addrlen &&
00088 os_memcmp(from->sun_path, dst->addr.sun_path,
00089 fromlen - sizeof(from->sun_family)) == 0) {
00090 if (prev == NULL)
00091 priv->ctrl_dst = dst->next;
00092 else
00093 prev->next = dst->next;
00094 os_free(dst);
00095 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
00096 (u8 *) from->sun_path,
00097 fromlen - sizeof(from->sun_family));
00098 return 0;
00099 }
00100 prev = dst;
00101 dst = dst->next;
00102 }
00103 return -1;
00104 }
00105
00106
00107 static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
00108 struct sockaddr_un *from,
00109 socklen_t fromlen,
00110 char *level)
00111 {
00112 struct wpa_ctrl_dst *dst;
00113
00114 wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
00115
00116 dst = priv->ctrl_dst;
00117 while (dst) {
00118 if (fromlen == dst->addrlen &&
00119 os_memcmp(from->sun_path, dst->addr.sun_path,
00120 fromlen - sizeof(from->sun_family)) == 0) {
00121 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
00122 "level", (u8 *) from->sun_path,
00123 fromlen - sizeof(from->sun_family));
00124 dst->debug_level = atoi(level);
00125 return 0;
00126 }
00127 dst = dst->next;
00128 }
00129
00130 return -1;
00131 }
00132
00133
00134 static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
00135 void *sock_ctx)
00136 {
00137 struct wpa_supplicant *wpa_s = eloop_ctx;
00138 struct ctrl_iface_priv *priv = sock_ctx;
00139 char buf[256];
00140 int res;
00141 struct sockaddr_un from;
00142 socklen_t fromlen = sizeof(from);
00143 char *reply = NULL;
00144 size_t reply_len = 0;
00145 int new_attached = 0;
00146
00147 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
00148 (struct sockaddr *) &from, &fromlen);
00149 if (res < 0) {
00150 perror("recvfrom(ctrl_iface)");
00151 return;
00152 }
00153 buf[res] = '\0';
00154
00155 if (os_strcmp(buf, "ATTACH") == 0) {
00156 if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen))
00157 reply_len = 1;
00158 else {
00159 new_attached = 1;
00160 reply_len = 2;
00161 }
00162 } else if (os_strcmp(buf, "DETACH") == 0) {
00163 if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen))
00164 reply_len = 1;
00165 else
00166 reply_len = 2;
00167 } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
00168 if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,
00169 buf + 6))
00170 reply_len = 1;
00171 else
00172 reply_len = 2;
00173 } else {
00174 reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
00175 &reply_len);
00176 }
00177
00178 if (reply) {
00179 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
00180 fromlen);
00181 os_free(reply);
00182 } else if (reply_len == 1) {
00183 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
00184 fromlen);
00185 } else if (reply_len == 2) {
00186 sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
00187 fromlen);
00188 }
00189
00190 if (new_attached)
00191 eapol_sm_notify_ctrl_attached(wpa_s->eapol);
00192 }
00193
00194
00195 static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
00196 {
00197 char *buf;
00198 size_t len;
00199 char *pbuf, *dir = NULL, *gid_str = NULL;
00200
00201 if (wpa_s->conf->ctrl_interface == NULL)
00202 return NULL;
00203
00204 pbuf = os_strdup(wpa_s->conf->ctrl_interface);
00205 if (pbuf == NULL)
00206 return NULL;
00207 if (os_strncmp(pbuf, "DIR=", 4) == 0) {
00208 dir = pbuf + 4;
00209 gid_str = os_strstr(dir, " GROUP=");
00210 if (gid_str) {
00211 *gid_str = '\0';
00212 gid_str += 7;
00213 }
00214 } else
00215 dir = pbuf;
00216
00217 len = os_strlen(dir) + os_strlen(wpa_s->ifname) + 2;
00218 buf = os_malloc(len);
00219 if (buf == NULL) {
00220 os_free(pbuf);
00221 return NULL;
00222 }
00223
00224 os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname);
00225 #ifdef __CYGWIN__
00226 {
00227
00228
00229 char *pos = buf;
00230 while (*pos) {
00231 if (*pos == '\\')
00232 *pos = '_';
00233 pos++;
00234 }
00235 }
00236 #endif
00237 os_free(pbuf);
00238 return buf;
00239 }
00240
00241
00242 static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
00243 const char *txt, size_t len)
00244 {
00245 struct wpa_supplicant *wpa_s = ctx;
00246 if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
00247 return;
00248 wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
00249 }
00250
00251
00252 struct ctrl_iface_priv *
00253 wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
00254 {
00255 struct ctrl_iface_priv *priv;
00256 struct sockaddr_un addr;
00257 char *fname = NULL;
00258 gid_t gid = 0;
00259 int gid_set = 0;
00260 char *buf, *dir = NULL, *gid_str = NULL;
00261 struct group *grp;
00262 char *endp;
00263
00264 priv = os_zalloc(sizeof(*priv));
00265 if (priv == NULL)
00266 return NULL;
00267 priv->wpa_s = wpa_s;
00268 priv->sock = -1;
00269
00270 if (wpa_s->conf->ctrl_interface == NULL)
00271 return priv;
00272
00273 buf = os_strdup(wpa_s->conf->ctrl_interface);
00274 if (buf == NULL)
00275 goto fail;
00276 if (os_strncmp(buf, "DIR=", 4) == 0) {
00277 dir = buf + 4;
00278 gid_str = os_strstr(dir, " GROUP=");
00279 if (gid_str) {
00280 *gid_str = '\0';
00281 gid_str += 7;
00282 }
00283 } else {
00284 dir = buf;
00285 gid_str = wpa_s->conf->ctrl_interface_group;
00286 }
00287
00288 if (mkdir(dir, S_IRWXU | S_IRWXG) < 0) {
00289 if (errno == EEXIST) {
00290 wpa_printf(MSG_DEBUG, "Using existing control "
00291 "interface directory.");
00292 } else {
00293 perror("mkdir[ctrl_interface]");
00294 goto fail;
00295 }
00296 }
00297
00298 if (gid_str) {
00299 grp = getgrnam(gid_str);
00300 if (grp) {
00301 gid = grp->gr_gid;
00302 gid_set = 1;
00303 wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
00304 " (from group name '%s')",
00305 (int) gid, gid_str);
00306 } else {
00307
00308 gid = strtol(gid_str, &endp, 10);
00309 if (*gid_str == '\0' || *endp != '\0') {
00310 wpa_printf(MSG_DEBUG, "CTRL: Invalid group "
00311 "'%s'", gid_str);
00312 goto fail;
00313 }
00314 gid_set = 1;
00315 wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
00316 (int) gid);
00317 }
00318 }
00319
00320 if (gid_set && chown(dir, -1, gid) < 0) {
00321 perror("chown[ctrl_interface]");
00322 goto fail;
00323 }
00324
00325 if (os_strlen(dir) + 1 + os_strlen(wpa_s->ifname) >=
00326 sizeof(addr.sun_path))
00327 goto fail;
00328
00329 priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
00330 if (priv->sock < 0) {
00331 perror("socket(PF_UNIX)");
00332 goto fail;
00333 }
00334
00335 os_memset(&addr, 0, sizeof(addr));
00336 addr.sun_family = AF_UNIX;
00337 fname = wpa_supplicant_ctrl_iface_path(wpa_s);
00338 if (fname == NULL)
00339 goto fail;
00340 os_strncpy(addr.sun_path, fname, sizeof(addr.sun_path));
00341 if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
00342 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
00343 strerror(errno));
00344 if (connect(priv->sock, (struct sockaddr *) &addr,
00345 sizeof(addr)) < 0) {
00346 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
00347 " allow connections - assuming it was left"
00348 "over from forced program termination");
00349 if (unlink(fname) < 0) {
00350 perror("unlink[ctrl_iface]");
00351 wpa_printf(MSG_ERROR, "Could not unlink "
00352 "existing ctrl_iface socket '%s'",
00353 fname);
00354 goto fail;
00355 }
00356 if (bind(priv->sock, (struct sockaddr *) &addr,
00357 sizeof(addr)) < 0) {
00358 perror("bind(PF_UNIX)");
00359 goto fail;
00360 }
00361 wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
00362 "ctrl_iface socket '%s'", fname);
00363 } else {
00364 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
00365 "be in use - cannot override it");
00366 wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
00367 "not used anymore", fname);
00368 os_free(fname);
00369 fname = NULL;
00370 goto fail;
00371 }
00372 }
00373
00374 if (gid_set && chown(fname, -1, gid) < 0) {
00375 perror("chown[ctrl_interface/ifname]");
00376 goto fail;
00377 }
00378
00379 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
00380 perror("chmod[ctrl_interface/ifname]");
00381 goto fail;
00382 }
00383 os_free(fname);
00384
00385 eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
00386 wpa_s, priv);
00387 wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
00388
00389 os_free(buf);
00390 return priv;
00391
00392 fail:
00393 if (priv->sock >= 0)
00394 close(priv->sock);
00395 os_free(priv);
00396 if (fname) {
00397 unlink(fname);
00398 os_free(fname);
00399 }
00400 os_free(buf);
00401 return NULL;
00402 }
00403
00404
00405 void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
00406 {
00407 struct wpa_ctrl_dst *dst, *prev;
00408
00409 if (priv->sock > -1) {
00410 char *fname;
00411 char *buf, *dir = NULL, *gid_str = NULL;
00412 eloop_unregister_read_sock(priv->sock);
00413 if (priv->ctrl_dst) {
00414
00415
00416
00417
00418
00419 wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
00420 "monitors to receive messages");
00421 os_sleep(1, 0);
00422 }
00423 close(priv->sock);
00424 priv->sock = -1;
00425 fname = wpa_supplicant_ctrl_iface_path(priv->wpa_s);
00426 if (fname) {
00427 unlink(fname);
00428 os_free(fname);
00429 }
00430
00431 buf = os_strdup(priv->wpa_s->conf->ctrl_interface);
00432 if (buf == NULL)
00433 goto free_dst;
00434 if (os_strncmp(buf, "DIR=", 4) == 0) {
00435 dir = buf + 4;
00436 gid_str = os_strstr(dir, " GROUP=");
00437 if (gid_str) {
00438 *gid_str = '\0';
00439 gid_str += 7;
00440 }
00441 } else
00442 dir = buf;
00443
00444 if (rmdir(dir) < 0) {
00445 if (errno == ENOTEMPTY) {
00446 wpa_printf(MSG_DEBUG, "Control interface "
00447 "directory not empty - leaving it "
00448 "behind");
00449 } else {
00450 perror("rmdir[ctrl_interface]");
00451 }
00452 }
00453 os_free(buf);
00454 }
00455
00456 free_dst:
00457 dst = priv->ctrl_dst;
00458 while (dst) {
00459 prev = dst;
00460 dst = dst->next;
00461 os_free(prev);
00462 }
00463 os_free(priv);
00464 }
00465
00466
00477 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
00478 int level, const char *buf,
00479 size_t len)
00480 {
00481 struct wpa_ctrl_dst *dst, *next;
00482 char levelstr[10];
00483 int idx;
00484 struct msghdr msg;
00485 struct iovec io[2];
00486
00487 dst = priv->ctrl_dst;
00488 if (priv->sock < 0 || dst == NULL)
00489 return;
00490
00491 os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
00492 io[0].iov_base = levelstr;
00493 io[0].iov_len = os_strlen(levelstr);
00494 io[1].iov_base = (char *) buf;
00495 io[1].iov_len = len;
00496 os_memset(&msg, 0, sizeof(msg));
00497 msg.msg_iov = io;
00498 msg.msg_iovlen = 2;
00499
00500 idx = 0;
00501 while (dst) {
00502 next = dst->next;
00503 if (level >= dst->debug_level) {
00504 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
00505 (u8 *) dst->addr.sun_path, dst->addrlen -
00506 sizeof(dst->addr.sun_family));
00507 msg.msg_name = (void *) &dst->addr;
00508 msg.msg_namelen = dst->addrlen;
00509 if (sendmsg(priv->sock, &msg, 0) < 0) {
00510 perror("sendmsg(CTRL_IFACE monitor)");
00511 dst->errors++;
00512 if (dst->errors > 10) {
00513 wpa_supplicant_ctrl_iface_detach(
00514 priv, &dst->addr,
00515 dst->addrlen);
00516 }
00517 } else
00518 dst->errors = 0;
00519 }
00520 idx++;
00521 dst = next;
00522 }
00523 }
00524
00525
00526 void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
00527 {
00528 wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor",
00529 priv->wpa_s->ifname);
00530 eloop_wait_for_read_sock(priv->sock);
00531 }
00532
00533
00534
00535
00536 struct ctrl_iface_global_priv {
00537 struct wpa_global *global;
00538 int sock;
00539 };
00540
00541
00542 static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
00543 void *sock_ctx)
00544 {
00545 struct wpa_global *global = eloop_ctx;
00546 char buf[256];
00547 int res;
00548 struct sockaddr_un from;
00549 socklen_t fromlen = sizeof(from);
00550 char *reply;
00551 size_t reply_len;
00552
00553 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
00554 (struct sockaddr *) &from, &fromlen);
00555 if (res < 0) {
00556 perror("recvfrom(ctrl_iface)");
00557 return;
00558 }
00559 buf[res] = '\0';
00560
00561 reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
00562 &reply_len);
00563
00564 if (reply) {
00565 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
00566 fromlen);
00567 os_free(reply);
00568 } else if (reply_len) {
00569 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
00570 fromlen);
00571 }
00572 }
00573
00574
00575 struct ctrl_iface_global_priv *
00576 wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
00577 {
00578 struct ctrl_iface_global_priv *priv;
00579 struct sockaddr_un addr;
00580
00581 priv = os_zalloc(sizeof(*priv));
00582 if (priv == NULL)
00583 return NULL;
00584 priv->global = global;
00585 priv->sock = -1;
00586
00587 if (global->params.ctrl_interface == NULL)
00588 return priv;
00589
00590 wpa_printf(MSG_DEBUG, "Global control interface '%s'",
00591 global->params.ctrl_interface);
00592
00593 priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
00594 if (priv->sock < 0) {
00595 perror("socket(PF_UNIX)");
00596 goto fail;
00597 }
00598
00599 os_memset(&addr, 0, sizeof(addr));
00600 addr.sun_family = AF_UNIX;
00601 os_strncpy(addr.sun_path, global->params.ctrl_interface,
00602 sizeof(addr.sun_path));
00603 if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
00604 perror("bind(PF_UNIX)");
00605 if (connect(priv->sock, (struct sockaddr *) &addr,
00606 sizeof(addr)) < 0) {
00607 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
00608 " allow connections - assuming it was left"
00609 "over from forced program termination");
00610 if (unlink(global->params.ctrl_interface) < 0) {
00611 perror("unlink[ctrl_iface]");
00612 wpa_printf(MSG_ERROR, "Could not unlink "
00613 "existing ctrl_iface socket '%s'",
00614 global->params.ctrl_interface);
00615 goto fail;
00616 }
00617 if (bind(priv->sock, (struct sockaddr *) &addr,
00618 sizeof(addr)) < 0) {
00619 perror("bind(PF_UNIX)");
00620 goto fail;
00621 }
00622 wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
00623 "ctrl_iface socket '%s'",
00624 global->params.ctrl_interface);
00625 } else {
00626 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
00627 "be in use - cannot override it");
00628 wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
00629 "not used anymore",
00630 global->params.ctrl_interface);
00631 goto fail;
00632 }
00633 }
00634
00635 eloop_register_read_sock(priv->sock,
00636 wpa_supplicant_global_ctrl_iface_receive,
00637 global, NULL);
00638
00639 return priv;
00640
00641 fail:
00642 if (priv->sock >= 0)
00643 close(priv->sock);
00644 os_free(priv);
00645 return NULL;
00646 }
00647
00648
00649 void
00650 wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
00651 {
00652 if (priv->sock >= 0) {
00653 eloop_unregister_read_sock(priv->sock);
00654 close(priv->sock);
00655 }
00656 if (priv->global->params.ctrl_interface)
00657 unlink(priv->global->params.ctrl_interface);
00658 os_free(priv);
00659 }
00660