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