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