]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/ctrl_iface_unix.c
wpa_supplicant: Add -G argument to specify global ctrl group
[thirdparty/hostap.git] / wpa_supplicant / ctrl_iface_unix.c
index 6f78aa54292973a136927a00e8940e3bc9d4cbb4..73d3837211f59afc200afde9a8b04e02e80017e8 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant / UNIX domain socket -based control interface
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, 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
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
 #include <sys/stat.h>
 #include <grp.h>
 #include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#ifdef ANDROID
+#include <cutils/sockets.h>
+#endif /* ANDROID */
 
 #include "utils/common.h"
 #include "utils/eloop.h"
@@ -132,7 +131,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);
@@ -262,6 +261,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
        char *buf, *dir = NULL, *gid_str = NULL;
        struct group *grp;
        char *endp;
+       int flags;
 
        priv = os_zalloc(sizeof(*priv));
        if (priv == NULL)
@@ -276,6 +276,13 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
        buf = os_strdup(wpa_s->conf->ctrl_interface);
        if (buf == NULL)
                goto fail;
+#ifdef ANDROID
+       os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s",
+                   wpa_s->conf->ctrl_interface);
+       priv->sock = android_get_control_socket(addr.sun_path);
+       if (priv->sock >= 0)
+               goto havesock;
+#endif /* ANDROID */
        if (os_strncmp(buf, "DIR=", 4) == 0) {
                dir = buf + 4;
                gid_str = os_strstr(dir, " GROUP=");
@@ -298,6 +305,22 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
                }
        }
 
+#ifdef ANDROID
+       /*
+        * wpa_supplicant is started from /init.*.rc on Android and that seems
+        * to be using umask 0077 which would leave the control interface
+        * directory without group access. This breaks things since Wi-Fi
+        * framework assumes that this directory can be accessed by other
+        * applications in the wifi group. Fix this by adding group access even
+        * if umask value would prevent this.
+        */
+       if (chmod(dir, S_IRWXU | S_IRWXG) < 0) {
+               wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
+                          strerror(errno));
+               /* Try to continue anyway */
+       }
+#endif /* ANDROID */
+
        if (gid_str) {
                grp = getgrnam(gid_str);
                if (grp) {
@@ -346,7 +369,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
        }
 
        os_memset(&addr, 0, sizeof(addr));
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
        addr.sun_len = sizeof(addr);
 #endif /* __FreeBSD__ */
        addr.sun_family = AF_UNIX;
@@ -371,7 +394,7 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
                        }
                        if (bind(priv->sock, (struct sockaddr *) &addr,
                                 sizeof(addr)) < 0) {
-                               perror("bind(PF_UNIX)");
+                               perror("supp-ctrl-iface-init: bind(PF_UNIX)");
                                goto fail;
                        }
                        wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -398,6 +421,23 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
        }
        os_free(fname);
 
+#ifdef ANDROID
+havesock:
+#endif /* ANDROID */
+
+       /*
+        * Make socket non-blocking so that we don't hang forever if
+        * target dies unexpectedly.
+        */
+       flags = fcntl(priv->sock, F_GETFL);
+       if (flags >= 0) {
+               flags |= O_NONBLOCK;
+               if (fcntl(priv->sock, F_SETFL, flags) < 0) {
+                       perror("fcntl(ctrl, O_NONBLOCK)");
+                       /* Not fatal, continue on.*/
+               }
+       }
+
        eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
                                 wpa_s, priv);
        wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
@@ -525,7 +565,9 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
                                           "%d - %s",
                                           idx, errno, strerror(errno));
                                dst->errors++;
-                               if (dst->errors > 10 || _errno == ENOENT) {
+                               if (dst->errors > 1000 ||
+                                   (_errno != ENOBUFS && dst->errors > 10) ||
+                                   _errno == ENOENT) {
                                        wpa_supplicant_ctrl_iface_detach(
                                                priv, &dst->addr,
                                                dst->addrlen);
@@ -635,6 +677,12 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
        if (global->params.ctrl_interface == NULL)
                return priv;
 
+#ifdef ANDROID
+       priv->sock = android_get_control_socket(global->params.ctrl_interface);
+       if (priv->sock >= 0)
+               goto havesock;
+#endif /* ANDROID */
+
        wpa_printf(MSG_DEBUG, "Global control interface '%s'",
                   global->params.ctrl_interface);
 
@@ -645,14 +693,15 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
        }
 
        os_memset(&addr, 0, sizeof(addr));
-#ifdef __FreeBSD__
+#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));
        if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               perror("bind(PF_UNIX)");
+               perror("supp-global-ctrl-iface-init (will try fixup): "
+                      "bind(PF_UNIX)");
                if (connect(priv->sock, (struct sockaddr *) &addr,
                            sizeof(addr)) < 0) {
                        wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
@@ -667,7 +716,7 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
                        }
                        if (bind(priv->sock, (struct sockaddr *) &addr,
                                 sizeof(addr)) < 0) {
-                               perror("bind(PF_UNIX)");
+                               perror("supp-glb-iface-init: bind(PF_UNIX)");
                                goto fail;
                        }
                        wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -683,6 +732,44 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
                }
        }
 
+       if (global->params.ctrl_interface_group) {
+               char *gid_str = global->params.ctrl_interface_group;
+               gid_t gid = 0;
+               struct group *grp;
+               char *endp;
+
+               grp = getgrnam(gid_str);
+               if (grp) {
+                       gid = grp->gr_gid;
+                       wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
+                                  " (from group name '%s')",
+                                  (int) gid, gid_str);
+               } else {
+                       /* Group name not found - try to parse this as gid */
+                       gid = strtol(gid_str, &endp, 10);
+                       if (*gid_str == '\0' || *endp != '\0') {
+                               wpa_printf(MSG_ERROR, "CTRL: Invalid group "
+                                          "'%s'", gid_str);
+                               goto fail;
+                       }
+                       wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
+                                  (int) gid);
+               }
+               if (chown(global->params.ctrl_interface, -1, gid) < 0) {
+                       perror("chown[global_ctrl_interface/ifname]");
+                       goto fail;
+               }
+
+               if (chmod(global->params.ctrl_interface, S_IRWXU | S_IRWXG) < 0)
+               {
+                       perror("chmod[global_ctrl_interface/ifname]");
+                       goto fail;
+               }
+       }
+
+#ifdef ANDROID
+havesock:
+#endif /* ANDROID */
        eloop_register_read_sock(priv->sock,
                                 wpa_supplicant_global_ctrl_iface_receive,
                                 global, NULL);