689248367fe9f5d82db428806397b71f0bfbfd91
[libeap.git] / hostapd / main.c
1 /*
2  * hostapd / main()
3  * Copyright (c) 2002-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 "includes.h"
16 #ifndef CONFIG_NATIVE_WINDOWS
17 #include <syslog.h>
18 #endif /* CONFIG_NATIVE_WINDOWS */
19
20 #include "common.h"
21 #include "eloop.h"
22 #include "crypto/tls.h"
23 #include "common/version.h"
24 #include "eap_server/eap.h"
25 #include "eap_server/tncs.h"
26 #include "hostapd.h"
27 #include "config.h"
28
29
30 extern int wpa_debug_level;
31 extern int wpa_debug_show_keys;
32 extern int wpa_debug_timestamp;
33
34
35 struct hapd_interfaces {
36         size_t count;
37         struct hostapd_iface **iface;
38 };
39
40
41 int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
42                                int (*cb)(struct hostapd_iface *iface,
43                                          void *ctx), void *ctx)
44 {
45         size_t i;
46         int ret;
47
48         for (i = 0; i < interfaces->count; i++) {
49                 ret = cb(interfaces->iface[i], ctx);
50                 if (ret)
51                         return ret;
52         }
53
54         return 0;
55 }
56
57
58 #ifndef CONFIG_NO_HOSTAPD_LOGGER
59 static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
60                               int level, const char *txt, size_t len)
61 {
62         struct hostapd_data *hapd = ctx;
63         char *format, *module_str;
64         int maxlen;
65         int conf_syslog_level, conf_stdout_level;
66         unsigned int conf_syslog, conf_stdout;
67
68         maxlen = len + 100;
69         format = os_malloc(maxlen);
70         if (!format)
71                 return;
72
73         if (hapd && hapd->conf) {
74                 conf_syslog_level = hapd->conf->logger_syslog_level;
75                 conf_stdout_level = hapd->conf->logger_stdout_level;
76                 conf_syslog = hapd->conf->logger_syslog;
77                 conf_stdout = hapd->conf->logger_stdout;
78         } else {
79                 conf_syslog_level = conf_stdout_level = 0;
80                 conf_syslog = conf_stdout = (unsigned int) -1;
81         }
82
83         switch (module) {
84         case HOSTAPD_MODULE_IEEE80211:
85                 module_str = "IEEE 802.11";
86                 break;
87         case HOSTAPD_MODULE_IEEE8021X:
88                 module_str = "IEEE 802.1X";
89                 break;
90         case HOSTAPD_MODULE_RADIUS:
91                 module_str = "RADIUS";
92                 break;
93         case HOSTAPD_MODULE_WPA:
94                 module_str = "WPA";
95                 break;
96         case HOSTAPD_MODULE_DRIVER:
97                 module_str = "DRIVER";
98                 break;
99         case HOSTAPD_MODULE_IAPP:
100                 module_str = "IAPP";
101                 break;
102         case HOSTAPD_MODULE_MLME:
103                 module_str = "MLME";
104                 break;
105         default:
106                 module_str = NULL;
107                 break;
108         }
109
110         if (hapd && hapd->conf && addr)
111                 os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s",
112                             hapd->conf->iface, MAC2STR(addr),
113                             module_str ? " " : "", module_str, txt);
114         else if (hapd && hapd->conf)
115                 os_snprintf(format, maxlen, "%s:%s%s %s",
116                             hapd->conf->iface, module_str ? " " : "",
117                             module_str, txt);
118         else if (addr)
119                 os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s",
120                             MAC2STR(addr), module_str ? " " : "",
121                             module_str, txt);
122         else
123                 os_snprintf(format, maxlen, "%s%s%s",
124                             module_str, module_str ? ": " : "", txt);
125
126         if ((conf_stdout & module) && level >= conf_stdout_level) {
127                 wpa_debug_print_timestamp();
128                 printf("%s\n", format);
129         }
130
131 #ifndef CONFIG_NATIVE_WINDOWS
132         if ((conf_syslog & module) && level >= conf_syslog_level) {
133                 int priority;
134                 switch (level) {
135                 case HOSTAPD_LEVEL_DEBUG_VERBOSE:
136                 case HOSTAPD_LEVEL_DEBUG:
137                         priority = LOG_DEBUG;
138                         break;
139                 case HOSTAPD_LEVEL_INFO:
140                         priority = LOG_INFO;
141                         break;
142                 case HOSTAPD_LEVEL_NOTICE:
143                         priority = LOG_NOTICE;
144                         break;
145                 case HOSTAPD_LEVEL_WARNING:
146                         priority = LOG_WARNING;
147                         break;
148                 default:
149                         priority = LOG_INFO;
150                         break;
151                 }
152                 syslog(priority, "%s", format);
153         }
154 #endif /* CONFIG_NATIVE_WINDOWS */
155
156         os_free(format);
157 }
158 #endif /* CONFIG_NO_HOSTAPD_LOGGER */
159
160
161 /**
162  * hostapd_init - Allocate and initialize per-interface data
163  * @config_file: Path to the configuration file
164  * Returns: Pointer to the allocated interface data or %NULL on failure
165  *
166  * This function is used to allocate main data structures for per-interface
167  * data. The allocated data buffer will be freed by calling
168  * hostapd_cleanup_iface().
169  */
170 static struct hostapd_iface * hostapd_init(const char *config_file)
171 {
172         struct hostapd_iface *hapd_iface = NULL;
173         struct hostapd_config *conf = NULL;
174         struct hostapd_data *hapd;
175         size_t i;
176
177         hapd_iface = os_zalloc(sizeof(*hapd_iface));
178         if (hapd_iface == NULL)
179                 goto fail;
180
181         hapd_iface->config_fname = os_strdup(config_file);
182         if (hapd_iface->config_fname == NULL)
183                 goto fail;
184
185         conf = hostapd_config_read(hapd_iface->config_fname);
186         if (conf == NULL)
187                 goto fail;
188         hapd_iface->conf = conf;
189
190         hapd_iface->num_bss = conf->num_bss;
191         hapd_iface->bss = os_zalloc(conf->num_bss *
192                                     sizeof(struct hostapd_data *));
193         if (hapd_iface->bss == NULL)
194                 goto fail;
195
196         for (i = 0; i < conf->num_bss; i++) {
197                 hapd = hapd_iface->bss[i] =
198                         hostapd_alloc_bss_data(hapd_iface, conf,
199                                                &conf->bss[i]);
200                 if (hapd == NULL)
201                         goto fail;
202         }
203
204         return hapd_iface;
205
206 fail:
207         if (conf)
208                 hostapd_config_free(conf);
209         if (hapd_iface) {
210                 for (i = 0; hapd_iface->bss && i < hapd_iface->num_bss; i++) {
211                         hapd = hapd_iface->bss[i];
212                         if (hapd && hapd->ssl_ctx)
213                                 tls_deinit(hapd->ssl_ctx);
214                 }
215
216                 os_free(hapd_iface->config_fname);
217                 os_free(hapd_iface->bss);
218                 os_free(hapd_iface);
219         }
220         return NULL;
221 }
222
223
224 static struct hostapd_iface *
225 hostapd_interface_init(struct hapd_interfaces *interfaces,
226                        const char *config_fname, int debug)
227 {
228         struct hostapd_iface *iface;
229         int k;
230
231         wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
232         iface = hostapd_init(config_fname);
233         if (!iface)
234                 return NULL;
235         iface->interfaces = interfaces;
236
237         for (k = 0; k < debug; k++) {
238                 if (iface->bss[0]->conf->logger_stdout_level > 0)
239                         iface->bss[0]->conf->logger_stdout_level--;
240         }
241
242         if (hostapd_setup_interface(iface)) {
243                 hostapd_interface_deinit(iface);
244                 return NULL;
245         }
246
247         return iface;
248 }
249
250
251 /**
252  * handle_term - SIGINT and SIGTERM handler to terminate hostapd process
253  */
254 static void handle_term(int sig, void *eloop_ctx, void *signal_ctx)
255 {
256         wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig);
257         eloop_terminate();
258 }
259
260
261 #ifndef CONFIG_NATIVE_WINDOWS
262 /**
263  * handle_reload - SIGHUP handler to reload configuration
264  */
265 static void handle_reload(int sig, void *eloop_ctx, void *signal_ctx)
266 {
267         struct hapd_interfaces *interfaces = eloop_ctx;
268         wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration",
269                    sig);
270         hostapd_for_each_interface(interfaces, handle_reload_iface, NULL);
271 }
272
273
274 static void handle_dump_state(int sig, void *eloop_ctx, void *signal_ctx)
275 {
276 #ifdef HOSTAPD_DUMP_STATE
277         struct hapd_interfaces *interfaces = eloop_ctx;
278         hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL);
279 #endif /* HOSTAPD_DUMP_STATE */
280 }
281 #endif /* CONFIG_NATIVE_WINDOWS */
282
283
284 static int hostapd_global_init(struct hapd_interfaces *interfaces)
285 {
286         hostapd_logger_register_cb(hostapd_logger_cb);
287
288         if (eap_server_register_methods()) {
289                 wpa_printf(MSG_ERROR, "Failed to register EAP methods");
290                 return -1;
291         }
292
293         if (eloop_init(interfaces)) {
294                 wpa_printf(MSG_ERROR, "Failed to initialize event loop");
295                 return -1;
296         }
297
298 #ifndef CONFIG_NATIVE_WINDOWS
299         eloop_register_signal(SIGHUP, handle_reload, NULL);
300         eloop_register_signal(SIGUSR1, handle_dump_state, NULL);
301 #endif /* CONFIG_NATIVE_WINDOWS */
302         eloop_register_signal_terminate(handle_term, NULL);
303
304 #ifndef CONFIG_NATIVE_WINDOWS
305         openlog("hostapd", 0, LOG_DAEMON);
306 #endif /* CONFIG_NATIVE_WINDOWS */
307
308         return 0;
309 }
310
311
312 static void hostapd_global_deinit(const char *pid_file)
313 {
314 #ifdef EAP_SERVER_TNC
315         tncs_global_deinit();
316 #endif /* EAP_SERVER_TNC */
317
318         eloop_destroy();
319
320 #ifndef CONFIG_NATIVE_WINDOWS
321         closelog();
322 #endif /* CONFIG_NATIVE_WINDOWS */
323
324         eap_server_unregister_methods();
325
326         os_daemonize_terminate(pid_file);
327 }
328
329
330 static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
331                               const char *pid_file)
332 {
333 #ifdef EAP_SERVER_TNC
334         int tnc = 0;
335         size_t i, k;
336
337         for (i = 0; !tnc && i < ifaces->count; i++) {
338                 for (k = 0; k < ifaces->iface[i]->num_bss; k++) {
339                         if (ifaces->iface[i]->bss[0]->conf->tnc) {
340                                 tnc++;
341                                 break;
342                         }
343                 }
344         }
345
346         if (tnc && tncs_global_init() < 0) {
347                 wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
348                 return -1;
349         }
350 #endif /* EAP_SERVER_TNC */
351
352         if (daemonize && os_daemonize(pid_file)) {
353                 perror("daemon");
354                 return -1;
355         }
356
357         eloop_run();
358
359         return 0;
360 }
361
362
363 static void show_version(void)
364 {
365         fprintf(stderr,
366                 "hostapd v" VERSION_STR "\n"
367                 "User space daemon for IEEE 802.11 AP management,\n"
368                 "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
369                 "Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> "
370                 "and contributors\n");
371 }
372
373
374 static void usage(void)
375 {
376         show_version();
377         fprintf(stderr,
378                 "\n"
379                 "usage: hostapd [-hdBKtv] [-P <PID file>] "
380                 "<configuration file(s)>\n"
381                 "\n"
382                 "options:\n"
383                 "   -h   show this usage\n"
384                 "   -d   show more debug messages (-dd for even more)\n"
385                 "   -B   run daemon in the background\n"
386                 "   -P   PID file\n"
387                 "   -K   include key data in debug messages\n"
388                 "   -t   include timestamps in some debug messages\n"
389                 "   -v   show hostapd version\n");
390
391         exit(1);
392 }
393
394
395 int main(int argc, char *argv[])
396 {
397         struct hapd_interfaces interfaces;
398         int ret = 1;
399         size_t i;
400         int c, debug = 0, daemonize = 0;
401         char *pid_file = NULL;
402
403         for (;;) {
404                 c = getopt(argc, argv, "BdhKP:tv");
405                 if (c < 0)
406                         break;
407                 switch (c) {
408                 case 'h':
409                         usage();
410                         break;
411                 case 'd':
412                         debug++;
413                         if (wpa_debug_level > 0)
414                                 wpa_debug_level--;
415                         break;
416                 case 'B':
417                         daemonize++;
418                         break;
419                 case 'K':
420                         wpa_debug_show_keys++;
421                         break;
422                 case 'P':
423                         os_free(pid_file);
424                         pid_file = os_rel2abs_path(optarg);
425                         break;
426                 case 't':
427                         wpa_debug_timestamp++;
428                         break;
429                 case 'v':
430                         show_version();
431                         exit(1);
432                         break;
433
434                 default:
435                         usage();
436                         break;
437                 }
438         }
439
440         if (optind == argc)
441                 usage();
442
443         interfaces.count = argc - optind;
444         interfaces.iface = os_malloc(interfaces.count *
445                                      sizeof(struct hostapd_iface *));
446         if (interfaces.iface == NULL) {
447                 wpa_printf(MSG_ERROR, "malloc failed\n");
448                 return -1;
449         }
450
451         if (hostapd_global_init(&interfaces))
452                 return -1;
453
454         /* Initialize interfaces */
455         for (i = 0; i < interfaces.count; i++) {
456                 interfaces.iface[i] = hostapd_interface_init(&interfaces,
457                                                              argv[optind + i],
458                                                              debug);
459                 if (!interfaces.iface[i])
460                         goto out;
461         }
462
463         if (hostapd_global_run(&interfaces, daemonize, pid_file))
464                 goto out;
465
466         ret = 0;
467
468  out:
469         /* Deinitialize all interfaces */
470         for (i = 0; i < interfaces.count; i++)
471                 hostapd_interface_deinit(interfaces.iface[i]);
472         os_free(interfaces.iface);
473
474         hostapd_global_deinit(pid_file);
475         os_free(pid_file);
476
477         return ret;
478 }