00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
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
00175
00176
00177
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
00192
00193
00194
00195
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
00324
00325
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
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
00454
00455
00456
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 }