$search
00001 /* 00002 * WPA Supplicant / UDP socket -based control interface 00003 * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 00017 #include "common.h" 00018 #include "eloop.h" 00019 #include "config.h" 00020 #include "eapol_supp/eapol_supp_sm.h" 00021 #include "wpa_supplicant_i.h" 00022 #include "ctrl_iface.h" 00023 #include "common/wpa_ctrl.h" 00024 00025 00026 #define COOKIE_LEN 8 00027 00028 /* Per-interface ctrl_iface */ 00029 00037 struct wpa_ctrl_dst { 00038 struct wpa_ctrl_dst *next; 00039 struct sockaddr_in addr; 00040 socklen_t addrlen; 00041 int debug_level; 00042 int errors; 00043 }; 00044 00045 00046 struct ctrl_iface_priv { 00047 struct wpa_supplicant *wpa_s; 00048 int sock; 00049 struct wpa_ctrl_dst *ctrl_dst; 00050 u8 cookie[COOKIE_LEN]; 00051 }; 00052 00053 00054 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 00055 int level, const char *buf, 00056 size_t len); 00057 00058 00059 static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv, 00060 struct sockaddr_in *from, 00061 socklen_t fromlen) 00062 { 00063 struct wpa_ctrl_dst *dst; 00064 00065 dst = os_zalloc(sizeof(*dst)); 00066 if (dst == NULL) 00067 return -1; 00068 os_memcpy(&dst->addr, from, sizeof(struct sockaddr_in)); 00069 dst->addrlen = fromlen; 00070 dst->debug_level = MSG_INFO; 00071 dst->next = priv->ctrl_dst; 00072 priv->ctrl_dst = dst; 00073 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d", 00074 inet_ntoa(from->sin_addr), ntohs(from->sin_port)); 00075 return 0; 00076 } 00077 00078 00079 static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv, 00080 struct sockaddr_in *from, 00081 socklen_t fromlen) 00082 { 00083 struct wpa_ctrl_dst *dst, *prev = NULL; 00084 00085 dst = priv->ctrl_dst; 00086 while (dst) { 00087 if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr && 00088 from->sin_port == dst->addr.sin_port) { 00089 if (prev == NULL) 00090 priv->ctrl_dst = dst->next; 00091 else 00092 prev->next = dst->next; 00093 os_free(dst); 00094 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached " 00095 "%s:%d", inet_ntoa(from->sin_addr), 00096 ntohs(from->sin_port)); 00097 return 0; 00098 } 00099 prev = dst; 00100 dst = dst->next; 00101 } 00102 return -1; 00103 } 00104 00105 00106 static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, 00107 struct sockaddr_in *from, 00108 socklen_t fromlen, 00109 char *level) 00110 { 00111 struct wpa_ctrl_dst *dst; 00112 00113 wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); 00114 00115 dst = priv->ctrl_dst; 00116 while (dst) { 00117 if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr && 00118 from->sin_port == dst->addr.sin_port) { 00119 wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor " 00120 "level %s:%d", inet_ntoa(from->sin_addr), 00121 ntohs(from->sin_port)); 00122 dst->debug_level = atoi(level); 00123 return 0; 00124 } 00125 dst = dst->next; 00126 } 00127 00128 return -1; 00129 } 00130 00131 00132 static char * 00133 wpa_supplicant_ctrl_iface_get_cookie(struct ctrl_iface_priv *priv, 00134 size_t *reply_len) 00135 { 00136 char *reply; 00137 reply = os_malloc(7 + 2 * COOKIE_LEN + 1); 00138 if (reply == NULL) { 00139 *reply_len = 1; 00140 return NULL; 00141 } 00142 00143 os_memcpy(reply, "COOKIE=", 7); 00144 wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1, 00145 priv->cookie, COOKIE_LEN); 00146 00147 *reply_len = 7 + 2 * COOKIE_LEN; 00148 return reply; 00149 } 00150 00151 00152 static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, 00153 void *sock_ctx) 00154 { 00155 struct wpa_supplicant *wpa_s = eloop_ctx; 00156 struct ctrl_iface_priv *priv = sock_ctx; 00157 char buf[256], *pos; 00158 int res; 00159 struct sockaddr_in from; 00160 socklen_t fromlen = sizeof(from); 00161 char *reply = NULL; 00162 size_t reply_len = 0; 00163 int new_attached = 0; 00164 u8 cookie[COOKIE_LEN]; 00165 00166 res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 00167 (struct sockaddr *) &from, &fromlen); 00168 if (res < 0) { 00169 perror("recvfrom(ctrl_iface)"); 00170 return; 00171 } 00172 if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) { 00173 /* 00174 * The OS networking stack is expected to drop this kind of 00175 * frames since the socket is bound to only localhost address. 00176 * Just in case, drop the frame if it is coming from any other 00177 * address. 00178 */ 00179 wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected " 00180 "source %s", inet_ntoa(from.sin_addr)); 00181 return; 00182 } 00183 buf[res] = '\0'; 00184 00185 if (os_strcmp(buf, "GET_COOKIE") == 0) { 00186 reply = wpa_supplicant_ctrl_iface_get_cookie(priv, &reply_len); 00187 goto done; 00188 } 00189 00190 /* 00191 * Require that the client includes a prefix with the 'cookie' value 00192 * fetched with GET_COOKIE command. This is used to verify that the 00193 * client has access to a bidirectional link over UDP in order to 00194 * avoid attacks using forged localhost IP address even if the OS does 00195 * not block such frames from remote destinations. 00196 */ 00197 if (os_strncmp(buf, "COOKIE=", 7) != 0) { 00198 wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - " 00199 "drop request"); 00200 return; 00201 } 00202 00203 if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) { 00204 wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the " 00205 "request - drop request"); 00206 return; 00207 } 00208 00209 if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) { 00210 wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - " 00211 "drop request"); 00212 return; 00213 } 00214 00215 pos = buf + 7 + 2 * COOKIE_LEN; 00216 while (*pos == ' ') 00217 pos++; 00218 00219 if (os_strcmp(pos, "ATTACH") == 0) { 00220 if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen)) 00221 reply_len = 1; 00222 else { 00223 new_attached = 1; 00224 reply_len = 2; 00225 } 00226 } else if (os_strcmp(pos, "DETACH") == 0) { 00227 if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen)) 00228 reply_len = 1; 00229 else 00230 reply_len = 2; 00231 } else if (os_strncmp(pos, "LEVEL ", 6) == 0) { 00232 if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen, 00233 pos + 6)) 00234 reply_len = 1; 00235 else 00236 reply_len = 2; 00237 } else { 00238 reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos, 00239 &reply_len); 00240 } 00241 00242 done: 00243 if (reply) { 00244 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, 00245 fromlen); 00246 os_free(reply); 00247 } else if (reply_len == 1) { 00248 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, 00249 fromlen); 00250 } else if (reply_len == 2) { 00251 sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, 00252 fromlen); 00253 } 00254 00255 if (new_attached) 00256 eapol_sm_notify_ctrl_attached(wpa_s->eapol); 00257 } 00258 00259 00260 static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, 00261 const char *txt, size_t len) 00262 { 00263 struct wpa_supplicant *wpa_s = ctx; 00264 if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) 00265 return; 00266 wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); 00267 } 00268 00269 00270 struct ctrl_iface_priv * 00271 wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) 00272 { 00273 struct ctrl_iface_priv *priv; 00274 struct sockaddr_in addr; 00275 00276 priv = os_zalloc(sizeof(*priv)); 00277 if (priv == NULL) 00278 return NULL; 00279 priv->wpa_s = wpa_s; 00280 priv->sock = -1; 00281 os_get_random(priv->cookie, COOKIE_LEN); 00282 00283 if (wpa_s->conf->ctrl_interface == NULL) 00284 return priv; 00285 00286 priv->sock = socket(PF_INET, SOCK_DGRAM, 0); 00287 if (priv->sock < 0) { 00288 perror("socket(PF_INET)"); 00289 goto fail; 00290 } 00291 00292 os_memset(&addr, 0, sizeof(addr)); 00293 addr.sin_family = AF_INET; 00294 addr.sin_addr.s_addr = htonl((127 << 24) | 1); 00295 addr.sin_port = htons(WPA_CTRL_IFACE_PORT); 00296 if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 00297 perror("bind(AF_INET)"); 00298 goto fail; 00299 } 00300 00301 eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, 00302 wpa_s, priv); 00303 wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); 00304 00305 return priv; 00306 00307 fail: 00308 if (priv->sock >= 0) 00309 close(priv->sock); 00310 os_free(priv); 00311 return NULL; 00312 } 00313 00314 00315 void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) 00316 { 00317 struct wpa_ctrl_dst *dst, *prev; 00318 00319 if (priv->sock > -1) { 00320 eloop_unregister_read_sock(priv->sock); 00321 if (priv->ctrl_dst) { 00322 /* 00323 * Wait a second before closing the control socket if 00324 * there are any attached monitors in order to allow 00325 * them to receive any pending messages. 00326 */ 00327 wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached " 00328 "monitors to receive messages"); 00329 os_sleep(1, 0); 00330 } 00331 close(priv->sock); 00332 priv->sock = -1; 00333 } 00334 00335 dst = priv->ctrl_dst; 00336 while (dst) { 00337 prev = dst; 00338 dst = dst->next; 00339 os_free(prev); 00340 } 00341 os_free(priv); 00342 } 00343 00344 00345 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 00346 int level, const char *buf, 00347 size_t len) 00348 { 00349 struct wpa_ctrl_dst *dst, *next; 00350 char levelstr[10]; 00351 int idx; 00352 char *sbuf; 00353 int llen; 00354 00355 dst = priv->ctrl_dst; 00356 if (priv->sock < 0 || dst == NULL) 00357 return; 00358 00359 os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); 00360 00361 llen = os_strlen(levelstr); 00362 sbuf = os_malloc(llen + len); 00363 if (sbuf == NULL) 00364 return; 00365 00366 os_memcpy(sbuf, levelstr, llen); 00367 os_memcpy(sbuf + llen, buf, len); 00368 00369 idx = 0; 00370 while (dst) { 00371 next = dst->next; 00372 if (level >= dst->debug_level) { 00373 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d", 00374 inet_ntoa(dst->addr.sin_addr), 00375 ntohs(dst->addr.sin_port)); 00376 if (sendto(priv->sock, sbuf, llen + len, 0, 00377 (struct sockaddr *) &dst->addr, 00378 sizeof(dst->addr)) < 0) { 00379 perror("sendto(CTRL_IFACE monitor)"); 00380 dst->errors++; 00381 if (dst->errors > 10) { 00382 wpa_supplicant_ctrl_iface_detach( 00383 priv, &dst->addr, 00384 dst->addrlen); 00385 } 00386 } else 00387 dst->errors = 0; 00388 } 00389 idx++; 00390 dst = next; 00391 } 00392 os_free(sbuf); 00393 } 00394 00395 00396 void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) 00397 { 00398 wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor", 00399 priv->wpa_s->ifname); 00400 eloop_wait_for_read_sock(priv->sock); 00401 } 00402 00403 00404 /* Global ctrl_iface */ 00405 00406 struct ctrl_iface_global_priv { 00407 int sock; 00408 u8 cookie[COOKIE_LEN]; 00409 }; 00410 00411 00412 static char * 00413 wpa_supplicant_global_get_cookie(struct ctrl_iface_global_priv *priv, 00414 size_t *reply_len) 00415 { 00416 char *reply; 00417 reply = os_malloc(7 + 2 * COOKIE_LEN + 1); 00418 if (reply == NULL) { 00419 *reply_len = 1; 00420 return NULL; 00421 } 00422 00423 os_memcpy(reply, "COOKIE=", 7); 00424 wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1, 00425 priv->cookie, COOKIE_LEN); 00426 00427 *reply_len = 7 + 2 * COOKIE_LEN; 00428 return reply; 00429 } 00430 00431 00432 static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, 00433 void *sock_ctx) 00434 { 00435 struct wpa_global *global = eloop_ctx; 00436 struct ctrl_iface_global_priv *priv = sock_ctx; 00437 char buf[256], *pos; 00438 int res; 00439 struct sockaddr_in from; 00440 socklen_t fromlen = sizeof(from); 00441 char *reply; 00442 size_t reply_len; 00443 u8 cookie[COOKIE_LEN]; 00444 00445 res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 00446 (struct sockaddr *) &from, &fromlen); 00447 if (res < 0) { 00448 perror("recvfrom(ctrl_iface)"); 00449 return; 00450 } 00451 if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) { 00452 /* 00453 * The OS networking stack is expected to drop this kind of 00454 * frames since the socket is bound to only localhost address. 00455 * Just in case, drop the frame if it is coming from any other 00456 * address. 00457 */ 00458 wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected " 00459 "source %s", inet_ntoa(from.sin_addr)); 00460 return; 00461 } 00462 buf[res] = '\0'; 00463 00464 if (os_strcmp(buf, "GET_COOKIE") == 0) { 00465 reply = wpa_supplicant_global_get_cookie(priv, &reply_len); 00466 goto done; 00467 } 00468 00469 if (os_strncmp(buf, "COOKIE=", 7) != 0) { 00470 wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - " 00471 "drop request"); 00472 return; 00473 } 00474 00475 if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) { 00476 wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the " 00477 "request - drop request"); 00478 return; 00479 } 00480 00481 if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) { 00482 wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - " 00483 "drop request"); 00484 return; 00485 } 00486 00487 pos = buf + 7 + 2 * COOKIE_LEN; 00488 while (*pos == ' ') 00489 pos++; 00490 00491 reply = wpa_supplicant_global_ctrl_iface_process(global, pos, 00492 &reply_len); 00493 00494 done: 00495 if (reply) { 00496 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, 00497 fromlen); 00498 os_free(reply); 00499 } else if (reply_len) { 00500 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, 00501 fromlen); 00502 } 00503 } 00504 00505 00506 struct ctrl_iface_global_priv * 00507 wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) 00508 { 00509 struct ctrl_iface_global_priv *priv; 00510 struct sockaddr_in addr; 00511 00512 priv = os_zalloc(sizeof(*priv)); 00513 if (priv == NULL) 00514 return NULL; 00515 priv->sock = -1; 00516 os_get_random(priv->cookie, COOKIE_LEN); 00517 00518 if (global->params.ctrl_interface == NULL) 00519 return priv; 00520 00521 wpa_printf(MSG_DEBUG, "Global control interface '%s'", 00522 global->params.ctrl_interface); 00523 00524 priv->sock = socket(PF_INET, SOCK_DGRAM, 0); 00525 if (priv->sock < 0) { 00526 perror("socket(PF_INET)"); 00527 goto fail; 00528 } 00529 00530 os_memset(&addr, 0, sizeof(addr)); 00531 addr.sin_family = AF_INET; 00532 addr.sin_addr.s_addr = htonl((127 << 24) | 1); 00533 addr.sin_port = htons(WPA_GLOBAL_CTRL_IFACE_PORT); 00534 if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 00535 perror("bind(AF_INET)"); 00536 goto fail; 00537 } 00538 00539 eloop_register_read_sock(priv->sock, 00540 wpa_supplicant_global_ctrl_iface_receive, 00541 global, priv); 00542 00543 return priv; 00544 00545 fail: 00546 if (priv->sock >= 0) 00547 close(priv->sock); 00548 os_free(priv); 00549 return NULL; 00550 } 00551 00552 00553 void 00554 wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) 00555 { 00556 if (priv->sock >= 0) { 00557 eloop_unregister_read_sock(priv->sock); 00558 close(priv->sock); 00559 } 00560 os_free(priv); 00561 }