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;
     74 	LONG ret;
     75 	struct wpa_interface iface;
     76 
     77 	ret = RegOpenKeyEx(_hk, name, 0, KEY_QUERY_VALUE, &hk);
     78 	if (ret != ERROR_SUCCESS) {
     79 		printf("Could not open wpa_supplicant interface key\n");
     80 		return -1;
     81 	}
     82 
     83 	os_memset(&iface, 0, sizeof(iface));
     84 	iface.driver = "ndis";
     85 
     86 	buflen = sizeof(ctrl_interface);
     87 	ret = RegQueryValueEx(hk, TEXT("ctrl_interface"), NULL, NULL,
     88 			      (LPBYTE) ctrl_interface, &buflen);
     89 	if (ret == ERROR_SUCCESS) {
     90 		ctrl_interface[TBUFLEN - 1] = TEXT('\0');
     91 		wpa_unicode2ascii_inplace(ctrl_interface);
     92 		printf("ctrl_interface[len=%d] '%s'\n",
     93 		       (int) buflen, (char *) ctrl_interface);
     94 		iface.ctrl_interface = (char *) ctrl_interface;
     95 	}
     96 
     97 	buflen = sizeof(adapter);
     98 	ret = RegQueryValueEx(hk, TEXT("adapter"), NULL, NULL,
     99 			      (LPBYTE) adapter, &buflen);
    100 	if (ret == ERROR_SUCCESS) {
    101 		adapter[TBUFLEN - 1] = TEXT('\0');
    102 		wpa_unicode2ascii_inplace(adapter);
    103 		printf("adapter[len=%d] '%s'\n",
    104 		       (int) buflen, (char *) adapter);
    105 		iface.ifname = (char *) adapter;
    106 	}
    107 
    108 	buflen = sizeof(config);
    109 	ret = RegQueryValueEx(hk, TEXT("config"), NULL, NULL,
    110 			      (LPBYTE) config, &buflen);
    111 	if (ret == ERROR_SUCCESS) {
    112 		config[sizeof(config) - 1] = '\0';
    113 		wpa_unicode2ascii_inplace(config);
    114 		printf("config[len=%d] '%s'\n",
    115 		       (int) buflen, (char *) config);
    116 		iface.confname = (char *) config;
    117 	}
    118 
    119 	RegCloseKey(hk);
    120 
    121 	if (wpa_supplicant_add_iface(global, &iface) == NULL)
    122 		return -1;
    123 
    124 	return 0;
    125 }
    126 
    127 
    128 static int wpa_supplicant_thread(void)
    129 {
    130 	int exitcode;
    131 	struct wpa_params params;
    132 	struct wpa_global *global;
    133 	HKEY hk, ihk;
    134 	DWORD val, buflen, i;
    135 	LONG ret;
    136 
    137 	if (os_program_init())
    138 		return -1;
    139 
    140 	os_memset(&params, 0, sizeof(params));
    141 	params.wpa_debug_level = MSG_INFO;
    142 
    143 	ret = RegOpenKeyEx(WPA_KEY_ROOT, WPA_KEY_PREFIX,
    144 			   0, KEY_QUERY_VALUE, &hk);
    145 	if (ret != ERROR_SUCCESS) {
    146 		printf("Could not open wpa_supplicant registry key\n");
    147 		return -1;
    148 	}
    149 
    150 	buflen = sizeof(val);
    151 	ret = RegQueryValueEx(hk, TEXT("debug_level"), NULL, NULL,
    152 			      (LPBYTE) &val, &buflen);
    153 	if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
    154 		params.wpa_debug_level = val;
    155 	}
    156 
    157 	buflen = sizeof(val);
    158 	ret = RegQueryValueEx(hk, TEXT("debug_show_keys"), NULL, NULL,
    159 			      (LPBYTE) &val, &buflen);
    160 	if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
    161 		params.wpa_debug_show_keys = val;
    162 	}
    163 
    164 	buflen = sizeof(val);
    165 	ret = RegQueryValueEx(hk, TEXT("debug_use_file"), NULL, NULL,
    166 			      (LPBYTE) &val, &buflen);
    167 	if (ret == ERROR_SUCCESS && buflen == sizeof(val) && val) {
    168 		params.wpa_debug_file_path = "\\Temp\\wpa_supplicant-log.txt";
    169 	}
    170 
    171 	exitcode = 0;
    172 	global = wpa_supplicant_init(&params);
    173 	if (global == NULL) {
    174 		printf("Failed to initialize wpa_supplicant\n");
    175 		exitcode = -1;
    176 	}
    177 
    178 	ret = RegOpenKeyEx(hk, TEXT("interfaces"), 0, KEY_ENUMERATE_SUB_KEYS,
    179 			   &ihk);
    180 	RegCloseKey(hk);
    181 	if (ret != ERROR_SUCCESS) {
    182 		printf("Could not open wpa_supplicant interfaces registry "
    183 		       "key\n");
    184 		return -1;
    185 	}
    186 
    187 	for (i = 0; ; i++) {
    188 		TCHAR name[255];
    189 		DWORD namelen;
    190 
    191 		namelen = 255;
    192 		ret = RegEnumKeyEx(ihk, i, name, &namelen, NULL, NULL, NULL,
    193 				   NULL);
    194 
    195 		if (ret == ERROR_NO_MORE_ITEMS)
    196 			break;
    197 
    198 		if (ret != ERROR_SUCCESS) {
    199 			printf("RegEnumKeyEx failed: 0x%x\n",
    200 			       (unsigned int) ret);
    201 			break;
    202 		}
    203 
    204 		if (namelen >= 255)
    205 			namelen = 255 - 1;
    206 		name[namelen] = '\0';
    207 
    208 		wpa_printf(MSG_DEBUG, "interface %d: %s\n", (int) i, name);
    209 		if (read_interface(global, ihk, name) < 0)
    210 			exitcode = -1;
    211 	}
    212 
    213 	RegCloseKey(ihk);
    214 
    215 	if (exitcode == 0)
    216 		exitcode = wpa_supplicant_run(global);
    217 
    218 	wpa_supplicant_deinit(global);
    219 
    220 	os_program_deinit();
    221 
    222 	return exitcode;
    223 }
    224 
    225 
    226 static DWORD svc_thread(LPDWORD param)
    227 {
    228 	int ret = wpa_supplicant_thread();
    229 
    230 	svc_status.dwCurrentState = SERVICE_STOPPED;
    231 	svc_status.dwWaitHint = 0;
    232 	if (!SetServiceStatus(svc_status_handle, &svc_status)) {
    233 		printf("SetServiceStatus() failed: %d\n",
    234 		       (int) GetLastError());
    235 	}
    236 
    237 	return ret;
    238 }
    239 
    240 
    241 static int register_service(const TCHAR *exe)
    242 {
    243 	SC_HANDLE svc, scm;
    244 	SERVICE_DESCRIPTION sd;
    245 
    246 	printf("Registering service: " TSTR "\n", WPASVC_NAME);
    247 
    248 	scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
    249 	if (!scm) {
    250 		printf("OpenSCManager failed: %d\n", (int) GetLastError());
    251 		return -1;
    252 	}
    253 
    254 	svc = CreateService(scm, WPASVC_NAME, WPASVC_DISPLAY_NAME,
    255 			    SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
    256 			    SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
    257 			    exe, NULL, NULL, NULL, NULL, NULL);
    258 
    259 	if (!svc) {
    260 		printf("CreateService failed: %d\n\n", (int) GetLastError());
    261 		CloseServiceHandle(scm);
    262 		return -1;
    263 	}
    264 
    265 	os_memset(&sd, 0, sizeof(sd));
    266 	sd.lpDescription = WPASVC_DESCRIPTION;
    267 	if (!ChangeServiceConfig2(svc, SERVICE_CONFIG_DESCRIPTION, &sd)) {
    268 		printf("ChangeServiceConfig2 failed: %d\n",
    269 		       (int) GetLastError());
    270 		/* This is not a fatal error, so continue anyway. */
    271 	}
    272 
    273 	CloseServiceHandle(svc);
    274 	CloseServiceHandle(scm);
    275 
    276 	printf("Service registered successfully.\n");
    277 
    278 	return 0;
    279 }
    280 
    281 
    282 static int unregister_service(void)
    283 {
    284 	SC_HANDLE svc, scm;
    285 	SERVICE_STATUS status;
    286 
    287 	printf("Unregistering service: " TSTR "\n", WPASVC_NAME);
    288 
    289 	scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
    290 	if (!scm) {
    291 		printf("OpenSCManager failed: %d\n", (int) GetLastError());
    292 		return -1;
    293 	}
    294 
    295 	svc = OpenService(scm, WPASVC_NAME, SERVICE_ALL_ACCESS | DELETE);
    296 	if (!svc) {
    297 		printf("OpenService failed: %d\n\n", (int) GetLastError());
    298 		CloseServiceHandle(scm);
    299 		return -1;
    300 	}
    301 
    302 	if (QueryServiceStatus(svc, &status)) {
    303 		if (status.dwCurrentState != SERVICE_STOPPED) {
    304 			printf("Service currently active - stopping "
    305 			       "service...\n");
    306 			if (!ControlService(svc, SERVICE_CONTROL_STOP,
    307 					    &status)) {
    308 				printf("ControlService failed: %d\n",
    309 				       (int) GetLastError());
    310 			}
    311 			Sleep(500);
    312 		}
    313 	}
    314 
    315 	if (DeleteService(svc)) {
    316 		printf("Service unregistered successfully.\n");
    317 	} else {
    318 		printf("DeleteService failed: %d\n", (int) GetLastError());
    319 	}
    320 
    321 	CloseServiceHandle(svc);
    322 	CloseServiceHandle(scm);
    323 
    324 	return 0;
    325 }
    326 
    327 
    328 static void WINAPI service_ctrl_handler(DWORD control_code)
    329 {
    330 	switch (control_code) {
    331 	case SERVICE_CONTROL_INTERROGATE:
    332 		break;
    333 	case SERVICE_CONTROL_SHUTDOWN:
    334 	case SERVICE_CONTROL_STOP:
    335 		svc_status.dwCurrentState = SERVICE_STOP_PENDING;
    336 		svc_status.dwWaitHint = 2000;
    337 		eloop_terminate();
    338 		SetEvent(kill_svc);
    339 		break;
    340 	}
    341 
    342 	if (!SetServiceStatus(svc_status_handle, &svc_status)) {
    343 		printf("SetServiceStatus() failed: %d\n",
    344 		       (int) GetLastError());
    345 	}
    346 }
    347 
    348 
    349 static void WINAPI service_start(DWORD argc, LPTSTR *argv)
    350 {
    351 	DWORD id;
    352 
    353 	svc_status_handle = RegisterServiceCtrlHandler(WPASVC_NAME,
    354 						       service_ctrl_handler);
    355 	if (svc_status_handle == (SERVICE_STATUS_HANDLE) 0) {
    356 		printf("RegisterServiceCtrlHandler failed: %d\n",
    357 		       (int) GetLastError());
    358 		return;
    359 	}
    360 
    361 	os_memset(&svc_status, 0, sizeof(svc_status));
    362 	svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    363 	svc_status.dwCurrentState = SERVICE_START_PENDING;
    364 	svc_status.dwWaitHint = 1000;
    365 
    366 	if (!SetServiceStatus(svc_status_handle, &svc_status)) {
    367 		printf("SetServiceStatus() failed: %d\n",
    368 		       (int) GetLastError());
    369 		return;
    370 	}
    371 
    372 	kill_svc = CreateEvent(0, TRUE, FALSE, 0);
    373 	if (!kill_svc) {
    374 		printf("CreateEvent failed: %d\n", (int) GetLastError());
    375 		return;
    376 	}
    377 
    378 	if (CreateThread(0, 0, (LPTHREAD_START_ROUTINE) svc_thread, 0, 0, &id)
    379 	    == 0) {
    380 		printf("CreateThread failed: %d\n", (int) GetLastError());
    381 		return;
    382 	}
    383 
    384 	if (svc_status.dwCurrentState == SERVICE_START_PENDING) {
    385 		svc_status.dwCurrentState = SERVICE_RUNNING;
    386 		svc_status.dwWaitHint = 0;
    387 		svc_status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
    388 			SERVICE_ACCEPT_SHUTDOWN;
    389 	}
    390 
    391 	if (!SetServiceStatus(svc_status_handle, &svc_status)) {
    392 		printf("SetServiceStatus() failed: %d\n",
    393 		       (int) GetLastError());
    394 		return;
    395 	}
    396 
    397 	/* wait until service gets killed */
    398 	WaitForSingleObject(kill_svc, INFINITE);
    399 }
    400 
    401 
    402 int main(int argc, char *argv[])
    403 {
    404 	SERVICE_TABLE_ENTRY dt[] = {
    405 		{ WPASVC_NAME, service_start },
    406 		{ NULL, NULL }
    407 	};
    408 
    409 	if (argc > 1) {
    410 		if (os_strcmp(argv[1], "reg") == 0) {
    411 			TCHAR *path;
    412 			int ret;
    413 
    414 			if (argc < 3) {
    415 				path = os_malloc(MAX_PATH * sizeof(TCHAR));
    416 				if (path == NULL)
    417 					return -1;
    418 				if (!GetModuleFileName(NULL, path, MAX_PATH)) {
    419 					printf("GetModuleFileName failed: "
    420 					       "%d\n", (int) GetLastError());
    421 					os_free(path);
    422 					return -1;
    423 				}
    424 			} else {
    425 				path = wpa_strdup_tchar(argv[2]);
    426 				if (path == NULL)
    427 					return -1;
    428 			}
    429 			ret = register_service(path);
    430 			os_free(path);
    431 			return ret;
    432 		} else if (os_strcmp(argv[1], "unreg") == 0) {
    433 			return unregister_service();
    434 		} else if (os_strcmp(argv[1], "app") == 0) {
    435 			return wpa_supplicant_thread();
    436 		}
    437 	}
    438 
    439 	if (!StartServiceCtrlDispatcher(dt)) {
    440 		printf("StartServiceCtrlDispatcher failed: %d\n",
    441 		       (int) GetLastError());
    442 	}
    443 
    444 	return 0;
    445 }
    446