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 */
39struct 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
48struct ctrl_iface_priv {
49	struct wpa_supplicant *wpa_s;
50	int sock;
51	struct wpa_ctrl_dst *ctrl_dst;
52};
53
54
55static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
56					   int level, const char *buf,
57					   size_t len);
58
59
60static 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
80static 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
108static 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
135static 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
196static 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
243static 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
253struct ctrl_iface_priv *
254wpa_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') {
318				wpa_printf(MSG_ERROR, "CTRL: Invalid group "
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
393havesock:
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
401fail:
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
414void 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
465free_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 */
485static 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
534void 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
577struct ctrl_iface_global_priv {
578	struct wpa_global *global;
579	int sock;
580};
581
582
583static 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
616struct ctrl_iface_global_priv *
617wpa_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	}
680havesock:
681	eloop_register_read_sock(priv->sock,
682				 wpa_supplicant_global_ctrl_iface_receive,
683				 global, NULL);
684
685	return priv;
686
687fail:
688	if (priv->sock >= 0)
689		close(priv->sock);
690	os_free(priv);
691	return NULL;
692}
693
694
695void
696wpa_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}
706