1189251Ssam/* 2189251Ssam * WPA Supplicant / UNIX domain socket -based control interface 3281806Srpaulo * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam#include <sys/un.h> 11189251Ssam#include <sys/stat.h> 12189251Ssam#include <grp.h> 13189775Ssam#include <stddef.h> 14252726Srpaulo#include <unistd.h> 15252726Srpaulo#include <fcntl.h> 16289549Srpaulo#ifdef __linux__ 17289549Srpaulo#include <sys/ioctl.h> 18289549Srpaulo#include <linux/sockios.h> 19289549Srpaulo#endif /* __linux__ */ 20252726Srpaulo#ifdef ANDROID 21252726Srpaulo#include <cutils/sockets.h> 22252726Srpaulo#endif /* ANDROID */ 23189251Ssam 24214734Srpaulo#include "utils/common.h" 25214734Srpaulo#include "utils/eloop.h" 26214734Srpaulo#include "utils/list.h" 27214734Srpaulo#include "eapol_supp/eapol_supp_sm.h" 28189251Ssam#include "config.h" 29189251Ssam#include "wpa_supplicant_i.h" 30189251Ssam#include "ctrl_iface.h" 31189251Ssam 32189251Ssam/* Per-interface ctrl_iface */ 33189251Ssam 34189251Ssam/** 35189251Ssam * struct wpa_ctrl_dst - Internal data structure of control interface monitors 36189251Ssam * 37189251Ssam * This structure is used to store information about registered control 38189251Ssam * interface monitors into struct wpa_supplicant. This data is private to 39189251Ssam * ctrl_iface_unix.c and should not be touched directly from other files. 40189251Ssam */ 41189251Ssamstruct wpa_ctrl_dst { 42214734Srpaulo struct dl_list list; 43189251Ssam struct sockaddr_un addr; 44189251Ssam socklen_t addrlen; 45189251Ssam int debug_level; 46189251Ssam int errors; 47189251Ssam}; 48189251Ssam 49189251Ssam 50189251Ssamstruct ctrl_iface_priv { 51189251Ssam struct wpa_supplicant *wpa_s; 52189251Ssam int sock; 53214734Srpaulo struct dl_list ctrl_dst; 54281806Srpaulo int android_control_socket; 55189251Ssam}; 56189251Ssam 57189251Ssam 58281806Srpaulostruct ctrl_iface_global_priv { 59281806Srpaulo struct wpa_global *global; 60281806Srpaulo int sock; 61281806Srpaulo struct dl_list ctrl_dst; 62281806Srpaulo int android_control_socket; 63281806Srpaulo}; 64281806Srpaulo 65281806Srpaulo 66281806Srpaulostatic void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, 67281806Srpaulo const char *ifname, int sock, 68281806Srpaulo struct dl_list *ctrl_dst, 69189251Ssam int level, const char *buf, 70281806Srpaulo size_t len, 71281806Srpaulo struct ctrl_iface_priv *priv, 72281806Srpaulo struct ctrl_iface_global_priv *gp); 73281806Srpaulostatic int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s, 74281806Srpaulo struct ctrl_iface_priv *priv); 75281806Srpaulostatic int wpas_ctrl_iface_global_reinit(struct wpa_global *global, 76281806Srpaulo struct ctrl_iface_global_priv *priv); 77189251Ssam 78189251Ssam 79289549Srpaulostatic void wpas_ctrl_sock_debug(const char *title, int sock, const char *buf, 80289549Srpaulo size_t len) 81289549Srpaulo{ 82289549Srpaulo#ifdef __linux__ 83289549Srpaulo socklen_t optlen; 84289549Srpaulo int sndbuf, outq; 85289549Srpaulo int level = MSG_MSGDUMP; 86289549Srpaulo 87289549Srpaulo if (len >= 5 && os_strncmp(buf, "PONG\n", 5) == 0) 88289549Srpaulo level = MSG_EXCESSIVE; 89289549Srpaulo 90289549Srpaulo optlen = sizeof(sndbuf); 91289549Srpaulo sndbuf = 0; 92289549Srpaulo if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0) 93289549Srpaulo sndbuf = -1; 94289549Srpaulo 95289549Srpaulo if (ioctl(sock, SIOCOUTQ, &outq) < 0) 96289549Srpaulo outq = -1; 97289549Srpaulo 98289549Srpaulo wpa_printf(level, 99289549Srpaulo "CTRL-DEBUG: %s: sock=%d sndbuf=%d outq=%d send_len=%d", 100289549Srpaulo title, sock, sndbuf, outq, (int) len); 101289549Srpaulo#endif /* __linux__ */ 102289549Srpaulo} 103289549Srpaulo 104289549Srpaulo 105281806Srpaulostatic int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst, 106189251Ssam struct sockaddr_un *from, 107281806Srpaulo socklen_t fromlen, int global) 108189251Ssam{ 109189251Ssam struct wpa_ctrl_dst *dst; 110281806Srpaulo char addr_txt[200]; 111189251Ssam 112189251Ssam dst = os_zalloc(sizeof(*dst)); 113189251Ssam if (dst == NULL) 114189251Ssam return -1; 115189251Ssam os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); 116189251Ssam dst->addrlen = fromlen; 117189251Ssam dst->debug_level = MSG_INFO; 118281806Srpaulo dl_list_add(ctrl_dst, &dst->list); 119281806Srpaulo printf_encode(addr_txt, sizeof(addr_txt), 120281806Srpaulo (u8 *) from->sun_path, 121281806Srpaulo fromlen - offsetof(struct sockaddr_un, sun_path)); 122281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE %smonitor attached %s", 123281806Srpaulo global ? "global " : "", addr_txt); 124189251Ssam return 0; 125189251Ssam} 126189251Ssam 127189251Ssam 128281806Srpaulostatic int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst, 129189251Ssam struct sockaddr_un *from, 130189251Ssam socklen_t fromlen) 131189251Ssam{ 132214734Srpaulo struct wpa_ctrl_dst *dst; 133189251Ssam 134281806Srpaulo dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) { 135189251Ssam if (fromlen == dst->addrlen && 136189251Ssam os_memcmp(from->sun_path, dst->addr.sun_path, 137209158Srpaulo fromlen - offsetof(struct sockaddr_un, sun_path)) 138209158Srpaulo == 0) { 139281806Srpaulo char addr_txt[200]; 140281806Srpaulo printf_encode(addr_txt, sizeof(addr_txt), 141281806Srpaulo (u8 *) from->sun_path, 142281806Srpaulo fromlen - 143281806Srpaulo offsetof(struct sockaddr_un, sun_path)); 144281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached %s", 145281806Srpaulo addr_txt); 146214734Srpaulo dl_list_del(&dst->list); 147189251Ssam os_free(dst); 148189251Ssam return 0; 149189251Ssam } 150189251Ssam } 151189251Ssam return -1; 152189251Ssam} 153189251Ssam 154189251Ssam 155189251Ssamstatic int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, 156189251Ssam struct sockaddr_un *from, 157189251Ssam socklen_t fromlen, 158189251Ssam char *level) 159189251Ssam{ 160189251Ssam struct wpa_ctrl_dst *dst; 161189251Ssam 162189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); 163189251Ssam 164214734Srpaulo dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) { 165189251Ssam if (fromlen == dst->addrlen && 166189251Ssam os_memcmp(from->sun_path, dst->addr.sun_path, 167209158Srpaulo fromlen - offsetof(struct sockaddr_un, sun_path)) 168209158Srpaulo == 0) { 169281806Srpaulo char addr_txt[200]; 170189251Ssam dst->debug_level = atoi(level); 171281806Srpaulo printf_encode(addr_txt, sizeof(addr_txt), 172281806Srpaulo (u8 *) from->sun_path, fromlen - 173281806Srpaulo offsetof(struct sockaddr_un, sun_path)); 174281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level to %d for %s", 175281806Srpaulo dst->debug_level, addr_txt); 176189251Ssam return 0; 177189251Ssam } 178189251Ssam } 179189251Ssam 180189251Ssam return -1; 181189251Ssam} 182189251Ssam 183189251Ssam 184189251Ssamstatic void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, 185189251Ssam void *sock_ctx) 186189251Ssam{ 187189251Ssam struct wpa_supplicant *wpa_s = eloop_ctx; 188189251Ssam struct ctrl_iface_priv *priv = sock_ctx; 189252726Srpaulo char buf[4096]; 190189251Ssam int res; 191189251Ssam struct sockaddr_un from; 192189251Ssam socklen_t fromlen = sizeof(from); 193281806Srpaulo char *reply = NULL, *reply_buf = NULL; 194189251Ssam size_t reply_len = 0; 195189251Ssam int new_attached = 0; 196189251Ssam 197189251Ssam res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 198189251Ssam (struct sockaddr *) &from, &fromlen); 199189251Ssam if (res < 0) { 200281806Srpaulo wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s", 201281806Srpaulo strerror(errno)); 202189251Ssam return; 203189251Ssam } 204189251Ssam buf[res] = '\0'; 205189251Ssam 206189251Ssam if (os_strcmp(buf, "ATTACH") == 0) { 207281806Srpaulo if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from, 208281806Srpaulo fromlen, 0)) 209189251Ssam reply_len = 1; 210189251Ssam else { 211189251Ssam new_attached = 1; 212189251Ssam reply_len = 2; 213189251Ssam } 214189251Ssam } else if (os_strcmp(buf, "DETACH") == 0) { 215281806Srpaulo if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from, 216281806Srpaulo fromlen)) 217189251Ssam reply_len = 1; 218189251Ssam else 219189251Ssam reply_len = 2; 220189251Ssam } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { 221189251Ssam if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen, 222189251Ssam buf + 6)) 223189251Ssam reply_len = 1; 224189251Ssam else 225189251Ssam reply_len = 2; 226189251Ssam } else { 227281806Srpaulo reply_buf = wpa_supplicant_ctrl_iface_process(wpa_s, buf, 228281806Srpaulo &reply_len); 229281806Srpaulo reply = reply_buf; 230289549Srpaulo 231289549Srpaulo /* 232289549Srpaulo * There could be some password/key material in the command, so 233289549Srpaulo * clear the buffer explicitly now that it is not needed 234289549Srpaulo * anymore. 235289549Srpaulo */ 236289549Srpaulo os_memset(buf, 0, res); 237189251Ssam } 238189251Ssam 239281806Srpaulo if (!reply && reply_len == 1) { 240281806Srpaulo reply = "FAIL\n"; 241281806Srpaulo reply_len = 5; 242281806Srpaulo } else if (!reply && reply_len == 2) { 243281806Srpaulo reply = "OK\n"; 244281806Srpaulo reply_len = 3; 245281806Srpaulo } 246281806Srpaulo 247189251Ssam if (reply) { 248289549Srpaulo wpas_ctrl_sock_debug("ctrl_sock-sendto", sock, reply, 249289549Srpaulo reply_len); 250281806Srpaulo if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, 251281806Srpaulo fromlen) < 0) { 252281806Srpaulo int _errno = errno; 253281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, 254281806Srpaulo "ctrl_iface sendto failed: %d - %s", 255281806Srpaulo _errno, strerror(_errno)); 256281806Srpaulo if (_errno == ENOBUFS || _errno == EAGAIN) { 257281806Srpaulo /* 258281806Srpaulo * The socket send buffer could be full. This 259281806Srpaulo * may happen if client programs are not 260281806Srpaulo * receiving their pending messages. Close and 261281806Srpaulo * reopen the socket as a workaround to avoid 262281806Srpaulo * getting stuck being unable to send any new 263281806Srpaulo * responses. 264281806Srpaulo */ 265281806Srpaulo sock = wpas_ctrl_iface_reinit(wpa_s, priv); 266281806Srpaulo if (sock < 0) { 267281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, "Failed to reinitialize ctrl_iface socket"); 268281806Srpaulo } 269281806Srpaulo } 270281806Srpaulo if (new_attached) { 271281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, "Failed to send response to ATTACH - detaching"); 272281806Srpaulo new_attached = 0; 273281806Srpaulo wpa_supplicant_ctrl_iface_detach( 274281806Srpaulo &priv->ctrl_dst, &from, fromlen); 275281806Srpaulo } 276281806Srpaulo } 277189251Ssam } 278281806Srpaulo os_free(reply_buf); 279189251Ssam 280189251Ssam if (new_attached) 281189251Ssam eapol_sm_notify_ctrl_attached(wpa_s->eapol); 282189251Ssam} 283189251Ssam 284189251Ssam 285189251Ssamstatic char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s) 286189251Ssam{ 287189251Ssam char *buf; 288189251Ssam size_t len; 289281806Srpaulo char *pbuf, *dir = NULL; 290189251Ssam int res; 291189251Ssam 292189251Ssam if (wpa_s->conf->ctrl_interface == NULL) 293189251Ssam return NULL; 294189251Ssam 295189251Ssam pbuf = os_strdup(wpa_s->conf->ctrl_interface); 296189251Ssam if (pbuf == NULL) 297189251Ssam return NULL; 298189251Ssam if (os_strncmp(pbuf, "DIR=", 4) == 0) { 299281806Srpaulo char *gid_str; 300189251Ssam dir = pbuf + 4; 301189251Ssam gid_str = os_strstr(dir, " GROUP="); 302281806Srpaulo if (gid_str) 303189251Ssam *gid_str = '\0'; 304189251Ssam } else 305189251Ssam dir = pbuf; 306189251Ssam 307189251Ssam len = os_strlen(dir) + os_strlen(wpa_s->ifname) + 2; 308189251Ssam buf = os_malloc(len); 309189251Ssam if (buf == NULL) { 310189251Ssam os_free(pbuf); 311189251Ssam return NULL; 312189251Ssam } 313189251Ssam 314189251Ssam res = os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname); 315281806Srpaulo if (os_snprintf_error(len, res)) { 316189251Ssam os_free(pbuf); 317189251Ssam os_free(buf); 318189251Ssam return NULL; 319189251Ssam } 320189251Ssam#ifdef __CYGWIN__ 321189251Ssam { 322189251Ssam /* Windows/WinPcap uses interface names that are not suitable 323189251Ssam * as a file name - convert invalid chars to underscores */ 324189251Ssam char *pos = buf; 325189251Ssam while (*pos) { 326189251Ssam if (*pos == '\\') 327189251Ssam *pos = '_'; 328189251Ssam pos++; 329189251Ssam } 330189251Ssam } 331189251Ssam#endif /* __CYGWIN__ */ 332189251Ssam os_free(pbuf); 333189251Ssam return buf; 334189251Ssam} 335189251Ssam 336189251Ssam 337289549Srpaulostatic void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, 338289549Srpaulo enum wpa_msg_type type, 339189251Ssam const char *txt, size_t len) 340189251Ssam{ 341189251Ssam struct wpa_supplicant *wpa_s = ctx; 342281806Srpaulo 343281806Srpaulo if (wpa_s == NULL) 344189251Ssam return; 345281806Srpaulo 346289549Srpaulo if (type != WPA_MSG_NO_GLOBAL && wpa_s->global->ctrl_iface) { 347281806Srpaulo struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface; 348281806Srpaulo if (!dl_list_empty(&priv->ctrl_dst)) { 349289549Srpaulo wpa_supplicant_ctrl_iface_send( 350289549Srpaulo wpa_s, 351289549Srpaulo type != WPA_MSG_PER_INTERFACE ? 352289549Srpaulo NULL : wpa_s->ifname, 353289549Srpaulo priv->sock, &priv->ctrl_dst, level, txt, len, 354289549Srpaulo NULL, priv); 355281806Srpaulo } 356281806Srpaulo } 357281806Srpaulo 358289549Srpaulo if (type == WPA_MSG_ONLY_GLOBAL || wpa_s->ctrl_iface == NULL) 359281806Srpaulo return; 360281806Srpaulo wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock, 361281806Srpaulo &wpa_s->ctrl_iface->ctrl_dst, 362281806Srpaulo level, txt, len, wpa_s->ctrl_iface, 363281806Srpaulo NULL); 364189251Ssam} 365189251Ssam 366189251Ssam 367281806Srpaulostatic int wpas_ctrl_iface_open_sock(struct wpa_supplicant *wpa_s, 368281806Srpaulo struct ctrl_iface_priv *priv) 369189251Ssam{ 370189251Ssam struct sockaddr_un addr; 371189251Ssam char *fname = NULL; 372189251Ssam gid_t gid = 0; 373189251Ssam int gid_set = 0; 374189251Ssam char *buf, *dir = NULL, *gid_str = NULL; 375189251Ssam struct group *grp; 376189251Ssam char *endp; 377252726Srpaulo int flags; 378189251Ssam 379189251Ssam buf = os_strdup(wpa_s->conf->ctrl_interface); 380189251Ssam if (buf == NULL) 381189251Ssam goto fail; 382252726Srpaulo#ifdef ANDROID 383252726Srpaulo os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s", 384252726Srpaulo wpa_s->conf->ctrl_interface); 385252726Srpaulo priv->sock = android_get_control_socket(addr.sun_path); 386281806Srpaulo if (priv->sock >= 0) { 387281806Srpaulo priv->android_control_socket = 1; 388252726Srpaulo goto havesock; 389281806Srpaulo } 390252726Srpaulo#endif /* ANDROID */ 391189251Ssam if (os_strncmp(buf, "DIR=", 4) == 0) { 392189251Ssam dir = buf + 4; 393189251Ssam gid_str = os_strstr(dir, " GROUP="); 394189251Ssam if (gid_str) { 395189251Ssam *gid_str = '\0'; 396189251Ssam gid_str += 7; 397189251Ssam } 398189251Ssam } else { 399189251Ssam dir = buf; 400189251Ssam gid_str = wpa_s->conf->ctrl_interface_group; 401189251Ssam } 402189251Ssam 403189251Ssam if (mkdir(dir, S_IRWXU | S_IRWXG) < 0) { 404189251Ssam if (errno == EEXIST) { 405189251Ssam wpa_printf(MSG_DEBUG, "Using existing control " 406189251Ssam "interface directory."); 407189251Ssam } else { 408281806Srpaulo wpa_printf(MSG_ERROR, "mkdir[ctrl_interface=%s]: %s", 409281806Srpaulo dir, strerror(errno)); 410189251Ssam goto fail; 411189251Ssam } 412189251Ssam } 413189251Ssam 414252726Srpaulo#ifdef ANDROID 415252726Srpaulo /* 416252726Srpaulo * wpa_supplicant is started from /init.*.rc on Android and that seems 417252726Srpaulo * to be using umask 0077 which would leave the control interface 418252726Srpaulo * directory without group access. This breaks things since Wi-Fi 419252726Srpaulo * framework assumes that this directory can be accessed by other 420252726Srpaulo * applications in the wifi group. Fix this by adding group access even 421252726Srpaulo * if umask value would prevent this. 422252726Srpaulo */ 423252726Srpaulo if (chmod(dir, S_IRWXU | S_IRWXG) < 0) { 424252726Srpaulo wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s", 425252726Srpaulo strerror(errno)); 426252726Srpaulo /* Try to continue anyway */ 427252726Srpaulo } 428252726Srpaulo#endif /* ANDROID */ 429252726Srpaulo 430189251Ssam if (gid_str) { 431189251Ssam grp = getgrnam(gid_str); 432189251Ssam if (grp) { 433189251Ssam gid = grp->gr_gid; 434189251Ssam gid_set = 1; 435189251Ssam wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d" 436189251Ssam " (from group name '%s')", 437189251Ssam (int) gid, gid_str); 438189251Ssam } else { 439189251Ssam /* Group name not found - try to parse this as gid */ 440189251Ssam gid = strtol(gid_str, &endp, 10); 441189251Ssam if (*gid_str == '\0' || *endp != '\0') { 442189251Ssam wpa_printf(MSG_ERROR, "CTRL: Invalid group " 443189251Ssam "'%s'", gid_str); 444189251Ssam goto fail; 445189251Ssam } 446189251Ssam gid_set = 1; 447189251Ssam wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", 448189251Ssam (int) gid); 449189251Ssam } 450189251Ssam } 451189251Ssam 452189251Ssam if (gid_set && chown(dir, -1, gid) < 0) { 453281806Srpaulo wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s", 454281806Srpaulo dir, (int) gid, strerror(errno)); 455189251Ssam goto fail; 456189251Ssam } 457189251Ssam 458209158Srpaulo /* Make sure the group can enter and read the directory */ 459209158Srpaulo if (gid_set && 460209158Srpaulo chmod(dir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP) < 0) { 461209158Srpaulo wpa_printf(MSG_ERROR, "CTRL: chmod[ctrl_interface]: %s", 462209158Srpaulo strerror(errno)); 463209158Srpaulo goto fail; 464209158Srpaulo } 465209158Srpaulo 466189251Ssam if (os_strlen(dir) + 1 + os_strlen(wpa_s->ifname) >= 467189251Ssam sizeof(addr.sun_path)) { 468189251Ssam wpa_printf(MSG_ERROR, "ctrl_iface path limit exceeded"); 469189251Ssam goto fail; 470189251Ssam } 471189251Ssam 472189251Ssam priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); 473189251Ssam if (priv->sock < 0) { 474281806Srpaulo wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno)); 475189251Ssam goto fail; 476189251Ssam } 477189251Ssam 478189251Ssam os_memset(&addr, 0, sizeof(addr)); 479214734Srpaulo#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 480189775Ssam addr.sun_len = sizeof(addr); 481209158Srpaulo#endif /* __FreeBSD__ */ 482189251Ssam addr.sun_family = AF_UNIX; 483189251Ssam fname = wpa_supplicant_ctrl_iface_path(wpa_s); 484189251Ssam if (fname == NULL) 485189251Ssam goto fail; 486189251Ssam os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); 487189251Ssam if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 488189251Ssam wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", 489189251Ssam strerror(errno)); 490189251Ssam if (connect(priv->sock, (struct sockaddr *) &addr, 491189251Ssam sizeof(addr)) < 0) { 492189251Ssam wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" 493189251Ssam " allow connections - assuming it was left" 494189251Ssam "over from forced program termination"); 495189251Ssam if (unlink(fname) < 0) { 496281806Srpaulo wpa_printf(MSG_ERROR, 497281806Srpaulo "Could not unlink existing ctrl_iface socket '%s': %s", 498281806Srpaulo fname, strerror(errno)); 499189251Ssam goto fail; 500189251Ssam } 501189251Ssam if (bind(priv->sock, (struct sockaddr *) &addr, 502189251Ssam sizeof(addr)) < 0) { 503281806Srpaulo wpa_printf(MSG_ERROR, "supp-ctrl-iface-init: bind(PF_UNIX): %s", 504281806Srpaulo strerror(errno)); 505189251Ssam goto fail; 506189251Ssam } 507189251Ssam wpa_printf(MSG_DEBUG, "Successfully replaced leftover " 508189251Ssam "ctrl_iface socket '%s'", fname); 509189251Ssam } else { 510189251Ssam wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " 511189251Ssam "be in use - cannot override it"); 512189251Ssam wpa_printf(MSG_INFO, "Delete '%s' manually if it is " 513189251Ssam "not used anymore", fname); 514189251Ssam os_free(fname); 515189251Ssam fname = NULL; 516189251Ssam goto fail; 517189251Ssam } 518189251Ssam } 519189251Ssam 520189251Ssam if (gid_set && chown(fname, -1, gid) < 0) { 521281806Srpaulo wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s", 522281806Srpaulo fname, (int) gid, strerror(errno)); 523189251Ssam goto fail; 524189251Ssam } 525189251Ssam 526189251Ssam if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { 527281806Srpaulo wpa_printf(MSG_ERROR, "chmod[ctrl_interface=%s]: %s", 528281806Srpaulo fname, strerror(errno)); 529189251Ssam goto fail; 530189251Ssam } 531189251Ssam os_free(fname); 532189251Ssam 533252726Srpaulo#ifdef ANDROID 534252726Srpaulohavesock: 535252726Srpaulo#endif /* ANDROID */ 536252726Srpaulo 537252726Srpaulo /* 538252726Srpaulo * Make socket non-blocking so that we don't hang forever if 539252726Srpaulo * target dies unexpectedly. 540252726Srpaulo */ 541252726Srpaulo flags = fcntl(priv->sock, F_GETFL); 542252726Srpaulo if (flags >= 0) { 543252726Srpaulo flags |= O_NONBLOCK; 544252726Srpaulo if (fcntl(priv->sock, F_SETFL, flags) < 0) { 545281806Srpaulo wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s", 546281806Srpaulo strerror(errno)); 547252726Srpaulo /* Not fatal, continue on.*/ 548252726Srpaulo } 549252726Srpaulo } 550252726Srpaulo 551189251Ssam eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, 552189251Ssam wpa_s, priv); 553189251Ssam wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); 554189251Ssam 555189251Ssam os_free(buf); 556281806Srpaulo return 0; 557189251Ssam 558189251Ssamfail: 559281806Srpaulo if (priv->sock >= 0) { 560189251Ssam close(priv->sock); 561281806Srpaulo priv->sock = -1; 562281806Srpaulo } 563189251Ssam if (fname) { 564189251Ssam unlink(fname); 565189251Ssam os_free(fname); 566189251Ssam } 567189251Ssam os_free(buf); 568281806Srpaulo return -1; 569189251Ssam} 570189251Ssam 571189251Ssam 572281806Srpaulostruct ctrl_iface_priv * 573281806Srpaulowpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) 574281806Srpaulo{ 575281806Srpaulo struct ctrl_iface_priv *priv; 576281806Srpaulo 577281806Srpaulo priv = os_zalloc(sizeof(*priv)); 578281806Srpaulo if (priv == NULL) 579281806Srpaulo return NULL; 580281806Srpaulo dl_list_init(&priv->ctrl_dst); 581281806Srpaulo priv->wpa_s = wpa_s; 582281806Srpaulo priv->sock = -1; 583281806Srpaulo 584281806Srpaulo if (wpa_s->conf->ctrl_interface == NULL) 585281806Srpaulo return priv; 586281806Srpaulo 587289549Srpaulo#ifdef ANDROID 588289549Srpaulo if (wpa_s->global->params.ctrl_interface) { 589289549Srpaulo int same = 0; 590289549Srpaulo 591289549Srpaulo if (wpa_s->global->params.ctrl_interface[0] == '/') { 592289549Srpaulo if (os_strcmp(wpa_s->global->params.ctrl_interface, 593289549Srpaulo wpa_s->conf->ctrl_interface) == 0) 594289549Srpaulo same = 1; 595289549Srpaulo } else if (os_strncmp(wpa_s->global->params.ctrl_interface, 596289549Srpaulo "@android:", 9) == 0 || 597289549Srpaulo os_strncmp(wpa_s->global->params.ctrl_interface, 598289549Srpaulo "@abstract:", 10) == 0) { 599289549Srpaulo char *pos; 600289549Srpaulo 601289549Srpaulo /* 602289549Srpaulo * Currently, Android uses @android:wpa_* as the naming 603289549Srpaulo * convention for the global ctrl interface. This logic 604289549Srpaulo * needs to be revisited if the above naming convention 605289549Srpaulo * is modified. 606289549Srpaulo */ 607289549Srpaulo pos = os_strchr(wpa_s->global->params.ctrl_interface, 608289549Srpaulo '_'); 609289549Srpaulo if (pos && 610289549Srpaulo os_strcmp(pos + 1, 611289549Srpaulo wpa_s->conf->ctrl_interface) == 0) 612289549Srpaulo same = 1; 613289549Srpaulo } 614289549Srpaulo 615289549Srpaulo if (same) { 616289549Srpaulo /* 617289549Srpaulo * The invalid configuration combination might be 618289549Srpaulo * possible to hit in an Android OTA upgrade case, so 619289549Srpaulo * instead of refusing to start the wpa_supplicant 620289549Srpaulo * process, do not open the per-interface ctrl_iface 621289549Srpaulo * and continue with the global control interface that 622289549Srpaulo * was set from the command line since the Wi-Fi 623289549Srpaulo * framework will use it for operations. 624289549Srpaulo */ 625289549Srpaulo wpa_printf(MSG_ERROR, 626289549Srpaulo "global ctrl interface %s matches ctrl interface %s - do not open per-interface ctrl interface", 627289549Srpaulo wpa_s->global->params.ctrl_interface, 628289549Srpaulo wpa_s->conf->ctrl_interface); 629289549Srpaulo return priv; 630289549Srpaulo } 631289549Srpaulo } 632289549Srpaulo#endif /* ANDROID */ 633289549Srpaulo 634281806Srpaulo if (wpas_ctrl_iface_open_sock(wpa_s, priv) < 0) { 635281806Srpaulo os_free(priv); 636281806Srpaulo return NULL; 637281806Srpaulo } 638281806Srpaulo 639281806Srpaulo return priv; 640281806Srpaulo} 641281806Srpaulo 642281806Srpaulo 643281806Srpaulostatic int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s, 644281806Srpaulo struct ctrl_iface_priv *priv) 645281806Srpaulo{ 646281806Srpaulo int res; 647281806Srpaulo 648281806Srpaulo if (priv->sock <= 0) 649281806Srpaulo return -1; 650281806Srpaulo 651281806Srpaulo /* 652281806Srpaulo * On Android, the control socket being used may be the socket 653281806Srpaulo * that is created when wpa_supplicant is started as a /init.*.rc 654281806Srpaulo * service. Such a socket is maintained as a key-value pair in 655281806Srpaulo * Android's environment. Closing this control socket would leave us 656281806Srpaulo * in a bad state with an invalid socket descriptor. 657281806Srpaulo */ 658281806Srpaulo if (priv->android_control_socket) 659281806Srpaulo return priv->sock; 660281806Srpaulo 661281806Srpaulo eloop_unregister_read_sock(priv->sock); 662281806Srpaulo close(priv->sock); 663281806Srpaulo priv->sock = -1; 664281806Srpaulo res = wpas_ctrl_iface_open_sock(wpa_s, priv); 665281806Srpaulo if (res < 0) 666281806Srpaulo return -1; 667281806Srpaulo return priv->sock; 668281806Srpaulo} 669281806Srpaulo 670281806Srpaulo 671189251Ssamvoid wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) 672189251Ssam{ 673189251Ssam struct wpa_ctrl_dst *dst, *prev; 674189251Ssam 675189251Ssam if (priv->sock > -1) { 676189251Ssam char *fname; 677281806Srpaulo char *buf, *dir = NULL; 678189251Ssam eloop_unregister_read_sock(priv->sock); 679214734Srpaulo if (!dl_list_empty(&priv->ctrl_dst)) { 680189251Ssam /* 681281806Srpaulo * Wait before closing the control socket if 682189251Ssam * there are any attached monitors in order to allow 683189251Ssam * them to receive any pending messages. 684189251Ssam */ 685189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached " 686189251Ssam "monitors to receive messages"); 687281806Srpaulo os_sleep(0, 100000); 688189251Ssam } 689189251Ssam close(priv->sock); 690189251Ssam priv->sock = -1; 691189251Ssam fname = wpa_supplicant_ctrl_iface_path(priv->wpa_s); 692189251Ssam if (fname) { 693189251Ssam unlink(fname); 694189251Ssam os_free(fname); 695189251Ssam } 696189251Ssam 697281806Srpaulo if (priv->wpa_s->conf->ctrl_interface == NULL) 698281806Srpaulo goto free_dst; 699189251Ssam buf = os_strdup(priv->wpa_s->conf->ctrl_interface); 700189251Ssam if (buf == NULL) 701189251Ssam goto free_dst; 702189251Ssam if (os_strncmp(buf, "DIR=", 4) == 0) { 703281806Srpaulo char *gid_str; 704189251Ssam dir = buf + 4; 705189251Ssam gid_str = os_strstr(dir, " GROUP="); 706281806Srpaulo if (gid_str) 707189251Ssam *gid_str = '\0'; 708189251Ssam } else 709189251Ssam dir = buf; 710189251Ssam 711189251Ssam if (rmdir(dir) < 0) { 712189251Ssam if (errno == ENOTEMPTY) { 713189251Ssam wpa_printf(MSG_DEBUG, "Control interface " 714189251Ssam "directory not empty - leaving it " 715189251Ssam "behind"); 716189251Ssam } else { 717281806Srpaulo wpa_printf(MSG_ERROR, 718281806Srpaulo "rmdir[ctrl_interface=%s]: %s", 719281806Srpaulo dir, strerror(errno)); 720189251Ssam } 721189251Ssam } 722189251Ssam os_free(buf); 723189251Ssam } 724189251Ssam 725189251Ssamfree_dst: 726214734Srpaulo dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst, 727214734Srpaulo list) 728214734Srpaulo os_free(dst); 729189251Ssam os_free(priv); 730189251Ssam} 731189251Ssam 732189251Ssam 733189251Ssam/** 734189251Ssam * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors 735281806Srpaulo * @ifname: Interface name for global control socket or %NULL 736281806Srpaulo * @sock: Local socket fd 737281806Srpaulo * @ctrl_dst: List of attached listeners 738189251Ssam * @level: Priority level of the message 739189251Ssam * @buf: Message data 740189251Ssam * @len: Message length 741189251Ssam * 742189251Ssam * Send a packet to all monitor programs attached to the control interface. 743189251Ssam */ 744281806Srpaulostatic void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, 745281806Srpaulo const char *ifname, int sock, 746281806Srpaulo struct dl_list *ctrl_dst, 747189251Ssam int level, const char *buf, 748281806Srpaulo size_t len, 749281806Srpaulo struct ctrl_iface_priv *priv, 750281806Srpaulo struct ctrl_iface_global_priv *gp) 751189251Ssam{ 752189251Ssam struct wpa_ctrl_dst *dst, *next; 753189251Ssam char levelstr[10]; 754189251Ssam int idx, res; 755189251Ssam struct msghdr msg; 756281806Srpaulo struct iovec io[5]; 757189251Ssam 758281806Srpaulo if (sock < 0 || dl_list_empty(ctrl_dst)) 759189251Ssam return; 760189251Ssam 761189251Ssam res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); 762281806Srpaulo if (os_snprintf_error(sizeof(levelstr), res)) 763189251Ssam return; 764281806Srpaulo idx = 0; 765281806Srpaulo if (ifname) { 766281806Srpaulo io[idx].iov_base = "IFNAME="; 767281806Srpaulo io[idx].iov_len = 7; 768281806Srpaulo idx++; 769281806Srpaulo io[idx].iov_base = (char *) ifname; 770281806Srpaulo io[idx].iov_len = os_strlen(ifname); 771281806Srpaulo idx++; 772281806Srpaulo io[idx].iov_base = " "; 773281806Srpaulo io[idx].iov_len = 1; 774281806Srpaulo idx++; 775281806Srpaulo } 776281806Srpaulo io[idx].iov_base = levelstr; 777281806Srpaulo io[idx].iov_len = os_strlen(levelstr); 778281806Srpaulo idx++; 779281806Srpaulo io[idx].iov_base = (char *) buf; 780281806Srpaulo io[idx].iov_len = len; 781281806Srpaulo idx++; 782189251Ssam os_memset(&msg, 0, sizeof(msg)); 783189251Ssam msg.msg_iov = io; 784281806Srpaulo msg.msg_iovlen = idx; 785189251Ssam 786281806Srpaulo dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) { 787281806Srpaulo int _errno; 788281806Srpaulo char addr_txt[200]; 789281806Srpaulo 790281806Srpaulo if (level < dst->debug_level) 791281806Srpaulo continue; 792281806Srpaulo 793281806Srpaulo printf_encode(addr_txt, sizeof(addr_txt), 794281806Srpaulo (u8 *) dst->addr.sun_path, dst->addrlen - 795281806Srpaulo offsetof(struct sockaddr_un, sun_path)); 796281806Srpaulo msg.msg_name = (void *) &dst->addr; 797281806Srpaulo msg.msg_namelen = dst->addrlen; 798289549Srpaulo wpas_ctrl_sock_debug("ctrl_sock-sendmsg", sock, buf, len); 799281806Srpaulo if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) { 800289549Srpaulo wpa_printf(MSG_MSGDUMP, 801289549Srpaulo "CTRL_IFACE monitor sent successfully to %s", 802281806Srpaulo addr_txt); 803281806Srpaulo dst->errors = 0; 804281806Srpaulo continue; 805189251Ssam } 806281806Srpaulo 807281806Srpaulo _errno = errno; 808281806Srpaulo wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor[%s]: %d - %s", 809281806Srpaulo addr_txt, errno, strerror(errno)); 810281806Srpaulo dst->errors++; 811281806Srpaulo 812281806Srpaulo if (dst->errors > 10 || _errno == ENOENT || _errno == EPERM) { 813281806Srpaulo wpa_printf(MSG_INFO, "CTRL_IFACE: Detach monitor %s that cannot receive messages", 814281806Srpaulo addr_txt); 815281806Srpaulo wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr, 816281806Srpaulo dst->addrlen); 817281806Srpaulo } 818281806Srpaulo 819281806Srpaulo if (_errno == ENOBUFS || _errno == EAGAIN) { 820281806Srpaulo /* 821281806Srpaulo * The socket send buffer could be full. This may happen 822281806Srpaulo * if client programs are not receiving their pending 823281806Srpaulo * messages. Close and reopen the socket as a workaround 824281806Srpaulo * to avoid getting stuck being unable to send any new 825281806Srpaulo * responses. 826281806Srpaulo */ 827281806Srpaulo if (priv) 828281806Srpaulo sock = wpas_ctrl_iface_reinit(wpa_s, priv); 829281806Srpaulo else if (gp) 830281806Srpaulo sock = wpas_ctrl_iface_global_reinit( 831281806Srpaulo wpa_s->global, gp); 832281806Srpaulo else 833281806Srpaulo break; 834281806Srpaulo if (sock < 0) { 835281806Srpaulo wpa_dbg(wpa_s, MSG_DEBUG, 836281806Srpaulo "Failed to reinitialize ctrl_iface socket"); 837281806Srpaulo break; 838281806Srpaulo } 839281806Srpaulo } 840189251Ssam } 841189251Ssam} 842189251Ssam 843189251Ssam 844189251Ssamvoid wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) 845189251Ssam{ 846189251Ssam char buf[256]; 847189251Ssam int res; 848189251Ssam struct sockaddr_un from; 849189251Ssam socklen_t fromlen = sizeof(from); 850189251Ssam 851189251Ssam for (;;) { 852189251Ssam wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to " 853189251Ssam "attach", priv->wpa_s->ifname); 854189251Ssam eloop_wait_for_read_sock(priv->sock); 855189251Ssam 856189251Ssam res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0, 857189251Ssam (struct sockaddr *) &from, &fromlen); 858189251Ssam if (res < 0) { 859281806Srpaulo wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s", 860281806Srpaulo strerror(errno)); 861189251Ssam continue; 862189251Ssam } 863189251Ssam buf[res] = '\0'; 864189251Ssam 865189251Ssam if (os_strcmp(buf, "ATTACH") == 0) { 866189251Ssam /* handle ATTACH signal of first monitor interface */ 867281806Srpaulo if (!wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, 868281806Srpaulo &from, fromlen, 869281806Srpaulo 0)) { 870281806Srpaulo if (sendto(priv->sock, "OK\n", 3, 0, 871281806Srpaulo (struct sockaddr *) &from, fromlen) < 872281806Srpaulo 0) { 873281806Srpaulo wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s", 874281806Srpaulo strerror(errno)); 875281806Srpaulo } 876189251Ssam /* OK to continue */ 877189251Ssam return; 878189251Ssam } else { 879281806Srpaulo if (sendto(priv->sock, "FAIL\n", 5, 0, 880281806Srpaulo (struct sockaddr *) &from, fromlen) < 881281806Srpaulo 0) { 882281806Srpaulo wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s", 883281806Srpaulo strerror(errno)); 884281806Srpaulo } 885189251Ssam } 886189251Ssam } else { 887189251Ssam /* return FAIL for all other signals */ 888281806Srpaulo if (sendto(priv->sock, "FAIL\n", 5, 0, 889281806Srpaulo (struct sockaddr *) &from, fromlen) < 0) { 890281806Srpaulo wpa_printf(MSG_DEBUG, 891281806Srpaulo "ctrl_iface sendto failed: %s", 892281806Srpaulo strerror(errno)); 893281806Srpaulo } 894189251Ssam } 895189251Ssam } 896189251Ssam} 897189251Ssam 898189251Ssam 899189251Ssam/* Global ctrl_iface */ 900189251Ssam 901189251Ssamstatic void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, 902189251Ssam void *sock_ctx) 903189251Ssam{ 904189251Ssam struct wpa_global *global = eloop_ctx; 905281806Srpaulo struct ctrl_iface_global_priv *priv = sock_ctx; 906281806Srpaulo char buf[4096]; 907189251Ssam int res; 908189251Ssam struct sockaddr_un from; 909189251Ssam socklen_t fromlen = sizeof(from); 910281806Srpaulo char *reply = NULL, *reply_buf = NULL; 911189251Ssam size_t reply_len; 912189251Ssam 913189251Ssam res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 914189251Ssam (struct sockaddr *) &from, &fromlen); 915189251Ssam if (res < 0) { 916281806Srpaulo wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s", 917281806Srpaulo strerror(errno)); 918189251Ssam return; 919189251Ssam } 920189251Ssam buf[res] = '\0'; 921189251Ssam 922281806Srpaulo if (os_strcmp(buf, "ATTACH") == 0) { 923281806Srpaulo if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from, 924281806Srpaulo fromlen, 1)) 925281806Srpaulo reply_len = 1; 926281806Srpaulo else 927281806Srpaulo reply_len = 2; 928281806Srpaulo } else if (os_strcmp(buf, "DETACH") == 0) { 929281806Srpaulo if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from, 930281806Srpaulo fromlen)) 931281806Srpaulo reply_len = 1; 932281806Srpaulo else 933281806Srpaulo reply_len = 2; 934281806Srpaulo } else { 935281806Srpaulo reply_buf = wpa_supplicant_global_ctrl_iface_process( 936281806Srpaulo global, buf, &reply_len); 937281806Srpaulo reply = reply_buf; 938289549Srpaulo 939289549Srpaulo /* 940289549Srpaulo * There could be some password/key material in the command, so 941289549Srpaulo * clear the buffer explicitly now that it is not needed 942289549Srpaulo * anymore. 943289549Srpaulo */ 944289549Srpaulo os_memset(buf, 0, res); 945281806Srpaulo } 946189251Ssam 947281806Srpaulo if (!reply && reply_len == 1) { 948281806Srpaulo reply = "FAIL\n"; 949281806Srpaulo reply_len = 5; 950281806Srpaulo } else if (!reply && reply_len == 2) { 951281806Srpaulo reply = "OK\n"; 952281806Srpaulo reply_len = 3; 953281806Srpaulo } 954281806Srpaulo 955189251Ssam if (reply) { 956289549Srpaulo wpas_ctrl_sock_debug("global_ctrl_sock-sendto", 957289549Srpaulo sock, reply, reply_len); 958281806Srpaulo if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, 959281806Srpaulo fromlen) < 0) { 960281806Srpaulo wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s", 961281806Srpaulo strerror(errno)); 962281806Srpaulo } 963189251Ssam } 964281806Srpaulo os_free(reply_buf); 965189251Ssam} 966189251Ssam 967189251Ssam 968281806Srpaulostatic int wpas_global_ctrl_iface_open_sock(struct wpa_global *global, 969281806Srpaulo struct ctrl_iface_global_priv *priv) 970189251Ssam{ 971189251Ssam struct sockaddr_un addr; 972281806Srpaulo const char *ctrl = global->params.ctrl_interface; 973281806Srpaulo int flags; 974189251Ssam 975281806Srpaulo wpa_printf(MSG_DEBUG, "Global control interface '%s'", ctrl); 976189251Ssam 977252726Srpaulo#ifdef ANDROID 978281806Srpaulo if (os_strncmp(ctrl, "@android:", 9) == 0) { 979281806Srpaulo priv->sock = android_get_control_socket(ctrl + 9); 980281806Srpaulo if (priv->sock < 0) { 981281806Srpaulo wpa_printf(MSG_ERROR, "Failed to open Android control " 982281806Srpaulo "socket '%s'", ctrl + 9); 983281806Srpaulo goto fail; 984281806Srpaulo } 985281806Srpaulo wpa_printf(MSG_DEBUG, "Using Android control socket '%s'", 986281806Srpaulo ctrl + 9); 987281806Srpaulo priv->android_control_socket = 1; 988252726Srpaulo goto havesock; 989281806Srpaulo } 990281806Srpaulo 991281806Srpaulo if (os_strncmp(ctrl, "@abstract:", 10) != 0) { 992281806Srpaulo /* 993281806Srpaulo * Backwards compatibility - try to open an Android control 994281806Srpaulo * socket and if that fails, assume this was a UNIX domain 995281806Srpaulo * socket instead. 996281806Srpaulo */ 997281806Srpaulo priv->sock = android_get_control_socket(ctrl); 998281806Srpaulo if (priv->sock >= 0) { 999281806Srpaulo wpa_printf(MSG_DEBUG, 1000281806Srpaulo "Using Android control socket '%s'", 1001281806Srpaulo ctrl); 1002281806Srpaulo priv->android_control_socket = 1; 1003281806Srpaulo goto havesock; 1004281806Srpaulo } 1005281806Srpaulo } 1006252726Srpaulo#endif /* ANDROID */ 1007252726Srpaulo 1008189251Ssam priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); 1009189251Ssam if (priv->sock < 0) { 1010281806Srpaulo wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno)); 1011189251Ssam goto fail; 1012189251Ssam } 1013189251Ssam 1014189251Ssam os_memset(&addr, 0, sizeof(addr)); 1015214734Srpaulo#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 1016189775Ssam addr.sun_len = sizeof(addr); 1017209158Srpaulo#endif /* __FreeBSD__ */ 1018189251Ssam addr.sun_family = AF_UNIX; 1019281806Srpaulo 1020281806Srpaulo if (os_strncmp(ctrl, "@abstract:", 10) == 0) { 1021281806Srpaulo addr.sun_path[0] = '\0'; 1022281806Srpaulo os_strlcpy(addr.sun_path + 1, ctrl + 10, 1023281806Srpaulo sizeof(addr.sun_path) - 1); 1024281806Srpaulo if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 1025281806Srpaulo 0) { 1026281806Srpaulo wpa_printf(MSG_ERROR, "supp-global-ctrl-iface-init: " 1027281806Srpaulo "bind(PF_UNIX;%s) failed: %s", 1028281806Srpaulo ctrl, strerror(errno)); 1029281806Srpaulo goto fail; 1030281806Srpaulo } 1031281806Srpaulo wpa_printf(MSG_DEBUG, "Using Abstract control socket '%s'", 1032281806Srpaulo ctrl + 10); 1033281806Srpaulo goto havesock; 1034281806Srpaulo } 1035281806Srpaulo 1036281806Srpaulo os_strlcpy(addr.sun_path, ctrl, sizeof(addr.sun_path)); 1037189251Ssam if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 1038281806Srpaulo wpa_printf(MSG_INFO, "supp-global-ctrl-iface-init(%s) (will try fixup): bind(PF_UNIX): %s", 1039281806Srpaulo ctrl, strerror(errno)); 1040189251Ssam if (connect(priv->sock, (struct sockaddr *) &addr, 1041189251Ssam sizeof(addr)) < 0) { 1042189251Ssam wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" 1043189251Ssam " allow connections - assuming it was left" 1044189251Ssam "over from forced program termination"); 1045281806Srpaulo if (unlink(ctrl) < 0) { 1046281806Srpaulo wpa_printf(MSG_ERROR, 1047281806Srpaulo "Could not unlink existing ctrl_iface socket '%s': %s", 1048281806Srpaulo ctrl, strerror(errno)); 1049189251Ssam goto fail; 1050189251Ssam } 1051189251Ssam if (bind(priv->sock, (struct sockaddr *) &addr, 1052189251Ssam sizeof(addr)) < 0) { 1053281806Srpaulo wpa_printf(MSG_ERROR, "supp-glb-iface-init: bind(PF_UNIX;%s): %s", 1054281806Srpaulo ctrl, strerror(errno)); 1055189251Ssam goto fail; 1056189251Ssam } 1057189251Ssam wpa_printf(MSG_DEBUG, "Successfully replaced leftover " 1058189251Ssam "ctrl_iface socket '%s'", 1059281806Srpaulo ctrl); 1060189251Ssam } else { 1061189251Ssam wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " 1062189251Ssam "be in use - cannot override it"); 1063189251Ssam wpa_printf(MSG_INFO, "Delete '%s' manually if it is " 1064189251Ssam "not used anymore", 1065281806Srpaulo ctrl); 1066189251Ssam goto fail; 1067189251Ssam } 1068189251Ssam } 1069189251Ssam 1070281806Srpaulo wpa_printf(MSG_DEBUG, "Using UNIX control socket '%s'", ctrl); 1071281806Srpaulo 1072281806Srpaulo if (global->params.ctrl_interface_group) { 1073281806Srpaulo char *gid_str = global->params.ctrl_interface_group; 1074281806Srpaulo gid_t gid = 0; 1075281806Srpaulo struct group *grp; 1076281806Srpaulo char *endp; 1077281806Srpaulo 1078281806Srpaulo grp = getgrnam(gid_str); 1079281806Srpaulo if (grp) { 1080281806Srpaulo gid = grp->gr_gid; 1081281806Srpaulo wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d" 1082281806Srpaulo " (from group name '%s')", 1083281806Srpaulo (int) gid, gid_str); 1084281806Srpaulo } else { 1085281806Srpaulo /* Group name not found - try to parse this as gid */ 1086281806Srpaulo gid = strtol(gid_str, &endp, 10); 1087281806Srpaulo if (*gid_str == '\0' || *endp != '\0') { 1088281806Srpaulo wpa_printf(MSG_ERROR, "CTRL: Invalid group " 1089281806Srpaulo "'%s'", gid_str); 1090281806Srpaulo goto fail; 1091281806Srpaulo } 1092281806Srpaulo wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", 1093281806Srpaulo (int) gid); 1094281806Srpaulo } 1095281806Srpaulo if (chown(ctrl, -1, gid) < 0) { 1096281806Srpaulo wpa_printf(MSG_ERROR, 1097281806Srpaulo "chown[global_ctrl_interface=%s,gid=%d]: %s", 1098281806Srpaulo ctrl, (int) gid, strerror(errno)); 1099281806Srpaulo goto fail; 1100281806Srpaulo } 1101281806Srpaulo 1102281806Srpaulo if (chmod(ctrl, S_IRWXU | S_IRWXG) < 0) { 1103281806Srpaulo wpa_printf(MSG_ERROR, 1104281806Srpaulo "chmod[global_ctrl_interface=%s]: %s", 1105281806Srpaulo ctrl, strerror(errno)); 1106281806Srpaulo goto fail; 1107281806Srpaulo } 1108281806Srpaulo } else { 1109281806Srpaulo if (chmod(ctrl, S_IRWXU) < 0) { 1110281806Srpaulo wpa_printf(MSG_DEBUG, 1111281806Srpaulo "chmod[global_ctrl_interface=%s](S_IRWXU): %s", 1112281806Srpaulo ctrl, strerror(errno)); 1113281806Srpaulo /* continue anyway since group change was not required 1114281806Srpaulo */ 1115281806Srpaulo } 1116281806Srpaulo } 1117281806Srpaulo 1118252726Srpaulohavesock: 1119281806Srpaulo 1120281806Srpaulo /* 1121281806Srpaulo * Make socket non-blocking so that we don't hang forever if 1122281806Srpaulo * target dies unexpectedly. 1123281806Srpaulo */ 1124281806Srpaulo flags = fcntl(priv->sock, F_GETFL); 1125281806Srpaulo if (flags >= 0) { 1126281806Srpaulo flags |= O_NONBLOCK; 1127281806Srpaulo if (fcntl(priv->sock, F_SETFL, flags) < 0) { 1128281806Srpaulo wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s", 1129281806Srpaulo strerror(errno)); 1130281806Srpaulo /* Not fatal, continue on.*/ 1131281806Srpaulo } 1132281806Srpaulo } 1133281806Srpaulo 1134189251Ssam eloop_register_read_sock(priv->sock, 1135189251Ssam wpa_supplicant_global_ctrl_iface_receive, 1136281806Srpaulo global, priv); 1137189251Ssam 1138281806Srpaulo return 0; 1139189251Ssam 1140189251Ssamfail: 1141281806Srpaulo if (priv->sock >= 0) { 1142189251Ssam close(priv->sock); 1143281806Srpaulo priv->sock = -1; 1144281806Srpaulo } 1145281806Srpaulo return -1; 1146189251Ssam} 1147189251Ssam 1148189251Ssam 1149281806Srpaulostruct ctrl_iface_global_priv * 1150281806Srpaulowpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) 1151281806Srpaulo{ 1152281806Srpaulo struct ctrl_iface_global_priv *priv; 1153281806Srpaulo 1154281806Srpaulo priv = os_zalloc(sizeof(*priv)); 1155281806Srpaulo if (priv == NULL) 1156281806Srpaulo return NULL; 1157281806Srpaulo dl_list_init(&priv->ctrl_dst); 1158281806Srpaulo priv->global = global; 1159281806Srpaulo priv->sock = -1; 1160281806Srpaulo 1161281806Srpaulo if (global->params.ctrl_interface == NULL) 1162281806Srpaulo return priv; 1163281806Srpaulo 1164281806Srpaulo if (wpas_global_ctrl_iface_open_sock(global, priv) < 0) { 1165281806Srpaulo os_free(priv); 1166281806Srpaulo return NULL; 1167281806Srpaulo } 1168281806Srpaulo 1169281806Srpaulo wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); 1170281806Srpaulo 1171281806Srpaulo return priv; 1172281806Srpaulo} 1173281806Srpaulo 1174281806Srpaulo 1175281806Srpaulostatic int wpas_ctrl_iface_global_reinit(struct wpa_global *global, 1176281806Srpaulo struct ctrl_iface_global_priv *priv) 1177281806Srpaulo{ 1178281806Srpaulo int res; 1179281806Srpaulo 1180281806Srpaulo if (priv->sock <= 0) 1181281806Srpaulo return -1; 1182281806Srpaulo 1183281806Srpaulo /* 1184281806Srpaulo * On Android, the control socket being used may be the socket 1185281806Srpaulo * that is created when wpa_supplicant is started as a /init.*.rc 1186281806Srpaulo * service. Such a socket is maintained as a key-value pair in 1187281806Srpaulo * Android's environment. Closing this control socket would leave us 1188281806Srpaulo * in a bad state with an invalid socket descriptor. 1189281806Srpaulo */ 1190281806Srpaulo if (priv->android_control_socket) 1191281806Srpaulo return priv->sock; 1192281806Srpaulo 1193281806Srpaulo eloop_unregister_read_sock(priv->sock); 1194281806Srpaulo close(priv->sock); 1195281806Srpaulo priv->sock = -1; 1196281806Srpaulo res = wpas_global_ctrl_iface_open_sock(global, priv); 1197281806Srpaulo if (res < 0) 1198281806Srpaulo return -1; 1199281806Srpaulo return priv->sock; 1200281806Srpaulo} 1201281806Srpaulo 1202281806Srpaulo 1203189251Ssamvoid 1204189251Ssamwpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) 1205189251Ssam{ 1206281806Srpaulo struct wpa_ctrl_dst *dst, *prev; 1207281806Srpaulo 1208189251Ssam if (priv->sock >= 0) { 1209189251Ssam eloop_unregister_read_sock(priv->sock); 1210189251Ssam close(priv->sock); 1211189251Ssam } 1212189251Ssam if (priv->global->params.ctrl_interface) 1213189251Ssam unlink(priv->global->params.ctrl_interface); 1214281806Srpaulo dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst, 1215281806Srpaulo list) 1216281806Srpaulo os_free(dst); 1217189251Ssam os_free(priv); 1218189251Ssam} 1219