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