$search
00001 /* 00002 * WPA Supplicant / main() function for Win32 service 00003 * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 * 00014 * The root of wpa_supplicant configuration in registry is 00015 * HKEY_LOCAL_MACHINE\\SOFTWARE\\%wpa_supplicant. This level includes global 00016 * parameters and a 'interfaces' subkey with all the interface configuration 00017 * (adapter to confname mapping). Each such mapping is a subkey that has 00018 * 'adapter' and 'config' values. 00019 * 00020 * This program can be run either as a normal command line application, e.g., 00021 * for debugging, with 'wpasvc.exe app' or as a Windows service. Service need 00022 * to be registered with 'wpasvc.exe reg <full path to wpasvc.exe>'. After 00023 * this, it can be started like any other Windows service (e.g., 'net start 00024 * wpasvc') or it can be configured to start automatically through the Services 00025 * tool in administrative tasks. The service can be unregistered with 00026 * 'wpasvc.exe unreg'. 00027 */ 00028 00029 #include "includes.h" 00030 #include <windows.h> 00031 00032 #include "common.h" 00033 #include "wpa_supplicant_i.h" 00034 #include "eloop.h" 00035 00036 #ifndef WPASVC_NAME 00037 #define WPASVC_NAME TEXT("wpasvc") 00038 #endif 00039 #ifndef WPASVC_DISPLAY_NAME 00040 #define WPASVC_DISPLAY_NAME TEXT("wpa_supplicant service") 00041 #endif 00042 #ifndef WPASVC_DESCRIPTION 00043 #define WPASVC_DESCRIPTION \ 00044 TEXT("Provides IEEE 802.1X and WPA/WPA2 supplicant functionality") 00045 #endif 00046 00047 static HANDLE kill_svc; 00048 00049 static SERVICE_STATUS_HANDLE svc_status_handle; 00050 static SERVICE_STATUS svc_status; 00051 00052 00053 #ifndef WPA_KEY_ROOT 00054 #define WPA_KEY_ROOT HKEY_LOCAL_MACHINE 00055 #endif 00056 #ifndef WPA_KEY_PREFIX 00057 #define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant") 00058 #endif 00059 00060 #ifdef UNICODE 00061 #define TSTR "%S" 00062 #else /* UNICODE */ 00063 #define TSTR "%s" 00064 #endif /* UNICODE */ 00065 00066 00067 static int read_interface(struct wpa_global *global, HKEY _hk, 00068 const TCHAR *name) 00069 { 00070 HKEY hk; 00071 #define TBUFLEN 255 00072 TCHAR adapter[TBUFLEN], config[TBUFLEN], ctrl_interface[TBUFLEN]; 00073 DWORD buflen, val; 00074 LONG ret; 00075 struct wpa_interface iface; 00076 int skip_on_error = 0; 00077 00078 ret = RegOpenKeyEx(_hk, name, 0, KEY_QUERY_VALUE, &hk); 00079 if (ret != ERROR_SUCCESS) { 00080 printf("Could not open wpa_supplicant interface key\n"); 00081 return -1; 00082 } 00083 00084 os_memset(&iface, 0, sizeof(iface)); 00085 iface.driver = "ndis"; 00086 00087 buflen = sizeof(ctrl_interface); 00088 ret = RegQueryValueEx(hk, TEXT("ctrl_interface"), NULL, NULL, 00089 (LPBYTE) ctrl_interface, &buflen); 00090 if (ret == ERROR_SUCCESS) { 00091 ctrl_interface[TBUFLEN - 1] = TEXT('\0'); 00092 wpa_unicode2ascii_inplace(ctrl_interface); 00093 printf("ctrl_interface[len=%d] '%s'\n", 00094 (int) buflen, (char *) ctrl_interface); 00095 iface.ctrl_interface = (char *) ctrl_interface; 00096 } 00097 00098 buflen = sizeof(adapter); 00099 ret = RegQueryValueEx(hk, TEXT("adapter"), NULL, NULL, 00100 (LPBYTE) adapter, &buflen); 00101 if (ret == ERROR_SUCCESS) { 00102 adapter[TBUFLEN - 1] = TEXT('\0'); 00103 wpa_unicode2ascii_inplace(adapter); 00104 printf("adapter[len=%d] '%s'\n", 00105 (int) buflen, (char *) adapter); 00106 iface.ifname = (char *) adapter; 00107 } 00108 00109 buflen = sizeof(config); 00110 ret = RegQueryValueEx(hk, TEXT("config"), NULL, NULL, 00111 (LPBYTE) config, &buflen); 00112 if (ret == ERROR_SUCCESS) { 00113 config[sizeof(config) - 1] = '\0'; 00114 wpa_unicode2ascii_inplace(config); 00115 printf("config[len=%d] '%s'\n", 00116 (int) buflen, (char *) config); 00117 iface.confname = (char *) config; 00118 } 00119 00120 buflen = sizeof(val); 00121 ret = RegQueryValueEx(hk, TEXT("skip_on_error"), NULL, NULL, 00122 (LPBYTE) &val, &buflen); 00123 if (ret == ERROR_SUCCESS && buflen == sizeof(val)) 00124 skip_on_error = val; 00125 00126 RegCloseKey(hk); 00127 00128 if (wpa_supplicant_add_iface(global, &iface) == NULL) { 00129 if (skip_on_error) 00130 wpa_printf(MSG_DEBUG, "Skipped interface '%s' due to " 00131 "initialization failure", iface.ifname); 00132 else 00133 return -1; 00134 } 00135 00136 return 0; 00137 } 00138 00139 00140 static int wpa_supplicant_thread(void) 00141 { 00142 int exitcode; 00143 struct wpa_params params; 00144 struct wpa_global *global; 00145 HKEY hk, ihk; 00146 DWORD val, buflen, i; 00147 LONG ret; 00148 00149 if (os_program_init()) 00150 return -1; 00151 00152 os_memset(¶ms, 0, sizeof(params)); 00153 params.wpa_debug_level = MSG_INFO; 00154 00155 ret = RegOpenKeyEx(WPA_KEY_ROOT, WPA_KEY_PREFIX, 00156 0, KEY_QUERY_VALUE, &hk); 00157 if (ret != ERROR_SUCCESS) { 00158 printf("Could not open wpa_supplicant registry key\n"); 00159 return -1; 00160 } 00161 00162 buflen = sizeof(val); 00163 ret = RegQueryValueEx(hk, TEXT("debug_level"), NULL, NULL, 00164 (LPBYTE) &val, &buflen); 00165 if (ret == ERROR_SUCCESS && buflen == sizeof(val)) { 00166 params.wpa_debug_level = val; 00167 } 00168 00169 buflen = sizeof(val); 00170 ret = RegQueryValueEx(hk, TEXT("debug_show_keys"), NULL, NULL, 00171 (LPBYTE) &val, &buflen); 00172 if (ret == ERROR_SUCCESS && buflen == sizeof(val)) { 00173 params.wpa_debug_show_keys = val; 00174 } 00175 00176 buflen = sizeof(val); 00177 ret = RegQueryValueEx(hk, TEXT("debug_timestamp"), NULL, NULL, 00178 (LPBYTE) &val, &buflen); 00179 if (ret == ERROR_SUCCESS && buflen == sizeof(val)) { 00180 params.wpa_debug_timestamp = val; 00181 } 00182 00183 buflen = sizeof(val); 00184 ret = RegQueryValueEx(hk, TEXT("debug_use_file"), NULL, NULL, 00185 (LPBYTE) &val, &buflen); 00186 if (ret == ERROR_SUCCESS && buflen == sizeof(val) && val) { 00187 params.wpa_debug_file_path = "\\Temp\\wpa_supplicant-log.txt"; 00188 } 00189 00190 exitcode = 0; 00191 global = wpa_supplicant_init(¶ms); 00192 if (global == NULL) { 00193 printf("Failed to initialize wpa_supplicant\n"); 00194 exitcode = -1; 00195 } 00196 00197 ret = RegOpenKeyEx(hk, TEXT("interfaces"), 0, KEY_ENUMERATE_SUB_KEYS, 00198 &ihk); 00199 RegCloseKey(hk); 00200 if (ret != ERROR_SUCCESS) { 00201 printf("Could not open wpa_supplicant interfaces registry " 00202 "key\n"); 00203 return -1; 00204 } 00205 00206 for (i = 0; ; i++) { 00207 TCHAR name[255]; 00208 DWORD namelen; 00209 00210 namelen = 255; 00211 ret = RegEnumKeyEx(ihk, i, name, &namelen, NULL, NULL, NULL, 00212 NULL); 00213 00214 if (ret == ERROR_NO_MORE_ITEMS) 00215 break; 00216 00217 if (ret != ERROR_SUCCESS) { 00218 printf("RegEnumKeyEx failed: 0x%x\n", 00219 (unsigned int) ret); 00220 break; 00221 } 00222 00223 if (namelen >= 255) 00224 namelen = 255 - 1; 00225 name[namelen] = '\0'; 00226 00227 wpa_printf(MSG_DEBUG, "interface %d: %s\n", (int) i, name); 00228 if (read_interface(global, ihk, name) < 0) 00229 exitcode = -1; 00230 } 00231 00232 RegCloseKey(ihk); 00233 00234 if (exitcode == 0) 00235 exitcode = wpa_supplicant_run(global); 00236 00237 wpa_supplicant_deinit(global); 00238 00239 os_program_deinit(); 00240 00241 return exitcode; 00242 } 00243 00244 00245 static DWORD svc_thread(LPDWORD param) 00246 { 00247 int ret = wpa_supplicant_thread(); 00248 00249 svc_status.dwCurrentState = SERVICE_STOPPED; 00250 svc_status.dwWaitHint = 0; 00251 if (!SetServiceStatus(svc_status_handle, &svc_status)) { 00252 printf("SetServiceStatus() failed: %d\n", 00253 (int) GetLastError()); 00254 } 00255 00256 return ret; 00257 } 00258 00259 00260 static int register_service(const TCHAR *exe) 00261 { 00262 SC_HANDLE svc, scm; 00263 SERVICE_DESCRIPTION sd; 00264 00265 printf("Registering service: " TSTR "\n", WPASVC_NAME); 00266 00267 scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE); 00268 if (!scm) { 00269 printf("OpenSCManager failed: %d\n", (int) GetLastError()); 00270 return -1; 00271 } 00272 00273 svc = CreateService(scm, WPASVC_NAME, WPASVC_DISPLAY_NAME, 00274 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, 00275 SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, 00276 exe, NULL, NULL, NULL, NULL, NULL); 00277 00278 if (!svc) { 00279 printf("CreateService failed: %d\n\n", (int) GetLastError()); 00280 CloseServiceHandle(scm); 00281 return -1; 00282 } 00283 00284 os_memset(&sd, 0, sizeof(sd)); 00285 sd.lpDescription = WPASVC_DESCRIPTION; 00286 if (!ChangeServiceConfig2(svc, SERVICE_CONFIG_DESCRIPTION, &sd)) { 00287 printf("ChangeServiceConfig2 failed: %d\n", 00288 (int) GetLastError()); 00289 /* This is not a fatal error, so continue anyway. */ 00290 } 00291 00292 CloseServiceHandle(svc); 00293 CloseServiceHandle(scm); 00294 00295 printf("Service registered successfully.\n"); 00296 00297 return 0; 00298 } 00299 00300 00301 static int unregister_service(void) 00302 { 00303 SC_HANDLE svc, scm; 00304 SERVICE_STATUS status; 00305 00306 printf("Unregistering service: " TSTR "\n", WPASVC_NAME); 00307 00308 scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE); 00309 if (!scm) { 00310 printf("OpenSCManager failed: %d\n", (int) GetLastError()); 00311 return -1; 00312 } 00313 00314 svc = OpenService(scm, WPASVC_NAME, SERVICE_ALL_ACCESS | DELETE); 00315 if (!svc) { 00316 printf("OpenService failed: %d\n\n", (int) GetLastError()); 00317 CloseServiceHandle(scm); 00318 return -1; 00319 } 00320 00321 if (QueryServiceStatus(svc, &status)) { 00322 if (status.dwCurrentState != SERVICE_STOPPED) { 00323 printf("Service currently active - stopping " 00324 "service...\n"); 00325 if (!ControlService(svc, SERVICE_CONTROL_STOP, 00326 &status)) { 00327 printf("ControlService failed: %d\n", 00328 (int) GetLastError()); 00329 } 00330 Sleep(500); 00331 } 00332 } 00333 00334 if (DeleteService(svc)) { 00335 printf("Service unregistered successfully.\n"); 00336 } else { 00337 printf("DeleteService failed: %d\n", (int) GetLastError()); 00338 } 00339 00340 CloseServiceHandle(svc); 00341 CloseServiceHandle(scm); 00342 00343 return 0; 00344 } 00345 00346 00347 static void WINAPI service_ctrl_handler(DWORD control_code) 00348 { 00349 switch (control_code) { 00350 case SERVICE_CONTROL_INTERROGATE: 00351 break; 00352 case SERVICE_CONTROL_SHUTDOWN: 00353 case SERVICE_CONTROL_STOP: 00354 svc_status.dwCurrentState = SERVICE_STOP_PENDING; 00355 svc_status.dwWaitHint = 2000; 00356 eloop_terminate(); 00357 SetEvent(kill_svc); 00358 break; 00359 } 00360 00361 if (!SetServiceStatus(svc_status_handle, &svc_status)) { 00362 printf("SetServiceStatus() failed: %d\n", 00363 (int) GetLastError()); 00364 } 00365 } 00366 00367 00368 static void WINAPI service_start(DWORD argc, LPTSTR *argv) 00369 { 00370 DWORD id; 00371 00372 svc_status_handle = RegisterServiceCtrlHandler(WPASVC_NAME, 00373 service_ctrl_handler); 00374 if (svc_status_handle == (SERVICE_STATUS_HANDLE) 0) { 00375 printf("RegisterServiceCtrlHandler failed: %d\n", 00376 (int) GetLastError()); 00377 return; 00378 } 00379 00380 os_memset(&svc_status, 0, sizeof(svc_status)); 00381 svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; 00382 svc_status.dwCurrentState = SERVICE_START_PENDING; 00383 svc_status.dwWaitHint = 1000; 00384 00385 if (!SetServiceStatus(svc_status_handle, &svc_status)) { 00386 printf("SetServiceStatus() failed: %d\n", 00387 (int) GetLastError()); 00388 return; 00389 } 00390 00391 kill_svc = CreateEvent(0, TRUE, FALSE, 0); 00392 if (!kill_svc) { 00393 printf("CreateEvent failed: %d\n", (int) GetLastError()); 00394 return; 00395 } 00396 00397 if (CreateThread(0, 0, (LPTHREAD_START_ROUTINE) svc_thread, 0, 0, &id) 00398 == 0) { 00399 printf("CreateThread failed: %d\n", (int) GetLastError()); 00400 return; 00401 } 00402 00403 if (svc_status.dwCurrentState == SERVICE_START_PENDING) { 00404 svc_status.dwCurrentState = SERVICE_RUNNING; 00405 svc_status.dwWaitHint = 0; 00406 svc_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | 00407 SERVICE_ACCEPT_SHUTDOWN; 00408 } 00409 00410 if (!SetServiceStatus(svc_status_handle, &svc_status)) { 00411 printf("SetServiceStatus() failed: %d\n", 00412 (int) GetLastError()); 00413 return; 00414 } 00415 00416 /* wait until service gets killed */ 00417 WaitForSingleObject(kill_svc, INFINITE); 00418 } 00419 00420 00421 int main(int argc, char *argv[]) 00422 { 00423 SERVICE_TABLE_ENTRY dt[] = { 00424 { WPASVC_NAME, service_start }, 00425 { NULL, NULL } 00426 }; 00427 00428 if (argc > 1) { 00429 if (os_strcmp(argv[1], "reg") == 0) { 00430 TCHAR *path; 00431 int ret; 00432 00433 if (argc < 3) { 00434 path = os_malloc(MAX_PATH * sizeof(TCHAR)); 00435 if (path == NULL) 00436 return -1; 00437 if (!GetModuleFileName(NULL, path, MAX_PATH)) { 00438 printf("GetModuleFileName failed: " 00439 "%d\n", (int) GetLastError()); 00440 os_free(path); 00441 return -1; 00442 } 00443 } else { 00444 path = wpa_strdup_tchar(argv[2]); 00445 if (path == NULL) 00446 return -1; 00447 } 00448 ret = register_service(path); 00449 os_free(path); 00450 return ret; 00451 } else if (os_strcmp(argv[1], "unreg") == 0) { 00452 return unregister_service(); 00453 } else if (os_strcmp(argv[1], "app") == 0) { 00454 return wpa_supplicant_thread(); 00455 } 00456 } 00457 00458 if (!StartServiceCtrlDispatcher(dt)) { 00459 printf("StartServiceCtrlDispatcher failed: %d\n", 00460 (int) GetLastError()); 00461 } 00462 00463 return 0; 00464 }