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