xref: /freebsd/contrib/wpa/wpa_supplicant/ctrl_iface_udp.c (revision b9f654b163bce26de79705e77b872427c9f2afa1)
1 /*
2  * WPA Supplicant / UDP socket -based control interface
3  * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "includes.h"
10 
11 #include "common.h"
12 #include "eloop.h"
13 #include "config.h"
14 #include "eapol_supp/eapol_supp_sm.h"
15 #include "wpa_supplicant_i.h"
16 #include "ctrl_iface.h"
17 #include "common/wpa_ctrl.h"
18 
19 
20 #define COOKIE_LEN 8
21 
22 /* Per-interface ctrl_iface */
23 
24 /**
25  * struct wpa_ctrl_dst - Internal data structure of control interface monitors
26  *
27  * This structure is used to store information about registered control
28  * interface monitors into struct wpa_supplicant. This data is private to
29  * ctrl_iface_udp.c and should not be touched directly from other files.
30  */
31 struct wpa_ctrl_dst {
32 	struct wpa_ctrl_dst *next;
33 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
34 	struct sockaddr_in6 addr;
35 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
36 	struct sockaddr_in addr;
37 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
38 	socklen_t addrlen;
39 	int debug_level;
40 	int errors;
41 };
42 
43 
44 struct ctrl_iface_priv {
45 	struct wpa_supplicant *wpa_s;
46 	int sock;
47 	struct wpa_ctrl_dst *ctrl_dst;
48 	u8 cookie[COOKIE_LEN];
49 };
50 
51 struct ctrl_iface_global_priv {
52 	int sock;
53 	struct wpa_ctrl_dst *ctrl_dst;
54 	u8 cookie[COOKIE_LEN];
55 };
56 
57 
58 static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
59 					   const char *ifname, int sock,
60 					   struct wpa_ctrl_dst **head,
61 					   int level, const char *buf,
62 					   size_t len);
63 
64 
65 static void wpas_ctrl_iface_free_dst(struct wpa_ctrl_dst *dst)
66 {
67 	struct wpa_ctrl_dst *prev;
68 
69 	while (dst) {
70 		prev = dst;
71 		dst = dst->next;
72 		os_free(prev);
73 	}
74 }
75 
76 
77 static int wpa_supplicant_ctrl_iface_attach(struct wpa_ctrl_dst **head,
78 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
79 					    struct sockaddr_in6 *from,
80 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
81 					    struct sockaddr_in *from,
82 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
83 					    socklen_t fromlen)
84 {
85 	struct wpa_ctrl_dst *dst;
86 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
87 	char addr[INET6_ADDRSTRLEN];
88 #endif /* CONFIG_UDP_IPV6 */
89 
90 	dst = os_zalloc(sizeof(*dst));
91 	if (dst == NULL)
92 		return -1;
93 	os_memcpy(&dst->addr, from, sizeof(*from));
94 	dst->addrlen = fromlen;
95 	dst->debug_level = MSG_INFO;
96 	dst->next = *head;
97 	*head = dst;
98 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
99 	wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
100 		   inet_ntop(AF_INET6, &from->sin6_addr, addr, sizeof(*from)),
101 		   ntohs(from->sin6_port));
102 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
103 	wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
104 		   inet_ntoa(from->sin_addr), ntohs(from->sin_port));
105 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
106 	return 0;
107 }
108 
109 
110 static int wpa_supplicant_ctrl_iface_detach(struct wpa_ctrl_dst **head,
111 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
112 					    struct sockaddr_in6 *from,
113 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
114 					    struct sockaddr_in *from,
115 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
116 					    socklen_t fromlen)
117 {
118 	struct wpa_ctrl_dst *dst, *prev = NULL;
119 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
120 	char addr[INET6_ADDRSTRLEN];
121 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
122 
123 	dst = *head;
124 	while (dst) {
125 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
126 		if (from->sin6_port == dst->addr.sin6_port &&
127 		    !os_memcmp(&from->sin6_addr, &dst->addr.sin6_addr,
128 			       sizeof(from->sin6_addr))) {
129 			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached %s:%d",
130 				   inet_ntop(AF_INET6, &from->sin6_addr, addr,
131 					     sizeof(*from)),
132 				   ntohs(from->sin6_port));
133 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
134 		if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
135 		    from->sin_port == dst->addr.sin_port) {
136 			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
137 				   "%s:%d", inet_ntoa(from->sin_addr),
138 				   ntohs(from->sin_port));
139 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
140 			if (prev == NULL)
141 				*head = dst->next;
142 			else
143 				prev->next = dst->next;
144 			os_free(dst);
145 			return 0;
146 		}
147 		prev = dst;
148 		dst = dst->next;
149 	}
150 	return -1;
151 }
152 
153 
154 static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
155 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
156 					   struct sockaddr_in6 *from,
157 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
158 					   struct sockaddr_in *from,
159 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
160 					   socklen_t fromlen,
161 					   char *level)
162 {
163 	struct wpa_ctrl_dst *dst;
164 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
165 	char addr[INET6_ADDRSTRLEN];
166 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
167 
168 	wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
169 
170 	dst = priv->ctrl_dst;
171 	while (dst) {
172 #if CONFIG_CTRL_IFACE_UDP_IPV6
173 		if (from->sin6_port == dst->addr.sin6_port &&
174 		    !os_memcmp(&from->sin6_addr, &dst->addr.sin6_addr,
175 			       sizeof(from->sin6_addr))) {
176 			wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level %s:%d",
177 				   inet_ntop(AF_INET6, &from->sin6_addr, addr,
178 					     sizeof(*from)),
179 				   ntohs(from->sin6_port));
180 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
181 		if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
182 		    from->sin_port == dst->addr.sin_port) {
183 			wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor "
184 				   "level %s:%d", inet_ntoa(from->sin_addr),
185 				   ntohs(from->sin_port));
186 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
187 			dst->debug_level = atoi(level);
188 			return 0;
189 		}
190 		dst = dst->next;
191 	}
192 
193 	return -1;
194 }
195 
196 
197 static char *
198 wpa_supplicant_ctrl_iface_get_cookie(struct ctrl_iface_priv *priv,
199 				     size_t *reply_len)
200 {
201 	char *reply;
202 	reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
203 	if (reply == NULL) {
204 		*reply_len = 1;
205 		return NULL;
206 	}
207 
208 	os_memcpy(reply, "COOKIE=", 7);
209 	wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
210 			 priv->cookie, COOKIE_LEN);
211 
212 	*reply_len = 7 + 2 * COOKIE_LEN;
213 	return reply;
214 }
215 
216 
217 static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
218 					      void *sock_ctx)
219 {
220 	struct wpa_supplicant *wpa_s = eloop_ctx;
221 	struct ctrl_iface_priv *priv = sock_ctx;
222 	char buf[4096], *pos;
223 	int res;
224 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
225 	struct sockaddr_in6 from;
226 #ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
227 	char addr[INET6_ADDRSTRLEN];
228 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
229 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
230 	struct sockaddr_in from;
231 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
232 	socklen_t fromlen = sizeof(from);
233 	char *reply = NULL;
234 	size_t reply_len = 0;
235 	int new_attached = 0;
236 	u8 cookie[COOKIE_LEN];
237 
238 	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
239 		       (struct sockaddr *) &from, &fromlen);
240 	if (res < 0) {
241 		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
242 			   strerror(errno));
243 		return;
244 	}
245 
246 #ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
247 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
248 	inet_ntop(AF_INET6, &from.sin6_addr, addr, sizeof(from));
249 	if (os_strcmp(addr, "::1")) {
250 		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected source %s",
251 			   addr);
252 	}
253 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
254 	if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
255 		/*
256 		 * The OS networking stack is expected to drop this kind of
257 		 * frames since the socket is bound to only localhost address.
258 		 * Just in case, drop the frame if it is coming from any other
259 		 * address.
260 		 */
261 		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
262 			   "source %s", inet_ntoa(from.sin_addr));
263 		return;
264 	}
265 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
266 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
267 
268 	buf[res] = '\0';
269 
270 	if (os_strcmp(buf, "GET_COOKIE") == 0) {
271 		reply = wpa_supplicant_ctrl_iface_get_cookie(priv, &reply_len);
272 		goto done;
273 	}
274 
275 	/*
276 	 * Require that the client includes a prefix with the 'cookie' value
277 	 * fetched with GET_COOKIE command. This is used to verify that the
278 	 * client has access to a bidirectional link over UDP in order to
279 	 * avoid attacks using forged localhost IP address even if the OS does
280 	 * not block such frames from remote destinations.
281 	 */
282 	if (os_strncmp(buf, "COOKIE=", 7) != 0) {
283 		wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
284 			   "drop request");
285 		return;
286 	}
287 
288 	if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
289 		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
290 			   "request - drop request");
291 		return;
292 	}
293 
294 	if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
295 		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
296 			   "drop request");
297 		return;
298 	}
299 
300 	pos = buf + 7 + 2 * COOKIE_LEN;
301 	while (*pos == ' ')
302 		pos++;
303 
304 	if (os_strcmp(pos, "ATTACH") == 0) {
305 		if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
306 						     &from, fromlen))
307 			reply_len = 1;
308 		else {
309 			new_attached = 1;
310 			reply_len = 2;
311 		}
312 	} else if (os_strcmp(pos, "DETACH") == 0) {
313 		if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst,
314 						     &from, fromlen))
315 			reply_len = 1;
316 		else
317 			reply_len = 2;
318 	} else if (os_strncmp(pos, "LEVEL ", 6) == 0) {
319 		if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,
320 						    pos + 6))
321 			reply_len = 1;
322 		else
323 			reply_len = 2;
324 	} else {
325 		reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos,
326 							  &reply_len);
327 	}
328 
329  done:
330 	if (reply) {
331 		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
332 		       fromlen);
333 		os_free(reply);
334 	} else if (reply_len == 1) {
335 		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
336 		       fromlen);
337 	} else if (reply_len == 2) {
338 		sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
339 		       fromlen);
340 	}
341 
342 	if (new_attached)
343 		eapol_sm_notify_ctrl_attached(wpa_s->eapol);
344 }
345 
346 
347 static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
348 					     enum wpa_msg_type type,
349 					     const char *txt, size_t len)
350 {
351 	struct wpa_supplicant *wpa_s = ctx;
352 
353 	if (!wpa_s)
354 		return;
355 
356 	if (type != WPA_MSG_NO_GLOBAL && wpa_s->global->ctrl_iface) {
357 		struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface;
358 
359 		if (priv->ctrl_dst) {
360 			wpa_supplicant_ctrl_iface_send(
361 				wpa_s,
362 				type != WPA_MSG_PER_INTERFACE ?
363 				NULL : wpa_s->ifname,
364 				priv->sock, &priv->ctrl_dst, level, txt, len);
365 		}
366 	}
367 
368 	if (type == WPA_MSG_ONLY_GLOBAL || !wpa_s->ctrl_iface)
369 		return;
370 
371 	wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock,
372 				       &wpa_s->ctrl_iface->ctrl_dst,
373 				       level, txt, len);
374 }
375 
376 
377 struct ctrl_iface_priv *
378 wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
379 {
380 	struct ctrl_iface_priv *priv;
381 	char port_str[40];
382 	int port = WPA_CTRL_IFACE_PORT;
383 	char *pos;
384 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
385 	struct sockaddr_in6 addr;
386 	int domain = PF_INET6;
387 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
388 	struct sockaddr_in addr;
389 	int domain = PF_INET;
390 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
391 
392 	priv = os_zalloc(sizeof(*priv));
393 	if (priv == NULL)
394 		return NULL;
395 	priv->wpa_s = wpa_s;
396 	priv->sock = -1;
397 	os_get_random(priv->cookie, COOKIE_LEN);
398 
399 	if (wpa_s->conf->ctrl_interface == NULL)
400 		return priv;
401 
402 	pos = os_strstr(wpa_s->conf->ctrl_interface, "udp:");
403 	if (pos) {
404 		pos += 4;
405 		port = atoi(pos);
406 		if (port <= 0) {
407 			wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port: %s",
408 				   wpa_s->conf->ctrl_interface);
409 			goto fail;
410 		}
411 	}
412 
413 	priv->sock = socket(domain, SOCK_DGRAM, 0);
414 	if (priv->sock < 0) {
415 		wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
416 		goto fail;
417 	}
418 
419 	os_memset(&addr, 0, sizeof(addr));
420 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
421 	addr.sin6_family = AF_INET6;
422 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
423 	addr.sin6_addr = in6addr_any;
424 #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
425 	inet_pton(AF_INET6, "::1", &addr.sin6_addr);
426 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
427 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
428 	addr.sin_family = AF_INET;
429 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
430 	addr.sin_addr.s_addr = INADDR_ANY;
431 #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
432 	addr.sin_addr.s_addr = htonl((127 << 24) | 1);
433 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
434 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
435 try_again:
436 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
437 	addr.sin6_port = htons(port);
438 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
439 	addr.sin_port = htons(port);
440 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
441 	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
442 		port--;
443 		if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT)
444 			goto try_again;
445 		wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
446 		goto fail;
447 	}
448 
449 	/* Update the ctrl_interface value to match the selected port */
450 	os_snprintf(port_str, sizeof(port_str), "udp:%d", port);
451 	os_free(wpa_s->conf->ctrl_interface);
452 	wpa_s->conf->ctrl_interface = os_strdup(port_str);
453 	if (!wpa_s->conf->ctrl_interface) {
454 		wpa_msg(wpa_s, MSG_ERROR, "Failed to malloc ctrl_interface");
455 		goto fail;
456 	}
457 
458 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
459 	wpa_msg(wpa_s, MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
460 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
461 
462 	eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
463 				 wpa_s, priv);
464 	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
465 
466 	return priv;
467 
468 fail:
469 	if (priv->sock >= 0)
470 		close(priv->sock);
471 	os_free(priv);
472 	return NULL;
473 }
474 
475 
476 void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
477 {
478 	if (priv->sock > -1) {
479 		eloop_unregister_read_sock(priv->sock);
480 		if (priv->ctrl_dst) {
481 			/*
482 			 * Wait before closing the control socket if
483 			 * there are any attached monitors in order to allow
484 			 * them to receive any pending messages.
485 			 */
486 			wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
487 				   "monitors to receive messages");
488 			os_sleep(0, 100000);
489 		}
490 		close(priv->sock);
491 		priv->sock = -1;
492 	}
493 
494 	wpas_ctrl_iface_free_dst(priv->ctrl_dst);
495 	os_free(priv);
496 }
497 
498 
499 static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
500 					   const char *ifname, int sock,
501 					   struct wpa_ctrl_dst **head,
502 					   int level, const char *buf,
503 					   size_t len)
504 {
505 	struct wpa_ctrl_dst *dst, *next;
506 	char levelstr[64];
507 	int idx;
508 	char *sbuf;
509 	int llen;
510 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
511 	char addr[INET6_ADDRSTRLEN];
512 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
513 
514 	dst = *head;
515 	if (sock < 0 || dst == NULL)
516 		return;
517 
518 	if (ifname)
519 		os_snprintf(levelstr, sizeof(levelstr), "IFACE=%s <%d>",
520 			    ifname, level);
521 	else
522 		os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
523 
524 	llen = os_strlen(levelstr);
525 	sbuf = os_malloc(llen + len);
526 	if (sbuf == NULL)
527 		return;
528 
529 	os_memcpy(sbuf, levelstr, llen);
530 	os_memcpy(sbuf + llen, buf, len);
531 
532 	idx = 0;
533 	while (dst) {
534 		next = dst->next;
535 		if (level >= dst->debug_level) {
536 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
537 			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
538 				   inet_ntop(AF_INET6, &dst->addr.sin6_addr,
539 					     addr, sizeof(dst->addr)),
540 				   ntohs(dst->addr.sin6_port));
541 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
542 			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
543 				   inet_ntoa(dst->addr.sin_addr),
544 				   ntohs(dst->addr.sin_port));
545 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
546 			if (sendto(sock, sbuf, llen + len, 0,
547 				   (struct sockaddr *) &dst->addr,
548 				   sizeof(dst->addr)) < 0) {
549 				wpa_printf(MSG_ERROR,
550 					   "sendto(CTRL_IFACE monitor): %s",
551 					   strerror(errno));
552 				dst->errors++;
553 				if (dst->errors > 10) {
554 					wpa_supplicant_ctrl_iface_detach(
555 						head, &dst->addr,
556 						dst->addrlen);
557 				}
558 			} else
559 				dst->errors = 0;
560 		}
561 		idx++;
562 		dst = next;
563 	}
564 	os_free(sbuf);
565 }
566 
567 
568 void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
569 {
570 	wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor",
571 		   priv->wpa_s->ifname);
572 	eloop_wait_for_read_sock(priv->sock);
573 }
574 
575 
576 /* Global ctrl_iface */
577 
578 static char *
579 wpa_supplicant_global_get_cookie(struct ctrl_iface_global_priv *priv,
580 				 size_t *reply_len)
581 {
582 	char *reply;
583 	reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
584 	if (reply == NULL) {
585 		*reply_len = 1;
586 		return NULL;
587 	}
588 
589 	os_memcpy(reply, "COOKIE=", 7);
590 	wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
591 			 priv->cookie, COOKIE_LEN);
592 
593 	*reply_len = 7 + 2 * COOKIE_LEN;
594 	return reply;
595 }
596 
597 
598 static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
599 						     void *sock_ctx)
600 {
601 	struct wpa_global *global = eloop_ctx;
602 	struct ctrl_iface_global_priv *priv = sock_ctx;
603 	char buf[4096], *pos;
604 	int res;
605 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
606 	struct sockaddr_in6 from;
607 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
608 	struct sockaddr_in from;
609 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
610 	socklen_t fromlen = sizeof(from);
611 	char *reply = NULL;
612 	size_t reply_len;
613 	u8 cookie[COOKIE_LEN];
614 
615 	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
616 		       (struct sockaddr *) &from, &fromlen);
617 	if (res < 0) {
618 		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
619 			   strerror(errno));
620 		return;
621 	}
622 
623 #ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
624 #ifndef CONFIG_CTRL_IFACE_UDP_IPV6
625 	if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
626 		/*
627 		 * The OS networking stack is expected to drop this kind of
628 		 * frames since the socket is bound to only localhost address.
629 		 * Just in case, drop the frame if it is coming from any other
630 		 * address.
631 		 */
632 		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
633 			   "source %s", inet_ntoa(from.sin_addr));
634 		return;
635 	}
636 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
637 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
638 
639 	buf[res] = '\0';
640 
641 	if (os_strcmp(buf, "GET_COOKIE") == 0) {
642 		reply = wpa_supplicant_global_get_cookie(priv, &reply_len);
643 		goto done;
644 	}
645 
646 	if (os_strncmp(buf, "COOKIE=", 7) != 0) {
647 		wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
648 			   "drop request");
649 		return;
650 	}
651 
652 	if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
653 		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
654 			   "request - drop request");
655 		return;
656 	}
657 
658 	if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
659 		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
660 			   "drop request");
661 		return;
662 	}
663 
664 	pos = buf + 7 + 2 * COOKIE_LEN;
665 	while (*pos == ' ')
666 		pos++;
667 
668 	if (os_strcmp(pos, "ATTACH") == 0) {
669 		if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
670 						     &from, fromlen))
671 			reply_len = 1;
672 		else
673 			reply_len = 2;
674 	} else if (os_strcmp(pos, "DETACH") == 0) {
675 		if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst,
676 						     &from, fromlen))
677 			reply_len = 1;
678 		else
679 			reply_len = 2;
680 	} else {
681 		reply = wpa_supplicant_global_ctrl_iface_process(global, pos,
682 								 &reply_len);
683 	}
684 
685  done:
686 	if (reply) {
687 		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
688 		       fromlen);
689 		os_free(reply);
690 	} else if (reply_len == 1) {
691 		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
692 		       fromlen);
693 	} else if (reply_len == 2) {
694 		sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
695 		       fromlen);
696 	}
697 }
698 
699 
700 struct ctrl_iface_global_priv *
701 wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
702 {
703 	struct ctrl_iface_global_priv *priv;
704 	struct sockaddr_in addr;
705 	char *pos;
706 	int port = WPA_GLOBAL_CTRL_IFACE_PORT;
707 
708 	priv = os_zalloc(sizeof(*priv));
709 	if (priv == NULL)
710 		return NULL;
711 	priv->sock = -1;
712 	os_get_random(priv->cookie, COOKIE_LEN);
713 
714 	if (global->params.ctrl_interface == NULL)
715 		return priv;
716 
717 	wpa_printf(MSG_DEBUG, "Global control interface '%s'",
718 		   global->params.ctrl_interface);
719 
720 	pos = os_strstr(global->params.ctrl_interface, "udp:");
721 	if (pos) {
722 		pos += 4;
723 		port = atoi(pos);
724 		if (port <= 0) {
725 			wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port %s",
726 				   global->params.ctrl_interface);
727 			goto fail;
728 		}
729 	}
730 
731 	priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
732 	if (priv->sock < 0) {
733 		wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
734 		goto fail;
735 	}
736 
737 	os_memset(&addr, 0, sizeof(addr));
738 	addr.sin_family = AF_INET;
739 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
740 	addr.sin_addr.s_addr = INADDR_ANY;
741 #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
742 	addr.sin_addr.s_addr = htonl((127 << 24) | 1);
743 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
744 try_again:
745 	addr.sin_port = htons(port);
746 	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
747 		port++;
748 		if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) <
749 		    WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT && !pos)
750 			goto try_again;
751 		wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
752 		goto fail;
753 	}
754 
755 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
756 	wpa_printf(MSG_DEBUG, "global_ctrl_iface_init UDP port: %d", port);
757 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
758 
759 	eloop_register_read_sock(priv->sock,
760 				 wpa_supplicant_global_ctrl_iface_receive,
761 				 global, priv);
762 	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
763 
764 	return priv;
765 
766 fail:
767 	if (priv->sock >= 0)
768 		close(priv->sock);
769 	os_free(priv);
770 	return NULL;
771 }
772 
773 
774 void
775 wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
776 {
777 	if (priv->sock >= 0) {
778 		eloop_unregister_read_sock(priv->sock);
779 		close(priv->sock);
780 	}
781 
782 	wpas_ctrl_iface_free_dst(priv->ctrl_dst);
783 	os_free(priv);
784 }
785