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