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