Home | History | Annotate | Download | only in wpa_supplicant
      1 /*
      2  * WPA Supplicant / main() function for Win32 service
      3  * Copyright (c) 2003-2006, Jouni Malinen <j (at) 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  * The root of wpa_supplicant configuration in registry is
     15  * HKEY_LOCAL_MACHINE\\SOFTWARE\\%wpa_supplicant. This level includes global
     16  * parameters and a 'interfaces' subkey with all the interface configuration
     17  * (adapter to confname mapping). Each such mapping is a subkey that has
     18  * 'adapter' and 'config' values.
     19  *
     20  * This program can be run either as a normal command line application, e.g.,
     21  * for debugging, with 'wpasvc.exe app' or as a Windows service. Service need
     22  * to be registered with 'wpasvc.exe reg <full path to wpasvc.exe>'. After
     23  * this, it can be started like any other Windows service (e.g., 'net start
     24  * wpasvc') or it can be configured to start automatically through the Services
     25  * tool in administrative tasks. The service can be unregistered with
     26  * 'wpasvc.exe unreg'.
     27  */
     28 
     29 #include "includes.h"
     30 #include <windows.h>
     31 
     32 #include "common.h"
     33 #include "wpa_supplicant_i.h"
     34 #include "eloop.h"
     35 
     36 #ifndef WPASVC_NAME
     37 #define WPASVC_NAME TEXT("wpasvc")
     38 #endif
     39 #ifndef WPASVC_DISPLAY_NAME
     40 #define WPASVC_DISPLAY_NAME TEXT("wpa_supplicant service")
     41 #endif
     42 #ifndef WPASVC_DESCRIPTION
     43 #define WPASVC_DESCRIPTION \
     44 TEXT("Provides IEEE 802.1X and WPA/WPA2 supplicant functionality")
     45 #endif
     46 
     47 static HANDLE kill_svc;
     48 
     49 static SERVICE_STATUS_HANDLE svc_status_handle;
     50 static SERVICE_STATUS svc_status;
     51 
     52 
     53 #ifndef WPA_KEY_ROOT
     54 #define WPA_KEY_ROOT HKEY_LOCAL_MACHINE
     55 #endif
     56 #ifndef WPA_KEY_PREFIX
     57 #define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant")
     58 #endif
     59 
     60 #ifdef UNICODE
     61 #define TSTR "%S"
     62 #else /* UNICODE */
     63 #define TSTR "%s"
     64 #endif /* UNICODE */
     65 
     66 
     67 static int read_interface(struct wpa_global *global, HKEY _hk,
     68 			  const TCHAR *name)
     69 {
     70 	HKEY hk;
     71 #define TBUFLEN 255
     72 	TCHAR adapter[TBUFLEN], config[TBUFLEN], ctrl_interface[TBUFLEN];
     73 	DWORD buflen, val;
     74 	LONG ret;
     75 	struct wpa_interface iface;
     76 	int skip_on_error = 0;
     77 
     78 	ret = RegOpenKeyEx(_hk, name, 0, KEY_QUERY_VALUE, &hk);
     79 	if (ret != ERROR_SUCCESS) {
     80 		printf("Could not open wpa_supplicant interface key\n");
     81 		return -1;
     82 	}
     83 
     84 	os_memset(&iface, 0, sizeof(iface));
     85 	iface.driver = "ndis";
     86 
     87 	buflen = sizeof(ctrl_interface);
     88 	ret = RegQueryValueEx(hk, TEXT("ctrl_interface"), NULL, NULL,
     89 			      (LPBYTE) ctrl_interface, &buflen);
     90 	if (ret == ERROR_SUCCESS) {
     91 		ctrl_interface[TBUFLEN - 1] = TEXT('\0');
     92 		wpa_unicode2ascii_inplace(ctrl_interface);
     93 		printf("ctrl_interface[len=%d] '%s'\n",
     94 		       (int) buflen, (char *) ctrl_interface);
     95 		iface.ctrl_interface = (char *) ctrl_interface;
     96 	}
     97 
     98 	buflen = sizeof(adapter);
     99 	ret = RegQueryValueEx(hk, TEXT("adapter"), NULL, NULL,
    100 			      (LPBYTE) adapter, &buflen);
    101 	if (ret == ERROR_SUCCESS) {
    102 		adapter[TBUFLEN - 1] = TEXT('\0');
    103 		wpa_unicode2ascii_inplace(adapter);
    104 		printf("adapter[len=%d] '%s'\n",
    105 		       (int) buflen, (char *) adapter);
    106 		iface.ifname = (char *) adapter;
    107 	}
    108 
    109 	buflen = sizeof(config);
    110 	ret = RegQueryValueEx(hk, TEXT("config"), NULL, NULL,
    111 			      (LPBYTE) config, &buflen);
    112 	if (ret == ERROR_SUCCESS) {
    113 		config[sizeof(config) - 1] = '\0';
    114 		wpa_unicode2ascii_inplace(config);
    115 		printf("config[len=%d] '%s'\n",
    116 		       (int) buflen, (char *) config);
    117 		iface.confname = (char *) config;
    118 	}
    119 
    120 	buflen = sizeof(val);
    121 	ret = RegQueryValueEx(hk, TEXT("skip_on_error"), NULL, NULL,
    122 			      (LPBYTE) &val, &buflen);
    123 	if (ret == ERROR_SUCCESS && buflen == sizeof(val))
    124 		skip_on_error = val;
    125 
    126 	RegCloseKey(hk);
    127 
    128 	if (wpa_supplicant_add_iface(global, &iface) == NULL) {
    129 		if (skip_on_error)
    130 			wpa_printf(MSG_DEBUG, "Skipped interface '%s' due to "
    131 				   "initialization failure", iface.ifname);
    132 		else
    133 			return -1;
    134 	}
    135 
    136 	return 0;
    137 }
    138 
    139 
    140 static int wpa_supplicant_thread(void)
    141 {
    142 	int exitcode;
    143 	struct wpa_params params;
    144 	struct wpa_global *global;
    145 	HKEY hk, ihk;
    146 	DWORD val, buflen, i;
    147 	LONG ret;
    148 
    149 	if (os_program_init())
    150 		return -1;
    151 
    152 	os_memset(&params, 0, sizeof(params));
    153 	params.wpa_debug_level = MSG_INFO;
    154 
    155 	ret = RegOpenKeyEx(WPA_KEY_ROOT, WPA_KEY_PREFIX,
    156 			   0, KEY_QUERY_VALUE, &hk);
    157 	if (ret != ERROR_SUCCESS) {
    158 		printf("Could not open wpa_supplicant registry key\n");
    159 		return -1;
    160 	}
    161 
    162 	buflen = sizeof(val);
    163 	ret = RegQueryValueEx(hk, TEXT("debug_level"), NULL, NULL,
    164 			      (LPBYTE) &val, &buflen);
    165 	if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
    166 		params.wpa_debug_level = val;
    167 	}
    168 
    169 	buflen = sizeof(val);
    170 	ret = RegQueryValueEx(hk, TEXT("debug_show_keys"), NULL, NULL,
    171 			      (LPBYTE) &val, &buflen);
    172 	if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
    173 		params.wpa_debug_show_keys = val;
    174 	}
    175 
    176 	buflen = sizeof(val);
    177 	ret = RegQueryValueEx(hk, TEXT("debug_timestamp"), NULL, NULL,
    178 			      (LPBYTE) &val, &buflen);
    179 	if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
    180 		params.wpa_debug_timestamp = val;
    181 	}
    182 
    183 	buflen = sizeof(val);
    184 	ret = RegQueryValueEx(hk, TEXT("debug_use_file"), NULL, NULL,
    185 			      (LPBYTE) &val, &buflen);
    186 	if (ret == ERROR_SUCCESS && buflen == sizeof(val) && val) {
    187 		params.wpa_debug_file_path = "\\Temp\\wpa_supplicant-log.txt";
    188 	}
    189 
    190 	exitcode = 0;
    191 	global = wpa_supplicant_init(&params);
    192 	if (global == NULL) {
    193 		printf("Failed to initialize wpa_supplicant\n");
    194 		exitcode = -1;
    195 	}
    196 
    197 	ret = RegOpenKeyEx(hk, TEXT("interfaces"), 0, KEY_ENUMERATE_SUB_KEYS,
    198 			   &ihk);
    199 	RegCloseKey(hk);
    200 	if (ret != ERROR_SUCCESS) {
    201 		printf("Could not open wpa_supplicant interfaces registry "
    202 		       "key\n");
    203 		return -1;
    204 	}
    205 
    206 	for (i = 0; ; i++) {
    207 		TCHAR name[255];
    208 		DWORD namelen;
    209 
    210 		namelen = 255;
    211 		ret = RegEnumKeyEx(ihk, i, name, &namelen, NULL, NULL, NULL,
    212 				   NULL);
    213 
    214 		if (ret == ERROR_NO_MORE_ITEMS)
    215 			break;
    216 
    217 		if (ret != ERROR_SUCCESS) {
    218 			printf("RegEnumKeyEx failed: 0x%x\n",
    219 			       (unsigned int) ret);
    220 			break;
    221 		}
    222 
    223 		if (namelen >= 255)
    224 			namelen = 255 - 1;
    225 		name[namelen] = '\0';
    226 
    227 		wpa_printf(MSG_DEBUG, "interface %d: %s\n", (int) i, name);
    228 		if (read_interface(global, ihk, name) < 0)
    229 			exitcode = -1;
    230 	}
    231 
    232 	RegCloseKey(ihk);
    233 
    234 	if (exitcode == 0)
    235 		exitcode = wpa_supplicant_run(global);
    236 
    237 	wpa_supplicant_deinit(global);
    238 
    239 	os_program_deinit();
    240 
    241 	return exitcode;
    242 }
    243 
    244 
    245 static DWORD svc_thread(LPDWORD param)
    246 {
    247 	int ret = wpa_supplicant_thread();
    248 
    249 	svc_status.dwCurrentState = SERVICE_STOPPED;
    250 	svc_status.dwWaitHint = 0;
    251 	if (!SetServiceStatus(svc_status_handle, &svc_status)) {
    252 		printf("SetServiceStatus() failed: %d\n",
    253 		       (int) GetLastError());
    254 	}
    255 
    256 	return ret;
    257 }
    258 
    259 
    260 static int register_service(const TCHAR *exe)
    261 {
    262 	SC_HANDLE svc, scm;
    263 	SERVICE_DESCRIPTION sd;
    264 
    265 	printf("Registering service: " TSTR "\n", WPASVC_NAME);
    266 
    267 	scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
    268 	if (!scm) {
    269 		printf("OpenSCManager failed: %d\n", (int) GetLastError());
    270 		return -1;
    271 	}
    272 
    273 	svc = CreateService(scm, WPASVC_NAME, WPASVC_DISPLAY_NAME,
    274 			    SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
    275 			    SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
    276 			    exe, NULL, NULL, NULL, NULL, NULL);
    277 
    278 	if (!svc) {
    279 		printf("CreateService failed: %d\n\n", (int) GetLastError());
    280 		CloseServiceHandle(scm);
    281 		return -1;
    282 	}
    283 
    284 	os_memset(&sd, 0, sizeof(sd));
    285 	sd.lpDescription = WPASVC_DESCRIPTION;
    286 	if (!ChangeServiceConfig2(svc, SERVICE_CONFIG_DESCRIPTION, &sd)) {
    287 		printf("ChangeServiceConfig2 failed: %d\n",
    288 		       (int) GetLastError());
    289 		/* This is not a fatal error, so continue anyway. */
    290 	}
    291 
    292 	CloseServiceHandle(svc);
    293 	CloseServiceHandle(scm);
    294 
    295 	printf("Service registered successfully.\n");
    296 
    297 	return 0;
    298 }
    299 
    300 
    301 static int unregister_service(void)
    302 {
    303 	SC_HANDLE svc, scm;
    304 	SERVICE_STATUS status;
    305 
    306 	printf("Unregistering service: " TSTR "\n", WPASVC_NAME);
    307 
    308 	scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
    309 	if (!scm) {
    310 		printf("OpenSCManager failed: %d\n", (int) GetLastError());
    311 		return -1;
    312 	}
    313 
    314 	svc = OpenService(scm, WPASVC_NAME, SERVICE_ALL_ACCESS | DELETE);
    315 	if (!svc) {
    316 		printf("OpenService failed: %d\n\n", (int) GetLastError());
    317 		CloseServiceHandle(scm);
    318 		return -1;
    319 	}
    320 
    321 	if (QueryServiceStatus(svc, &status)) {
    322 		if (status.dwCurrentState != SERVICE_STOPPED) {
    323 			printf("Service currently active - stopping "
    324 			       "service...\n");
    325 			if (!ControlService(svc, SERVICE_CONTROL_STOP,
    326 					    &status)) {
    327 				printf("ControlService failed: %d\n",
    328 				       (int) GetLastError());
    329 			}
    330 			Sleep(500);
    331 		}
    332 	}
    333 
    334 	if (DeleteService(svc)) {
    335 		printf("Service unregistered successfully.\n");
    336 	} else {
    337 		printf("DeleteService failed: %d\n", (int) GetLastError());
    338 	}
    339 
    340 	CloseServiceHandle(svc);
    341 	CloseServiceHandle(scm);
    342 
    343 	return 0;
    344 }
    345 
    346 
    347 static void WINAPI service_ctrl_handler(DWORD control_code)
    348 {
    349 	switch (control_code) {
    350 	case SERVICE_CONTROL_INTERROGATE:
    351 		break;
    352 	case SERVICE_CONTROL_SHUTDOWN:
    353 	case SERVICE_CONTROL_STOP:
    354 		svc_status.dwCurrentState = SERVICE_STOP_PENDING;
    355 		svc_status.dwWaitHint = 2000;
    356 		eloop_terminate();
    357 		SetEvent(kill_svc);
    358 		break;
    359 	}
    360 
    361 	if (!SetServiceStatus(svc_status_handle, &svc_status)) {
    362 		printf("SetServiceStatus() failed: %d\n",
    363 		       (int) GetLastError());
    364 	}
    365 }
    366 
    367 
    368 static void WINAPI service_start(DWORD argc, LPTSTR *argv)
    369 {
    370 	DWORD id;
    371 
    372 	svc_status_handle = RegisterServiceCtrlHandler(WPASVC_NAME,
    373 						       service_ctrl_handler);
    374 	if (svc_status_handle == (SERVICE_STATUS_HANDLE) 0) {
    375 		printf("RegisterServiceCtrlHandler failed: %d\n",
    376 		       (int) GetLastError());
    377 		return;
    378 	}
    379 
    380 	os_memset(&svc_status, 0, sizeof(svc_status));
    381 	svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    382 	svc_status.dwCurrentState = SERVICE_START_PENDING;
    383 	svc_status.dwWaitHint = 1000;
    384 
    385 	if (!SetServiceStatus(svc_status_handle, &svc_status)) {
    386 		printf("SetServiceStatus() failed: %d\n",
    387 		       (int) GetLastError());
    388 		return;
    389 	}
    390 
    391 	kill_svc = CreateEvent(0, TRUE, FALSE, 0);
    392 	if (!kill_svc) {
    393 		printf("CreateEvent failed: %d\n", (int) GetLastError());
    394 		return;
    395 	}
    396 
    397 	if (CreateThread(0, 0, (LPTHREAD_START_ROUTINE) svc_thread, 0, 0, &id)
    398 	    == 0) {
    399 		printf("CreateThread failed: %d\n", (int) GetLastError());
    400 		return;
    401 	}
    402 
    403 	if (svc_status.dwCurrentState == SERVICE_START_PENDING) {
    404 		svc_status.dwCurrentState = SERVICE_RUNNING;
    405 		svc_status.dwWaitHint = 0;
    406 		svc_status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
    407 			SERVICE_ACCEPT_SHUTDOWN;
    408 	}
    409 
    410 	if (!SetServiceStatus(svc_status_handle, &svc_status)) {
    411 		printf("SetServiceStatus() failed: %d\n",
    412 		       (int) GetLastError());
    413 		return;
    414 	}
    415 
    416 	/* wait until service gets killed */
    417 	WaitForSingleObject(kill_svc, INFINITE);
    418 }
    419 
    420 
    421 int main(int argc, char *argv[])
    422 {
    423 	SERVICE_TABLE_ENTRY dt[] = {
    424 		{ WPASVC_NAME, service_start },
    425 		{ NULL, NULL }
    426 	};
    427 
    428 	if (argc > 1) {
    429 		if (os_strcmp(argv[1], "reg") == 0) {
    430 			TCHAR *path;
    431 			int ret;
    432 
    433 			if (argc < 3) {
    434 				path = os_malloc(MAX_PATH * sizeof(TCHAR));
    435 				if (path == NULL)
    436 					return -1;
    437 				if (!GetModuleFileName(NULL, path, MAX_PATH)) {
    438 					printf("GetModuleFileName failed: "
    439 					       "%d\n", (int) GetLastError());
    440 					os_free(path);
    441 					return -1;
    442 				}
    443 			} else {
    444 				path = wpa_strdup_tchar(argv[2]);
    445 				if (path == NULL)
    446 					return -1;
    447 			}
    448 			ret = register_service(path);
    449 			os_free(path);
    450 			return ret;
    451 		} else if (os_strcmp(argv[1], "unreg") == 0) {
    452 			return unregister_service();
    453 		} else if (os_strcmp(argv[1], "app") == 0) {
    454 			return wpa_supplicant_thread();
    455 		}
    456 	}
    457 
    458 	if (!StartServiceCtrlDispatcher(dt)) {
    459 		printf("StartServiceCtrlDispatcher failed: %d\n",
    460 		       (int) GetLastError());
    461 	}
    462 
    463 	return 0;
    464 }
    465