Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 706 lines (621 sloc) 16.982 kb
845e012 auto import from //depot/cupcake/@135843
The Android Open Source Project authored
1 /*
2 * WPA Supplicant / UNIX domain socket -based control interface
3 * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15 #include "includes.h"
16 #include <sys/un.h>
17 #include <sys/stat.h>
18 #include <grp.h>
19 #ifdef ANDROID
20 #include <cutils/sockets.h>
21 #endif
22
23 #include "common.h"
24 #include "eloop.h"
25 #include "config.h"
26 #include "eapol_sm.h"
27 #include "wpa_supplicant_i.h"
28 #include "ctrl_iface.h"
29
30 /* Per-interface ctrl_iface */
31
32 /**
33 * struct wpa_ctrl_dst - Internal data structure of control interface monitors
34 *
35 * This structure is used to store information about registered control
36 * interface monitors into struct wpa_supplicant. This data is private to
37 * ctrl_iface_unix.c and should not be touched directly from other files.
38 */
39 struct wpa_ctrl_dst {
40 struct wpa_ctrl_dst *next;
41 struct sockaddr_un addr;
42 socklen_t addrlen;
43 int debug_level;
44 int errors;
45 };
46
47
48 struct ctrl_iface_priv {
49 struct wpa_supplicant *wpa_s;
50 int sock;
51 struct wpa_ctrl_dst *ctrl_dst;
52 };
53
54
55 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
56 int level, const char *buf,
57 size_t len);
58
59
60 static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
61 struct sockaddr_un *from,
62 socklen_t fromlen)
63 {
64 struct wpa_ctrl_dst *dst;
65
66 dst = os_zalloc(sizeof(*dst));
67 if (dst == NULL)
68 return -1;
69 os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
70 dst->addrlen = fromlen;
71 dst->debug_level = MSG_INFO;
72 dst->next = priv->ctrl_dst;
73 priv->ctrl_dst = dst;
74 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
75 (u8 *) from->sun_path, fromlen - sizeof(from->sun_family));
76 return 0;
77 }
78
79
80 static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
81 struct sockaddr_un *from,
82 socklen_t fromlen)
83 {
84 struct wpa_ctrl_dst *dst, *prev = NULL;
85
86 dst = priv->ctrl_dst;
87 while (dst) {
88 if (fromlen == dst->addrlen &&
89 os_memcmp(from->sun_path, dst->addr.sun_path,
90 fromlen - sizeof(from->sun_family)) == 0) {
91 if (prev == NULL)
92 priv->ctrl_dst = dst->next;
93 else
94 prev->next = dst->next;
95 os_free(dst);
96 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
97 (u8 *) from->sun_path,
98 fromlen - sizeof(from->sun_family));
99 return 0;
100 }
101 prev = dst;
102 dst = dst->next;
103 }
104 return -1;
105 }
106
107
108 static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
109 struct sockaddr_un *from,
110 socklen_t fromlen,
111 char *level)
112 {
113 struct wpa_ctrl_dst *dst;
114
115 wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
116
117 dst = priv->ctrl_dst;
118 while (dst) {
119 if (fromlen == dst->addrlen &&
120 os_memcmp(from->sun_path, dst->addr.sun_path,
121 fromlen - sizeof(from->sun_family)) == 0) {
122 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
123 "level", (u8 *) from->sun_path,
124 fromlen - sizeof(from->sun_family));
125 dst->debug_level = atoi(level);
126 return 0;
127 }
128 dst = dst->next;
129 }
130
131 return -1;
132 }
133
134
135 static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
136 void *sock_ctx)
137 {
138 struct wpa_supplicant *wpa_s = eloop_ctx;
139 struct ctrl_iface_priv *priv = sock_ctx;
140 char buf[256];
141 int res;
142 struct sockaddr_un from;
143 socklen_t fromlen = sizeof(from);
144 char *reply = NULL;
145 size_t reply_len = 0;
146 int new_attached = 0;
147
148 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
149 (struct sockaddr *) &from, &fromlen);
150 if (res < 0) {
151 perror("recvfrom(ctrl_iface)");
152 return;
153 }
154 buf[res] = '\0';
155
156 if (os_strcmp(buf, "ATTACH") == 0) {
157 if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen))
158 reply_len = 1;
159 else {
160 new_attached = 1;
161 reply_len = 2;
162 }
163 } else if (os_strcmp(buf, "DETACH") == 0) {
164 if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen))
165 reply_len = 1;
166 else
167 reply_len = 2;
168 } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
169 if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,
170 buf + 6))
171 reply_len = 1;
172 else
173 reply_len = 2;
174 } else {
175 reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
176 &reply_len);
177 }
178
179 if (reply) {
180 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
181 fromlen);
182 os_free(reply);
183 } else if (reply_len == 1) {
184 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
185 fromlen);
186 } else if (reply_len == 2) {
187 sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
188 fromlen);
189 }
190
191 if (new_attached)
192 eapol_sm_notify_ctrl_attached(wpa_s->eapol);
193 }
194
195
196 static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
197 {
198 char *buf;
199 size_t len;
200 char *pbuf, *dir = NULL, *gid_str = NULL;
201
202 if (wpa_s->conf->ctrl_interface == NULL)
203 return NULL;
204
205 pbuf = os_strdup(wpa_s->conf->ctrl_interface);
206 if (pbuf == NULL)
207 return NULL;
208 if (os_strncmp(pbuf, "DIR=", 4) == 0) {
209 dir = pbuf + 4;
210 gid_str = os_strstr(dir, " GROUP=");
211 if (gid_str) {
212 *gid_str = '\0';
213 gid_str += 7;
214 }
215 } else
216 dir = pbuf;
217
218 len = os_strlen(dir) + os_strlen(wpa_s->ifname) + 2;
219 buf = os_malloc(len);
220 if (buf == NULL) {
221 os_free(pbuf);
222 return NULL;
223 }
224
225 os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname);
226 #ifdef __CYGWIN__
227 {
228 /* Windows/WinPcap uses interface names that are not suitable
229 * as a file name - convert invalid chars to underscores */
230 char *pos = buf;
231 while (*pos) {
232 if (*pos == '\\')
233 *pos = '_';
234 pos++;
235 }
236 }
237 #endif /* __CYGWIN__ */
238 os_free(pbuf);
239 return buf;
240 }
241
242
243 static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
244 const char *txt, size_t len)
245 {
246 struct wpa_supplicant *wpa_s = ctx;
247 if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
248 return;
249 wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
250 }
251
252
253 struct ctrl_iface_priv *
254 wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
255 {
256 struct ctrl_iface_priv *priv;
257 struct sockaddr_un addr;
258 char *fname = NULL;
259 gid_t gid = 0;
260 int gid_set = 0;
261 char *buf, *dir = NULL, *gid_str = NULL;
262 struct group *grp;
263 char *endp;
264
265 priv = os_zalloc(sizeof(*priv));
266 if (priv == NULL)
267 return NULL;
268 priv->wpa_s = wpa_s;
269 priv->sock = -1;
270
271 if (wpa_s->conf->ctrl_interface == NULL)
272 return priv;
273
274 buf = os_strdup(wpa_s->conf->ctrl_interface);
275 if (buf == NULL)
276 goto fail;
277 #ifdef ANDROID
278 os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s",
279 wpa_s->conf->ctrl_interface);
280 priv->sock = android_get_control_socket(addr.sun_path);
281 if (priv->sock >= 0)
282 goto havesock;
283 #endif
284 if (os_strncmp(buf, "DIR=", 4) == 0) {
285 dir = buf + 4;
286 gid_str = os_strstr(dir, " GROUP=");
287 if (gid_str) {
288 *gid_str = '\0';
289 gid_str += 7;
290 }
291 } else {
292 dir = buf;
293 gid_str = wpa_s->conf->ctrl_interface_group;
294 }
295
296 if (mkdir(dir, S_IRWXU | S_IRWXG) < 0) {
297 if (errno == EEXIST) {
298 wpa_printf(MSG_DEBUG, "Using existing control "
299 "interface directory.");
300 } else {
301 perror("mkdir[ctrl_interface]");
302 goto fail;
303 }
304 }
305
306 if (gid_str) {
307 grp = getgrnam(gid_str);
308 if (grp) {
309 gid = grp->gr_gid;
310 gid_set = 1;
311 wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
312 " (from group name '%s')",
313 (int) gid, gid_str);
314 } else {
315 /* Group name not found - try to parse this as gid */
316 gid = strtol(gid_str, &endp, 10);
317 if (*gid_str == '\0' || *endp != '\0') {
dc9507e AI 146505: am: CL 146027 Update wpa_supplicant from 0.5.10 to 0.5.11
Dmitry Shmidt authored
318 wpa_printf(MSG_ERROR, "CTRL: Invalid group "
845e012 auto import from //depot/cupcake/@135843
The Android Open Source Project authored
319 "'%s'", gid_str);
320 goto fail;
321 }
322 gid_set = 1;
323 wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
324 (int) gid);
325 }
326 }
327
328 if (gid_set && chown(dir, -1, gid) < 0) {
329 perror("chown[ctrl_interface]");
330 goto fail;
331 }
332
333 if (os_strlen(dir) + 1 + os_strlen(wpa_s->ifname) >=
334 sizeof(addr.sun_path))
335 goto fail;
336
337 priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
338 if (priv->sock < 0) {
339 perror("socket(PF_UNIX)");
340 goto fail;
341 }
342
343 os_memset(&addr, 0, sizeof(addr));
344 addr.sun_family = AF_UNIX;
345 fname = wpa_supplicant_ctrl_iface_path(wpa_s);
346 if (fname == NULL)
347 goto fail;
348 os_strncpy(addr.sun_path, fname, sizeof(addr.sun_path));
349 if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
350 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
351 strerror(errno));
352 if (connect(priv->sock, (struct sockaddr *) &addr,
353 sizeof(addr)) < 0) {
354 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
355 " allow connections - assuming it was left"
356 "over from forced program termination");
357 if (unlink(fname) < 0) {
358 perror("unlink[ctrl_iface]");
359 wpa_printf(MSG_ERROR, "Could not unlink "
360 "existing ctrl_iface socket '%s'",
361 fname);
362 goto fail;
363 }
364 if (bind(priv->sock, (struct sockaddr *) &addr,
365 sizeof(addr)) < 0) {
366 perror("bind(PF_UNIX)");
367 goto fail;
368 }
369 wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
370 "ctrl_iface socket '%s'", fname);
371 } else {
372 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
373 "be in use - cannot override it");
374 wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
375 "not used anymore", fname);
376 os_free(fname);
377 fname = NULL;
378 goto fail;
379 }
380 }
381
382 if (gid_set && chown(fname, -1, gid) < 0) {
383 perror("chown[ctrl_interface/ifname]");
384 goto fail;
385 }
386
387 if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
388 perror("chmod[ctrl_interface/ifname]");
389 goto fail;
390 }
391 os_free(fname);
392
393 havesock:
394 eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
395 wpa_s, priv);
396 wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
397
398 os_free(buf);
399 return priv;
400
401 fail:
402 if (priv->sock >= 0)
403 close(priv->sock);
404 os_free(priv);
405 if (fname) {
406 unlink(fname);
407 os_free(fname);
408 }
409 os_free(buf);
410 return NULL;
411 }
412
413
414 void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
415 {
416 struct wpa_ctrl_dst *dst, *prev;
417
418 if (priv->sock > -1) {
419 char *fname;
420 char *buf, *dir = NULL, *gid_str = NULL;
421 eloop_unregister_read_sock(priv->sock);
422 if (priv->ctrl_dst) {
423 /*
424 * Wait a second before closing the control socket if
425 * there are any attached monitors in order to allow
426 * them to receive any pending messages.
427 */
428 wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
429 "monitors to receive messages");
430 os_sleep(1, 0);
431 }
432 close(priv->sock);
433 priv->sock = -1;
434 fname = wpa_supplicant_ctrl_iface_path(priv->wpa_s);
435 if (fname) {
436 unlink(fname);
437 os_free(fname);
438 }
439
440 buf = os_strdup(priv->wpa_s->conf->ctrl_interface);
441 if (buf == NULL)
442 goto free_dst;
443 if (os_strncmp(buf, "DIR=", 4) == 0) {
444 dir = buf + 4;
445 gid_str = os_strstr(dir, " GROUP=");
446 if (gid_str) {
447 *gid_str = '\0';
448 gid_str += 7;
449 }
450 } else
451 dir = buf;
452
453 if (rmdir(dir) < 0) {
454 if (errno == ENOTEMPTY) {
455 wpa_printf(MSG_DEBUG, "Control interface "
456 "directory not empty - leaving it "
457 "behind");
458 } else {
459 perror("rmdir[ctrl_interface]");
460 }
461 }
462 os_free(buf);
463 }
464
465 free_dst:
466 dst = priv->ctrl_dst;
467 while (dst) {
468 prev = dst;
469 dst = dst->next;
470 os_free(prev);
471 }
472 os_free(priv);
473 }
474
475
476 /**
477 * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors
478 * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
479 * @level: Priority level of the message
480 * @buf: Message data
481 * @len: Message length
482 *
483 * Send a packet to all monitor programs attached to the control interface.
484 */
485 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
486 int level, const char *buf,
487 size_t len)
488 {
489 struct wpa_ctrl_dst *dst, *next;
490 char levelstr[10];
491 int idx;
492 struct msghdr msg;
493 struct iovec io[2];
494
495 dst = priv->ctrl_dst;
496 if (priv->sock < 0 || dst == NULL)
497 return;
498
499 os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
500 io[0].iov_base = levelstr;
501 io[0].iov_len = os_strlen(levelstr);
502 io[1].iov_base = (char *) buf;
503 io[1].iov_len = len;
504 os_memset(&msg, 0, sizeof(msg));
505 msg.msg_iov = io;
506 msg.msg_iovlen = 2;
507
508 idx = 0;
509 while (dst) {
510 next = dst->next;
511 if (level >= dst->debug_level) {
512 wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
513 (u8 *) dst->addr.sun_path, dst->addrlen -
514 sizeof(dst->addr.sun_family));
515 msg.msg_name = (void *) &dst->addr;
516 msg.msg_namelen = dst->addrlen;
517 if (sendmsg(priv->sock, &msg, 0) < 0) {
518 perror("sendmsg(CTRL_IFACE monitor)");
519 dst->errors++;
520 if (dst->errors > 10) {
521 wpa_supplicant_ctrl_iface_detach(
522 priv, &dst->addr,
523 dst->addrlen);
524 }
525 } else
526 dst->errors = 0;
527 }
528 idx++;
529 dst = next;
530 }
531 }
532
533
534 void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
535 {
536 char buf[256];
537 int res;
538 struct sockaddr_un from;
539 socklen_t fromlen = sizeof(from);
540
541 for (;;) {
542 wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to "
543 "attach", priv->wpa_s->ifname);
544 eloop_wait_for_read_sock(priv->sock);
545
546 res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0,
547 (struct sockaddr *) &from, &fromlen);
548 if (res < 0) {
549 perror("recvfrom(ctrl_iface)");
550 continue;
551 }
552 buf[res] = '\0';
553
554 if (os_strcmp(buf, "ATTACH") == 0) {
555 /* handle ATTACH signal of first monitor interface */
556 if (!wpa_supplicant_ctrl_iface_attach(priv, &from,
557 fromlen)) {
558 sendto(priv->sock, "OK\n", 3, 0,
559 (struct sockaddr *) &from, fromlen);
560 /* OK to continue */
561 return;
562 } else {
563 sendto(priv->sock, "FAIL\n", 5, 0,
564 (struct sockaddr *) &from, fromlen);
565 }
566 } else {
567 /* return FAIL for all other signals */
568 sendto(priv->sock, "FAIL\n", 5, 0,
569 (struct sockaddr *) &from, fromlen);
570 }
571 }
572 }
573
574
575 /* Global ctrl_iface */
576
577 struct ctrl_iface_global_priv {
578 struct wpa_global *global;
579 int sock;
580 };
581
582
583 static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
584 void *sock_ctx)
585 {
586 struct wpa_global *global = eloop_ctx;
587 char buf[256];
588 int res;
589 struct sockaddr_un from;
590 socklen_t fromlen = sizeof(from);
591 char *reply;
592 size_t reply_len;
593
594 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
595 (struct sockaddr *) &from, &fromlen);
596 if (res < 0) {
597 perror("recvfrom(ctrl_iface)");
598 return;
599 }
600 buf[res] = '\0';
601
602 reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
603 &reply_len);
604
605 if (reply) {
606 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
607 fromlen);
608 os_free(reply);
609 } else if (reply_len) {
610 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
611 fromlen);
612 }
613 }
614
615
616 struct ctrl_iface_global_priv *
617 wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
618 {
619 struct ctrl_iface_global_priv *priv;
620 struct sockaddr_un addr;
621
622 priv = os_zalloc(sizeof(*priv));
623 if (priv == NULL)
624 return NULL;
625 priv->global = global;
626 priv->sock = -1;
627
628 if (global->params.ctrl_interface == NULL)
629 return priv;
630
631 #ifdef ANDROID
632 priv->sock = android_get_control_socket(global->params.ctrl_interface);
633 if (priv->sock >= 0)
634 goto havesock;
635 #endif
636 wpa_printf(MSG_DEBUG, "Global control interface '%s'",
637 global->params.ctrl_interface);
638
639 priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
640 if (priv->sock < 0) {
641 perror("socket(PF_UNIX)");
642 goto fail;
643 }
644
645 os_memset(&addr, 0, sizeof(addr));
646 addr.sun_family = AF_UNIX;
647 os_strncpy(addr.sun_path, global->params.ctrl_interface,
648 sizeof(addr.sun_path));
649 if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
650 perror("bind(PF_UNIX)");
651 if (connect(priv->sock, (struct sockaddr *) &addr,
652 sizeof(addr)) < 0) {
653 wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
654 " allow connections - assuming it was left"
655 "over from forced program termination");
656 if (unlink(global->params.ctrl_interface) < 0) {
657 perror("unlink[ctrl_iface]");
658 wpa_printf(MSG_ERROR, "Could not unlink "
659 "existing ctrl_iface socket '%s'",
660 global->params.ctrl_interface);
661 goto fail;
662 }
663 if (bind(priv->sock, (struct sockaddr *) &addr,
664 sizeof(addr)) < 0) {
665 perror("bind(PF_UNIX)");
666 goto fail;
667 }
668 wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
669 "ctrl_iface socket '%s'",
670 global->params.ctrl_interface);
671 } else {
672 wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
673 "be in use - cannot override it");
674 wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
675 "not used anymore",
676 global->params.ctrl_interface);
677 goto fail;
678 }
679 }
680 havesock:
681 eloop_register_read_sock(priv->sock,
682 wpa_supplicant_global_ctrl_iface_receive,
683 global, NULL);
684
685 return priv;
686
687 fail:
688 if (priv->sock >= 0)
689 close(priv->sock);
690 os_free(priv);
691 return NULL;
692 }
693
694
695 void
696 wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
697 {
698 if (priv->sock >= 0) {
699 eloop_unregister_read_sock(priv->sock);
700 close(priv->sock);
701 }
702 if (priv->global->params.ctrl_interface)
703 unlink(priv->global->params.ctrl_interface);
704 os_free(priv);
705 }
Something went wrong with that request. Please try again.