Tor 0.4.9.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"
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
45static SERVICE_STATUS service_status;
46static 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. */
52static char **backup_argv;
53static int backup_argc;
54
55static void nt_service_control(DWORD request);
56static void nt_service_body(int argc, char **argv);
57static void nt_service_main(void);
58static SC_HANDLE nt_service_open_scm(void);
59static SC_HANDLE nt_service_open(SC_HANDLE hSCManager);
60static int nt_service_start(SC_HANDLE hService);
61static int nt_service_stop(SC_HANDLE hService);
62static int nt_service_install(int argc, char **argv);
63static int nt_service_remove(void);
64static int nt_service_cmd_start(void);
65static int nt_service_cmd_stop(void);
66
67/** Struct to hold dynamically loaded NT-service related function pointers.
68 */
69struct {
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. */
153static void
154nt_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 */
209int
210nt_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>. */
229void
230nt_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. */
237static void
238nt_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. */
263static void
264nt_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
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
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);
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. */
312static void
313nt_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
331 if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
332 if (tor_init(backup_argc, backup_argv))
333 return;
335 switch (get_options()->command) {
336 case CMD_RUN_TOR:
337 run_tor_main_loop();
338 break;
342 case CMD_DUMP_CONFIG:
343 case CMD_KEYGEN:
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;
350 case CMD_IMMEDIATE:
351 default:
352 log_err(LD_CONFIG, "Illegal command number %d: internal error.",
354 }
355 tor_cleanup();
356 }
357 }
358}
359
360/** Return a handle to the service control manager on success, or NULL on
361 * failure. */
362static SC_HANDLE
363nt_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. */
380static SC_HANDLE
381nt_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. */
397static int
398nt_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. */
436static int
437nt_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 */
483static char *
484nt_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. */
537static int
538nt_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);
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);
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);
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. */
668static int
669nt_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. */
701static int
702nt_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. */
723static int
724nt_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
744int
745nt_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) */
void tor_libevent_exit_loop_after_delay(struct event_base *base, const struct timeval *delay)
struct event_base * tor_libevent_get_base(void)
Header for compat_libevent.c.
void set_main_thread(void)
const or_options_t * get_options(void)
Definition: config.c:944
tor_cmdline_mode_t command
Definition: config.c:2468
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:533
void pubsub_install(void)
Definition: main.c:1283
void pubsub_connect(void)
Definition: main.c:1295
Header file for main.c.
Header file for mainloop.c.
#define tor_free(p)
Definition: malloc.h:56
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:59
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.