Tor  0.4.7.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-2021, 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 
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 
67 /** Struct to hold dynamically loaded NT-service related function pointers.
68  */
69 struct {
70  int loaded;
71 
72  /** @{ */
73  /** Function pointers for Windows API functions related to service
74  * management. These are NULL, or they point to the . They're set by
75  * calling the LOAD macro below. */
76 
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);
145  /** @} */
146 } service_fns = { 0,
147  NULL, NULL, NULL, NULL, NULL, NULL,
148  NULL, NULL, NULL, NULL, NULL, NULL,
149  NULL};
150 
151 /** Loads functions used by NT services. Returns on success, or prints a
152  * complaint to stdout and exits on error. */
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 
205 /** If we're compiled to run as an NT service, and the service wants to
206  * shut down, then change our current status and return 1. Else
207  * return 0.
208  */
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 
228 /** Set the dwCurrentState field for our service to <b>state</b>. */
229 void
230 nt_service_set_state(DWORD state)
231 {
232  service_status.dwCurrentState = state;
233 }
234 
235 /** Handles service control requests, such as stopping or starting the
236  * Tor service. */
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;
253  &exit_now);
254  return;
255  }
256  service_fns.SetServiceStatus_fn(hStatus, &service_status);
257 }
258 
259 /** Called when the service is started via the system's service control
260  * manager. This calls tor_init() and starts the main event loop. If
261  * tor_init() fails, the service will be stopped and exit code set to
262  * NT_SERVICE_ERROR_TORINIT_FAILED. */
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  pubsub_install();
287  r = tor_init(backup_argc, backup_argv);
288 
289  if (r) {
290  /* Failed to start the Tor service */
291  r = NT_SERVICE_ERROR_TORINIT_FAILED;
292  service_status.dwCurrentState = SERVICE_STOPPED;
293  service_status.dwWin32ExitCode = r;
294  service_status.dwServiceSpecificExitCode = r;
295  service_fns.SetServiceStatus_fn(hStatus, &service_status);
296  return;
297  }
298 
299  pubsub_connect();
300 
301  /* Set the service's status to SERVICE_RUNNING and start the main
302  * event loop */
303  service_status.dwCurrentState = SERVICE_RUNNING;
304  service_fns.SetServiceStatus_fn(hStatus, &service_status);
305  set_main_thread();
306  run_tor_main_loop();
307  tor_cleanup();
308 }
309 
310 /** Main service entry point. Starts the service control dispatcher and waits
311  * until the service status is set to SERVICE_STOPPED. */
312 static void
313 nt_service_main(void)
314 {
315  SERVICE_TABLE_ENTRYA table[2];
316  DWORD result = 0;
317  char *errmsg;
318  nt_service_loadlibrary();
319  table[0].lpServiceName = (char*)GENSRV_SERVICENAME;
320  table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTIONA)nt_service_body;
321  table[1].lpServiceName = NULL;
322  table[1].lpServiceProc = NULL;
323 
324  if (!service_fns.StartServiceCtrlDispatcherA_fn(table)) {
325  result = GetLastError();
326  errmsg = format_win32_error(result);
327  printf("Service error %d : %s\n", (int) result, errmsg);
328  tor_free(errmsg);
329 
330  pubsub_install();
331  if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
332  if (tor_init(backup_argc, backup_argv))
333  return;
334  pubsub_connect();
335  switch (get_options()->command) {
336  case CMD_RUN_TOR:
337  run_tor_main_loop();
338  break;
340  case CMD_HASH_PASSWORD:
341  case CMD_VERIFY_CONFIG:
342  case CMD_DUMP_CONFIG:
343  case CMD_KEYGEN:
344  case CMD_KEY_EXPIRATION:
345  log_err(LD_CONFIG, "Unsupported command (--list-fingerprint, "
346  "--hash-password, --keygen, --dump-config, --verify-config, "
347  "or --key-expiration) in NT service.");
348  break;
349  case CMD_RUN_UNITTESTS:
350  case CMD_IMMEDIATE:
351  default:
352  log_err(LD_CONFIG, "Illegal command number %d: internal error.",
353  get_options()->command);
354  }
355  tor_cleanup();
356  }
357  }
358 }
359 
360 /** Return a handle to the service control manager on success, or NULL on
361  * failure. */
362 static SC_HANDLE
363 nt_service_open_scm(void)
364 {
365  SC_HANDLE hSCManager;
366  char *errmsg = NULL;
367 
368  nt_service_loadlibrary();
369  if ((hSCManager = service_fns.OpenSCManagerA_fn(
370  NULL, NULL, SC_MANAGER_CREATE_SERVICE)) == NULL) {
371  errmsg = format_win32_error(GetLastError());
372  printf("OpenSCManager() failed : %s\n", errmsg);
373  tor_free(errmsg);
374  }
375  return hSCManager;
376 }
377 
378 /** Open a handle to the Tor service using <b>hSCManager</b>. Return NULL
379  * on failure. */
380 static SC_HANDLE
381 nt_service_open(SC_HANDLE hSCManager)
382 {
383  SC_HANDLE hService;
384  char *errmsg = NULL;
385  nt_service_loadlibrary();
386  if ((hService = service_fns.OpenServiceA_fn(hSCManager, GENSRV_SERVICENAME,
387  SERVICE_ALL_ACCESS)) == NULL) {
388  errmsg = format_win32_error(GetLastError());
389  printf("OpenService() failed : %s\n", errmsg);
390  tor_free(errmsg);
391  }
392  return hService;
393 }
394 
395 /** Start the Tor service. Return 0 if the service is started or was
396  * previously running. Return -1 on error. */
397 static int
398 nt_service_start(SC_HANDLE hService)
399 {
400  char *errmsg = NULL;
401 
402  nt_service_loadlibrary();
403 
404  service_fns.QueryServiceStatus_fn(hService, &service_status);
405  if (service_status.dwCurrentState == SERVICE_RUNNING) {
406  printf("Service is already running\n");
407  return 0;
408  }
409 
410  if (service_fns.StartServiceA_fn(hService, 0, NULL)) {
411  /* Loop until the service has finished attempting to start */
412  while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
413  (service_status.dwCurrentState == SERVICE_START_PENDING)) {
414  Sleep(500);
415  }
416 
417  /* Check if it started successfully or not */
418  if (service_status.dwCurrentState == SERVICE_RUNNING) {
419  printf("Service started successfully\n");
420  return 0;
421  } else {
422  errmsg = format_win32_error(service_status.dwWin32ExitCode);
423  printf("Service failed to start : %s\n", errmsg);
424  tor_free(errmsg);
425  }
426  } else {
427  errmsg = format_win32_error(GetLastError());
428  printf("StartService() failed : %s\n", errmsg);
429  tor_free(errmsg);
430  }
431  return -1;
432 }
433 
434 /** Stop the Tor service. Return 0 if the service is stopped or was not
435  * previously running. Return -1 on error. */
436 static int
437 nt_service_stop(SC_HANDLE hService)
438 {
439 /** Wait at most 10 seconds for the service to stop. */
440 #define MAX_SERVICE_WAIT_TIME 10
441  int wait_time;
442  char *errmsg = NULL;
443  nt_service_loadlibrary();
444 
445  service_fns.QueryServiceStatus_fn(hService, &service_status);
446  if (service_status.dwCurrentState == SERVICE_STOPPED) {
447  printf("Service is already stopped\n");
448  return 0;
449  }
450 
451  if (service_fns.ControlService_fn(hService, SERVICE_CONTROL_STOP,
452  &service_status)) {
453  wait_time = 0;
454  while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
455  (service_status.dwCurrentState != SERVICE_STOPPED) &&
456  (wait_time < MAX_SERVICE_WAIT_TIME)) {
457  Sleep(1000);
458  wait_time++;
459  }
460  if (service_status.dwCurrentState == SERVICE_STOPPED) {
461  printf("Service stopped successfully\n");
462  return 0;
463  } else if (wait_time == MAX_SERVICE_WAIT_TIME) {
464  printf("Service did not stop within %d seconds.\n", wait_time);
465  } else {
466  errmsg = format_win32_error(GetLastError());
467  printf("QueryServiceStatus() failed : %s\n",errmsg);
468  tor_free(errmsg);
469  }
470  } else {
471  errmsg = format_win32_error(GetLastError());
472  printf("ControlService() failed : %s\n", errmsg);
473  tor_free(errmsg);
474  }
475  return -1;
476 }
477 
478 /** Build a formatted command line used for the NT service. Return a
479  * pointer to the formatted string on success, or NULL on failure. Set
480  * *<b>using_default_torrc</b> to true if we're going to use the default
481  * location to torrc, or 1 if an option was specified on the command line.
482  */
483 static char *
484 nt_service_command_line(int *using_default_torrc)
485 {
486  TCHAR tor_exe[MAX_PATH+1];
487  char tor_exe_ascii[MAX_PATH*2+1];
488  char *command=NULL, *options=NULL;
489  smartlist_t *sl;
490  int i;
491  *using_default_torrc = 1;
492 
493  /* Get the location of tor.exe */
494  if (0 == GetModuleFileName(NULL, tor_exe, MAX_PATH))
495  return NULL;
496 
497  /* Get the service arguments */
498  sl = smartlist_new();
499  for (i = 1; i < backup_argc; ++i) {
500  if (!strcmp(backup_argv[i], "--options") ||
501  !strcmp(backup_argv[i], "-options")) {
502  while (++i < backup_argc) {
503  if (!strcmp(backup_argv[i], "-f") ||
504  !strcmp(backup_argv[i], "--torrc-file"))
505  *using_default_torrc = 0;
506  smartlist_add(sl, backup_argv[i]);
507  }
508  }
509  }
510  if (smartlist_len(sl))
511  options = smartlist_join_strings(sl,"\" \"",0,NULL);
512  smartlist_free(sl);
513 
514 #ifdef UNICODE
515  wcstombs(tor_exe_ascii, tor_exe, sizeof(tor_exe_ascii));
516  tor_exe_ascii[sizeof(tor_exe_ascii)-1] = '\0';
517 #else
518  strlcpy(tor_exe_ascii, tor_exe, sizeof(tor_exe_ascii));
519 #endif /* defined(UNICODE) */
520 
521  /* Allocate a string for the NT service command line and */
522  /* Format the service command */
523  if (options) {
524  tor_asprintf(&command, "\"%s\" --nt-service \"%s\"",
525  tor_exe_ascii, options);
526  } else { /* ! options */
527  tor_asprintf(&command, "\"%s\" --nt-service", tor_exe_ascii);
528  }
529 
530  tor_free(options);
531  return command;
532 }
533 
534 /** Creates a Tor NT service, set to start on boot. The service will be
535  * started if installation succeeds. Returns 0 on success, or -1 on
536  * failure. */
537 static int
538 nt_service_install(int argc, char **argv)
539 {
540  /* Notes about developing NT services:
541  *
542  * 1. Don't count on your CWD. If an absolute path is not given, the
543  * fopen() function goes wrong.
544  * 2. The parameters given to the nt_service_body() function differ
545  * from those given to main() function.
546  */
547 
548  SC_HANDLE hSCManager = NULL;
549  SC_HANDLE hService = NULL;
550  SERVICE_DESCRIPTIONA sdBuff;
551  char *command;
552  char *errmsg;
553  const char *user_acct = NULL;
554  const char *password = "";
555  int i;
556  OSVERSIONINFOEX info;
557  SID_NAME_USE sidUse;
558  DWORD sidLen = 0, domainLen = 0;
559  int is_win2k_or_worse = 0;
560  int using_default_torrc = 0;
561 
562  nt_service_loadlibrary();
563 
564  /* Open the service control manager so we can create a new service */
565  if ((hSCManager = nt_service_open_scm()) == NULL)
566  return -1;
567  /* Build the command line used for the service */
568  if ((command = nt_service_command_line(&using_default_torrc)) == NULL) {
569  printf("Unable to build service command line.\n");
570  service_fns.CloseServiceHandle_fn(hSCManager);
571  return -1;
572  }
573 
574  for (i=1; i < argc; ++i) {
575  if (!strcmp(argv[i], "--user") && i+1<argc) {
576  user_acct = argv[i+1];
577  ++i;
578  }
579  if (!strcmp(argv[i], "--password") && i+1<argc) {
580  password = argv[i+1];
581  ++i;
582  }
583  }
584 
585  /* Compute our version and see whether we're running win2k or earlier. */
586  memset(&info, 0, sizeof(info));
587  info.dwOSVersionInfoSize = sizeof(info);
588  if (! GetVersionEx((LPOSVERSIONINFO)&info)) {
589  printf("Call to GetVersionEx failed.\n");
590  is_win2k_or_worse = 1;
591  } else {
592  if (info.dwMajorVersion < 5 ||
593  (info.dwMajorVersion == 5 && info.dwMinorVersion == 0))
594  is_win2k_or_worse = 1;
595  }
596 
597  if (!user_acct) {
598  if (is_win2k_or_worse) {
599  /* On Win2k, there is no LocalService account, so we actually need to
600  * fall back on NULL (the system account). */
601  printf("Running on Win2K or earlier, so the LocalService account "
602  "doesn't exist. Falling back to SYSTEM account.\n");
603  } else {
604  /* Genericity is apparently _so_ last year in Redmond, where some
605  * accounts are accounts that you can look up, and some accounts
606  * are magic and undetectable via the security subsystem. See
607  * https://msdn2.microsoft.com/en-us/library/ms684188.aspx
608  */
609  printf("Running on a Post-Win2K OS, so we'll assume that the "
610  "LocalService account exists.\n");
611  user_acct = GENSRV_USERACCT;
612  }
613  } else if (0 && service_fns.LookupAccountNameA_fn(NULL, // On this system
614  user_acct,
615  NULL, &sidLen, // Don't care about the SID
616  NULL, &domainLen, // Don't care about the domain
617  &sidUse) == 0) {
618  /* XXXX For some reason, the above test segfaults. Fix that. */
619  printf("User \"%s\" doesn't seem to exist.\n", user_acct);
620  tor_free(command);
621  return -1;
622  } else {
623  printf("Will try to install service as user \"%s\".\n", user_acct);
624  }
625  /* XXXX This warning could be better about explaining how to resolve the
626  * situation. */
627  if (using_default_torrc)
628  printf("IMPORTANT NOTE:\n"
629  " The Tor service will run under the account \"%s\". This means\n"
630  " that Tor will look for its configuration file under that\n"
631  " account's Application Data directory, which is probably not\n"
632  " the same as yours.\n", user_acct?user_acct:"<local system>");
633 
634  /* Create the Tor service, set to auto-start on boot */
635  if ((hService = service_fns.CreateServiceA_fn(hSCManager, GENSRV_SERVICENAME,
636  GENSRV_DISPLAYNAME,
637  SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
638  SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
639  command, NULL, NULL, NULL,
640  user_acct, password)) == NULL) {
641  errmsg = format_win32_error(GetLastError());
642  printf("CreateService() failed : %s\n", errmsg);
643  service_fns.CloseServiceHandle_fn(hSCManager);
644  tor_free(errmsg);
645  tor_free(command);
646  return -1;
647  }
648  printf("Done with CreateService.\n");
649 
650  /* Set the service's description */
651  sdBuff.lpDescription = (char*)GENSRV_DESCRIPTION;
652  service_fns.ChangeServiceConfig2A_fn(hService, SERVICE_CONFIG_DESCRIPTION,
653  &sdBuff);
654  printf("Service installed successfully\n");
655 
656  /* Start the service initially */
657  nt_service_start(hService);
658 
659  service_fns.CloseServiceHandle_fn(hService);
660  service_fns.CloseServiceHandle_fn(hSCManager);
661  tor_free(command);
662 
663  return 0;
664 }
665 
666 /** Removes the Tor NT service. Returns 0 if the service was successfully
667  * removed, or -1 on error. */
668 static int
669 nt_service_remove(void)
670 {
671  SC_HANDLE hSCManager = NULL;
672  SC_HANDLE hService = NULL;
673  char *errmsg;
674 
675  nt_service_loadlibrary();
676  if ((hSCManager = nt_service_open_scm()) == NULL)
677  return -1;
678  if ((hService = nt_service_open(hSCManager)) == NULL) {
679  service_fns.CloseServiceHandle_fn(hSCManager);
680  return -1;
681  }
682 
683  nt_service_stop(hService);
684  if (service_fns.DeleteService_fn(hService) == FALSE) {
685  errmsg = format_win32_error(GetLastError());
686  printf("DeleteService() failed : %s\n", errmsg);
687  tor_free(errmsg);
688  service_fns.CloseServiceHandle_fn(hService);
689  service_fns.CloseServiceHandle_fn(hSCManager);
690  return -1;
691  }
692 
693  service_fns.CloseServiceHandle_fn(hService);
694  service_fns.CloseServiceHandle_fn(hSCManager);
695  printf("Service removed successfully\n");
696 
697  return 0;
698 }
699 
700 /** Starts the Tor service. Returns 0 on success, or -1 on error. */
701 static int
702 nt_service_cmd_start(void)
703 {
704  SC_HANDLE hSCManager;
705  SC_HANDLE hService;
706  int start;
707 
708  if ((hSCManager = nt_service_open_scm()) == NULL)
709  return -1;
710  if ((hService = nt_service_open(hSCManager)) == NULL) {
711  service_fns.CloseServiceHandle_fn(hSCManager);
712  return -1;
713  }
714 
715  start = nt_service_start(hService);
716  service_fns.CloseServiceHandle_fn(hService);
717  service_fns.CloseServiceHandle_fn(hSCManager);
718 
719  return start;
720 }
721 
722 /** Stops the Tor service. Returns 0 on success, or -1 on error. */
723 static int
724 nt_service_cmd_stop(void)
725 {
726  SC_HANDLE hSCManager;
727  SC_HANDLE hService;
728  int stop;
729 
730  if ((hSCManager = nt_service_open_scm()) == NULL)
731  return -1;
732  if ((hService = nt_service_open(hSCManager)) == NULL) {
733  service_fns.CloseServiceHandle_fn(hSCManager);
734  return -1;
735  }
736 
737  stop = nt_service_stop(hService);
738  service_fns.CloseServiceHandle_fn(hService);
739  service_fns.CloseServiceHandle_fn(hSCManager);
740 
741  return stop;
742 }
743 
744 int
745 nt_service_parse_options(int argc, char **argv, int *should_exit)
746 {
747  backup_argv = argv;
748  backup_argc = argc;
749  *should_exit = 0;
750 
751  if ((argc >= 3) &&
752  (!strcmp(argv[1], "-service") || !strcmp(argv[1], "--service"))) {
753  nt_service_loadlibrary();
754  *should_exit = 1;
755  if (!strcmp(argv[2], "install"))
756  return nt_service_install(argc, argv);
757  if (!strcmp(argv[2], "remove"))
758  return nt_service_remove();
759  if (!strcmp(argv[2], "start"))
760  return nt_service_cmd_start();
761  if (!strcmp(argv[2], "stop"))
762  return nt_service_cmd_stop();
763  printf("Unrecognized service command '%s'\n", argv[2]);
764  return 1;
765  }
766  if (argc >= 2) {
767  if (!strcmp(argv[1], "-nt-service") || !strcmp(argv[1], "--nt-service")) {
768  nt_service_loadlibrary();
769  nt_service_main();
770  *should_exit = 1;
771  return 0;
772  }
773  // These values have been deprecated since 0.1.1.2-alpha; we've warned
774  // about them since 0.1.2.7-alpha.
775  if (!strcmp(argv[1], "-install") || !strcmp(argv[1], "--install")) {
776  nt_service_loadlibrary();
777  fprintf(stderr,
778  "The %s option is deprecated; use \"--service install\" instead.",
779  argv[1]);
780  *should_exit = 1;
781  return nt_service_install(argc, argv);
782  }
783  if (!strcmp(argv[1], "-remove") || !strcmp(argv[1], "--remove")) {
784  nt_service_loadlibrary();
785  fprintf(stderr,
786  "The %s option is deprecated; use \"--service remove\" instead.",
787  argv[1]);
788  *should_exit = 1;
789  return nt_service_remove();
790  }
791  }
792  *should_exit = 0;
793  return 0;
794 }
795 
796 #endif /* defined(_WIN32) */
struct event_base * tor_libevent_get_base(void)
void tor_libevent_exit_loop_after_delay(struct event_base *base, const struct timeval *delay)
Header for compat_libevent.c.
void set_main_thread(void)
const or_options_t * get_options(void)
Definition: config.c:919
tor_cmdline_mode_t command
Definition: config.c:2440
Header file for config.c.
#define LD_GENERAL
Definition: log.h:62
#define LD_CONFIG
Definition: log.h:68
int tor_init(int argc, char *argv[])
Definition: main.c:537
void pubsub_install(void)
Definition: main.c:1281
void pubsub_connect(void)
Definition: main.c:1293
Header file for main.c.
Header file for mainloop.c.
#define tor_free(p)
Definition: malloc.h:52
Header file for ntmain.c.
Master header file for Tor-specific functionality.
int tor_asprintf(char **strp, const char *fmt,...)
Definition: printf.c:75
void tor_cleanup(void)
Definition: shutdown.c:58
Header file for shutdown.c.
char * smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, size_t *len_out)
Definition: smartlist.c:279
smartlist_t * smartlist_new(void)
void smartlist_add(smartlist_t *sl, void *element)
@ CMD_HASH_PASSWORD
@ CMD_LIST_FINGERPRINT
@ CMD_VERIFY_CONFIG
@ CMD_RUN_TOR
@ CMD_KEY_EXPIRATION
@ CMD_KEYGEN
@ CMD_DUMP_CONFIG
@ CMD_IMMEDIATE
@ CMD_RUN_UNITTESTS
Header for win32err.c.
Header for winlib.c.