Home | History | Annotate | Download | only in wpa_supplicant
      1 /*
      2  * WPA Supplicant / UDP socket -based control interface
      3  * Copyright (c) 2004-2005, Jouni Malinen <j (at) 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 
     17 #include "common.h"
     18 #include "eloop.h"
     19 #include "config.h"
     20 #include "eapol_supp/eapol_supp_sm.h"
     21 #include "wpa_supplicant_i.h"
     22 #include "ctrl_iface.h"
     23 #include "wpa_ctrl.h"
     24 
     25 
     26 #define COOKIE_LEN 8
     27 
     28 /* Per-interface ctrl_iface */
     29 
     30 /**
     31  * struct wpa_ctrl_dst - Internal data structure of control interface monitors
     32  *
     33  * This structure is used to store information about registered control
     34  * interface monitors into struct wpa_supplicant. This data is private to
     35  * ctrl_iface_udp.c and should not be touched directly from other files.
     36  */
     37 struct wpa_ctrl_dst {
     38 	struct wpa_ctrl_dst *next;
     39 	struct sockaddr_in addr;
     40 	socklen_t addrlen;
     41 	int debug_level;
     42 	int errors;
     43 };
     44 
     45 
     46 struct ctrl_iface_priv {
     47 	struct wpa_supplicant *wpa_s;
     48 	int sock;
     49 	struct wpa_ctrl_dst *ctrl_dst;
     50 	u8 cookie[COOKIE_LEN];
     51 };
     52 
     53 
     54 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
     55 					   int level, const char *buf,
     56 					   size_t len);
     57 
     58 
     59 static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
     60 					    struct sockaddr_in *from,
     61 					    socklen_t fromlen)
     62 {
     63 	struct wpa_ctrl_dst *dst;
     64 
     65 	dst = os_zalloc(sizeof(*dst));
     66 	if (dst == NULL)
     67 		return -1;
     68 	os_memcpy(&dst->addr, from, sizeof(struct sockaddr_in));
     69 	dst->addrlen = fromlen;
     70 	dst->debug_level = MSG_INFO;
     71 	dst->next = priv->ctrl_dst;
     72 	priv->ctrl_dst = dst;
     73 	wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
     74 		   inet_ntoa(from->sin_addr), ntohs(from->sin_port));
     75 	return 0;
     76 }
     77 
     78 
     79 static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
     80 					    struct sockaddr_in *from,
     81 					    socklen_t fromlen)
     82 {
     83 	struct wpa_ctrl_dst *dst, *prev = NULL;
     84 
     85 	dst = priv->ctrl_dst;
     86 	while (dst) {
     87 		if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
     88 		    from->sin_port == dst->addr.sin_port) {
     89 			if (prev == NULL)
     90 				priv->ctrl_dst = dst->next;
     91 			else
     92 				prev->next = dst->next;
     93 			os_free(dst);
     94 			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
     95 				   "%s:%d", inet_ntoa(from->sin_addr),
     96 				   ntohs(from->sin_port));
     97 			return 0;
     98 		}
     99 		prev = dst;
    100 		dst = dst->next;
    101 	}
    102 	return -1;
    103 }
    104 
    105 
    106 static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
    107 					   struct sockaddr_in *from,
    108 					   socklen_t fromlen,
    109 					   char *level)
    110 {
    111 	struct wpa_ctrl_dst *dst;
    112 
    113 	wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
    114 
    115 	dst = priv->ctrl_dst;
    116 	while (dst) {
    117 		if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
    118 		    from->sin_port == dst->addr.sin_port) {
    119 			wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor "
    120 				   "level %s:%d", inet_ntoa(from->sin_addr),
    121 				   ntohs(from->sin_port));
    122 			dst->debug_level = atoi(level);
    123 			return 0;
    124 		}
    125 		dst = dst->next;
    126 	}
    127 
    128 	return -1;
    129 }
    130 
    131 
    132 static char *
    133 wpa_supplicant_ctrl_iface_get_cookie(struct ctrl_iface_priv *priv,
    134 				     size_t *reply_len)
    135 {
    136 	char *reply;
    137 	reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
    138 	if (reply == NULL) {
    139 		*reply_len = 1;
    140 		return NULL;
    141 	}
    142 
    143 	os_memcpy(reply, "COOKIE=", 7);
    144 	wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
    145 			 priv->cookie, COOKIE_LEN);
    146 
    147 	*reply_len = 7 + 2 * COOKIE_LEN;
    148 	return reply;
    149 }
    150 
    151 
    152 static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
    153 					      void *sock_ctx)
    154 {
    155 	struct wpa_supplicant *wpa_s = eloop_ctx;
    156 	struct ctrl_iface_priv *priv = sock_ctx;
    157 	char buf[256], *pos;
    158 	int res;
    159 	struct sockaddr_in from;
    160 	socklen_t fromlen = sizeof(from);
    161 	char *reply = NULL;
    162 	size_t reply_len = 0;
    163 	int new_attached = 0;
    164 	u8 cookie[COOKIE_LEN];
    165 
    166 	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
    167 		       (struct sockaddr *) &from, &fromlen);
    168 	if (res < 0) {
    169 		perror("recvfrom(ctrl_iface)");
    170 		return;
    171 	}
    172 	if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
    173 		/*
    174 		 * The OS networking stack is expected to drop this kind of
    175 		 * frames since the socket is bound to only localhost address.
    176 		 * Just in case, drop the frame if it is coming from any other
    177 		 * address.
    178 		 */
    179 		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
    180 			   "source %s", inet_ntoa(from.sin_addr));
    181 		return;
    182 	}
    183 	buf[res] = '\0';
    184 
    185 	if (os_strcmp(buf, "GET_COOKIE") == 0) {
    186 		reply = wpa_supplicant_ctrl_iface_get_cookie(priv, &reply_len);
    187 		goto done;
    188 	}
    189 
    190 	/*
    191 	 * Require that the client includes a prefix with the 'cookie' value
    192 	 * fetched with GET_COOKIE command. This is used to verify that the
    193 	 * client has access to a bidirectional link over UDP in order to
    194 	 * avoid attacks using forged localhost IP address even if the OS does
    195 	 * not block such frames from remote destinations.
    196 	 */
    197 	if (os_strncmp(buf, "COOKIE=", 7) != 0) {
    198 		wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
    199 			   "drop request");
    200 		return;
    201 	}
    202 
    203 	if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
    204 		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
    205 			   "request - drop request");
    206 		return;
    207 	}
    208 
    209 	if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
    210 		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
    211 			   "drop request");
    212 		return;
    213 	}
    214 
    215 	pos = buf + 7 + 2 * COOKIE_LEN;
    216 	while (*pos == ' ')
    217 		pos++;
    218 
    219 	if (os_strcmp(pos, "ATTACH") == 0) {
    220 		if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen))
    221 			reply_len = 1;
    222 		else {
    223 			new_attached = 1;
    224 			reply_len = 2;
    225 		}
    226 	} else if (os_strcmp(pos, "DETACH") == 0) {
    227 		if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen))
    228 			reply_len = 1;
    229 		else
    230 			reply_len = 2;
    231 	} else if (os_strncmp(pos, "LEVEL ", 6) == 0) {
    232 		if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,
    233 						    pos + 6))
    234 			reply_len = 1;
    235 		else
    236 			reply_len = 2;
    237 	} else {
    238 		reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos,
    239 							  &reply_len);
    240 	}
    241 
    242  done:
    243 	if (reply) {
    244 		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
    245 		       fromlen);
    246 		os_free(reply);
    247 	} else if (reply_len == 1) {
    248 		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
    249 		       fromlen);
    250 	} else if (reply_len == 2) {
    251 		sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
    252 		       fromlen);
    253 	}
    254 
    255 	if (new_attached)
    256 		eapol_sm_notify_ctrl_attached(wpa_s->eapol);
    257 }
    258 
    259 
    260 static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
    261 					     const char *txt, size_t len)
    262 {
    263 	struct wpa_supplicant *wpa_s = ctx;
    264 	if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
    265 		return;
    266 	wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
    267 }
    268 
    269 
    270 struct ctrl_iface_priv *
    271 wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
    272 {
    273 	struct ctrl_iface_priv *priv;
    274 	struct sockaddr_in addr;
    275 
    276 	priv = os_zalloc(sizeof(*priv));
    277 	if (priv == NULL)
    278 		return NULL;
    279 	priv->wpa_s = wpa_s;
    280 	priv->sock = -1;
    281 	os_get_random(priv->cookie, COOKIE_LEN);
    282 
    283 	if (wpa_s->conf->ctrl_interface == NULL)
    284 		return priv;
    285 
    286 	priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
    287 	if (priv->sock < 0) {
    288 		perror("socket(PF_INET)");
    289 		goto fail;
    290 	}
    291 
    292 	os_memset(&addr, 0, sizeof(addr));
    293 	addr.sin_family = AF_INET;
    294 	addr.sin_addr.s_addr = htonl((127 << 24) | 1);
    295 	addr.sin_port = htons(WPA_CTRL_IFACE_PORT);
    296 	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
    297 		perror("bind(AF_INET)");
    298 		goto fail;
    299 	}
    300 
    301 	eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
    302 				 wpa_s, priv);
    303 	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
    304 
    305 	return priv;
    306 
    307 fail:
    308 	if (priv->sock >= 0)
    309 		close(priv->sock);
    310 	os_free(priv);
    311 	return NULL;
    312 }
    313 
    314 
    315 void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
    316 {
    317 	struct wpa_ctrl_dst *dst, *prev;
    318 
    319 	if (priv->sock > -1) {
    320 		eloop_unregister_read_sock(priv->sock);
    321 		if (priv->ctrl_dst) {
    322 			/*
    323 			 * Wait a second before closing the control socket if
    324 			 * there are any attached monitors in order to allow
    325 			 * them to receive any pending messages.
    326 			 */
    327 			wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
    328 				   "monitors to receive messages");
    329 			os_sleep(1, 0);
    330 		}
    331 		close(priv->sock);
    332 		priv->sock = -1;
    333 	}
    334 
    335 	dst = priv->ctrl_dst;
    336 	while (dst) {
    337 		prev = dst;
    338 		dst = dst->next;
    339 		os_free(prev);
    340 	}
    341 	os_free(priv);
    342 }
    343 
    344 
    345 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
    346 					   int level, const char *buf,
    347 					   size_t len)
    348 {
    349 	struct wpa_ctrl_dst *dst, *next;
    350 	char levelstr[10];
    351 	int idx;
    352 	char *sbuf;
    353 	int llen;
    354 
    355 	dst = priv->ctrl_dst;
    356 	if (priv->sock < 0 || dst == NULL)
    357 		return;
    358 
    359 	os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
    360 
    361 	llen = os_strlen(levelstr);
    362 	sbuf = os_malloc(llen + len);
    363 	if (sbuf == NULL)
    364 		return;
    365 
    366 	os_memcpy(sbuf, levelstr, llen);
    367 	os_memcpy(sbuf + llen, buf, len);
    368 
    369 	idx = 0;
    370 	while (dst) {
    371 		next = dst->next;
    372 		if (level >= dst->debug_level) {
    373 			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
    374 				   inet_ntoa(dst->addr.sin_addr),
    375 				   ntohs(dst->addr.sin_port));
    376 			if (sendto(priv->sock, sbuf, llen + len, 0,
    377 				   (struct sockaddr *) &dst->addr,
    378 				   sizeof(dst->addr)) < 0) {
    379 				perror("sendto(CTRL_IFACE monitor)");
    380 				dst->errors++;
    381 				if (dst->errors > 10) {
    382 					wpa_supplicant_ctrl_iface_detach(
    383 						priv, &dst->addr,
    384 						dst->addrlen);
    385 				}
    386 			} else
    387 				dst->errors = 0;
    388 		}
    389 		idx++;
    390 		dst = next;
    391 	}
    392 	os_free(sbuf);
    393 }
    394 
    395 
    396 void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
    397 {
    398 	wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor",
    399 		   priv->wpa_s->ifname);
    400 	eloop_wait_for_read_sock(priv->sock);
    401 }
    402 
    403 
    404 /* Global ctrl_iface */
    405 
    406 struct ctrl_iface_global_priv {
    407 	int sock;
    408 	u8 cookie[COOKIE_LEN];
    409 };
    410 
    411 
    412 static char *
    413 wpa_supplicant_global_get_cookie(struct ctrl_iface_global_priv *priv,
    414 				 size_t *reply_len)
    415 {
    416 	char *reply;
    417 	reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
    418 	if (reply == NULL) {
    419 		*reply_len = 1;
    420 		return NULL;
    421 	}
    422 
    423 	os_memcpy(reply, "COOKIE=", 7);
    424 	wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
    425 			 priv->cookie, COOKIE_LEN);
    426 
    427 	*reply_len = 7 + 2 * COOKIE_LEN;
    428 	return reply;
    429 }
    430 
    431 
    432 static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
    433 						     void *sock_ctx)
    434 {
    435 	struct wpa_global *global = eloop_ctx;
    436 	struct ctrl_iface_global_priv *priv = sock_ctx;
    437 	char buf[256], *pos;
    438 	int res;
    439 	struct sockaddr_in from;
    440 	socklen_t fromlen = sizeof(from);
    441 	char *reply;
    442 	size_t reply_len;
    443 	u8 cookie[COOKIE_LEN];
    444 
    445 	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
    446 		       (struct sockaddr *) &from, &fromlen);
    447 	if (res < 0) {
    448 		perror("recvfrom(ctrl_iface)");
    449 		return;
    450 	}
    451 	if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
    452 		/*
    453 		 * The OS networking stack is expected to drop this kind of
    454 		 * frames since the socket is bound to only localhost address.
    455 		 * Just in case, drop the frame if it is coming from any other
    456 		 * address.
    457 		 */
    458 		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
    459 			   "source %s", inet_ntoa(from.sin_addr));
    460 		return;
    461 	}
    462 	buf[res] = '\0';
    463 
    464 	if (os_strcmp(buf, "GET_COOKIE") == 0) {
    465 		reply = wpa_supplicant_global_get_cookie(priv, &reply_len);
    466 		goto done;
    467 	}
    468 
    469 	if (os_strncmp(buf, "COOKIE=", 7) != 0) {
    470 		wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
    471 			   "drop request");
    472 		return;
    473 	}
    474 
    475 	if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
    476 		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
    477 			   "request - drop request");
    478 		return;
    479 	}
    480 
    481 	if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
    482 		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
    483 			   "drop request");
    484 		return;
    485 	}
    486 
    487 	pos = buf + 7 + 2 * COOKIE_LEN;
    488 	while (*pos == ' ')
    489 		pos++;
    490 
    491 	reply = wpa_supplicant_global_ctrl_iface_process(global, pos,
    492 							 &reply_len);
    493 
    494  done:
    495 	if (reply) {
    496 		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
    497 		       fromlen);
    498 		os_free(reply);
    499 	} else if (reply_len) {
    500 		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
    501 		       fromlen);
    502 	}
    503 }
    504 
    505 
    506 struct ctrl_iface_global_priv *
    507 wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
    508 {
    509 	struct ctrl_iface_global_priv *priv;
    510 	struct sockaddr_in addr;
    511 
    512 	priv = os_zalloc(sizeof(*priv));
    513 	if (priv == NULL)
    514 		return NULL;
    515 	priv->sock = -1;
    516 	os_get_random(priv->cookie, COOKIE_LEN);
    517 
    518 	if (global->params.ctrl_interface == NULL)
    519 		return priv;
    520 
    521 	wpa_printf(MSG_DEBUG, "Global control interface '%s'",
    522 		   global->params.ctrl_interface);
    523 
    524 	priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
    525 	if (priv->sock < 0) {
    526 		perror("socket(PF_INET)");
    527 		goto fail;
    528 	}
    529 
    530 	os_memset(&addr, 0, sizeof(addr));
    531 	addr.sin_family = AF_INET;
    532 	addr.sin_addr.s_addr = htonl((127 << 24) | 1);
    533 	addr.sin_port = htons(WPA_GLOBAL_CTRL_IFACE_PORT);
    534 	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
    535 		perror("bind(AF_INET)");
    536 		goto fail;
    537 	}
    538 
    539 	eloop_register_read_sock(priv->sock,
    540 				 wpa_supplicant_global_ctrl_iface_receive,
    541 				 global, priv);
    542 
    543 	return priv;
    544 
    545 fail:
    546 	if (priv->sock >= 0)
    547 		close(priv->sock);
    548 	os_free(priv);
    549 	return NULL;
    550 }
    551 
    552 
    553 void
    554 wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
    555 {
    556 	if (priv->sock >= 0) {
    557 		eloop_unregister_read_sock(priv->sock);
    558 		close(priv->sock);
    559 	}
    560 	os_free(priv);
    561 }
    562