Verify that os_get_random() success for SA Query id
[libeap.git] / hostapd / ctrl_iface.c
1 /*
2  * hostapd / UNIX domain socket -based control interface
3  * Copyright (c) 2004-2009, Jouni Malinen <j@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 "utils/includes.h"
16
17 #ifndef CONFIG_NATIVE_WINDOWS
18
19 #include <sys/un.h>
20 #include <sys/stat.h>
21 #include <stddef.h>
22
23 #include "utils/common.h"
24 #include "utils/eloop.h"
25 #include "common/ieee802_11_defs.h"
26 #include "drivers/driver.h"
27 #include "radius/radius_client.h"
28 #include "ap/hostapd.h"
29 #include "ap/ap_config.h"
30 #include "ap/ieee802_1x.h"
31 #include "ap/wpa_auth.h"
32 #include "ap/ieee802_11.h"
33 #include "ap/sta_info.h"
34 #include "ap/accounting.h"
35 #include "ap/wps_hostapd.h"
36 #include "ap/ctrl_iface_ap.h"
37 #include "ctrl_iface.h"
38
39
40 struct wpa_ctrl_dst {
41         struct wpa_ctrl_dst *next;
42         struct sockaddr_un addr;
43         socklen_t addrlen;
44         int debug_level;
45         int errors;
46 };
47
48
49 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
50                                     const char *buf, size_t len);
51
52
53 static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
54                                      struct sockaddr_un *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_un));
63         dst->addrlen = fromlen;
64         dst->debug_level = MSG_INFO;
65         dst->next = hapd->ctrl_dst;
66         hapd->ctrl_dst = dst;
67         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
68                     (u8 *) from->sun_path,
69                     fromlen - offsetof(struct sockaddr_un, sun_path));
70         return 0;
71 }
72
73
74 static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
75                                      struct sockaddr_un *from,
76                                      socklen_t fromlen)
77 {
78         struct wpa_ctrl_dst *dst, *prev = NULL;
79
80         dst = hapd->ctrl_dst;
81         while (dst) {
82                 if (fromlen == dst->addrlen &&
83                     os_memcmp(from->sun_path, dst->addr.sun_path,
84                               fromlen - offsetof(struct sockaddr_un, sun_path))
85                     == 0) {
86                         if (prev == NULL)
87                                 hapd->ctrl_dst = dst->next;
88                         else
89                                 prev->next = dst->next;
90                         os_free(dst);
91                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
92                                     (u8 *) from->sun_path,
93                                     fromlen -
94                                     offsetof(struct sockaddr_un, sun_path));
95                         return 0;
96                 }
97                 prev = dst;
98                 dst = dst->next;
99         }
100         return -1;
101 }
102
103
104 static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
105                                     struct sockaddr_un *from,
106                                     socklen_t fromlen,
107                                     char *level)
108 {
109         struct wpa_ctrl_dst *dst;
110
111         wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
112
113         dst = hapd->ctrl_dst;
114         while (dst) {
115                 if (fromlen == dst->addrlen &&
116                     os_memcmp(from->sun_path, dst->addr.sun_path,
117                               fromlen - offsetof(struct sockaddr_un, sun_path))
118                     == 0) {
119                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
120                                     "level", (u8 *) from->sun_path, fromlen -
121                                     offsetof(struct sockaddr_un, sun_path));
122                         dst->debug_level = atoi(level);
123                         return 0;
124                 }
125                 dst = dst->next;
126         }
127
128         return -1;
129 }
130
131
132 static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
133                                       const char *txtaddr)
134 {
135         u8 addr[ETH_ALEN];
136         struct sta_info *sta;
137
138         wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
139
140         if (hwaddr_aton(txtaddr, addr))
141                 return -1;
142
143         sta = ap_get_sta(hapd, addr);
144         if (sta)
145                 return 0;
146
147         wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
148                    "notification", MAC2STR(addr));
149         sta = ap_sta_add(hapd, addr);
150         if (sta == NULL)
151                 return -1;
152
153         hostapd_new_assoc_sta(hapd, sta, 0);
154         return 0;
155 }
156
157
158 #ifdef CONFIG_IEEE80211W
159 #ifdef NEED_AP_MLME
160 static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
161                                        const char *txtaddr)
162 {
163         u8 addr[ETH_ALEN];
164         u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
165
166         wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
167
168         if (hwaddr_aton(txtaddr, addr) ||
169             os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
170                 return -1;
171
172         ieee802_11_send_sa_query_req(hapd, addr, trans_id);
173
174         return 0;
175 }
176 #endif /* NEED_AP_MLME */
177 #endif /* CONFIG_IEEE80211W */
178
179
180 #ifdef CONFIG_WPS
181 static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
182 {
183         char *pin = os_strchr(txt, ' ');
184         char *timeout_txt;
185         int timeout;
186
187         if (pin == NULL)
188                 return -1;
189         *pin++ = '\0';
190
191         timeout_txt = os_strchr(pin, ' ');
192         if (timeout_txt) {
193                 *timeout_txt++ = '\0';
194                 timeout = atoi(timeout_txt);
195         } else
196                 timeout = 0;
197
198         return hostapd_wps_add_pin(hapd, txt, pin, timeout);
199 }
200
201
202 #ifdef CONFIG_WPS_OOB
203 static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
204 {
205         char *path, *method, *name;
206
207         path = os_strchr(txt, ' ');
208         if (path == NULL)
209                 return -1;
210         *path++ = '\0';
211
212         method = os_strchr(path, ' ');
213         if (method == NULL)
214                 return -1;
215         *method++ = '\0';
216
217         name = os_strchr(method, ' ');
218         if (name != NULL)
219                 *name++ = '\0';
220
221         return hostapd_wps_start_oob(hapd, txt, path, method, name);
222 }
223 #endif /* CONFIG_WPS_OOB */
224 #endif /* CONFIG_WPS */
225
226
227 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
228                                        void *sock_ctx)
229 {
230         struct hostapd_data *hapd = eloop_ctx;
231         char buf[256];
232         int res;
233         struct sockaddr_un from;
234         socklen_t fromlen = sizeof(from);
235         char *reply;
236         const int reply_size = 4096;
237         int reply_len;
238
239         res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
240                        (struct sockaddr *) &from, &fromlen);
241         if (res < 0) {
242                 perror("recvfrom(ctrl_iface)");
243                 return;
244         }
245         buf[res] = '\0';
246         wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
247
248         reply = os_malloc(reply_size);
249         if (reply == NULL) {
250                 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
251                        fromlen);
252                 return;
253         }
254
255         os_memcpy(reply, "OK\n", 3);
256         reply_len = 3;
257
258         if (os_strcmp(buf, "PING") == 0) {
259                 os_memcpy(reply, "PONG\n", 5);
260                 reply_len = 5;
261         } else if (os_strcmp(buf, "MIB") == 0) {
262                 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
263                 if (reply_len >= 0) {
264                         res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
265                                           reply_size - reply_len);
266                         if (res < 0)
267                                 reply_len = -1;
268                         else
269                                 reply_len += res;
270                 }
271                 if (reply_len >= 0) {
272                         res = ieee802_1x_get_mib(hapd, reply + reply_len,
273                                                  reply_size - reply_len);
274                         if (res < 0)
275                                 reply_len = -1;
276                         else
277                                 reply_len += res;
278                 }
279 #ifndef CONFIG_NO_RADIUS
280                 if (reply_len >= 0) {
281                         res = radius_client_get_mib(hapd->radius,
282                                                     reply + reply_len,
283                                                     reply_size - reply_len);
284                         if (res < 0)
285                                 reply_len = -1;
286                         else
287                                 reply_len += res;
288                 }
289 #endif /* CONFIG_NO_RADIUS */
290         } else if (os_strcmp(buf, "STA-FIRST") == 0) {
291                 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
292                                                          reply_size);
293         } else if (os_strncmp(buf, "STA ", 4) == 0) {
294                 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
295                                                    reply_size);
296         } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
297                 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
298                                                         reply_size);
299         } else if (os_strcmp(buf, "ATTACH") == 0) {
300                 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
301                         reply_len = -1;
302         } else if (os_strcmp(buf, "DETACH") == 0) {
303                 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
304                         reply_len = -1;
305         } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
306                 if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
307                                                     buf + 6))
308                         reply_len = -1;
309         } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
310                 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
311                         reply_len = -1;
312 #ifdef CONFIG_IEEE80211W
313 #ifdef NEED_AP_MLME
314         } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
315                 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
316                         reply_len = -1;
317 #endif /* NEED_AP_MLME */
318 #endif /* CONFIG_IEEE80211W */
319 #ifdef CONFIG_WPS
320         } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
321                 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
322                         reply_len = -1;
323         } else if (os_strcmp(buf, "WPS_PBC") == 0) {
324                 if (hostapd_wps_button_pushed(hapd))
325                         reply_len = -1;
326 #ifdef CONFIG_WPS_OOB
327         } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
328                 if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
329                         reply_len = -1;
330 #endif /* CONFIG_WPS_OOB */
331 #endif /* CONFIG_WPS */
332         } else {
333                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
334                 reply_len = 16;
335         }
336
337         if (reply_len < 0) {
338                 os_memcpy(reply, "FAIL\n", 5);
339                 reply_len = 5;
340         }
341         sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
342         os_free(reply);
343 }
344
345
346 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
347 {
348         char *buf;
349         size_t len;
350
351         if (hapd->conf->ctrl_interface == NULL)
352                 return NULL;
353
354         len = os_strlen(hapd->conf->ctrl_interface) +
355                 os_strlen(hapd->conf->iface) + 2;
356         buf = os_malloc(len);
357         if (buf == NULL)
358                 return NULL;
359
360         os_snprintf(buf, len, "%s/%s",
361                     hapd->conf->ctrl_interface, hapd->conf->iface);
362         buf[len - 1] = '\0';
363         return buf;
364 }
365
366
367 static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
368                                       const char *txt, size_t len)
369 {
370         struct hostapd_data *hapd = ctx;
371         if (hapd == NULL)
372                 return;
373         hostapd_ctrl_iface_send(hapd, level, txt, len);
374 }
375
376
377 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
378 {
379         struct sockaddr_un addr;
380         int s = -1;
381         char *fname = NULL;
382
383         hapd->ctrl_sock = -1;
384
385         if (hapd->conf->ctrl_interface == NULL)
386                 return 0;
387
388         if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
389                 if (errno == EEXIST) {
390                         wpa_printf(MSG_DEBUG, "Using existing control "
391                                    "interface directory.");
392                 } else {
393                         perror("mkdir[ctrl_interface]");
394                         goto fail;
395                 }
396         }
397
398         if (hapd->conf->ctrl_interface_gid_set &&
399             chown(hapd->conf->ctrl_interface, 0,
400                   hapd->conf->ctrl_interface_gid) < 0) {
401                 perror("chown[ctrl_interface]");
402                 return -1;
403         }
404
405         if (os_strlen(hapd->conf->ctrl_interface) + 1 +
406             os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
407                 goto fail;
408
409         s = socket(PF_UNIX, SOCK_DGRAM, 0);
410         if (s < 0) {
411                 perror("socket(PF_UNIX)");
412                 goto fail;
413         }
414
415         os_memset(&addr, 0, sizeof(addr));
416 #ifdef __FreeBSD__
417         addr.sun_len = sizeof(addr);
418 #endif /* __FreeBSD__ */
419         addr.sun_family = AF_UNIX;
420         fname = hostapd_ctrl_iface_path(hapd);
421         if (fname == NULL)
422                 goto fail;
423         os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
424         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
425                 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
426                            strerror(errno));
427                 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
428                         wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
429                                    " allow connections - assuming it was left"
430                                    "over from forced program termination");
431                         if (unlink(fname) < 0) {
432                                 perror("unlink[ctrl_iface]");
433                                 wpa_printf(MSG_ERROR, "Could not unlink "
434                                            "existing ctrl_iface socket '%s'",
435                                            fname);
436                                 goto fail;
437                         }
438                         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
439                             0) {
440                                 perror("bind(PF_UNIX)");
441                                 goto fail;
442                         }
443                         wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
444                                    "ctrl_iface socket '%s'", fname);
445                 } else {
446                         wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
447                                    "be in use - cannot override it");
448                         wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
449                                    "not used anymore", fname);
450                         os_free(fname);
451                         fname = NULL;
452                         goto fail;
453                 }
454         }
455
456         if (hapd->conf->ctrl_interface_gid_set &&
457             chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
458                 perror("chown[ctrl_interface/ifname]");
459                 goto fail;
460         }
461
462         if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
463                 perror("chmod[ctrl_interface/ifname]");
464                 goto fail;
465         }
466         os_free(fname);
467
468         hapd->ctrl_sock = s;
469         eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
470                                  NULL);
471         hapd->msg_ctx = hapd;
472         wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
473
474         return 0;
475
476 fail:
477         if (s >= 0)
478                 close(s);
479         if (fname) {
480                 unlink(fname);
481                 os_free(fname);
482         }
483         return -1;
484 }
485
486
487 void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
488 {
489         struct wpa_ctrl_dst *dst, *prev;
490
491         if (hapd->ctrl_sock > -1) {
492                 char *fname;
493                 eloop_unregister_read_sock(hapd->ctrl_sock);
494                 close(hapd->ctrl_sock);
495                 hapd->ctrl_sock = -1;
496                 fname = hostapd_ctrl_iface_path(hapd);
497                 if (fname)
498                         unlink(fname);
499                 os_free(fname);
500
501                 if (hapd->conf->ctrl_interface &&
502                     rmdir(hapd->conf->ctrl_interface) < 0) {
503                         if (errno == ENOTEMPTY) {
504                                 wpa_printf(MSG_DEBUG, "Control interface "
505                                            "directory not empty - leaving it "
506                                            "behind");
507                         } else {
508                                 perror("rmdir[ctrl_interface]");
509                         }
510                 }
511         }
512
513         dst = hapd->ctrl_dst;
514         while (dst) {
515                 prev = dst;
516                 dst = dst->next;
517                 os_free(prev);
518         }
519 }
520
521
522 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
523                                     const char *buf, size_t len)
524 {
525         struct wpa_ctrl_dst *dst, *next;
526         struct msghdr msg;
527         int idx;
528         struct iovec io[2];
529         char levelstr[10];
530
531         dst = hapd->ctrl_dst;
532         if (hapd->ctrl_sock < 0 || dst == NULL)
533                 return;
534
535         os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
536         io[0].iov_base = levelstr;
537         io[0].iov_len = os_strlen(levelstr);
538         io[1].iov_base = (char *) buf;
539         io[1].iov_len = len;
540         os_memset(&msg, 0, sizeof(msg));
541         msg.msg_iov = io;
542         msg.msg_iovlen = 2;
543
544         idx = 0;
545         while (dst) {
546                 next = dst->next;
547                 if (level >= dst->debug_level) {
548                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
549                                     (u8 *) dst->addr.sun_path, dst->addrlen -
550                                     offsetof(struct sockaddr_un, sun_path));
551                         msg.msg_name = &dst->addr;
552                         msg.msg_namelen = dst->addrlen;
553                         if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
554                                 int _errno = errno;
555                                 wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
556                                            "%d - %s",
557                                            idx, errno, strerror(errno));
558                                 dst->errors++;
559                                 if (dst->errors > 10 || _errno == ENOENT) {
560                                         hostapd_ctrl_iface_detach(
561                                                 hapd, &dst->addr,
562                                                 dst->addrlen);
563                                 }
564                         } else
565                                 dst->errors = 0;
566                 }
567                 idx++;
568                 dst = next;
569         }
570 }
571
572 #endif /* CONFIG_NATIVE_WINDOWS */