autoreconf
[libeap.git] / wpa_supplicant / ctrl_iface_unix.c
index bf6328e..6040828 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / UNIX domain socket -based control interface
- * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 #include <sys/un.h>
 #include <sys/stat.h>
 #include <grp.h>
+#include <stddef.h>
 
-#include "common.h"
-#include "eloop.h"
-#include "config.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/list.h"
 #include "eapol_supp/eapol_supp_sm.h"
+#include "config.h"
 #include "wpa_supplicant_i.h"
 #include "ctrl_iface.h"
 
@@ -34,7 +36,7 @@
  * ctrl_iface_unix.c and should not be touched directly from other files.
  */
 struct wpa_ctrl_dst {
-       struct wpa_ctrl_dst *next;
+       struct dl_list list;
        struct sockaddr_un addr;
        socklen_t addrlen;
        int debug_level;
@@ -45,7 +47,7 @@ struct wpa_ctrl_dst {
 struct ctrl_iface_priv {
        struct wpa_supplicant *wpa_s;
        int sock;
-       struct wpa_ctrl_dst *ctrl_dst;
+       struct dl_list ctrl_dst;
 };
 
 
@@ -66,10 +68,10 @@ static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
        os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
        dst->addrlen = fromlen;
        dst->debug_level = MSG_INFO;
-       dst->next = priv->ctrl_dst;
-       priv->ctrl_dst = dst;
+       dl_list_add(&priv->ctrl_dst, &dst->list);
        wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
-                   (u8 *) from->sun_path, fromlen - sizeof(from->sun_family));
+                   (u8 *) from->sun_path,
+                   fromlen - offsetof(struct sockaddr_un, sun_path));
        return 0;
 }
 
@@ -78,25 +80,21 @@ static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
                                            struct sockaddr_un *from,
                                            socklen_t fromlen)
 {
-       struct wpa_ctrl_dst *dst, *prev = NULL;
+       struct wpa_ctrl_dst *dst;
 
-       dst = priv->ctrl_dst;
-       while (dst) {
+       dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) {
                if (fromlen == dst->addrlen &&
                    os_memcmp(from->sun_path, dst->addr.sun_path,
-                             fromlen - sizeof(from->sun_family)) == 0) {
-                       if (prev == NULL)
-                               priv->ctrl_dst = dst->next;
-                       else
-                               prev->next = dst->next;
+                             fromlen - offsetof(struct sockaddr_un, sun_path))
+                   == 0) {
+                       dl_list_del(&dst->list);
                        os_free(dst);
                        wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
                                    (u8 *) from->sun_path,
-                                   fromlen - sizeof(from->sun_family));
+                                   fromlen -
+                                   offsetof(struct sockaddr_un, sun_path));
                        return 0;
                }
-               prev = dst;
-               dst = dst->next;
        }
        return -1;
 }
@@ -111,18 +109,18 @@ static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
 
        wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
 
-       dst = priv->ctrl_dst;
-       while (dst) {
+       dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) {
                if (fromlen == dst->addrlen &&
                    os_memcmp(from->sun_path, dst->addr.sun_path,
-                             fromlen - sizeof(from->sun_family)) == 0) {
+                             fromlen - offsetof(struct sockaddr_un, sun_path))
+                   == 0) {
                        wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
                                    "level", (u8 *) from->sun_path,
-                                   fromlen - sizeof(from->sun_family));
+                                   fromlen -
+                                   offsetof(struct sockaddr_un, sun_path));
                        dst->debug_level = atoi(level);
                        return 0;
                }
-               dst = dst->next;
        }
 
        return -1;
@@ -134,7 +132,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
 {
        struct wpa_supplicant *wpa_s = eloop_ctx;
        struct ctrl_iface_priv *priv = sock_ctx;
-       char buf[256];
+       char buf[4096];
        int res;
        struct sockaddr_un from;
        socklen_t fromlen = sizeof(from);
@@ -268,6 +266,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
        priv = os_zalloc(sizeof(*priv));
        if (priv == NULL)
                return NULL;
+       dl_list_init(&priv->ctrl_dst);
        priv->wpa_s = wpa_s;
        priv->sock = -1;
 
@@ -326,6 +325,14 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
                goto fail;
        }
 
