Remove the GPL notification from files contributed by Jouni Malinen
[mech_eap.git] / wpa_supplicant / ctrl_iface_udp.c
1 /*
2  * WPA Supplicant / UDP socket -based control interface
3  * Copyright (c) 2004-2005, 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         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 }