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