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