+       /* Make sure the group can enter and read the directory */
+       if (gid_set &&
+           chmod(dir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP) < 0) {
+               wpa_printf(MSG_ERROR, "CTRL: chmod[ctrl_interface]: %s",
+                          strerror(errno));
+               goto fail;
+       }
+
        if (os_strlen(dir) + 1 + os_strlen(wpa_s->ifname) >=
            sizeof(addr.sun_path)) {
                wpa_printf(MSG_ERROR, "ctrl_iface path limit exceeded");
@@ -339,6 +346,9 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
        }
 
        os_memset(&addr, 0, sizeof(addr));
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+       addr.sun_len = sizeof(addr);
+#endif /* __FreeBSD__ */
        addr.sun_family = AF_UNIX;
        fname = wpa_supplicant_ctrl_iface_path(wpa_s);
        if (fname == NULL)
@@ -416,7 +426,7 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
                char *fname;
                char *buf, *dir = NULL, *gid_str = NULL;
                eloop_unregister_read_sock(priv->sock);
-               if (priv->ctrl_dst) {
+               if (!dl_list_empty(&priv->ctrl_dst)) {
                        /*
                         * Wait a second before closing the control socket if
                         * there are any attached monitors in order to allow
@@ -460,12 +470,9 @@ void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
        }
 
 free_dst:
-       dst = priv->ctrl_dst;
-       while (dst) {
-               prev = dst;
-               dst = dst->next;
-               os_free(prev);
-       }
+       dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst,
+                             list)
+               os_free(dst);
        os_free(priv);
 }
 
@@ -489,8 +496,7 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
        struct msghdr msg;
        struct iovec io[2];
 
-       dst = priv->ctrl_dst;
-       if (priv->sock < 0 || dst == NULL)
+       if (priv->sock < 0 || dl_list_empty(&priv->ctrl_dst))
                return;
 
        res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
@@ -505,18 +511,23 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
        msg.msg_iovlen = 2;
 
        idx = 0;
-       while (dst) {
-               next = dst->next;
+       dl_list_for_each_safe(dst, next, &priv->ctrl_dst, struct wpa_ctrl_dst,
+                             list) {
                if (level >= dst->debug_level) {
                        wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
                                    (u8 *) dst->addr.sun_path, dst->addrlen -
-                                   sizeof(dst->addr.sun_family));
+                                   offsetof(struct sockaddr_un, sun_path));
                        msg.msg_name = (void *) &dst->addr;
                        msg.msg_namelen = dst->addrlen;
                        if (sendmsg(priv->sock, &msg, 0) < 0) {
-                               perror("sendmsg(CTRL_IFACE monitor)");
+                               int _errno = errno;
+                               wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
+                                          "%d - %s",
+                                          idx, errno, strerror(errno));
                                dst->errors++;
-                               if (dst->errors > 10) {
+                               if (dst->errors > 1000 ||
+                                   (_errno != ENOBUFS && dst->errors > 10) ||
+                                   _errno == ENOENT) {
                                        wpa_supplicant_ctrl_iface_detach(
                                                priv, &dst->addr,
                                                dst->addrlen);
@@ -525,7 +536,6 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
                                dst->errors = 0;
                }
                idx++;
-               dst = next;
        }
 }
 
@@ -637,6 +647,9 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
        }
 
        os_memset(&addr, 0, sizeof(addr));
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+       addr.sun_len = sizeof(addr);
+#endif /* __FreeBSD__ */
        addr.sun_family = AF_UNIX;
        os_strlcpy(addr.sun_path, global->params.ctrl_interface,
                   sizeof(addr.sun_path));