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