main.c revision 1e78e76961664775f58b139f8c6388cfa0485f3d
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	if (conf)
198		hostapd_config_free(conf);
199	if (hapd_iface) {
200		os_free(hapd_iface->config_fname);
201		os_free(hapd_iface->bss);
202		os_free(hapd_iface);
203	}
204	return NULL;
205}
206
207
208static int hostapd_driver_init(struct hostapd_iface *iface)
209{
210	struct wpa_init_params params;
211	size_t i;
212	struct hostapd_data *hapd = iface->bss[0];
213	struct hostapd_bss_config *conf = hapd->conf;
214	u8 *b = conf->bssid;
215	struct wpa_driver_capa capa;
216
217	if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) {
218		wpa_printf(MSG_ERROR, "No hostapd driver wrapper available");
219		return -1;
220	}
221
222	/* Initialize the driver interface */
223	if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5]))
224		b = NULL;
225
226	os_memset(&params, 0, sizeof(params));
227	for (i = 0; wpa_drivers[i]; i++) {
228		if (wpa_drivers[i] != hapd->driver)
229			continue;
230
231		if (global.drv_priv[i] == NULL &&
232		    wpa_drivers[i]->global_init) {
233			global.drv_priv[i] = wpa_drivers[i]->global_init();
234			if (global.drv_priv[i] == NULL) {
235				wpa_printf(MSG_ERROR, "Failed to initialize "
236					   "driver '%s'",
237					   wpa_drivers[i]->name);
238				return -1;
239			}
240		}
241
242		params.global_priv = global.drv_priv[i];
243		break;
244	}
245	params.bssid = b;
246	params.ifname = hapd->conf->iface;
247	params.ssid = hapd->conf->ssid.ssid;
248	params.ssid_len = hapd->conf->ssid.ssid_len;
249	params.test_socket = hapd->conf->test_socket;
250	params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
251
252	params.num_bridge = hapd->iface->num_bss;
253	params.bridge = os_calloc(hapd->iface->num_bss, sizeof(char *));
254	if (params.bridge == NULL)
255		return -1;
256	for (i = 0; i < hapd->iface->num_bss; i++) {
257		struct hostapd_data *bss = hapd->iface->bss[i];
258		if (bss->conf->bridge[0])
259			params.bridge[i] = bss->conf->bridge;
260	}
261
262	params.own_addr = hapd->own_addr;
263
264	hapd->drv_priv = hapd->driver->hapd_init(hapd, &params);
265	os_free(params.bridge);
266	if (hapd->drv_priv == NULL) {
267		wpa_printf(MSG_ERROR, "%s driver initialization failed.",
268			   hapd->driver->name);
269		hapd->driver = NULL;
270		return -1;
271	}
272
273	if (hapd->driver->get_capa &&
274	    hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
275		iface->drv_flags = capa.flags;
276		iface->probe_resp_offloads = capa.probe_resp_offloads;
277		iface->extended_capa = capa.extended_capa;
278		iface->extended_capa_mask = capa.extended_capa_mask;
279		iface->extended_capa_len = capa.extended_capa_len;
280	}
281
282	return 0;
283}
284
285
286static struct hostapd_iface *
287hostapd_interface_init(struct hapd_interfaces *interfaces,
288		       const char *config_fname, int debug)
289{
290	struct hostapd_iface *iface;
291	int k;
292
293	wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
294	iface = hostapd_init(config_fname);
295	if (!iface)
296		return NULL;
297	iface->interfaces = interfaces;
298
299	for (k = 0; k < debug; k++) {
300		if (iface->bss[0]->conf->logger_stdout_level > 0)
301			iface->bss[0]->conf->logger_stdout_level--;
302	}
303
304	if (iface->conf->bss[0].iface[0] != 0 ||
305	    hostapd_drv_none(iface->bss[0])) {
306		if (hostapd_driver_init(iface) ||
307			hostapd_setup_interface(iface)) {
308			hostapd_interface_deinit_free(iface);
309			return NULL;
310		}
311	}
312
313	return iface;
314}
315
316
317/**
318 * handle_term - SIGINT and SIGTERM handler to terminate hostapd process
319 */
320static void handle_term(int sig, void *signal_ctx)
321{
322	wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig);
323	eloop_terminate();
324}
325
326
327#ifndef CONFIG_NATIVE_WINDOWS
328
329static int handle_reload_iface(struct hostapd_iface *iface, void *ctx)
330{
331	if (hostapd_reload_config(iface) < 0) {
332		wpa_printf(MSG_WARNING, "Failed to read new configuration "
333			   "file - continuing with old.");
334	}
335	return 0;
336}
337
338
339/**
340 * handle_reload - SIGHUP handler to reload configuration
341 */
342static void handle_reload(int sig, void *signal_ctx)
343{
344	struct hapd_interfaces *interfaces = signal_ctx;
345	wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration",
346		   sig);
347	hostapd_for_each_interface(interfaces, handle_reload_iface, NULL);
348}
349
350
351static void handle_dump_state(int sig, void *signal_ctx)
352{
353#ifdef HOSTAPD_DUMP_STATE
354	struct hapd_interfaces *interfaces = signal_ctx;
355	hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL);
356#endif /* HOSTAPD_DUMP_STATE */
357}
358#endif /* CONFIG_NATIVE_WINDOWS */
359
360
361static int hostapd_global_init(struct hapd_interfaces *interfaces,
362			       const char *entropy_file)
363{
364	int i;
365
366	os_memset(&global, 0, sizeof(global));
367
368	hostapd_logger_register_cb(hostapd_logger_cb);
369
370	if (eap_server_register_methods()) {
371		wpa_printf(MSG_ERROR, "Failed to register EAP methods");
372		return -1;
373	}
374
375	if (eloop_init()) {
376		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
377		return -1;
378	}
379
380	random_init(entropy_file);
381
382#ifndef CONFIG_NATIVE_WINDOWS
383	eloop_register_signal(SIGHUP, handle_reload, interfaces);
384	eloop_register_signal(SIGUSR1, handle_dump_state, interfaces);
385#endif /* CONFIG_NATIVE_WINDOWS */
386	eloop_register_signal_terminate(handle_term, interfaces);
387
388#ifndef CONFIG_NATIVE_WINDOWS
389	openlog("hostapd", 0, LOG_DAEMON);
390#endif /* CONFIG_NATIVE_WINDOWS */
391
392	for (i = 0; wpa_drivers[i]; i++)
393		global.drv_count++;
394	if (global.drv_count == 0) {
395		wpa_printf(MSG_ERROR, "No drivers enabled");
396		return -1;
397	}
398	global.drv_priv = os_calloc(global.drv_count, sizeof(void *));
399	if (global.drv_priv == NULL)
400		return -1;
401
402	return 0;
403}
404
405
406static void hostapd_global_deinit(const char *pid_file)
407{
408	int i;
409
410	for (i = 0; wpa_drivers[i] && global.drv_priv; i++) {
411		if (!global.drv_priv[i])
412			continue;
413		wpa_drivers[i]->global_deinit(global.drv_priv[i]);
414	}
415	os_free(global.drv_priv);
416	global.drv_priv = NULL;
417
418#ifdef EAP_SERVER_TNC
419	tncs_global_deinit();
420#endif /* EAP_SERVER_TNC */
421
422	random_deinit();
423
424	eloop_destroy();
425
426#ifndef CONFIG_NATIVE_WINDOWS
427	closelog();
428#endif /* CONFIG_NATIVE_WINDOWS */
429
430	eap_server_unregister_methods();
431
432	os_daemonize_terminate(pid_file);
433}
434
435
436static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
437			      const char *pid_file)
438{
439#ifdef EAP_SERVER_TNC
440	int tnc = 0;
441	size_t i, k;
442
443	for (i = 0; !tnc && i < ifaces->count; i++) {
444		for (k = 0; k < ifaces->iface[i]->num_bss; k++) {
445			if (ifaces->iface[i]->bss[0]->conf->tnc) {
446				tnc++;
447				break;
448			}
449		}
450	}
451
452	if (tnc && tncs_global_init() < 0) {
453		wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
454		return -1;
455	}
456#endif /* EAP_SERVER_TNC */
457
458	if (daemonize && os_daemonize(pid_file)) {
459		perror("daemon");
460		return -1;
461	}
462
463	eloop_run();
464
465	return 0;
466}
467
468
469static void show_version(void)
470{
471	fprintf(stderr,
472		"hostapd v" VERSION_STR "\n"
473		"User space daemon for IEEE 802.11 AP management,\n"
474		"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
475		"Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi> "
476		"and contributors\n");
477}
478
479
480static void usage(void)
481{
482	show_version();
483	fprintf(stderr,
484		"\n"
485		"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
486		"\\\n"
487		"         [-g <global ctrl_iface>] [-G <group>] \\\n"
488		"         <configuration file(s)>\n"
489		"\n"
490		"options:\n"
491		"   -h   show this usage\n"
492		"   -d   show more debug messages (-dd for even more)\n"
493		"   -B   run daemon in the background\n"
494		"   -e   entropy file\n"
495		"   -g   global control interface path\n"
496		"   -G   group for control interfaces\n"
497		"   -P   PID file\n"
498		"   -K   include key data in debug messages\n"
499#ifdef CONFIG_DEBUG_FILE
500		"   -f   log output to debug file instead of stdout\n"
501#endif /* CONFIG_DEBUG_FILE */
502		"   -t   include timestamps in some debug messages\n"
503		"   -v   show hostapd version\n");
504
505	exit(1);
506}
507
508
509static const char * hostapd_msg_ifname_cb(void *ctx)
510{
511	struct hostapd_data *hapd = ctx;
512	if (hapd && hapd->iconf && hapd->iconf->bss)
513		return hapd->iconf->bss->iface;
514	return NULL;
515}
516
517
518static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
519					 const char *path)
520{
521	char *pos;
522	os_free(interfaces->global_iface_path);
523	interfaces->global_iface_path = os_strdup(path);
524	if (interfaces->global_iface_path == NULL)
525		return -1;
526	pos = os_strrchr(interfaces->global_iface_path, '/');
527	if (pos == NULL) {
528		wpa_printf(MSG_ERROR, "No '/' in the global control interface "
529			   "file");
530		os_free(interfaces->global_iface_path);
531		interfaces->global_iface_path = NULL;
532		return -1;
533	}
534
535	*pos = '\0';
536	interfaces->global_iface_name = pos + 1;
537
538	return 0;
539}
540
541
542static int hostapd_get_ctrl_iface_group(struct hapd_interfaces *interfaces,
543					const char *group)
544{
545#ifndef CONFIG_NATIVE_WINDOWS
546	struct group *grp;
547	grp = getgrnam(group);
548	if (grp == NULL) {
549		wpa_printf(MSG_ERROR, "Unknown group '%s'", group);
550		return -1;
551	}
552	interfaces->ctrl_iface_group = grp->gr_gid;
553#endif /* CONFIG_NATIVE_WINDOWS */
554	return 0;
555}
556
557
558int main(int argc, char *argv[])
559{
560	struct hapd_interfaces interfaces;
561	int ret = 1;
562	size_t i;
563	int c, debug = 0, daemonize = 0;
564	char *pid_file = NULL;
565	const char *log_file = NULL;
566	const char *entropy_file = NULL;
567
568	if (os_program_init())
569		return -1;
570
571	os_memset(&interfaces, 0, sizeof(interfaces));
572	interfaces.reload_config = hostapd_reload_config;
573	interfaces.config_read_cb = hostapd_config_read;
574	interfaces.for_each_interface = hostapd_for_each_interface;
575	interfaces.ctrl_iface_init = hostapd_ctrl_iface_init;
576	interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
577	interfaces.driver_init = hostapd_driver_init;
578	interfaces.global_iface_path = NULL;
579	interfaces.global_iface_name = NULL;
580	interfaces.global_ctrl_sock = -1;
581
582	for (;;) {
583		c = getopt(argc, argv, "Bde:f:hKP:tvg:G:");
584		if (c < 0)
585			break;
586		switch (c) {
587		case 'h':
588			usage();
589			break;
590		case 'd':
591			debug++;
592			if (wpa_debug_level > 0)
593				wpa_debug_level--;
594			break;
595		case 'B':
596			daemonize++;
597			break;
598		case 'e':
599			entropy_file = optarg;
600			break;
601		case 'f':
602			log_file = optarg;
603			break;
604		case 'K':
605			wpa_debug_show_keys++;
606			break;
607		case 'P':
608			os_free(pid_file);
609			pid_file = os_rel2abs_path(optarg);
610			break;
611		case 't':
612			wpa_debug_timestamp++;
613			break;
614		case 'v':
615			show_version();
616			exit(1);
617			break;
618		case 'g':
619			if (hostapd_get_global_ctrl_iface(&interfaces, optarg))
620				return -1;
621			break;
622		case 'G':
623			if (hostapd_get_ctrl_iface_group(&interfaces, optarg))
624				return -1;
625			break;
626		default:
627			usage();
628			break;
629		}
630	}
631
632	if (optind == argc && interfaces.global_iface_path == NULL)
633		usage();
634
635	wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
636
637	if (log_file)
638		wpa_debug_open_file(log_file);
639
640	interfaces.count = argc - optind;
641	if (interfaces.count) {
642		interfaces.iface = os_calloc(interfaces.count,
643					     sizeof(struct hostapd_iface *));
644		if (interfaces.iface == NULL) {
645			wpa_printf(MSG_ERROR, "malloc failed");
646			return -1;
647		}
648	}
649
650	if (hostapd_global_init(&interfaces, entropy_file))
651		return -1;
652
653	/* Initialize interfaces */
654	for (i = 0; i < interfaces.count; i++) {
655		interfaces.iface[i] = hostapd_interface_init(&interfaces,
656							     argv[optind + i],
657							     debug);
658		if (!interfaces.iface[i])
659			goto out;
660	}
661
662	hostapd_global_ctrl_iface_init(&interfaces);
663
664	if (hostapd_global_run(&interfaces, daemonize, pid_file))
665		goto out;
666
667	ret = 0;
668
669 out:
670	hostapd_global_ctrl_iface_deinit(&interfaces);
671	/* Deinitialize all interfaces */
672	for (i = 0; i < interfaces.count; i++)
673		hostapd_interface_deinit_free(interfaces.iface[i]);
674	os_free(interfaces.iface);
675
676	hostapd_global_deinit(pid_file);
677	os_free(pid_file);
678
679	if (log_file)
680		wpa_debug_close_file();
681
682	os_program_deinit();
683
684	return ret;
685}
686