1/*
2 * hostapd / main()
3 * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "utils/includes.h"
10#ifndef CONFIG_NATIVE_WINDOWS
11#include <syslog.h>
12#include <grp.h>
13#endif /* CONFIG_NATIVE_WINDOWS */
14
15#include "utils/common.h"
16#include "utils/eloop.h"
17#include "crypto/random.h"
18#include "crypto/tls.h"
19#include "common/version.h"
20#include "drivers/driver.h"
21#include "eap_server/eap.h"
22#include "eap_server/tncs.h"
23#include "ap/hostapd.h"
24#include "ap/ap_config.h"
25#include "ap/ap_drv_ops.h"
26#include "config_file.h"
27#include "eap_register.h"
28#include "dump_state.h"
29#include "ctrl_iface.h"
30
31
32extern int wpa_debug_level;
33extern int wpa_debug_show_keys;
34extern int wpa_debug_timestamp;
35
36extern struct wpa_driver_ops *wpa_drivers[];
37
38
39struct hapd_global {
40	void **drv_priv;
41	size_t drv_count;
42};
43
44static struct hapd_global global;
45
46
47#ifndef CONFIG_NO_HOSTAPD_LOGGER
48static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
49			      int level, const char *txt, size_t len)
50{
51	struct hostapd_data *hapd = ctx;
52	char *format, *module_str;
53	int maxlen;
54	int conf_syslog_level, conf_stdout_level;
55	unsigned int conf_syslog, conf_stdout;
56
57	maxlen = len + 100;
58	format = os_malloc(maxlen);
59	if (!format)
60		return;
61
62	if (hapd && hapd->conf) {
63		conf_syslog_level = hapd->conf->logger_syslog_level;
64		conf_stdout_level = hapd->conf->logger_stdout_level;
65		conf_syslog = hapd->conf->logger_syslog;
66		conf_stdout = hapd->conf->logger_stdout;
67	} else {
68		conf_syslog_level = conf_stdout_level = 0;
69		conf_syslog = conf_stdout = (unsigned int) -1;
70	}
71
72	switch (module) {
73	case HOSTAPD_MODULE_IEEE80211:
74		module_str = "IEEE 802.11";
75		break;
76	case HOSTAPD_MODULE_IEEE8021X:
77		module_str = "IEEE 802.1X";
78		break;
79	case HOSTAPD_MODULE_RADIUS:
80		module_str = "RADIUS";
81		break;
82	case HOSTAPD_MODULE_WPA:
83		module_str = "WPA";
84		break;
85	case HOSTAPD_MODULE_DRIVER:
86		module_str = "DRIVER";
87		break;
88	case HOSTAPD_MODULE_IAPP:
89		module_str = "IAPP";
90		break;
91	case HOSTAPD_MODULE_MLME:
92		module_str = "MLME";
93		break;
94	default:
95		module_str = NULL;
96		break;
97	}
98
99	if (hapd && hapd->conf && addr)
100		os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s",
101			    hapd->conf->iface, MAC2STR(addr),
102			    module_str ? " " : "", module_str, txt);
103	else if (hapd && hapd->conf)
104		os_snprintf(format, maxlen, "%s:%s%s %s",
105			    hapd->conf->iface, module_str ? " " : "",
106			    module_str, txt);
107	else if (addr)
108		os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s",
109			    MAC2STR(addr), module_str ? " " : "",
110			    module_str, txt);
111	else
112		os_snprintf(format, maxlen, "%s%s%s",
113			    module_str, module_str ? ": " : "", txt);
114
115	if ((conf_stdout & module) && level >= conf_stdout_level) {
116		wpa_debug_print_timestamp();
117		printf("%s\n", format);
118	}
119
120#ifndef CONFIG_NATIVE_WINDOWS
121	if ((conf_syslog & module) && level >= conf_syslog_level) {
122		int priority;
123		switch (level) {
124		case HOSTAPD_LEVEL_DEBUG_VERBOSE:
125		case HOSTAPD_LEVEL_DEBUG:
126			priority = LOG_DEBUG;
127			break;
128		case HOSTAPD_LEVEL_INFO:
129			priority = LOG_INFO;
130			break;
131		case HOSTAPD_LEVEL_NOTICE:
132			priority = LOG_NOTICE;
133			break;
134		case HOSTAPD_LEVEL_WARNING:
135			priority = LOG_WARNING;
136			break;
137		default:
138			priority = LOG_INFO;
139			break;
140		}
141		syslog(priority, "%s", format);
142	}
143#endif /* CONFIG_NATIVE_WINDOWS */
144
145	os_free(format);
146}
147#endif /* CONFIG_NO_HOSTAPD_LOGGER */
148
149
150/**
151 * hostapd_init - Allocate and initialize per-interface data
152 * @config_file: Path to the configuration file
153 * Returns: Pointer to the allocated interface data or %NULL on failure
154 *
155 * This function is used to allocate main data structures for per-interface
156 * data. The allocated data buffer will be freed by calling
157 * hostapd_cleanup_iface().
158 */
159static struct hostapd_iface * hostapd_init(const char *config_file)
160{
161	struct hostapd_iface *hapd_iface = NULL;
162	struct hostapd_config *conf = NULL;
163	struct hostapd_data *hapd;
164	size_t i;
165
166	hapd_iface = os_zalloc(sizeof(*hapd_iface));
167	if (hapd_iface == NULL)
168		goto fail;
169
170	hapd_iface->config_fname = os_strdup(config_file);
171	if (hapd_iface->config_fname == NULL)
172		goto fail;
173
174	conf = hostapd_config_read(hapd_iface->config_fname);
175	if (conf == NULL)
176		goto fail;
177	hapd_iface->conf = conf;
178
179	hapd_iface->num_bss = conf->num_bss;
180	hapd_iface->bss = os_calloc(conf->num_bss,
181				    sizeof(struct hostapd_data *));
182	if (hapd_iface->bss == NULL)
183		goto fail;
184
185	for (i = 0; i < conf->num_bss; i++) {
186		hapd = hapd_iface->bss[i] =
187			hostapd_alloc_bss_data(hapd_iface, conf,
188					       &conf->bss[i]);
189		if (hapd == NULL)
190			goto fail;
191		hapd->msg_ctx = hapd;
192	}
193
194	return hapd_iface;
195
196fail:
197	wpa_printf(MSG_ERROR, "Failed to set up interface with %s",
198		   config_file);
199	if (conf)
200		hostapd_config_free(conf);
201	if (hapd_iface) {
202		os_free(hapd_iface->config_fname);
203		os_free(hapd_iface->bss);
204		os_free(hapd_iface);
205	}
206	return NULL;
207}
208
209
210static int hostapd_driver_init(struct hostapd_iface *iface)
211{
212	struct wpa_init_params params;
213	size_t i;
214	struct hostapd_data *hapd = iface->bss[0];
215	struct hostapd_bss_config *conf = hapd->conf;
216	u8 *b = conf->bssid;
217	struct wpa_driver_capa capa;
218
219	if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) {
220		wpa_printf(MSG_ERROR, "No hostapd driver wrapper available");
221		return -1;
222	}
223
224	/* Initialize the driver interface */
225	if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5]))
226		b = NULL;
227
228	os_memset(&params, 0, sizeof(params));
229	for (i = 0; wpa_drivers[i]; i++) {
230		if (wpa_drivers[i] != hapd->driver)
231			continue;
232
233		if (global.drv_priv[i] == NULL &&
234		    wpa_drivers[i]->global_init) {
235			global.drv_priv[i] = wpa_drivers[i]->global_init();
236			if (global.drv_priv[i] == NULL) {
237				wpa_printf(MSG_ERROR, "Failed to initialize "
238					   "driver '%s'",
239					   wpa_drivers[i]->name);
240				return -1;
241			}
242		}
243
244		params.global_priv = global.drv_priv[i];
245		break;
246	}
247	params.bssid = b;
248	params.ifname = hapd->conf->iface;
249	params.ssid = hapd->conf->ssid.ssid;
250	params.ssid_len = hapd->conf->ssid.ssid_len;
251	params.test_socket = hapd->conf->test_socket;
252	params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
253
254	params.num_bridge = hapd->iface->num_bss;
255	params.bridge = os_calloc(hapd->iface->num_bss, sizeof(char *));
256	if (params.bridge == NULL)
257		return -1;
258	for (i = 0; i < hapd->iface->num_bss; i++) {
259		struct hostapd_data *bss = hapd->iface->bss[i];
260		if (bss->conf->bridge[0])
261			params.bridge[i] = bss->conf->bridge;
262	}
263
264	params.own_addr = hapd->own_addr;
265
266	hapd->drv_priv = hapd->driver->hapd_init(hapd, &params);
267	os_free(params.bridge);
268	if (hapd->drv_priv == NULL) {
269		wpa_printf(MSG_ERROR, "%s driver initialization failed.",
270			   hapd->driver->name);
271		hapd->driver = NULL;
272		return -1;
273	}
274
275	if (hapd->driver->get_capa &&
276	    hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
277		iface->drv_flags = capa.flags;
278		iface->probe_resp_offloads = capa.probe_resp_offloads;
279		iface->extended_capa = capa.extended_capa;
280		iface->extended_capa_mask = capa.extended_capa_mask;
281		iface->extended_capa_len = capa.extended_capa_len;
282		iface->drv_max_acl_mac_addrs = capa.max_acl_mac_addrs;
283	}
284
285	return 0;
286}
287
288
289static struct hostapd_iface *
290hostapd_interface_init(struct hapd_interfaces *interfaces,
291		       const char *config_fname, int debug)
292{
293	struct hostapd_iface *iface;
294	int k;
295
296	wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
297	iface = hostapd_init(config_fname);
298	if (!iface)
299		return NULL;
300	iface->interfaces = interfaces;
301
302	for (k = 0; k < debug; k++) {
303		if (iface->bss[0]->conf->logger_stdout_level > 0)
304			iface->bss[0]->conf->logger_stdout_level--;
305	}
306
307	if (iface->conf->bss[0].iface[0] == '\0' &&
308	    !hostapd_drv_none(iface->bss[0])) {
309		wpa_printf(MSG_ERROR, "Interface name not specified in %s",
310			   config_fname);
311		hostapd_interface_deinit_free(iface);
312		return NULL;
313	}
314
315	if (hostapd_driver_init(iface) ||
316	    hostapd_setup_interface(iface)) {
317		hostapd_interface_deinit_free(iface);
318		return NULL;
319	}
320
321	return iface;
322}
323
324
325/**
326 * handle_term - SIGINT and SIGTERM handler to terminate hostapd process
327 */
328static void handle_term(int sig, void *signal_ctx)
329{
330	wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig);
331	eloop_terminate();
332}
333
334
335#ifndef CONFIG_NATIVE_WINDOWS
336
337static int handle_reload_iface(struct hostapd_iface *iface, void *ctx)
338{
339	if (hostapd_reload_config(iface) < 0) {
340		wpa_printf(MSG_WARNING, "Failed to read new configuration "
341			   "file - continuing with old.");
342	}
343	return 0;
344}
345
346
347/**
348 * handle_reload - SIGHUP handler to reload configuration
349 */
350static void handle_reload(int sig, void *signal_ctx)
351{
352	struct hapd_interfaces *interfaces = signal_ctx;
353	wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration",
354		   sig);
355	hostapd_for_each_interface(interfaces, handle_reload_iface, NULL);
356}
357
358
359static void handle_dump_state(int sig, void *signal_ctx)
360{
361#ifdef HOSTAPD_DUMP_STATE
362	struct hapd_interfaces *interfaces = signal_ctx;
363	hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL);
364#endif /* HOSTAPD_DUMP_STATE */
365}
366#endif /* CONFIG_NATIVE_WINDOWS */
367
368
369static int hostapd_global_init(struct hapd_interfaces *interfaces,
370			       const char *entropy_file)
371{
372	int i;
373
374	os_memset(&global, 0, sizeof(global));
375
376	hostapd_logger_register_cb(hostapd_logger_cb);
377
378	if (eap_server_register_methods()) {
379		wpa_printf(MSG_ERROR, "Failed to register EAP methods");
380		return -1;
381	}
382
383	if (eloop_init()) {
384		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
385		return -1;
386	}
387
388	random_init(entropy_file);
389
390#ifndef CONFIG_NATIVE_WINDOWS
391	eloop_register_signal(SIGHUP, handle_reload, interfaces);
392	eloop_register_signal(SIGUSR1, handle_dump_state, interfaces);
393#endif /* CONFIG_NATIVE_WINDOWS */
394	eloop_register_signal_terminate(handle_term, interfaces);
395
396#ifndef CONFIG_NATIVE_WINDOWS
397	openlog("hostapd", 0, LOG_DAEMON);
398#endif /* CONFIG_NATIVE_WINDOWS */
399
400	for (i = 0; wpa_drivers[i]; i++)
401		global.drv_count++;
402	if (global.drv_count == 0) {
403		wpa_printf(MSG_ERROR, "No drivers enabled");
404		return -1;
405	}
406	global.drv_priv = os_calloc(global.drv_count, sizeof(void *));
407	if (global.drv_priv == NULL)
408		return -1;
409
410	return 0;
411}
412
413
414static void hostapd_global_deinit(const char *pid_file)
415{
416	int i;
417
418	for (i = 0; wpa_drivers[i] && global.drv_priv; i++) {
419		if (!global.drv_priv[i])
420			continue;
421		wpa_drivers[i]->global_deinit(global.drv_priv[i]);
422	}
423	os_free(global.drv_priv);
424	global.drv_priv = NULL;
425
426#ifdef EAP_SERVER_TNC
427	tncs_global_deinit();
428#endif /* EAP_SERVER_TNC */
429
430	random_deinit();
431
432	eloop_destroy();
433
434#ifndef CONFIG_NATIVE_WINDOWS
435	closelog();
436#endif /* CONFIG_NATIVE_WINDOWS */
437
438	eap_server_unregister_methods();
439
440	os_daemonize_terminate(pid_file);
441}
442
443
444static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
445			      const char *pid_file)
446{
447#ifdef EAP_SERVER_TNC
448	int tnc = 0;
449	size_t i, k;
450
451	for (i = 0; !tnc && i < ifaces->count; i++) {
452		for (k = 0; k < ifaces->iface[i]->num_bss; k++) {
453			if (ifaces->iface[i]->bss[0]->conf->tnc) {
454				tnc++;
455				break;
456			}
457		}
458	}
459
460	if (tnc && tncs_global_init() < 0) {
461		wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
462		return -1;
463	}
464#endif /* EAP_SERVER_TNC */
465
466	if (daemonize && os_daemonize(pid_file)) {
467		perror("daemon");
468		return -1;
469	}
470
471	eloop_run();
472
473	return 0;
474}
475
476
477static void show_version(void)
478{
479	fprintf(stderr,
480		"hostapd v" VERSION_STR "\n"
481		"User space daemon for IEEE 802.11 AP management,\n"
482		"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
483		"Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> "
484		"and contributors\n");
485}
486
487
488static void usage(void)
489{
490	show_version();
491	fprintf(stderr,
492		"\n"
493		"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
494		"\\\n"
495		"         [-g <global ctrl_iface>] [-G <group>] \\\n"
496		"         <configuration file(s)>\n"
497		"\n"
498		"options:\n"
499		"   -h   show this usage\n"
500		"   -d   show more debug messages (-dd for even more)\n"
501		"   -B   run daemon in the background\n"
502		"   -e   entropy file\n"
503		"   -g   global control interface path\n"
504		"   -G   group for control interfaces\n"
505		"   -P   PID file\n"
506		"   -K   include key data in debug messages\n"
507#ifdef CONFIG_DEBUG_FILE
508		"   -f   log output to debug file instead of stdout\n"
509#endif /* CONFIG_DEBUG_FILE */
510		"   -t   include timestamps in some debug messages\n"
511		"   -v   show hostapd version\n");
512
513	exit(1);
514}
515
516
517static const char * hostapd_msg_ifname_cb(void *ctx)
518{
519	struct hostapd_data *hapd = ctx;
520	if (hapd && hapd->iconf && hapd->iconf->bss)
521		return hapd->iconf->bss->iface;
522	return NULL;
523}
524
525
526static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
527					 const char *path)
528{
529	char *pos;
530	os_free(interfaces->global_iface_path);
531	interfaces->global_iface_path = os_strdup(path);
532	if (interfaces->global_iface_path == NULL)
533		return -1;
534	pos = os_strrchr(interfaces->global_iface_path, '/');
535	if (pos == NULL) {
536		wpa_printf(MSG_ERROR, "No '/' in the global control interface "
537			   "file");
538		os_free(interfaces->global_iface_path);
539		interfaces->global_iface_path = NULL;
540		return -1;
541	}
542
543	*pos = '\0';
544	interfaces->global_iface_name = pos + 1;
545
546	return 0;
547}
548
549
550static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces,
551					const char *group)
552{
553#ifndef CONFIG_NATIVE_WINDOWS
554	struct group *grp;
555	grp = getgrnam(group);
556	if (grp == NULL) {
557		wpa_printf(MSG_ERROR, "Unknown group '%s'", group);
558		return -1;
559	}
560	interfaces->ctrl_iface_group = grp->gr_gid;
561#endif /* CONFIG_NATIVE_WINDOWS */
562	return 0;
563}
564
565
566int main(int argc, char *argv[])
567{
568	struct hapd_interfaces interfaces;
569	int ret = 1;
570	size_t i;
571	int c, debug = 0, daemonize = 0;
572	char *pid_file = NULL;
573	const char *log_file = NULL;
574	const char *entropy_file = NULL;
575
576	if (os_program_init())
577		return -1;
578
579	os_memset(&interfaces, 0, sizeof(interfaces));
580	interfaces.reload_config = hostapd_reload_config;
581	interfaces.config_read_cb = hostapd_config_read;
582	interfaces.for_each_interface = hostapd_for_each_interface;
583	interfaces.ctrl_iface_init = hostapd_ctrl_iface_init;
584	interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
585	interfaces.driver_init = hostapd_driver_init;
586	interfaces.global_iface_path = NULL;
587	interfaces.global_iface_name = NULL;
588	interfaces.global_ctrl_sock = -1;
589
590	for (;;) {
591		c = getopt(argc, argv, "Bde:f:hKP:tvg:G:");
592		if (c < 0)
593			break;
594		switch (c) {
595		case 'h':
596			usage();
597			break;
598		case 'd':
599			debug++;
600			if (wpa_debug_level > 0)
601				wpa_debug_level--;
602			break;
603		case 'B':
604			daemonize++;
605			break;
606		case 'e':
607			entropy_file = optarg;
608			break;
609		case 'f':
610			log_file = optarg;
611			break;
612		case 'K':
613			wpa_debug_show_keys++;
614			break;
615		case 'P':
616			os_free(pid_file);
617			pid_file = os_rel2abs_path(optarg);
618			break;
619		case 't':
620			wpa_debug_timestamp++;
621			break;
622		case 'v':
623			show_version();
624			exit(1);
625			break;
626		case 'g':
627			if (hostapd_get_global_ctrl_iface(&interfaces, optarg))
628				return -1;
629			break;
630		case 'G':
631			if (hostapd_get_ctrl_iface_group(&interfaces, optarg))
632				return -1;
633			break;
634		default:
635			usage();
636			break;
637		}
638	}
639
640	if (optind == argc && interfaces.global_iface_path == NULL)
641		usage();
642
643	wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
644
645	if (log_file)
646		wpa_debug_open_file(log_file);
647
648	interfaces.count = argc - optind;
649	if (interfaces.count) {
650		interfaces.iface = os_calloc(interfaces.count,
651					     sizeof(struct hostapd_iface *));
652		if (interfaces.iface == NULL) {
653			wpa_printf(MSG_ERROR, "malloc failed");
654			return -1;
655		}
656	}
657
658	if (hostapd_global_init(&interfaces, entropy_file)) {
659		wpa_printf(MSG_ERROR, "Failed to initilize global context");
660		return -1;
661	}
662
663	/* Initialize interfaces */
664	for (i = 0; i < interfaces.count; i++) {
665		interfaces.iface[i] = hostapd_interface_init(&interfaces,
666							     argv[optind + i],
667							     debug);
668		if (!interfaces.iface[i]) {
669			wpa_printf(MSG_ERROR, "Failed to initialize interface");
670			goto out;
671		}
672	}
673
674	hostapd_global_ctrl_iface_init(&interfaces);
675
676	if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
677		wpa_printf(MSG_ERROR, "Failed to start eloop");
678		goto out;
679	}
680
681	ret = 0;
682
683 out:
684	hostapd_global_ctrl_iface_deinit(&interfaces);
685	/* Deinitialize all interfaces */
686	for (i = 0; i < interfaces.count; i++)
687		hostapd_interface_deinit_free(interfaces.iface[i]);
688	os_free(interfaces.iface);
689
690	hostapd_global_deinit(pid_file);
691	os_free(pid_file);
692
693	if (log_file)
694		wpa_debug_close_file();
695
696	os_program_deinit();
697
698	return ret;
699}
700