1 | #include <machine/rtems-bsd-user-space.h> |
---|
2 | |
---|
3 | /* |
---|
4 | * WPA Supplicant / UNIX domain socket -based control interface |
---|
5 | * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> |
---|
6 | * |
---|
7 | * This software may be distributed under the terms of the BSD license. |
---|
8 | * See README for more details. |
---|
9 | */ |
---|
10 | |
---|
11 | #include "includes.h" |
---|
12 | #include <sys/un.h> |
---|
13 | #include <sys/stat.h> |
---|
14 | #include <grp.h> |
---|
15 | #include <stddef.h> |
---|
16 | #include <unistd.h> |
---|
17 | #include <fcntl.h> |
---|
18 | #ifdef __linux__ |
---|
19 | #include <sys/ioctl.h> |
---|
20 | #include <linux/sockios.h> |
---|
21 | #endif /* __linux__ */ |
---|
22 | #ifdef ANDROID |
---|
23 | #include <cutils/sockets.h> |
---|
24 | #endif /* ANDROID */ |
---|
25 | |
---|
26 | #include "utils/common.h" |
---|
27 | #include "utils/eloop.h" |
---|
28 | #include "utils/list.h" |
---|
29 | #include "eapol_supp/eapol_supp_sm.h" |
---|
30 | #include "config.h" |
---|
31 | #include "wpa_supplicant_i.h" |
---|
32 | #include "ctrl_iface.h" |
---|
33 | |
---|
34 | /* Per-interface ctrl_iface */ |
---|
35 | |
---|
36 | /** |
---|
37 | * struct wpa_ctrl_dst - Internal data structure of control interface monitors |
---|
38 | * |
---|
39 | * This structure is used to store information about registered control |
---|
40 | * interface monitors into struct wpa_supplicant. This data is private to |
---|
41 | * ctrl_iface_unix.c and should not be touched directly from other files. |
---|
42 | */ |
---|
43 | struct wpa_ctrl_dst { |
---|
44 | struct dl_list list; |
---|
45 | struct sockaddr_un addr; |
---|
46 | socklen_t addrlen; |
---|
47 | int debug_level; |
---|
48 | int errors; |
---|
49 | }; |
---|
50 | |
---|
51 | |
---|
52 | struct ctrl_iface_priv { |
---|
53 | struct wpa_supplicant *wpa_s; |
---|
54 | int sock; |
---|
55 | struct dl_list ctrl_dst; |
---|
56 | int android_control_socket; |
---|
57 | }; |
---|
58 | |
---|
59 | |
---|
60 | struct ctrl_iface_global_priv { |
---|
61 | struct wpa_global *global; |
---|
62 | int sock; |
---|
63 | struct dl_list ctrl_dst; |
---|
64 | int android_control_socket; |
---|
65 | }; |
---|
66 | |
---|
67 | |
---|
68 | static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, |
---|
69 | const char *ifname, int sock, |
---|
70 | struct dl_list *ctrl_dst, |
---|
71 | int level, const char *buf, |
---|
72 | size_t len, |
---|
73 | struct ctrl_iface_priv *priv, |
---|
74 | struct ctrl_iface_global_priv *gp); |
---|
75 | static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s, |
---|
76 | struct ctrl_iface_priv *priv); |
---|
77 | static int wpas_ctrl_iface_global_reinit(struct wpa_global *global, |
---|
78 | struct ctrl_iface_global_priv *priv); |
---|
79 | |
---|
80 | |
---|
81 | static void wpas_ctrl_sock_debug(const char *title, int sock, const char *buf, |
---|
82 | size_t len) |
---|
83 | { |
---|
84 | #ifdef __linux__ |
---|
85 | socklen_t optlen; |
---|
86 | int sndbuf, outq; |
---|
87 | int level = MSG_MSGDUMP; |
---|
88 | |
---|
89 | if (len >= 5 && os_strncmp(buf, "PONG\n", 5) == 0) |
---|
90 | level = MSG_EXCESSIVE; |
---|
91 | |
---|
92 | optlen = sizeof(sndbuf); |
---|
93 | sndbuf = 0; |
---|
94 | if (getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0) |
---|
95 | sndbuf = -1; |
---|
96 | |
---|
97 | if (ioctl(sock, SIOCOUTQ, &outq) < 0) |
---|
98 | outq = -1; |
---|
99 | |
---|
100 | wpa_printf(level, |
---|
101 | "CTRL-DEBUG: %s: sock=%d sndbuf=%d outq=%d send_len=%d", |
---|
102 | title, sock, sndbuf, outq, (int) len); |
---|
103 | #endif /* __linux__ */ |
---|
104 | } |
---|
105 | |
---|
106 | |
---|
107 | static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst, |
---|
108 | struct sockaddr_un *from, |
---|
109 | socklen_t fromlen, int global) |
---|
110 | { |
---|
111 | struct wpa_ctrl_dst *dst; |
---|
112 | char addr_txt[200]; |
---|
113 | |
---|
114 | dst = os_zalloc(sizeof(*dst)); |
---|
115 | if (dst == NULL) |
---|
116 | return -1; |
---|
117 | os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un)); |
---|
118 | dst->addrlen = fromlen; |
---|
119 | dst->debug_level = MSG_INFO; |
---|
120 | dl_list_add(ctrl_dst, &dst->list); |
---|
121 | printf_encode(addr_txt, sizeof(addr_txt), |
---|
122 | (u8 *) from->sun_path, |
---|
123 | fromlen - offsetof(struct sockaddr_un, sun_path)); |
---|
124 | wpa_printf(MSG_DEBUG, "CTRL_IFACE %smonitor attached %s", |
---|
125 | global ? "global " : "", addr_txt); |
---|
126 | return 0; |
---|
127 | } |
---|
128 | |
---|
129 | |
---|
130 | static int wpa_supplicant_ctrl_iface_detach(struct dl_list *ctrl_dst, |
---|
131 | struct sockaddr_un *from, |
---|
132 | socklen_t fromlen) |
---|
133 | { |
---|
134 | struct wpa_ctrl_dst *dst; |
---|
135 | |
---|
136 | dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) { |
---|
137 | if (fromlen == dst->addrlen && |
---|
138 | os_memcmp(from->sun_path, dst->addr.sun_path, |
---|
139 | fromlen - offsetof(struct sockaddr_un, sun_path)) |
---|
140 | == 0) { |
---|
141 | char addr_txt[200]; |
---|
142 | printf_encode(addr_txt, sizeof(addr_txt), |
---|
143 | (u8 *) from->sun_path, |
---|
144 | fromlen - |
---|
145 | offsetof(struct sockaddr_un, sun_path)); |
---|
146 | wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached %s", |
---|
147 | addr_txt); |
---|
148 | dl_list_del(&dst->list); |
---|
149 | os_free(dst); |
---|
150 | return 0; |
---|
151 | } |
---|
152 | } |
---|
153 | return -1; |
---|
154 | } |
---|
155 | |
---|
156 | |
---|
157 | static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, |
---|
158 | struct sockaddr_un *from, |
---|
159 | socklen_t fromlen, |
---|
160 | char *level) |
---|
161 | { |
---|
162 | struct wpa_ctrl_dst *dst; |
---|
163 | |
---|
164 | wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); |
---|
165 | |
---|
166 | dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) { |
---|
167 | if (fromlen == dst->addrlen && |
---|
168 | os_memcmp(from->sun_path, dst->addr.sun_path, |
---|
169 | fromlen - offsetof(struct sockaddr_un, sun_path)) |
---|
170 | == 0) { |
---|
171 | char addr_txt[200]; |
---|
172 | dst->debug_level = atoi(level); |
---|
173 | printf_encode(addr_txt, sizeof(addr_txt), |
---|
174 | (u8 *) from->sun_path, fromlen - |
---|
175 | offsetof(struct sockaddr_un, sun_path)); |
---|
176 | wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level to %d for %s", |
---|
177 | dst->debug_level, addr_txt); |
---|
178 | return 0; |
---|
179 | } |
---|
180 | } |
---|
181 | |
---|
182 | return -1; |
---|
183 | } |
---|
184 | |
---|
185 | |
---|
186 | static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, |
---|
187 | void *sock_ctx) |
---|
188 | { |
---|
189 | struct wpa_supplicant *wpa_s = eloop_ctx; |
---|
190 | struct ctrl_iface_priv *priv = sock_ctx; |
---|
191 | char buf[4096]; |
---|
192 | int res; |
---|
193 | struct sockaddr_un from; |
---|
194 | socklen_t fromlen = sizeof(from); |
---|
195 | char *reply = NULL, *reply_buf = NULL; |
---|
196 | size_t reply_len = 0; |
---|
197 | int new_attached = 0; |
---|
198 | |
---|
199 | res = recvfrom(sock, buf, sizeof(buf) - 1, 0, |
---|
200 | (struct sockaddr *) &from, &fromlen); |
---|
201 | if (res < 0) { |
---|
202 | wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s", |
---|
203 | strerror(errno)); |
---|
204 | return; |
---|
205 | } |
---|
206 | buf[res] = '\0'; |
---|
207 | |
---|
208 | if (os_strcmp(buf, "ATTACH") == 0) { |
---|
209 | if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from, |
---|
210 | fromlen, 0)) |
---|
211 | reply_len = 1; |
---|
212 | else { |
---|
213 | new_attached = 1; |
---|
214 | reply_len = 2; |
---|
215 | } |
---|
216 | } else if (os_strcmp(buf, "DETACH") == 0) { |
---|
217 | if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from, |
---|
218 | fromlen)) |
---|
219 | reply_len = 1; |
---|
220 | else |
---|
221 | reply_len = 2; |
---|
222 | } else if (os_strncmp(buf, "LEVEL ", 6) == 0) { |
---|
223 | if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen, |
---|
224 | buf + 6)) |
---|
225 | reply_len = 1; |
---|
226 | else |
---|
227 | reply_len = 2; |
---|
228 | } else { |
---|
229 | reply_buf = wpa_supplicant_ctrl_iface_process(wpa_s, buf, |
---|
230 | &reply_len); |
---|
231 | reply = reply_buf; |
---|
232 | |
---|
233 | /* |
---|
234 | * There could be some password/key material in the command, so |
---|
235 | * clear the buffer explicitly now that it is not needed |
---|
236 | * anymore. |
---|
237 | */ |
---|
238 | os_memset(buf, 0, res); |
---|
239 | } |
---|
240 | |
---|
241 | if (!reply && reply_len == 1) { |
---|
242 | reply = "FAIL\n"; |
---|
243 | reply_len = 5; |
---|
244 | } else if (!reply && reply_len == 2) { |
---|
245 | reply = "OK\n"; |
---|
246 | reply_len = 3; |
---|
247 | } |
---|
248 | |
---|
249 | if (reply) { |
---|
250 | wpas_ctrl_sock_debug("ctrl_sock-sendto", sock, reply, |
---|
251 | reply_len); |
---|
252 | if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, |
---|
253 | fromlen) < 0) { |
---|
254 | int _errno = errno; |
---|
255 | wpa_dbg(wpa_s, MSG_DEBUG, |
---|
256 | "ctrl_iface sendto failed: %d - %s", |
---|
257 | _errno, strerror(_errno)); |
---|
258 | if (_errno == ENOBUFS || _errno == EAGAIN) { |
---|
259 | /* |
---|
260 | * The socket send buffer could be full. This |
---|
261 | * may happen if client programs are not |
---|
262 | * receiving their pending messages. Close and |
---|
263 | * reopen the socket as a workaround to avoid |
---|
264 | * getting stuck being unable to send any new |
---|
265 | * responses. |
---|
266 | */ |
---|
267 | sock = wpas_ctrl_iface_reinit(wpa_s, priv); |
---|
268 | if (sock < 0) { |
---|
269 | wpa_dbg(wpa_s, MSG_DEBUG, "Failed to reinitialize ctrl_iface socket"); |
---|
270 | } |
---|
271 | } |
---|
272 | if (new_attached) { |
---|
273 | wpa_dbg(wpa_s, MSG_DEBUG, "Failed to send response to ATTACH - detaching"); |
---|
274 | new_attached = 0; |
---|
275 | wpa_supplicant_ctrl_iface_detach( |
---|
276 | &priv->ctrl_dst, &from, fromlen); |
---|
277 | } |
---|
278 | } |
---|
279 | } |
---|
280 | os_free(reply_buf); |
---|
281 | |
---|
282 | if (new_attached) |
---|
283 | eapol_sm_notify_ctrl_attached(wpa_s->eapol); |
---|
284 | } |
---|
285 | |
---|
286 | |
---|
287 | static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s) |
---|
288 | { |
---|
289 | char *buf; |
---|
290 | size_t len; |
---|
291 | char *pbuf, *dir = NULL; |
---|
292 | int res; |
---|
293 | |
---|
294 | if (wpa_s->conf->ctrl_interface == NULL) |
---|
295 | return NULL; |
---|
296 | |
---|
297 | pbuf = os_strdup(wpa_s->conf->ctrl_interface); |
---|
298 | if (pbuf == NULL) |
---|
299 | return NULL; |
---|
300 | if (os_strncmp(pbuf, "DIR=", 4) == 0) { |
---|
301 | char *gid_str; |
---|
302 | dir = pbuf + 4; |
---|
303 | gid_str = os_strstr(dir, " GROUP="); |
---|
304 | if (gid_str) |
---|
305 | *gid_str = '\0'; |
---|
306 | } else |
---|
307 | dir = pbuf; |
---|
308 | |
---|
309 | len = os_strlen(dir) + os_strlen(wpa_s->ifname) + 2; |
---|
310 | buf = os_malloc(len); |
---|
311 | if (buf == NULL) { |
---|
312 | os_free(pbuf); |
---|
313 | return NULL; |
---|
314 | } |
---|
315 | |
---|
316 | res = os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname); |
---|
317 | if (os_snprintf_error(len, res)) { |
---|
318 | os_free(pbuf); |
---|
319 | os_free(buf); |
---|
320 | return NULL; |
---|
321 | } |
---|
322 | #ifdef __CYGWIN__ |
---|
323 | { |
---|
324 | /* Windows/WinPcap uses interface names that are not suitable |
---|
325 | * as a file name - convert invalid chars to underscores */ |
---|
326 | char *pos = buf; |
---|
327 | while (*pos) { |
---|
328 | if (*pos == '\\') |
---|
329 | *pos = '_'; |
---|
330 | pos++; |
---|
331 | } |
---|
332 | } |
---|
333 | #endif /* __CYGWIN__ */ |
---|
334 | os_free(pbuf); |
---|
335 | return buf; |
---|
336 | } |
---|
337 | |
---|
338 | |
---|
339 | static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, |
---|
340 | enum wpa_msg_type type, |
---|
341 | const char *txt, size_t len) |
---|
342 | { |
---|
343 | struct wpa_supplicant *wpa_s = ctx; |
---|
344 | |
---|
345 | if (wpa_s == NULL) |
---|
346 | return; |
---|
347 | |
---|
348 | if (type != WPA_MSG_NO_GLOBAL && wpa_s->global->ctrl_iface) { |
---|
349 | struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface; |
---|
350 | if (!dl_list_empty(&priv->ctrl_dst)) { |
---|
351 | wpa_supplicant_ctrl_iface_send( |
---|
352 | wpa_s, |
---|
353 | type != WPA_MSG_PER_INTERFACE ? |
---|
354 | NULL : wpa_s->ifname, |
---|
355 | priv->sock, &priv->ctrl_dst, level, txt, len, |
---|
356 | NULL, priv); |
---|
357 | } |
---|
358 | } |
---|
359 | |
---|
360 | if (type == WPA_MSG_ONLY_GLOBAL || wpa_s->ctrl_iface == NULL) |
---|
361 | return; |
---|
362 | wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock, |
---|
363 | &wpa_s->ctrl_iface->ctrl_dst, |
---|
364 | level, txt, len, wpa_s->ctrl_iface, |
---|
365 | NULL); |
---|
366 | } |
---|
367 | |
---|
368 | |
---|
369 | static int wpas_ctrl_iface_open_sock(struct wpa_supplicant *wpa_s, |
---|
370 | struct ctrl_iface_priv *priv) |
---|
371 | { |
---|
372 | struct sockaddr_un addr; |
---|
373 | char *fname = NULL; |
---|
374 | gid_t gid = 0; |
---|
375 | int gid_set = 0; |
---|
376 | char *buf, *dir = NULL, *gid_str = NULL; |
---|
377 | struct group *grp; |
---|
378 | char *endp; |
---|
379 | int flags; |
---|
380 | |
---|
381 | buf = os_strdup(wpa_s->conf->ctrl_interface); |
---|
382 | if (buf == NULL) |
---|
383 | goto fail; |
---|
384 | #ifdef ANDROID |
---|
385 | os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s", |
---|
386 | wpa_s->conf->ctrl_interface); |
---|
387 | priv->sock = android_get_control_socket(addr.sun_path); |
---|
388 | if (priv->sock >= 0) { |
---|
389 | priv->android_control_socket = 1; |
---|
390 | goto havesock; |
---|
391 | } |
---|
392 | #endif /* ANDROID */ |
---|
393 | if (os_strncmp(buf, "DIR=", 4) == 0) { |
---|
394 | dir = buf + 4; |
---|
395 | gid_str = os_strstr(dir, " GROUP="); |
---|
396 | if (gid_str) { |
---|
397 | *gid_str = '\0'; |
---|
398 | gid_str += 7; |
---|
399 | } |
---|
400 | } else { |
---|
401 | dir = buf; |
---|
402 | gid_str = wpa_s->conf->ctrl_interface_group; |
---|
403 | } |
---|
404 | |
---|
405 | if (mkdir(dir, S_IRWXU | S_IRWXG) < 0) { |
---|
406 | if (errno == EEXIST) { |
---|
407 | wpa_printf(MSG_DEBUG, "Using existing control " |
---|
408 | "interface directory."); |
---|
409 | } else { |
---|
410 | wpa_printf(MSG_ERROR, "mkdir[ctrl_interface=%s]: %s", |
---|
411 | dir, strerror(errno)); |
---|
412 | goto fail; |
---|
413 | } |
---|
414 | } |
---|
415 | |
---|
416 | #ifdef ANDROID |
---|
417 | /* |
---|
418 | * wpa_supplicant is started from /init.*.rc on Android and that seems |
---|
419 | * to be using umask 0077 which would leave the control interface |
---|
420 | * directory without group access. This breaks things since Wi-Fi |
---|
421 | * framework assumes that this directory can be accessed by other |
---|
422 | * applications in the wifi group. Fix this by adding group access even |
---|
423 | * if umask value would prevent this. |
---|
424 | */ |
---|
425 | if (chmod(dir, S_IRWXU | S_IRWXG) < 0) { |
---|
426 | wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s", |
---|
427 | strerror(errno)); |
---|
428 | /* Try to continue anyway */ |
---|
429 | } |
---|
430 | #endif /* ANDROID */ |
---|
431 | |
---|
432 | if (gid_str) { |
---|
433 | grp = getgrnam(gid_str); |
---|
434 | if (grp) { |
---|
435 | gid = grp->gr_gid; |
---|
436 | gid_set = 1; |
---|
437 | wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d" |
---|
438 | " (from group name '%s')", |
---|
439 | (int) gid, gid_str); |
---|
440 | } else { |
---|
441 | /* Group name not found - try to parse this as gid */ |
---|
442 | gid = strtol(gid_str, &endp, 10); |
---|
443 | if (*gid_str == '\0' || *endp != '\0') { |
---|
444 | wpa_printf(MSG_ERROR, "CTRL: Invalid group " |
---|
445 | "'%s'", gid_str); |
---|
446 | goto fail; |
---|
447 | } |
---|
448 | gid_set = 1; |
---|
449 | wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", |
---|
450 | (int) gid); |
---|
451 | } |
---|
452 | } |
---|
453 | |
---|
454 | if (gid_set && chown(dir, -1, gid) < 0) { |
---|
455 | wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s", |
---|
456 | dir, (int) gid, strerror(errno)); |
---|
457 | goto fail; |
---|
458 | } |
---|
459 | |
---|
460 | /* Make sure the group can enter and read the directory */ |
---|
461 | if (gid_set && |
---|
462 | chmod(dir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP) < 0) { |
---|
463 | wpa_printf(MSG_ERROR, "CTRL: chmod[ctrl_interface]: %s", |
---|
464 | strerror(errno)); |
---|
465 | goto fail; |
---|
466 | } |
---|
467 | |
---|
468 | if (os_strlen(dir) + 1 + os_strlen(wpa_s->ifname) >= |
---|
469 | sizeof(addr.sun_path)) { |
---|
470 | wpa_printf(MSG_ERROR, "ctrl_iface path limit exceeded"); |
---|
471 | goto fail; |
---|
472 | } |
---|
473 | |
---|
474 | priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); |
---|
475 | if (priv->sock < 0) { |
---|
476 | wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno)); |
---|
477 | goto fail; |
---|
478 | } |
---|
479 | |
---|
480 | os_memset(&addr, 0, sizeof(addr)); |
---|
481 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
---|
482 | addr.sun_len = sizeof(addr); |
---|
483 | #endif /* __FreeBSD__ */ |
---|
484 | addr.sun_family = AF_UNIX; |
---|
485 | fname = wpa_supplicant_ctrl_iface_path(wpa_s); |
---|
486 | if (fname == NULL) |
---|
487 | goto fail; |
---|
488 | os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path)); |
---|
489 | if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { |
---|
490 | wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s", |
---|
491 | strerror(errno)); |
---|
492 | if (connect(priv->sock, (struct sockaddr *) &addr, |
---|
493 | sizeof(addr)) < 0) { |
---|
494 | wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" |
---|
495 | " allow connections - assuming it was left" |
---|
496 | "over from forced program termination"); |
---|
497 | if (unlink(fname) < 0) { |
---|
498 | wpa_printf(MSG_ERROR, |
---|
499 | "Could not unlink existing ctrl_iface socket '%s': %s", |
---|
500 | fname, strerror(errno)); |
---|
501 | goto fail; |
---|
502 | } |
---|
503 | if (bind(priv->sock, (struct sockaddr *) &addr, |
---|
504 | sizeof(addr)) < 0) { |
---|
505 | wpa_printf(MSG_ERROR, "supp-ctrl-iface-init: bind(PF_UNIX): %s", |
---|
506 | strerror(errno)); |
---|
507 | goto fail; |
---|
508 | } |
---|
509 | wpa_printf(MSG_DEBUG, "Successfully replaced leftover " |
---|
510 | "ctrl_iface socket '%s'", fname); |
---|
511 | } else { |
---|
512 | wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " |
---|
513 | "be in use - cannot override it"); |
---|
514 | wpa_printf(MSG_INFO, "Delete '%s' manually if it is " |
---|
515 | "not used anymore", fname); |
---|
516 | os_free(fname); |
---|
517 | fname = NULL; |
---|
518 | goto fail; |
---|
519 | } |
---|
520 | } |
---|
521 | |
---|
522 | if (gid_set && chown(fname, -1, gid) < 0) { |
---|
523 | wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s", |
---|
524 | fname, (int) gid, strerror(errno)); |
---|
525 | goto fail; |
---|
526 | } |
---|
527 | |
---|
528 | if (chmod(fname, S_IRWXU | S_IRWXG) < 0) { |
---|
529 | wpa_printf(MSG_ERROR, "chmod[ctrl_interface=%s]: %s", |
---|
530 | fname, strerror(errno)); |
---|
531 | goto fail; |
---|
532 | } |
---|
533 | os_free(fname); |
---|
534 | |
---|
535 | #ifdef ANDROID |
---|
536 | havesock: |
---|
537 | #endif /* ANDROID */ |
---|
538 | |
---|
539 | /* |
---|
540 | * Make socket non-blocking so that we don't hang forever if |
---|
541 | * target dies unexpectedly. |
---|
542 | */ |
---|
543 | flags = fcntl(priv->sock, F_GETFL); |
---|
544 | if (flags >= 0) { |
---|
545 | flags |= O_NONBLOCK; |
---|
546 | if (fcntl(priv->sock, F_SETFL, flags) < 0) { |
---|
547 | wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s", |
---|
548 | strerror(errno)); |
---|
549 | /* Not fatal, continue on.*/ |
---|
550 | } |
---|
551 | } |
---|
552 | |
---|
553 | eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, |
---|
554 | wpa_s, priv); |
---|
555 | wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); |
---|
556 | |
---|
557 | os_free(buf); |
---|
558 | return 0; |
---|
559 | |
---|
560 | fail: |
---|
561 | if (priv->sock >= 0) { |
---|
562 | close(priv->sock); |
---|
563 | priv->sock = -1; |
---|
564 | } |
---|
565 | if (fname) { |
---|
566 | unlink(fname); |
---|
567 | os_free(fname); |
---|
568 | } |
---|
569 | os_free(buf); |
---|
570 | return -1; |
---|
571 | } |
---|
572 | |
---|
573 | |
---|
574 | struct ctrl_iface_priv * |
---|
575 | wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) |
---|
576 | { |
---|
577 | struct ctrl_iface_priv *priv; |
---|
578 | |
---|
579 | priv = os_zalloc(sizeof(*priv)); |
---|
580 | if (priv == NULL) |
---|
581 | return NULL; |
---|
582 | dl_list_init(&priv->ctrl_dst); |
---|
583 | priv->wpa_s = wpa_s; |
---|
584 | priv->sock = -1; |
---|
585 | |
---|
586 | if (wpa_s->conf->ctrl_interface == NULL) |
---|
587 | return priv; |
---|
588 | |
---|
589 | #ifdef ANDROID |
---|
590 | if (wpa_s->global->params.ctrl_interface) { |
---|
591 | int same = 0; |
---|
592 | |
---|
593 | if (wpa_s->global->params.ctrl_interface[0] == '/') { |
---|
594 | if (os_strcmp(wpa_s->global->params.ctrl_interface, |
---|
595 | wpa_s->conf->ctrl_interface) == 0) |
---|
596 | same = 1; |
---|
597 | } else if (os_strncmp(wpa_s->global->params.ctrl_interface, |
---|
598 | "@android:", 9) == 0 || |
---|
599 | os_strncmp(wpa_s->global->params.ctrl_interface, |
---|
600 | "@abstract:", 10) == 0) { |
---|
601 | char *pos; |
---|
602 | |
---|
603 | /* |
---|
604 | * Currently, Android uses @android:wpa_* as the naming |
---|
605 | * convention for the global ctrl interface. This logic |
---|
606 | * needs to be revisited if the above naming convention |
---|
607 | * is modified. |
---|
608 | */ |
---|
609 | pos = os_strchr(wpa_s->global->params.ctrl_interface, |
---|
610 | '_'); |
---|
611 | if (pos && |
---|
612 | os_strcmp(pos + 1, |
---|
613 | wpa_s->conf->ctrl_interface) == 0) |
---|
614 | same = 1; |
---|
615 | } |
---|
616 | |
---|
617 | if (same) { |
---|
618 | /* |
---|
619 | * The invalid configuration combination might be |
---|
620 | * possible to hit in an Android OTA upgrade case, so |
---|
621 | * instead of refusing to start the wpa_supplicant |
---|
622 | * process, do not open the per-interface ctrl_iface |
---|
623 | * and continue with the global control interface that |
---|
624 | * was set from the command line since the Wi-Fi |
---|
625 | * framework will use it for operations. |
---|
626 | */ |
---|
627 | wpa_printf(MSG_ERROR, |
---|
628 | "global ctrl interface %s matches ctrl interface %s - do not open per-interface ctrl interface", |
---|
629 | wpa_s->global->params.ctrl_interface, |
---|
630 | wpa_s->conf->ctrl_interface); |
---|
631 | return priv; |
---|
632 | } |
---|
633 | } |
---|
634 | #endif /* ANDROID */ |
---|
635 | |
---|
636 | if (wpas_ctrl_iface_open_sock(wpa_s, priv) < 0) { |
---|
637 | os_free(priv); |
---|
638 | return NULL; |
---|
639 | } |
---|
640 | |
---|
641 | return priv; |
---|
642 | } |
---|
643 | |
---|
644 | |
---|
645 | static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s, |
---|
646 | struct ctrl_iface_priv *priv) |
---|
647 | { |
---|
648 | int res; |
---|
649 | |
---|
650 | if (priv->sock <= 0) |
---|
651 | return -1; |
---|
652 | |
---|
653 | /* |
---|
654 | * On Android, the control socket being used may be the socket |
---|
655 | * that is created when wpa_supplicant is started as a /init.*.rc |
---|
656 | * service. Such a socket is maintained as a key-value pair in |
---|
657 | * Android's environment. Closing this control socket would leave us |
---|
658 | * in a bad state with an invalid socket descriptor. |
---|
659 | */ |
---|
660 | if (priv->android_control_socket) |
---|
661 | return priv->sock; |
---|
662 | |
---|
663 | eloop_unregister_read_sock(priv->sock); |
---|
664 | close(priv->sock); |
---|
665 | priv->sock = -1; |
---|
666 | res = wpas_ctrl_iface_open_sock(wpa_s, priv); |
---|
667 | if (res < 0) |
---|
668 | return -1; |
---|
669 | return priv->sock; |
---|
670 | } |
---|
671 | |
---|
672 | |
---|
673 | void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) |
---|
674 | { |
---|
675 | struct wpa_ctrl_dst *dst, *prev; |
---|
676 | |
---|
677 | if (priv->sock > -1) { |
---|
678 | char *fname; |
---|
679 | char *buf, *dir = NULL; |
---|
680 | eloop_unregister_read_sock(priv->sock); |
---|
681 | if (!dl_list_empty(&priv->ctrl_dst)) { |
---|
682 | /* |
---|
683 | * Wait before closing the control socket if |
---|
684 | * there are any attached monitors in order to allow |
---|
685 | * them to receive any pending messages. |
---|
686 | */ |
---|
687 | wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached " |
---|
688 | "monitors to receive messages"); |
---|
689 | os_sleep(0, 100000); |
---|
690 | } |
---|
691 | close(priv->sock); |
---|
692 | priv->sock = -1; |
---|
693 | fname = wpa_supplicant_ctrl_iface_path(priv->wpa_s); |
---|
694 | if (fname) { |
---|
695 | unlink(fname); |
---|
696 | os_free(fname); |
---|
697 | } |
---|
698 | |
---|
699 | if (priv->wpa_s->conf->ctrl_interface == NULL) |
---|
700 | goto free_dst; |
---|
701 | buf = os_strdup(priv->wpa_s->conf->ctrl_interface); |
---|
702 | if (buf == NULL) |
---|
703 | goto free_dst; |
---|
704 | if (os_strncmp(buf, "DIR=", 4) == 0) { |
---|
705 | char *gid_str; |
---|
706 | dir = buf + 4; |
---|
707 | gid_str = os_strstr(dir, " GROUP="); |
---|
708 | if (gid_str) |
---|
709 | *gid_str = '\0'; |
---|
710 | } else |
---|
711 | dir = buf; |
---|
712 | |
---|
713 | if (rmdir(dir) < 0) { |
---|
714 | if (errno == ENOTEMPTY) { |
---|
715 | wpa_printf(MSG_DEBUG, "Control interface " |
---|
716 | "directory not empty - leaving it " |
---|
717 | "behind"); |
---|
718 | } else { |
---|
719 | wpa_printf(MSG_ERROR, |
---|
720 | "rmdir[ctrl_interface=%s]: %s", |
---|
721 | dir, strerror(errno)); |
---|
722 | } |
---|
723 | } |
---|
724 | os_free(buf); |
---|
725 | } |
---|
726 | |
---|
727 | free_dst: |
---|
728 | dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst, |
---|
729 | list) |
---|
730 | os_free(dst); |
---|
731 | os_free(priv); |
---|
732 | } |
---|
733 | |
---|
734 | |
---|
735 | /** |
---|
736 | * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors |
---|
737 | * @ifname: Interface name for global control socket or %NULL |
---|
738 | * @sock: Local socket fd |
---|
739 | * @ctrl_dst: List of attached listeners |
---|
740 | * @level: Priority level of the message |
---|
741 | * @buf: Message data |
---|
742 | * @len: Message length |
---|
743 | * |
---|
744 | * Send a packet to all monitor programs attached to the control interface. |
---|
745 | */ |
---|
746 | static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, |
---|
747 | const char *ifname, int sock, |
---|
748 | struct dl_list *ctrl_dst, |
---|
749 | int level, const char *buf, |
---|
750 | size_t len, |
---|
751 | struct ctrl_iface_priv *priv, |
---|
752 | struct ctrl_iface_global_priv *gp) |
---|
753 | { |
---|
754 | struct wpa_ctrl_dst *dst, *next; |
---|
755 | char levelstr[10]; |
---|
756 | int idx, res; |
---|
757 | struct msghdr msg; |
---|
758 | struct iovec io[5]; |
---|
759 | |
---|
760 | if (sock < 0 || dl_list_empty(ctrl_dst)) |
---|
761 | return; |
---|
762 | |
---|
763 | res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); |
---|
764 | if (os_snprintf_error(sizeof(levelstr), res)) |
---|
765 | return; |
---|
766 | idx = 0; |
---|
767 | if (ifname) { |
---|
768 | io[idx].iov_base = "IFNAME="; |
---|
769 | io[idx].iov_len = 7; |
---|
770 | idx++; |
---|
771 | io[idx].iov_base = (char *) ifname; |
---|
772 | io[idx].iov_len = os_strlen(ifname); |
---|
773 | idx++; |
---|
774 | io[idx].iov_base = " "; |
---|
775 | io[idx].iov_len = 1; |
---|
776 | idx++; |
---|
777 | } |
---|
778 | io[idx].iov_base = levelstr; |
---|
779 | io[idx].iov_len = os_strlen(levelstr); |
---|
780 | idx++; |
---|
781 | io[idx].iov_base = (char *) buf; |
---|
782 | io[idx].iov_len = len; |
---|
783 | idx++; |
---|
784 | os_memset(&msg, 0, sizeof(msg)); |
---|
785 | msg.msg_iov = io; |
---|
786 | msg.msg_iovlen = idx; |
---|
787 | |
---|
788 | dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) { |
---|
789 | int _errno; |
---|
790 | char addr_txt[200]; |
---|
791 | |
---|
792 | if (level < dst->debug_level) |
---|
793 | continue; |
---|
794 | |
---|
795 | printf_encode(addr_txt, sizeof(addr_txt), |
---|
796 | (u8 *) dst->addr.sun_path, dst->addrlen - |
---|
797 | offsetof(struct sockaddr_un, sun_path)); |
---|
798 | msg.msg_name = (void *) &dst->addr; |
---|
799 | msg.msg_namelen = dst->addrlen; |
---|
800 | wpas_ctrl_sock_debug("ctrl_sock-sendmsg", sock, buf, len); |
---|
801 | if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) { |
---|
802 | wpa_printf(MSG_MSGDUMP, |
---|
803 | "CTRL_IFACE monitor sent successfully to %s", |
---|
804 | addr_txt); |
---|
805 | dst->errors = 0; |
---|
806 | continue; |
---|
807 | } |
---|
808 | |
---|
809 | _errno = errno; |
---|
810 | wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor[%s]: %d - %s", |
---|
811 | addr_txt, errno, strerror(errno)); |
---|
812 | dst->errors++; |
---|
813 | |
---|
814 | if (dst->errors > 10 || _errno == ENOENT || _errno == EPERM) { |
---|
815 | wpa_printf(MSG_INFO, "CTRL_IFACE: Detach monitor %s that cannot receive messages", |
---|
816 | addr_txt); |
---|
817 | wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr, |
---|
818 | dst->addrlen); |
---|
819 | } |
---|
820 | |
---|
821 | if (_errno == ENOBUFS || _errno == EAGAIN) { |
---|
822 | /* |
---|
823 | * The socket send buffer could be full. This may happen |
---|
824 | * if client programs are not receiving their pending |
---|
825 | * messages. Close and reopen the socket as a workaround |
---|
826 | * to avoid getting stuck being unable to send any new |
---|
827 | * responses. |
---|
828 | */ |
---|
829 | if (priv) |
---|
830 | sock = wpas_ctrl_iface_reinit(wpa_s, priv); |
---|
831 | else if (gp) |
---|
832 | sock = wpas_ctrl_iface_global_reinit( |
---|
833 | wpa_s->global, gp); |
---|
834 | else |
---|
835 | break; |
---|
836 | if (sock < 0) { |
---|
837 | wpa_dbg(wpa_s, MSG_DEBUG, |
---|
838 | "Failed to reinitialize ctrl_iface socket"); |
---|
839 | break; |
---|
840 | } |
---|
841 | } |
---|
842 | } |
---|
843 | } |
---|
844 | |
---|
845 | |
---|
846 | void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) |
---|
847 | { |
---|
848 | char buf[256]; |
---|
849 | int res; |
---|
850 | struct sockaddr_un from; |
---|
851 | socklen_t fromlen = sizeof(from); |
---|
852 | |
---|
853 | for (;;) { |
---|
854 | wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to " |
---|
855 | "attach", priv->wpa_s->ifname); |
---|
856 | eloop_wait_for_read_sock(priv->sock); |
---|
857 | |
---|
858 | res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0, |
---|
859 | (struct sockaddr *) &from, &fromlen); |
---|
860 | if (res < 0) { |
---|
861 | wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s", |
---|
862 | strerror(errno)); |
---|
863 | continue; |
---|
864 | } |
---|
865 | buf[res] = '\0'; |
---|
866 | |
---|
867 | if (os_strcmp(buf, "ATTACH") == 0) { |
---|
868 | /* handle ATTACH signal of first monitor interface */ |
---|
869 | if (!wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, |
---|
870 | &from, fromlen, |
---|
871 | 0)) { |
---|
872 | if (sendto(priv->sock, "OK\n", 3, 0, |
---|
873 | (struct sockaddr *) &from, fromlen) < |
---|
874 | 0) { |
---|
875 | wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s", |
---|
876 | strerror(errno)); |
---|
877 | } |
---|
878 | /* OK to continue */ |
---|
879 | return; |
---|
880 | } else { |
---|
881 | if (sendto(priv->sock, "FAIL\n", 5, 0, |
---|
882 | (struct sockaddr *) &from, fromlen) < |
---|
883 | 0) { |
---|
884 | wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s", |
---|
885 | strerror(errno)); |
---|
886 | } |
---|
887 | } |
---|
888 | } else { |
---|
889 | /* return FAIL for all other signals */ |
---|
890 | if (sendto(priv->sock, "FAIL\n", 5, 0, |
---|
891 | (struct sockaddr *) &from, fromlen) < 0) { |
---|
892 | wpa_printf(MSG_DEBUG, |
---|
893 | "ctrl_iface sendto failed: %s", |
---|
894 | strerror(errno)); |
---|
895 | } |
---|
896 | } |
---|
897 | } |
---|
898 | } |
---|
899 | |
---|
900 | |
---|
901 | /* Global ctrl_iface */ |
---|
902 | |
---|
903 | static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, |
---|
904 | void *sock_ctx) |
---|
905 | { |
---|
906 | struct wpa_global *global = eloop_ctx; |
---|
907 | struct ctrl_iface_global_priv *priv = sock_ctx; |
---|
908 | char buf[4096]; |
---|
909 | int res; |
---|
910 | struct sockaddr_un from; |
---|
911 | socklen_t fromlen = sizeof(from); |
---|
912 | char *reply = NULL, *reply_buf = NULL; |
---|
913 | size_t reply_len; |
---|
914 | |
---|
915 | res = recvfrom(sock, buf, sizeof(buf) - 1, 0, |
---|
916 | (struct sockaddr *) &from, &fromlen); |
---|
917 | if (res < 0) { |
---|
918 | wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s", |
---|
919 | strerror(errno)); |
---|
920 | return; |
---|
921 | } |
---|
922 | buf[res] = '\0'; |
---|
923 | |
---|
924 | if (os_strcmp(buf, "ATTACH") == 0) { |
---|
925 | if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst, &from, |
---|
926 | fromlen, 1)) |
---|
927 | reply_len = 1; |
---|
928 | else |
---|
929 | reply_len = 2; |
---|
930 | } else if (os_strcmp(buf, "DETACH") == 0) { |
---|
931 | if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst, &from, |
---|
932 | fromlen)) |
---|
933 | reply_len = 1; |
---|
934 | else |
---|
935 | reply_len = 2; |
---|
936 | } else { |
---|
937 | reply_buf = wpa_supplicant_global_ctrl_iface_process( |
---|
938 | global, buf, &reply_len); |
---|
939 | reply = reply_buf; |
---|
940 | |
---|
941 | /* |
---|
942 | * There could be some password/key material in the command, so |
---|
943 | * clear the buffer explicitly now that it is not needed |
---|
944 | * anymore. |
---|
945 | */ |
---|
946 | os_memset(buf, 0, res); |
---|
947 | } |
---|
948 | |
---|
949 | if (!reply && reply_len == 1) { |
---|
950 | reply = "FAIL\n"; |
---|
951 | reply_len = 5; |
---|
952 | } else if (!reply && reply_len == 2) { |
---|
953 | reply = "OK\n"; |
---|
954 | reply_len = 3; |
---|
955 | } |
---|
956 | |
---|
957 | if (reply) { |
---|
958 | wpas_ctrl_sock_debug("global_ctrl_sock-sendto", |
---|
959 | sock, reply, reply_len); |
---|
960 | if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, |
---|
961 | fromlen) < 0) { |
---|
962 | wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s", |
---|
963 | strerror(errno)); |
---|
964 | } |
---|
965 | } |
---|
966 | os_free(reply_buf); |
---|
967 | } |
---|
968 | |
---|
969 | |
---|
970 | static int wpas_global_ctrl_iface_open_sock(struct wpa_global *global, |
---|
971 | struct ctrl_iface_global_priv *priv) |
---|
972 | { |
---|
973 | struct sockaddr_un addr; |
---|
974 | const char *ctrl = global->params.ctrl_interface; |
---|
975 | int flags; |
---|
976 | |
---|
977 | wpa_printf(MSG_DEBUG, "Global control interface '%s'", ctrl); |
---|
978 | |
---|
979 | #ifdef ANDROID |
---|
980 | if (os_strncmp(ctrl, "@android:", 9) == 0) { |
---|
981 | priv->sock = android_get_control_socket(ctrl + 9); |
---|
982 | if (priv->sock < 0) { |
---|
983 | wpa_printf(MSG_ERROR, "Failed to open Android control " |
---|
984 | "socket '%s'", ctrl + 9); |
---|
985 | goto fail; |
---|
986 | } |
---|
987 | wpa_printf(MSG_DEBUG, "Using Android control socket '%s'", |
---|
988 | ctrl + 9); |
---|
989 | priv->android_control_socket = 1; |
---|
990 | goto havesock; |
---|
991 | } |
---|
992 | |
---|
993 | if (os_strncmp(ctrl, "@abstract:", 10) != 0) { |
---|
994 | /* |
---|
995 | * Backwards compatibility - try to open an Android control |
---|
996 | * socket and if that fails, assume this was a UNIX domain |
---|
997 | * socket instead. |
---|
998 | */ |
---|
999 | priv->sock = android_get_control_socket(ctrl); |
---|
1000 | if (priv->sock >= 0) { |
---|
1001 | wpa_printf(MSG_DEBUG, |
---|
1002 | "Using Android control socket '%s'", |
---|
1003 | ctrl); |
---|
1004 | priv->android_control_socket = 1; |
---|
1005 | goto havesock; |
---|
1006 | } |
---|
1007 | } |
---|
1008 | #endif /* ANDROID */ |
---|
1009 | |
---|
1010 | priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); |
---|
1011 | if (priv->sock < 0) { |
---|
1012 | wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno)); |
---|
1013 | goto fail; |
---|
1014 | } |
---|
1015 | |
---|
1016 | os_memset(&addr, 0, sizeof(addr)); |
---|
1017 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
---|
1018 | addr.sun_len = sizeof(addr); |
---|
1019 | #endif /* __FreeBSD__ */ |
---|
1020 | addr.sun_family = AF_UNIX; |
---|
1021 | |
---|
1022 | if (os_strncmp(ctrl, "@abstract:", 10) == 0) { |
---|
1023 | addr.sun_path[0] = '\0'; |
---|
1024 | os_strlcpy(addr.sun_path + 1, ctrl + 10, |
---|
1025 | sizeof(addr.sun_path) - 1); |
---|
1026 | if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < |
---|
1027 | 0) { |
---|
1028 | wpa_printf(MSG_ERROR, "supp-global-ctrl-iface-init: " |
---|
1029 | "bind(PF_UNIX;%s) failed: %s", |
---|
1030 | ctrl, strerror(errno)); |
---|
1031 | goto fail; |
---|
1032 | } |
---|
1033 | wpa_printf(MSG_DEBUG, "Using Abstract control socket '%s'", |
---|
1034 | ctrl + 10); |
---|
1035 | goto havesock; |
---|
1036 | } |
---|
1037 | |
---|
1038 | os_strlcpy(addr.sun_path, ctrl, sizeof(addr.sun_path)); |
---|
1039 | if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { |
---|
1040 | wpa_printf(MSG_INFO, "supp-global-ctrl-iface-init(%s) (will try fixup): bind(PF_UNIX): %s", |
---|
1041 | ctrl, strerror(errno)); |
---|
1042 | if (connect(priv->sock, (struct sockaddr *) &addr, |
---|
1043 | sizeof(addr)) < 0) { |
---|
1044 | wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not" |
---|
1045 | " allow connections - assuming it was left" |
---|
1046 | "over from forced program termination"); |
---|
1047 | if (unlink(ctrl) < 0) { |
---|
1048 | wpa_printf(MSG_ERROR, |
---|
1049 | "Could not unlink existing ctrl_iface socket '%s': %s", |
---|
1050 | ctrl, strerror(errno)); |
---|
1051 | goto fail; |
---|
1052 | } |
---|
1053 | if (bind(priv->sock, (struct sockaddr *) &addr, |
---|
1054 | sizeof(addr)) < 0) { |
---|
1055 | wpa_printf(MSG_ERROR, "supp-glb-iface-init: bind(PF_UNIX;%s): %s", |
---|
1056 | ctrl, strerror(errno)); |
---|
1057 | goto fail; |
---|
1058 | } |
---|
1059 | wpa_printf(MSG_DEBUG, "Successfully replaced leftover " |
---|
1060 | "ctrl_iface socket '%s'", |
---|
1061 | ctrl); |
---|
1062 | } else { |
---|
1063 | wpa_printf(MSG_INFO, "ctrl_iface exists and seems to " |
---|
1064 | "be in use - cannot override it"); |
---|
1065 | wpa_printf(MSG_INFO, "Delete '%s' manually if it is " |
---|
1066 | "not used anymore", |
---|
1067 | ctrl); |
---|
1068 | goto fail; |
---|
1069 | } |
---|
1070 | } |
---|
1071 | |
---|
1072 | wpa_printf(MSG_DEBUG, "Using UNIX control socket '%s'", ctrl); |
---|
1073 | |
---|
1074 | if (global->params.ctrl_interface_group) { |
---|
1075 | char *gid_str = global->params.ctrl_interface_group; |
---|
1076 | gid_t gid = 0; |
---|
1077 | struct group *grp; |
---|
1078 | char *endp; |
---|
1079 | |
---|
1080 | grp = getgrnam(gid_str); |
---|
1081 | if (grp) { |
---|
1082 | gid = grp->gr_gid; |
---|
1083 | wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d" |
---|
1084 | " (from group name '%s')", |
---|
1085 | (int) gid, gid_str); |
---|
1086 | } else { |
---|
1087 | /* Group name not found - try to parse this as gid */ |
---|
1088 | gid = strtol(gid_str, &endp, 10); |
---|
1089 | if (*gid_str == '\0' || *endp != '\0') { |
---|
1090 | wpa_printf(MSG_ERROR, "CTRL: Invalid group " |
---|
1091 | "'%s'", gid_str); |
---|
1092 | goto fail; |
---|
1093 | } |
---|
1094 | wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d", |
---|
1095 | (int) gid); |
---|
1096 | } |
---|
1097 | if (chown(ctrl, -1, gid) < 0) { |
---|
1098 | wpa_printf(MSG_ERROR, |
---|
1099 | "chown[global_ctrl_interface=%s,gid=%d]: %s", |
---|
1100 | ctrl, (int) gid, strerror(errno)); |
---|
1101 | goto fail; |
---|
1102 | } |
---|
1103 | |
---|
1104 | if (chmod(ctrl, S_IRWXU | S_IRWXG) < 0) { |
---|
1105 | wpa_printf(MSG_ERROR, |
---|
1106 | "chmod[global_ctrl_interface=%s]: %s", |
---|
1107 | ctrl, strerror(errno)); |
---|
1108 | goto fail; |
---|
1109 | } |
---|
1110 | } else { |
---|
1111 | if (chmod(ctrl, S_IRWXU) < 0) { |
---|
1112 | wpa_printf(MSG_DEBUG, |
---|
1113 | "chmod[global_ctrl_interface=%s](S_IRWXU): %s", |
---|
1114 | ctrl, strerror(errno)); |
---|
1115 | /* continue anyway since group change was not required |
---|
1116 | */ |
---|
1117 | } |
---|
1118 | } |
---|
1119 | |
---|
1120 | havesock: |
---|
1121 | |
---|
1122 | /* |
---|
1123 | * Make socket non-blocking so that we don't hang forever if |
---|
1124 | * target dies unexpectedly. |
---|
1125 | */ |
---|
1126 | flags = fcntl(priv->sock, F_GETFL); |
---|
1127 | if (flags >= 0) { |
---|
1128 | flags |= O_NONBLOCK; |
---|
1129 | if (fcntl(priv->sock, F_SETFL, flags) < 0) { |
---|
1130 | wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s", |
---|
1131 | strerror(errno)); |
---|
1132 | /* Not fatal, continue on.*/ |
---|
1133 | } |
---|
1134 | } |
---|
1135 | |
---|
1136 | eloop_register_read_sock(priv->sock, |
---|
1137 | wpa_supplicant_global_ctrl_iface_receive, |
---|
1138 | global, priv); |
---|
1139 | |
---|
1140 | return 0; |
---|
1141 | |
---|
1142 | fail: |
---|
1143 | if (priv->sock >= 0) { |
---|
1144 | close(priv->sock); |
---|
1145 | priv->sock = -1; |
---|
1146 | } |
---|
1147 | return -1; |
---|
1148 | } |
---|
1149 | |
---|
1150 | |
---|
1151 | struct ctrl_iface_global_priv * |
---|
1152 | wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) |
---|
1153 | { |
---|
1154 | struct ctrl_iface_global_priv *priv; |
---|
1155 | |
---|
1156 | priv = os_zalloc(sizeof(*priv)); |
---|
1157 | if (priv == NULL) |
---|
1158 | return NULL; |
---|
1159 | dl_list_init(&priv->ctrl_dst); |
---|
1160 | priv->global = global; |
---|
1161 | priv->sock = -1; |
---|
1162 | |
---|
1163 | if (global->params.ctrl_interface == NULL) |
---|
1164 | return priv; |
---|
1165 | |
---|
1166 | if (wpas_global_ctrl_iface_open_sock(global, priv) < 0) { |
---|
1167 | os_free(priv); |
---|
1168 | return NULL; |
---|
1169 | } |
---|
1170 | |
---|
1171 | wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); |
---|
1172 | |
---|
1173 | return priv; |
---|
1174 | } |
---|
1175 | |
---|
1176 | |
---|
1177 | static int wpas_ctrl_iface_global_reinit(struct wpa_global *global, |
---|
1178 | struct ctrl_iface_global_priv *priv) |
---|
1179 | { |
---|
1180 | int res; |
---|
1181 | |
---|
1182 | if (priv->sock <= 0) |
---|
1183 | return -1; |
---|
1184 | |
---|
1185 | /* |
---|
1186 | * On Android, the control socket being used may be the socket |
---|
1187 | * that is created when wpa_supplicant is started as a /init.*.rc |
---|
1188 | * service. Such a socket is maintained as a key-value pair in |
---|
1189 | * Android's environment. Closing this control socket would leave us |
---|
1190 | * in a bad state with an invalid socket descriptor. |
---|
1191 | */ |
---|
1192 | if (priv->android_control_socket) |
---|
1193 | return priv->sock; |
---|
1194 | |
---|
1195 | eloop_unregister_read_sock(priv->sock); |
---|
1196 | close(priv->sock); |
---|
1197 | priv->sock = -1; |
---|
1198 | res = wpas_global_ctrl_iface_open_sock(global, priv); |
---|
1199 | if (res < 0) |
---|
1200 | return -1; |
---|
1201 | return priv->sock; |
---|
1202 | } |
---|
1203 | |
---|
1204 | |
---|
1205 | void |
---|
1206 | wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) |
---|
1207 | { |
---|
1208 | struct wpa_ctrl_dst *dst, *prev; |
---|
1209 | |
---|
1210 | if (priv->sock >= 0) { |
---|
1211 | eloop_unregister_read_sock(priv->sock); |
---|
1212 | close(priv->sock); |
---|
1213 | } |
---|
1214 | if (priv->global->params.ctrl_interface) |
---|
1215 | unlink(priv->global->params.ctrl_interface); |
---|
1216 | dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst, |
---|
1217 | list) |
---|
1218 | os_free(dst); |
---|
1219 | os_free(priv); |
---|
1220 | } |
---|