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