tor  0.4.2.0-alpha-dev
ntmain.c
Go to the documentation of this file.
1 /* Copyright (c) 2001-2004, Roger Dingledine.
2  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3  * Copyright (c) 2007-2019, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
5 
20 #ifdef _WIN32
21 
22 #include "core/or/or.h"
23 
24 #include "app/config/config.h"
25 #include "app/main/main.h"
26 #include "app/main/ntmain.h"
27 #include "app/main/shutdown.h"
28 #include "core/mainloop/mainloop.h"
30 #include "lib/fs/winlib.h"
31 #include "lib/log/win32err.h"
32 
33 #include <windows.h>
34 #define GENSRV_SERVICENAME "tor"
35 #define GENSRV_DISPLAYNAME "Tor Win32 Service"
36 #define GENSRV_DESCRIPTION \
37  "Provides an anonymous Internet communication system"
38 #define GENSRV_USERACCT "NT AUTHORITY\\LocalService"
39 
40 // Cheating: using the pre-defined error codes, tricks Windows into displaying
41 // a semi-related human-readable error message if startup fails as
42 // opposed to simply scaring people with Error: 0xffffffff
43 #define NT_SERVICE_ERROR_TORINIT_FAILED ERROR_EXCEPTION_IN_SERVICE
44 
45 static SERVICE_STATUS service_status;
46 static SERVICE_STATUS_HANDLE hStatus;
47 
48 /* XXXX This 'backup argv' and 'backup argc' business is an ugly hack. This
49  * is a job for arguments, not globals. Alas, some of the functions that
50  * use them use them need to have fixed signatures, so they can be passed
51  * to the NT service functions. */
52 static char **backup_argv;
53 static int backup_argc;
54 
55 static void nt_service_control(DWORD request);
56 static void nt_service_body(int argc, char **argv);
57 static void nt_service_main(void);
58 static SC_HANDLE nt_service_open_scm(void);
59 static SC_HANDLE nt_service_open(SC_HANDLE hSCManager);
60 static int nt_service_start(SC_HANDLE hService);
61 static int nt_service_stop(SC_HANDLE hService);
62 static int nt_service_install(int argc, char **argv);
63 static int nt_service_remove(void);
64 static int nt_service_cmd_start(void);
65 static int nt_service_cmd_stop(void);
66 
69 struct service_fns {
70  int loaded;
71 
77  BOOL (WINAPI *ChangeServiceConfig2A_fn)(
78  SC_HANDLE hService,
79  DWORD dwInfoLevel,
80  LPVOID lpInfo);
81 
82  BOOL (WINAPI *CloseServiceHandle_fn)(
83  SC_HANDLE hSCObject);
84 
85  BOOL (WINAPI *ControlService_fn)(
86  SC_HANDLE hService,
87  DWORD dwControl,
88  LPSERVICE_STATUS lpServiceStatus);
89 
90  SC_HANDLE (WINAPI *CreateServiceA_fn)(
91  SC_HANDLE hSCManager,
92  LPCSTR lpServiceName,
93  LPCSTR lpDisplayName,
94  DWORD dwDesiredAccess,
95  DWORD dwServiceType,
96  DWORD dwStartType,
97  DWORD dwErrorControl,
98  LPCSTR lpBinaryPathName,
99  LPCSTR lpLoadOrderGroup,
100  LPDWORD lpdwTagId,
101  LPCSTR lpDependencies,
102  LPCSTR lpServiceStartName,
103  LPCSTR lpPassword);
104 
105  BOOL (WINAPI *DeleteService_fn)(
106  SC_HANDLE hService);
107 
108  SC_HANDLE (WINAPI *OpenSCManagerA_fn)(
109  LPCSTR lpMachineName,
110  LPCSTR lpDatabaseName,
111  DWORD dwDesiredAccess);
112 
113  SC_HANDLE (WINAPI *OpenServiceA_fn)(
114  SC_HANDLE hSCManager,
115  LPCSTR lpServiceName,
116  DWORD dwDesiredAccess);
117 
118  BOOL (WINAPI *QueryServiceStatus_fn)(
119  SC_HANDLE hService,
120  LPSERVICE_STATUS lpServiceStatus);
121 
122  SERVICE_STATUS_HANDLE (WINAPI *RegisterServiceCtrlHandlerA_fn)(
123  LPCSTR lpServiceName,
124  LPHANDLER_FUNCTION lpHandlerProc);
125 
126  BOOL (WINAPI *SetServiceStatus_fn)(SERVICE_STATUS_HANDLE,
127  LPSERVICE_STATUS);
128 
129  BOOL (WINAPI *StartServiceCtrlDispatcherA_fn)(
130  const SERVICE_TABLE_ENTRYA* lpServiceTable);
131 
132  BOOL (WINAPI *StartServiceA_fn)(
133  SC_HANDLE hService,
134  DWORD dwNumServiceArgs,
135  LPCSTR* lpServiceArgVectors);
136 
137  BOOL (WINAPI *LookupAccountNameA_fn)(
138  LPCSTR lpSystemName,
139  LPCSTR lpAccountName,
140  PSID Sid,
141  LPDWORD cbSid,
142  LPTSTR ReferencedDomainName,
143  LPDWORD cchReferencedDomainName,
144  PSID_NAME_USE peUse);
146 } service_fns = { 0,
147  NULL, NULL, NULL, NULL, NULL, NULL,
148  NULL, NULL, NULL, NULL, NULL, NULL,
149  NULL};
150 
153 static void
154 nt_service_loadlibrary(void)
155 {
156  HMODULE library = 0;
157  void *fn;
158 
159  if (service_fns.loaded)
160  return;
161 
162  if (!(library = load_windows_system_library(TEXT("advapi32.dll")))) {
163  log_err(LD_GENERAL, "Couldn't open advapi32.dll. Are you trying to use "
164  "NT services on Windows 98? That doesn't work.");
165  goto err;
166  }
167 
168 /* Helper macro: try to load a function named <b>f</b> from "library" into
169  * service_functions.<b>f</b>_fn. On failure, log an error message, and goto
170  * err.
171  */
172 #define LOAD(f) STMT_BEGIN \
173  if (!(fn = GetProcAddress(library, #f))) { \
174  log_err(LD_BUG, \
175  "Couldn't find %s in advapi32.dll! We probably got the " \
176  "name wrong.", #f); \
177  goto err; \
178  } else { \
179  service_fns.f ## _fn = fn; \
180  } \
181  STMT_END
182 
183  LOAD(ChangeServiceConfig2A);
184  LOAD(CloseServiceHandle);
185  LOAD(ControlService);
186  LOAD(CreateServiceA);
187  LOAD(DeleteService);
188  LOAD(OpenSCManagerA);
189  LOAD(OpenServiceA);
190  LOAD(QueryServiceStatus);
191  LOAD(RegisterServiceCtrlHandlerA);
192  LOAD(SetServiceStatus);
193  LOAD(StartServiceCtrlDispatcherA);
194  LOAD(StartServiceA);
195  LOAD(LookupAccountNameA);
196 
197  service_fns.loaded = 1;
198 
199  return;
200  err:
201  printf("Unable to load library support for NT services: exiting.\n");
202  exit(1); // exit ok: ntmain can't read libraries
203 }
204 
209 int
210 nt_service_is_stopping(void)
211 {
212  /* If we haven't loaded the function pointers, we can't possibly be an NT
213  * service trying to shut down. */
214  if (!service_fns.loaded)
215  return 0;
216 
217  if (service_status.dwCurrentState == SERVICE_STOP_PENDING) {
218  service_status.dwWin32ExitCode = 0;
219  service_status.dwCurrentState = SERVICE_STOPPED;
220  service_fns.SetServiceStatus_fn(hStatus, &service_status);
221  return 1;
222  } else if (service_status.dwCurrentState == SERVICE_STOPPED) {
223  return 1;
224  }
225  return 0;
226 }
227 
229 void
230 nt_service_set_state(DWORD state)
231 {
232  service_status.dwCurrentState = state;
233 }
234 
237 static void
238 nt_service_control(DWORD request)
239 {
240  static struct timeval exit_now;
241  exit_now.tv_sec = 0;
242  exit_now.tv_usec = 0;
243 
244  nt_service_loadlibrary();
245 
246  switch (request) {
247  case SERVICE_CONTROL_STOP:
248  case SERVICE_CONTROL_SHUTDOWN:
249  log_notice(LD_GENERAL,
250  "Got stop/shutdown request; shutting down cleanly.");
251  service_status.dwCurrentState = SERVICE_STOP_PENDING;
252  tor_libevent_exit_loop_after_delay(tor_libevent_get_base(),
253  &exit_now);
254  return;
255  }
256  service_fns.SetServiceStatus_fn(hStatus, &service_status);
257 }
258 
263 static void
264 nt_service_body(int argc, char **argv)
265 {
266  int r;
267  (void) argc; /* unused */
268  (void) argv; /* unused */
269  nt_service_loadlibrary();
270  service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
271  service_status.dwCurrentState = SERVICE_START_PENDING;
272  service_status.dwControlsAccepted =
273  SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
274  service_status.dwWin32ExitCode = 0;
275  service_status.dwServiceSpecificExitCode = 0;
276  service_status.dwCheckPoint = 0;
277  service_status.dwWaitHint = 1000;
278  hStatus = service_fns.RegisterServiceCtrlHandlerA_fn(GENSRV_SERVICENAME,
279  (LPHANDLER_FUNCTION) nt_service_control);
280 
281  if (hStatus == 0) {
282  /* Failed to register the service control handler function */
283  return;
284  }
285 
286  r = tor_init(backup_argc, backup_argv);
287  if (r) {
288  /* Failed to start the Tor service */
289  r = NT_SERVICE_ERROR_TORINIT_FAILED;
290  service_status.dwCurrentState = SERVICE_STOPPED;
291  service_status.dwWin32ExitCode = r;
292  service_status.dwServiceSpecificExitCode = r;
293  service_fns.SetServiceStatus_fn(hStatus, &service_status);
294  return;
295  }
296 
297  /* Set the service's status to SERVICE_RUNNING and start the main
298  * event loop */
299  service_status.dwCurrentState = SERVICE_RUNNING;
300  service_fns.SetServiceStatus_fn(hStatus, &service_status);
301  set_main_thread();
302  run_tor_main_loop();
303  tor_cleanup();
304 }
305 
308 static void
309 nt_service_main(void)
310 {
311  SERVICE_TABLE_ENTRYA table[2];
312  DWORD result = 0;
313  char *errmsg;
314  nt_service_loadlibrary();
315  table[0].lpServiceName = (char*)GENSRV_SERVICENAME;
316  table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTIONA)nt_service_body;
317  table[1].lpServiceName = NULL;
318  table[1].lpServiceProc = NULL;
319 
320  if (!service_fns.StartServiceCtrlDispatcherA_fn(table)) {
321  result = GetLastError();
322  errmsg = format_win32_error(result);
323  printf("Service error %d : %s\n", (int) result, errmsg);
324  tor_free(errmsg);
325  if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
326  if (tor_init(backup_argc, backup_argv))
327  return;
328  switch (get_options()->command) {
329  case CMD_RUN_TOR:
330  run_tor_main_loop();
331  break;
332  case CMD_LIST_FINGERPRINT:
333  case CMD_HASH_PASSWORD:
334  case CMD_VERIFY_CONFIG:
335  case CMD_DUMP_CONFIG:
336  case CMD_KEYGEN:
337  case CMD_KEY_EXPIRATION:
338  log_err(LD_CONFIG, "Unsupported command (--list-fingerprint, "
339  "--hash-password, --keygen, --dump-config, --verify-config, "
340  "or --key-expiration) in NT service.");
341  break;
342  case CMD_RUN_UNITTESTS:
343  default:
344  log_err(LD_CONFIG, "Illegal command number %d: internal error.",
345  get_options()->command);
346  }
347  tor_cleanup();
348  }
349  }
350 }
351 
354 static SC_HANDLE
355 nt_service_open_scm(void)
356 {
357  SC_HANDLE hSCManager;
358  char *errmsg = NULL;
359 
360  nt_service_loadlibrary();
361  if ((hSCManager = service_fns.OpenSCManagerA_fn(
362  NULL, NULL, SC_MANAGER_CREATE_SERVICE)) == NULL) {
363  errmsg = format_win32_error(GetLastError());
364  printf("OpenSCManager() failed : %s\n", errmsg);
365  tor_free(errmsg);
366  }
367  return hSCManager;
368 }
369 
372 static SC_HANDLE
373 nt_service_open(SC_HANDLE hSCManager)
374 {
375  SC_HANDLE hService;
376  char *errmsg = NULL;
377  nt_service_loadlibrary();
378  if ((hService = service_fns.OpenServiceA_fn(hSCManager, GENSRV_SERVICENAME,
379  SERVICE_ALL_ACCESS)) == NULL) {
380  errmsg = format_win32_error(GetLastError());
381  printf("OpenService() failed : %s\n", errmsg);
382  tor_free(errmsg);
383  }
384  return hService;
385 }
386 
389 static int
390 nt_service_start(SC_HANDLE hService)
391 {
392  char *errmsg = NULL;
393 
394  nt_service_loadlibrary();
395 
396  service_fns.QueryServiceStatus_fn(hService, &service_status);
397  if (service_status.dwCurrentState == SERVICE_RUNNING) {
398  printf("Service is already running\n");
399  return 0;
400  }
401 
402  if (service_fns.StartServiceA_fn(hService, 0, NULL)) {
403  /* Loop until the service has finished attempting to start */
404  while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
405  (service_status.dwCurrentState == SERVICE_START_PENDING)) {
406  Sleep(500);
407  }
408 
409  /* Check if it started successfully or not */
410  if (service_status.dwCurrentState == SERVICE_RUNNING) {
411  printf("Service started successfully\n");
412  return 0;
413  } else {
414  errmsg = format_win32_error(service_status.dwWin32ExitCode);
415  printf("Service failed to start : %s\n", errmsg);
416  tor_free(errmsg);
417  }
418  } else {
419  errmsg = format_win32_error(GetLastError());
420  printf("StartService() failed : %s\n", errmsg);
421  tor_free(errmsg);
422  }
423  return -1;
424 }
425 
428 static int
429 nt_service_stop(SC_HANDLE hService)
430 {
432 #define MAX_SERVICE_WAIT_TIME 10
433  int wait_time;
434  char *errmsg = NULL;
435  nt_service_loadlibrary();
436 
437  service_fns.QueryServiceStatus_fn(hService, &service_status);
438  if (service_status.dwCurrentState == SERVICE_STOPPED) {
439  printf("Service is already stopped\n");
440  return 0;
441  }
442 
443  if (service_fns.ControlService_fn(hService, SERVICE_CONTROL_STOP,
444  &service_status)) {
445  wait_time = 0;
446  while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
447  (service_status.dwCurrentState != SERVICE_STOPPED) &&
448  (wait_time < MAX_SERVICE_WAIT_TIME)) {
449  Sleep(1000);
450  wait_time++;
451  }
452  if (service_status.dwCurrentState == SERVICE_STOPPED) {
453  printf("Service stopped successfully\n");
454  return 0;
455  } else if (wait_time == MAX_SERVICE_WAIT_TIME) {
456  printf("Service did not stop within %d seconds.\n", wait_time);
457  } else {
458  errmsg = format_win32_error(GetLastError());
459  printf("QueryServiceStatus() failed : %s\n",errmsg);
460  tor_free(errmsg);
461  }
462  } else {
463  errmsg = format_win32_error(GetLastError());
464  printf("ControlService() failed : %s\n", errmsg);
465  tor_free(errmsg);
466  }
467  return -1;
468 }
469 
475 static char *
476 nt_service_command_line(int *using_default_torrc)
477 {
478  TCHAR tor_exe[MAX_PATH+1];
479  char tor_exe_ascii[MAX_PATH*2+1];
480  char *command=NULL, *options=NULL;
481  smartlist_t *sl;
482  int i;
483  *using_default_torrc = 1;
484 
485  /* Get the location of tor.exe */
486  if (0 == GetModuleFileName(NULL, tor_exe, MAX_PATH))
487  return NULL;
488 
489  /* Get the service arguments */
490  sl = smartlist_new();
491  for (i = 1; i < backup_argc; ++i) {
492  if (!strcmp(backup_argv[i], "--options") ||
493  !strcmp(backup_argv[i], "-options")) {
494  while (++i < backup_argc) {
495  if (!strcmp(backup_argv[i], "-f"))
496  *using_default_torrc = 0;
497  smartlist_add(sl, backup_argv[i]);
498  }
499  }
500  }
501  if (smartlist_len(sl))
502  options = smartlist_join_strings(sl,"\" \"",0,NULL);
503  smartlist_free(sl);
504 
505 #ifdef UNICODE
506  wcstombs(tor_exe_ascii, tor_exe, sizeof(tor_exe_ascii));
507  tor_exe_ascii[sizeof(tor_exe_ascii)-1] = '\0';
508 #else
509  strlcpy(tor_exe_ascii, tor_exe, sizeof(tor_exe_ascii));
510 #endif /* defined(UNICODE) */
511 
512  /* Allocate a string for the NT service command line and */
513  /* Format the service command */
514  if (options) {
515  tor_asprintf(&command, "\"%s\" --nt-service \"%s\"",
516  tor_exe_ascii, options);
517  } else { /* ! options */
518  tor_asprintf(&command, "\"%s\" --nt-service", tor_exe_ascii);
519  }
520 
521  tor_free(options);
522  return command;
523 }
524 
528 static int
529 nt_service_install(int argc, char **argv)
530 {
531  /* Notes about developing NT services:
532  *
533  * 1. Don't count on your CWD. If an absolute path is not given, the
534  * fopen() function goes wrong.
535  * 2. The parameters given to the nt_service_body() function differ
536  * from those given to main() function.
537  */
538 
539  SC_HANDLE hSCManager = NULL;
540  SC_HANDLE hService = NULL;
541  SERVICE_DESCRIPTIONA sdBuff;
542  char *command;
543  char *errmsg;
544  const char *user_acct = NULL;
545  const char *password = "";
546  int i;
547  OSVERSIONINFOEX info;
548  SID_NAME_USE sidUse;
549  DWORD sidLen = 0, domainLen = 0;
550  int is_win2k_or_worse = 0;
551  int using_default_torrc = 0;
552 
553  nt_service_loadlibrary();
554 
555  /* Open the service control manager so we can create a new service */
556  if ((hSCManager = nt_service_open_scm()) == NULL)
557  return -1;
558  /* Build the command line used for the service */
559  if ((command = nt_service_command_line(&using_default_torrc)) == NULL) {
560  printf("Unable to build service command line.\n");
561  service_fns.CloseServiceHandle_fn(hSCManager);
562  return -1;
563  }
564 
565  for (i=1; i < argc; ++i) {
566  if (!strcmp(argv[i], "--user") && i+1<argc) {
567  user_acct = argv[i+1];
568  ++i;
569  }
570  if (!strcmp(argv[i], "--password") && i+1<argc) {
571  password = argv[i+1];
572  ++i;
573  }
574  }
575 
576  /* Compute our version and see whether we're running win2k or earlier. */
577  memset(&info, 0, sizeof(info));
578  info.dwOSVersionInfoSize = sizeof(info);
579  if (! GetVersionEx((LPOSVERSIONINFO)&info)) {
580  printf("Call to GetVersionEx failed.\n");
581  is_win2k_or_worse = 1;
582  } else {
583  if (info.dwMajorVersion < 5 ||
584  (info.dwMajorVersion == 5 && info.dwMinorVersion == 0))
585  is_win2k_or_worse = 1;
586  }
587 
588  if (!user_acct) {
589  if (is_win2k_or_worse) {
590  /* On Win2k, there is no LocalService account, so we actually need to
591  * fall back on NULL (the system account). */
592  printf("Running on Win2K or earlier, so the LocalService account "
593  "doesn't exist. Falling back to SYSTEM account.\n");
594  } else {
595  /* Genericity is apparently _so_ last year in Redmond, where some
596  * accounts are accounts that you can look up, and some accounts
597  * are magic and undetectable via the security subsystem. See
598  * http://msdn2.microsoft.com/en-us/library/ms684188.aspx
599  */
600  printf("Running on a Post-Win2K OS, so we'll assume that the "
601  "LocalService account exists.\n");
602  user_acct = GENSRV_USERACCT;
603  }
604  } else if (0 && service_fns.LookupAccountNameA_fn(NULL, // On this system
605  user_acct,
606  NULL, &sidLen, // Don't care about the SID
607  NULL, &domainLen, // Don't care about the domain
608  &sidUse) == 0) {
609  /* XXXX For some reason, the above test segfaults. Fix that. */
610  printf("User \"%s\" doesn't seem to exist.\n", user_acct);
611  tor_free(command);
612  return -1;
613  } else {
614  printf("Will try to install service as user \"%s\".\n", user_acct);
615  }
616  /* XXXX This warning could be better about explaining how to resolve the
617  * situation. */
618  if (using_default_torrc)
619  printf("IMPORTANT NOTE:\n"
620  " The Tor service will run under the account \"%s\". This means\n"
621  " that Tor will look for its configuration file under that\n"
622  " account's Application Data directory, which is probably not\n"
623  " the same as yours.\n", user_acct?user_acct:"<local system>");
624 
625  /* Create the Tor service, set to auto-start on boot */
626  if ((hService = service_fns.CreateServiceA_fn(hSCManager, GENSRV_SERVICENAME,
627  GENSRV_DISPLAYNAME,
628  SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
629  SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
630  command, NULL, NULL, NULL,
631  user_acct, password)) == NULL) {
632  errmsg = format_win32_error(GetLastError());
633  printf("CreateService() failed : %s\n", errmsg);
634  service_fns.CloseServiceHandle_fn(hSCManager);
635  tor_free(errmsg);
636  tor_free(command);
637  return -1;
638  }
639  printf("Done with CreateService.\n");
640 
641  /* Set the service's description */
642  sdBuff.lpDescription = (char*)GENSRV_DESCRIPTION;
643  service_fns.ChangeServiceConfig2A_fn(hService, SERVICE_CONFIG_DESCRIPTION,
644  &sdBuff);
645  printf("Service installed successfully\n");
646 
647  /* Start the service initially */
648  nt_service_start(hService);
649 
650  service_fns.CloseServiceHandle_fn(hService);
651  service_fns.CloseServiceHandle_fn(hSCManager);
652  tor_free(command);
653 
654  return 0;
655 }
656 
659 static int
660 nt_service_remove(void)
661 {
662  SC_HANDLE hSCManager = NULL;
663  SC_HANDLE hService = NULL;
664  char *errmsg;
665 
666  nt_service_loadlibrary();
667  if ((hSCManager = nt_service_open_scm()) == NULL)
668  return -1;
669  if ((hService = nt_service_open(hSCManager)) == NULL) {
670  service_fns.CloseServiceHandle_fn(hSCManager);
671  return -1;
672  }
673 
674  nt_service_stop(hService);
675  if (service_fns.DeleteService_fn(hService) == FALSE) {
676  errmsg = format_win32_error(GetLastError());
677  printf("DeleteService() failed : %s\n", errmsg);
678  tor_free(errmsg);
679  service_fns.CloseServiceHandle_fn(hService);
680  service_fns.CloseServiceHandle_fn(hSCManager);
681  return -1;
682  }
683 
684  service_fns.CloseServiceHandle_fn(hService);
685  service_fns.CloseServiceHandle_fn(hSCManager);
686  printf("Service removed successfully\n");
687 
688  return 0;
689 }
690 
692 static int
693 nt_service_cmd_start(void)
694 {
695  SC_HANDLE hSCManager;
696  SC_HANDLE hService;
697  int start;
698 
699  if ((hSCManager = nt_service_open_scm()) == NULL)
700  return -1;
701  if ((hService = nt_service_open(hSCManager)) == NULL) {
702  service_fns.CloseServiceHandle_fn(hSCManager);
703  return -1;
704  }
705 
706  start = nt_service_start(hService);
707  service_fns.CloseServiceHandle_fn(hService);
708  service_fns.CloseServiceHandle_fn(hSCManager);
709 
710  return start;
711 }
712 
714 static int
715 nt_service_cmd_stop(void)
716 {
717  SC_HANDLE hSCManager;
718  SC_HANDLE hService;
719  int stop;
720 
721  if ((hSCManager = nt_service_open_scm()) == NULL)
722  return -1;
723  if ((hService = nt_service_open(hSCManager)) == NULL) {
724  service_fns.CloseServiceHandle_fn(hSCManager);
725  return -1;
726  }
727 
728  stop = nt_service_stop(hService);
729  service_fns.CloseServiceHandle_fn(hService);
730  service_fns.CloseServiceHandle_fn(hSCManager);
731 
732  return stop;
733 }
734 
735 int
736 nt_service_parse_options(int argc, char **argv, int *should_exit)
737 {
738  backup_argv = argv;
739  backup_argc = argc;
740  *should_exit = 0;
741 
742  if ((argc >= 3) &&
743  (!strcmp(argv[1], "-service") || !strcmp(argv[1], "--service"))) {
744  nt_service_loadlibrary();
745  *should_exit = 1;
746  if (!strcmp(argv[2], "install"))
747  return nt_service_install(argc, argv);
748  if (!strcmp(argv[2], "remove"))
749  return nt_service_remove();
750  if (!strcmp(argv[2], "start"))
751  return nt_service_cmd_start();
752  if (!strcmp(argv[2], "stop"))
753  return nt_service_cmd_stop();
754  printf("Unrecognized service command '%s'\n", argv[2]);
755  return 1;
756  }
757  if (argc >= 2) {
758  if (!strcmp(argv[1], "-nt-service") || !strcmp(argv[1], "--nt-service")) {
759  nt_service_loadlibrary();
760  nt_service_main();
761  *should_exit = 1;
762  return 0;
763  }
764  // These values have been deprecated since 0.1.1.2-alpha; we've warned
765  // about them since 0.1.2.7-alpha.
766  if (!strcmp(argv[1], "-install") || !strcmp(argv[1], "--install")) {
767  nt_service_loadlibrary();
768  fprintf(stderr,
769  "The %s option is deprecated; use \"--service install\" instead.",
770  argv[1]);
771  *should_exit = 1;
772  return nt_service_install(argc, argv);
773  }
774  if (!strcmp(argv[1], "-remove") || !strcmp(argv[1], "--remove")) {
775  nt_service_loadlibrary();
776  fprintf(stderr,
777  "The %s option is deprecated; use \"--service remove\" instead.",
778  argv[1]);
779  *should_exit = 1;
780  return nt_service_remove();
781  }
782  }
783  *should_exit = 0;
784  return 0;
785 }
786 
787 #endif /* defined(_WIN32) */
void tor_cleanup(void)
Definition: shutdown.c:59
Header for win32err.c.
#define LD_GENERAL
Definition: log.h:60
Header file for shutdown.c.
Header file for ntmain.c.
void smartlist_add(smartlist_t *sl, void *element)
Header file for config.c.
#define tor_free(p)
Definition: malloc.h:52
Header file for mainloop.c.
Header file for main.c.
void tor_libevent_exit_loop_after_delay(struct event_base *base, const struct timeval *delay)
int tor_asprintf(char **strp, const char *fmt,...)
Definition: printf.c:75
Master header file for Tor-specific functionality.
void set_main_thread(void)
int tor_init(int argc, char *argv[])
Definition: main.c:528
char * smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, size_t *len_out)
Definition: smartlist.c:279
Header for compat_libevent.c.
Header for winlib.c.
#define LD_CONFIG
Definition: log.h:66