ctrl_iface_unix.c

Go to the documentation of this file.
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 /* Per-interface ctrl_iface */
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                 /* Windows/WinPcap uses interface names that are not suitable
00228                  * as a file name - convert invalid chars to underscores */
00229                 char *pos = buf;
00230                 while (*pos) {
00231                         if (*pos == '\\')
00232                                 *pos = '_';
00233                         pos++;
00234                 }
00235         }
00236 #endif /* __CYGWIN__ */
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                         /* Group name not found - try to parse this as gid */
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                          * Wait a second before closing the control socket if
00416                          * there are any attached monitors in order to allow
00417                          * them to receive any pending messages.
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 /* Global ctrl_iface */
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 

Generated on Sun Dec 31 13:48:52 2006 for wpa_supplicant by  doxygen 1.4.2