4f403563d1cf9966b4d04b81c6aaa1a1f544b300
[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 "hostapd.h"
22 #include "eloop.h"
23 #include "common/version.h"
24 #include "config.h"
25 #include "tls.h"
26 #include "eap_server/eap.h"
27 #include "eap_server/tncs.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(int (*cb)(struct hostapd_iface *iface,
42                                          void *ctx), void *ctx)
43 {
44         struct hapd_interfaces *interfaces = eloop_get_user_data();
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 * hostapd_interface_init(const char *config_fname,
225                                                      int debug)
226 {
227         struct hostapd_iface *iface;
228         int k;
229
230         wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
231         iface = hostapd_init(config_fname);
232         if (!iface)
233                 return NULL;
234
235         for (k = 0; k < debug; k++) {
236                 if (iface->bss[0]->conf->logger_stdout_level > 0)
237                         iface->bss[0]->conf->logger_stdout_level--;
238         }
239
240         if (hostapd_setup_interface(iface)) {
241                 hostapd_interface_deinit(iface);
242                 return NULL;
243         }
244
245         return iface;
246 }
247
248
249 /**
250  * handle_term - SIGINT and SIGTERM handler to terminate hostapd process
251  */
252 static void handle_term(int sig, void *eloop_ctx, void *signal_ctx)
253 {
254         wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig);
255         eloop_terminate();
256 }
257
258
259 #ifndef CONFIG_NATIVE_WINDOWS
260 /**
261  * handle_reload - SIGHUP handler to reload configuration
262  */
263 static void handle_reload(int sig, void *eloop_ctx, void *signal_ctx)
264 {
265         wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration",
266                    sig);
267         hostapd_for_each_interface(handle_reload_iface, NULL);
268 }
269
270
271 static void handle_dump_state(int sig, void *eloop_ctx, void *signal_ctx)
272 {
273 #ifdef HOSTAPD_DUMP_STATE
274         hostapd_for_each_interface(handle_dump_state_iface, NULL);
275 #endif /* HOSTAPD_DUMP_STATE */
276 }
277 #endif /* CONFIG_NATIVE_WINDOWS */
278
279
280 static int hostapd_global_init(struct hapd_interfaces *interfaces)
281 {
282         hostapd_logger_register_cb(hostapd_logger_cb);
283
284         if (eap_server_register_methods()) {
285                 wpa_printf(MSG_ERROR, "Failed to register EAP methods");
286                 return -1;
287         }
288
289         if (eloop_init(interfaces)) {
290                 wpa_printf(MSG_ERROR, "Failed to initialize event loop");
291                 return -1;
292         }
293
294 #ifndef CONFIG_NATIVE_WINDOWS
295         eloop_register_signal(SIGHUP, handle_reload, NULL);
296         eloop_register_signal(SIGUSR1, handle_dump_state, NULL);
297 #endif /* CONFIG_NATIVE_WINDOWS */
298         eloop_register_signal_terminate(handle_term, NULL);
299
300 #ifndef CONFIG_NATIVE_WINDOWS
301         openlog("hostapd", 0, LOG_DAEMON);
302 #endif /* CONFIG_NATIVE_WINDOWS */
303
304         return 0;
305 }
306
307
308 static void hostapd_global_deinit(const char *pid_file)
309 {
310 #ifdef EAP_SERVER_TNC
311         tncs_global_deinit();
312 #endif /* EAP_SERVER_TNC */
313
314         eloop_destroy();
315
316 #ifndef CONFIG_NATIVE_WINDOWS
317         closelog();
318 #endif /* CONFIG_NATIVE_WINDOWS */
319
320         eap_server_unregister_methods();
321
322         os_daemonize_terminate(pid_file);
323 }
324
325
326 static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
327                               const char *pid_file)
328 {
329 #ifdef EAP_SERVER_TNC
330         int tnc = 0;
331         size_t i, k;
332
333         for (i = 0; !tnc && i < ifaces->count; i++) {
334                 for (k = 0; k < ifaces->iface[i]->num_bss; k++) {
335                         if (ifaces->iface[i]->bss[0]->conf->tnc) {
336                                 tnc++;
337                                 break;
338                         }
339                 }
340         }
341
342         if (tnc && tncs_global_init() < 0) {
343                 wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
344                 return -1;
345         }
346 #endif /* EAP_SERVER_TNC */
347
348         if (daemonize && os_daemonize(pid_file)) {
349                 perror("daemon");
350                 return -1;
351         }
352
353         eloop_run();
354
355         return 0;
356 }
357
358
359 static void show_version(void)
360 {
361         fprintf(stderr,
362                 "hostapd v" VERSION_STR "\n"
363                 "User space daemon for IEEE 802.11 AP management,\n"
364                 "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
365                 "Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> "
366                 "and contributors\n");
367 }
368
369
370 static void usage(void)
371 {
372         show_version();
373         fprintf(stderr,
374                 "\n"
375                 "usage: hostapd [-hdBKtv] [-P <PID file>] "
376                 "<configuration file(s)>\n"
377                 "\n"
378                 "options:\n"
379                 "   -h   show this usage\n"
380                 "   -d   show more debug messages (-dd for even more)\n"
381                 "   -B   run daemon in the background\n"
382                 "   -P   PID file\n"
383                 "   -K   include key data in debug messages\n"
384                 "   -t   include timestamps in some debug messages\n"
385                 "   -v   show hostapd version\n");
386
387         exit(1);
388 }
389
390
391 int main(int argc, char *argv[])
392 {
393         struct hapd_interfaces interfaces;
394         int ret = 1;
395         size_t i;
396         int c, debug = 0, daemonize = 0;
397         char *pid_file = NULL;
398
399         for (;;) {
400                 c = getopt(argc, argv, "BdhKP:tv");
401                 if (c < 0)
402                         break;
403                 switch (c) {
404                 case 'h':
405                         usage();
406                         break;
407                 case 'd':
408                         debug++;
409                         if (wpa_debug_level > 0)
410                                 wpa_debug_level--;
411                         break;
412                 case 'B':
413                         daemonize++;
414                         break;
415                 case 'K':
416                         wpa_debug_show_keys++;
417                         break;
418                 case 'P':
419                         os_free(pid_file);
420                         pid_file = os_rel2abs_path(optarg);
421                         break;
422                 case 't':
423                         wpa_debug_timestamp++;
424                         break;
425                 case 'v':
426                         show_version();
427                         exit(1);
428                         break;
429
430                 default:
431                         usage();
432                         break;
433                 }
434         }
435
436         if (optind == argc)
437                 usage();
438
439         interfaces.count = argc - optind;
440         interfaces.iface = os_malloc(interfaces.count *
441                                      sizeof(struct hostapd_iface *));
442         if (interfaces.iface == NULL) {
443                 wpa_printf(MSG_ERROR, "malloc failed\n");
444                 return -1;
445         }
446
447         if (hostapd_global_init(&interfaces))
448                 return -1;
449
450         /* Initialize interfaces */
451         for (i = 0; i < interfaces.count; i++) {
452                 interfaces.iface[i] = hostapd_interface_init(argv[optind + i],
453                                                              debug);
454                 if (!interfaces.iface[i])
455                         goto out;
456         }
457
458         if (hostapd_global_run(&interfaces, daemonize, pid_file))
459                 goto out;
460
461         ret = 0;
462
463  out:
464         /* Deinitialize all interfaces */
465         for (i = 0; i < interfaces.count; i++)
466                 hostapd_interface_deinit(interfaces.iface[i]);
467         os_free(interfaces.iface);
468
469         hostapd_global_deinit(pid_file);
470         os_free(pid_file);
471
472         return ret;
473 }