Tor 0.4.9.2-alpha-dev
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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:
346 log_err(LD_CONFIG, "Unsupported command (--list-fingerprint, "
347 "--hash-password, --keygen, --dump-config, --verify-config, "
348 "or --key-expiration) in NT service.");
349 break;
351 case CMD_IMMEDIATE:
352 default:
353 log_err(LD_CONFIG, "Illegal command number %d: internal error.",
355 }
356 tor_cleanup();
357 }
358 }
359}
360
361/** Return a handle to the service control manager on success, or NULL on
362 * failure. */
363static SC_HANDLE
364nt_service_open_scm(void)
365{
366 SC_HANDLE hSCManager;
367 char *errmsg = NULL;
368
369 nt_service_loadlibrary();
370 if ((hSCManager = service_fns.OpenSCManagerA_fn(
371 NULL, NULL, SC_MANAGER_CREATE_SERVICE)) == NULL) {
372 errmsg = format_win32_error(GetLastError());
373 printf("OpenSCManager() failed : %s\n", errmsg);
374 tor_free(errmsg);
375 }
376 return hSCManager;
377}
378
379/** Open a handle to the Tor service using <b>hSCManager</b>. Return NULL
380 * on failure. */
381static SC_HANDLE
382nt_service_open(SC_HANDLE hSCManager)
383{
384 SC_HANDLE hService;
385 char *errmsg = NULL;
386 nt_service_loadlibrary();
387 if ((hService = service_fns.OpenServiceA_fn(hSCManager, GENSRV_SERVICENAME,
388 SERVICE_ALL_ACCESS)) == NULL) {
389 errmsg = format_win32_error(GetLastError());
390 printf("OpenService() failed : %s\n", errmsg);
391 tor_free(errmsg);
392 }
393 return hService;
394}
395
396/** Start the Tor service. Return 0 if the service is started or was
397 * previously running. Return -1 on error. */
398static int
399nt_service_start(SC_HANDLE hService)
400{
401 char *errmsg = NULL;
402
403 nt_service_loadlibrary();
404
405 service_fns.QueryServiceStatus_fn(hService, &service_status);
406 if (service_status.dwCurrentState == SERVICE_RUNNING) {
407 printf("Service is already running\n");
408 return 0;
409 }
410
411 if (service_fns.StartServiceA_fn(hService, 0, NULL)) {
412 /* Loop until the service has finished attempting to start */
413 while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
414 (service_status.dwCurrentState == SERVICE_START_PENDING)) {
415 Sleep(500);
416 }
417
418 /* Check if it started successfully or not */
419 if (service_status.dwCurrentState == SERVICE_RUNNING) {
420 printf("Service started successfully\n");
421 return 0;
422 } else {
423 errmsg = format_win32_error(service_status.dwWin32ExitCode);
424 printf("Service failed to start : %s\n", errmsg);
425 tor_free(errmsg);
426 }
427 } else {
428 errmsg = format_win32_error(GetLastError());
429 printf("StartService() failed : %s\n", errmsg);
430 tor_free(errmsg);
431 }
432 return -1;
433}
434
435/** Stop the Tor service. Return 0 if the service is stopped or was not
436 * previously running. Return -1 on error. */
437static int
438nt_service_stop(SC_HANDLE hService)
439{
440/** Wait at most 10 seconds for the service to stop. */
441#define MAX_SERVICE_WAIT_TIME 10
442 int wait_time;
443 char *errmsg = NULL;
444 nt_service_loadlibrary();
445
446 service_fns.QueryServiceStatus_fn(hService, &service_status);
447 if (service_status.dwCurrentState == SERVICE_STOPPED) {
448 printf("Service is already stopped\n");
449 return 0;
450 }
451
452 if (service_fns.ControlService_fn(hService, SERVICE_CONTROL_STOP,
453 &service_status)) {
454 wait_time = 0;
455 while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
456 (service_status.dwCurrentState != SERVICE_STOPPED) &&
457 (wait_time < MAX_SERVICE_WAIT_TIME)) {
458 Sleep(1000);
459 wait_time++;
460 }
461 if (service_status.dwCurrentState == SERVICE_STOPPED) {
462 printf("Service stopped successfully\n");
463 return 0;
464 } else if (wait_time == MAX_SERVICE_WAIT_TIME) {
465 printf("Service did not stop within %d seconds.\n", wait_time);
466 } else {
467 errmsg = format_win32_error(GetLastError());
468 printf("QueryServiceStatus() failed : %s\n",errmsg);
469 tor_free(errmsg);
470 }
471 } else {
472 errmsg = format_win32_error(GetLastError());
473 printf("ControlService() failed : %s\n", errmsg);
474 tor_free(errmsg);
475 }
476 return -1;
477}
478
479/** Build a formatted command line used for the NT service. Return a
480 * pointer to the formatted string on success, or NULL on failure. Set
481 * *<b>using_default_torrc</b> to true if we're going to use the default
482 * location to torrc, or 1 if an option was specified on the command line.
483 */
484static char *
485nt_service_command_line(int *using_default_torrc)
486{
487 TCHAR tor_exe[MAX_PATH+1];
488 char tor_exe_ascii[MAX_PATH*2+1];
489 char *command=NULL, *options=NULL;
490 smartlist_t *sl;
491 int i;
492 *using_default_torrc = 1;
493
494 /* Get the location of tor.exe */
495 if (0 == GetModuleFileName(NULL, tor_exe, MAX_PATH))
496 return NULL;
497
498 /* Get the service arguments */
499 sl = smartlist_new();
500 for (i = 1; i < backup_argc; ++i) {
501 if (!strcmp(backup_argv[i], "--options") ||
502 !strcmp(backup_argv[i], "-options")) {
503 while (++i < backup_argc) {
504 if (!strcmp(backup_argv[i], "-f") ||
505 !strcmp(backup_argv[i], "--torrc-file"))
506 *using_default_torrc = 0;
507 smartlist_add(sl, backup_argv[i]);
508 }
509 }
510 }
511 if (smartlist_len(sl))
512 options = smartlist_join_strings(sl,"\" \"",0,NULL);
513 smartlist_free(sl);
514
515#ifdef UNICODE
516 wcstombs(tor_exe_ascii, tor_exe, sizeof(tor_exe_ascii));
517 tor_exe_ascii[sizeof(tor_exe_ascii)-1] = '\0';
518#else
519 strlcpy(tor_exe_ascii, tor_exe, sizeof(tor_exe_ascii));
520#endif /* defined(UNICODE) */
521
522 /* Allocate a string for the NT service command line and */
523 /* Format the service command */
524 if (options) {
525 tor_asprintf(&command, "\"%s\" --nt-service \"%s\"",
526 tor_exe_ascii, options);
527 } else { /* ! options */
528 tor_asprintf(&command, "\"%s\" --nt-service", tor_exe_ascii);
529 }
530
531 tor_free(options);
532 return command;
533}
534
535/** Creates a Tor NT service, set to start on boot. The service will be
536 * started if installation succeeds. Returns 0 on success, or -1 on
537 * failure. */
538static int
539nt_service_install(int argc, char **argv)
540{
541 /* Notes about developing NT services:
542 *
543 * 1. Don't count on your CWD. If an absolute path is not given, the
544 * fopen() function goes wrong.
545 * 2. The parameters given to the nt_service_body() function differ
546 * from those given to main() function.
547 */
548
549 SC_HANDLE hSCManager = NULL;
550 SC_HANDLE hService = NULL;
551 SERVICE_DESCRIPTIONA sdBuff;
552 char *command;
553 char *errmsg;
554 const char *user_acct = NULL;
555 const char *password = "";
556 int i;
557 OSVERSIONINFOEX info;
558 SID_NAME_USE sidUse;
559 DWORD sidLen = 0, domainLen = 0;
560 int is_win2k_or_worse = 0;
561 int using_default_torrc = 0;
562
563 nt_service_loadlibrary();
564
565 /* Open the service control manager so we can create a new service */
566 if ((hSCManager = nt_service_open_scm()) == NULL)
567 return -1;
568 /* Build the command line used for the service */
569 if ((command = nt_service_command_line(&using_default_torrc)) == NULL) {
570 printf("Unable to build service command line.\n");
571 service_fns.CloseServiceHandle_fn(hSCManager);
572 return -1;
573 }
574
575 for (i=1; i < argc; ++i) {
576 if (!strcmp(argv[i], "--user") && i+1<argc) {
577 user_acct = argv[i+1];
578 ++i;
579 }
580 if (!strcmp(argv[i], "--password") && i+1<argc) {
581 password = argv[i+1];
582 ++i;
583 }
584 }
585
586 /* Compute our version and see whether we're running win2k or earlier. */
587 memset(&info, 0, sizeof(info));
588 info.dwOSVersionInfoSize = sizeof(info);
589 if (! GetVersionEx((LPOSVERSIONINFO)&info)) {
590 printf("Call to GetVersionEx failed.\n");
591 is_win2k_or_worse = 1;
592 } else {
593 if (info.dwMajorVersion < 5 ||
594 (info.dwMajorVersion == 5 && info.dwMinorVersion == 0))
595 is_win2k_or_worse = 1;
596 }
597
598 if (!user_acct) {
599 if (is_win2k_or_worse) {
600 /* On Win2k, there is no LocalService account, so we actually need to
601 * fall back on NULL (the system account). */
602 printf("Running on Win2K or earlier, so the LocalService account "
603 "doesn't exist. Falling back to SYSTEM account.\n");
604 } else {
605 /* Genericity is apparently _so_ last year in Redmond, where some
606 * accounts are accounts that you can look up, and some accounts
607 * are magic and undetectable via the security subsystem. See
608 * https://msdn2.microsoft.com/en-us/library/ms684188.aspx
609 */
610 printf("Running on a Post-Win2K OS, so we'll assume that the "
611 "LocalService account exists.\n");
612 user_acct = GENSRV_USERACCT;
613 }
614 } else if (0 && service_fns.LookupAccountNameA_fn(NULL, // On this system
615 user_acct,
616 NULL, &sidLen, // Don't care about the SID
617 NULL, &domainLen, // Don't care about the domain
618 &sidUse) == 0) {
619 /* XXXX For some reason, the above test segfaults. Fix that. */
620 printf("User \"%s\" doesn't seem to exist.\n", user_acct);
622 return -1;
623 } else {
624 printf("Will try to install service as user \"%s\".\n", user_acct);
625 }
626 /* XXXX This warning could be better about explaining how to resolve the
627 * situation. */
628 if (using_default_torrc)
629 printf("IMPORTANT NOTE:\n"
630 " The Tor service will run under the account \"%s\". This means\n"
631 " that Tor will look for its configuration file under that\n"
632 " account's Application Data directory, which is probably not\n"
633 " the same as yours.\n", user_acct?user_acct:"<local system>");
634
635 /* Create the Tor service, set to auto-start on boot */
636 if ((hService = service_fns.CreateServiceA_fn(hSCManager, GENSRV_SERVICENAME,
637 GENSRV_DISPLAYNAME,
638 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
639 SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
640 command, NULL, NULL, NULL,
641 user_acct, password)) == NULL) {
642 errmsg = format_win32_error(GetLastError());
643 printf("CreateService() failed : %s\n", errmsg);
644 service_fns.CloseServiceHandle_fn(hSCManager);
645 tor_free(errmsg);
647 return -1;
648 }
649 printf("Done with CreateService.\n");
650
651 /* Set the service's description */
652 sdBuff.lpDescription = (char*)GENSRV_DESCRIPTION;
653 service_fns.ChangeServiceConfig2A_fn(hService, SERVICE_CONFIG_DESCRIPTION,
654 &sdBuff);
655 printf("Service installed successfully\n");
656
657 /* Start the service initially */
658 nt_service_start(hService);
659
660 service_fns.CloseServiceHandle_fn(hService);
661 service_fns.CloseServiceHandle_fn(hSCManager);
663
664 return 0;
665}
666
667/** Removes the Tor NT service. Returns 0 if the service was successfully
668 * removed, or -1 on error. */
669static int
670nt_service_remove(void)
671{
672 SC_HANDLE hSCManager = NULL;
673 SC_HANDLE hService = NULL;
674 char *errmsg;
675
676 nt_service_loadlibrary();
677 if ((hSCManager = nt_service_open_scm()) == NULL)
678 return -1;
679 if ((hService = nt_service_open(hSCManager)) == NULL) {
680 service_fns.CloseServiceHandle_fn(hSCManager);
681 return -1;
682 }
683
684 nt_service_stop(hService);
685 if (service_fns.DeleteService_fn(hService) == FALSE) {
686 errmsg = format_win32_error(GetLastError());
687 printf("DeleteService() failed : %s\n", errmsg);
688 tor_free(errmsg);
689 service_fns.CloseServiceHandle_fn(hService);
690 service_fns.CloseServiceHandle_fn(hSCManager);
691 return -1;
692 }
693
694 service_fns.CloseServiceHandle_fn(hService);
695 service_fns.CloseServiceHandle_fn(hSCManager);
696 printf("Service removed successfully\n");
697
698 return 0;
699}
700
701/** Starts the Tor service. Returns 0 on success, or -1 on error. */
702static int
703nt_service_cmd_start(void)
704{
705 SC_HANDLE hSCManager;
706 SC_HANDLE hService;
707 int start;
708
709 if ((hSCManager = nt_service_open_scm()) == NULL)
710 return -1;
711 if ((hService = nt_service_open(hSCManager)) == NULL) {
712 service_fns.CloseServiceHandle_fn(hSCManager);
713 return -1;
714 }
715
716 start = nt_service_start(hService);
717 service_fns.CloseServiceHandle_fn(hService);
718 service_fns.CloseServiceHandle_fn(hSCManager);
719
720 return start;
721}
722
723/** Stops the Tor service. Returns 0 on success, or -1 on error. */
724static int
725nt_service_cmd_stop(void)
726{
727 SC_HANDLE hSCManager;
728 SC_HANDLE hService;
729 int stop;
730
731 if ((hSCManager = nt_service_open_scm()) == NULL)
732 return -1;
733 if ((hService = nt_service_open(hSCManager)) == NULL) {
734 service_fns.CloseServiceHandle_fn(hSCManager);
735 return -1;
736 }
737
738 stop = nt_service_stop(hService);
739 service_fns.CloseServiceHandle_fn(hService);
740 service_fns.CloseServiceHandle_fn(hSCManager);
741
742 return stop;
743}
744
745int
746nt_service_parse_options(int argc, char **argv, int *should_exit)
747{
748 backup_argv = argv;
749 backup_argc = argc;
750 *should_exit = 0;
751
752 if ((argc >= 3) &&
753 (!strcmp(argv[1], "-service") || !strcmp(argv[1], "--service"))) {
754 nt_service_loadlibrary();
755 *should_exit = 1;
756 if (!strcmp(argv[2], "install"))
757 return nt_service_install(argc, argv);
758 if (!strcmp(argv[2], "remove"))
759 return nt_service_remove();
760 if (!strcmp(argv[2], "start"))
761 return nt_service_cmd_start();
762 if (!strcmp(argv[2], "stop"))
763 return nt_service_cmd_stop();
764 printf("Unrecognized service command '%s'\n", argv[2]);
765 return 1;
766 }
767 if (argc >= 2) {
768 if (!strcmp(argv[1], "-nt-service") || !strcmp(argv[1], "--nt-service")) {
769 nt_service_loadlibrary();
770 nt_service_main();
771 *should_exit = 1;
772 return 0;
773 }
774 // These values have been deprecated since 0.1.1.2-alpha; we've warned
775 // about them since 0.1.2.7-alpha.
776 if (!strcmp(argv[1], "-install") || !strcmp(argv[1], "--install")) {
777 nt_service_loadlibrary();
778 fprintf(stderr,
779 "The %s option is deprecated; use \"--service install\" instead.",
780 argv[1]);
781 *should_exit = 1;
782 return nt_service_install(argc, argv);
783 }
784 if (!strcmp(argv[1], "-remove") || !strcmp(argv[1], "--remove")) {
785 nt_service_loadlibrary();
786 fprintf(stderr,
787 "The %s option is deprecated; use \"--service remove\" instead.",
788 argv[1]);
789 *should_exit = 1;
790 return nt_service_remove();
791 }
792 }
793 *should_exit = 0;
794 return 0;
795}
796
797#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:947
tor_cmdline_mode_t command
Definition: config.c:2477
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:539
void pubsub_install(void)
Definition: main.c:1341
void pubsub_connect(void)
Definition: main.c:1353
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:60
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_KEYGEN_FAMILY
@ CMD_RUN_UNITTESTS
Header for win32err.c.
Header for winlib.c.