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"
43#define NT_SERVICE_ERROR_TORINIT_FAILED ERROR_EXCEPTION_IN_SERVICE
45static SERVICE_STATUS service_status;
46static SERVICE_STATUS_HANDLE hStatus;
52static char **backup_argv;
53static int backup_argc;
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);
77 BOOL (WINAPI *ChangeServiceConfig2A_fn)(
82 BOOL (WINAPI *CloseServiceHandle_fn)(
85 BOOL (WINAPI *ControlService_fn)(
88 LPSERVICE_STATUS lpServiceStatus);
90 SC_HANDLE (WINAPI *CreateServiceA_fn)(
94 DWORD dwDesiredAccess,
98 LPCSTR lpBinaryPathName,
99 LPCSTR lpLoadOrderGroup,
101 LPCSTR lpDependencies,
102 LPCSTR lpServiceStartName,
105 BOOL (WINAPI *DeleteService_fn)(
108 SC_HANDLE (WINAPI *OpenSCManagerA_fn)(
109 LPCSTR lpMachineName,
110 LPCSTR lpDatabaseName,
111 DWORD dwDesiredAccess);
113 SC_HANDLE (WINAPI *OpenServiceA_fn)(
114 SC_HANDLE hSCManager,
115 LPCSTR lpServiceName,
116 DWORD dwDesiredAccess);
118 BOOL (WINAPI *QueryServiceStatus_fn)(
120 LPSERVICE_STATUS lpServiceStatus);
122 SERVICE_STATUS_HANDLE (WINAPI *RegisterServiceCtrlHandlerA_fn)(
123 LPCSTR lpServiceName,
124 LPHANDLER_FUNCTION lpHandlerProc);
126 BOOL (WINAPI *SetServiceStatus_fn)(SERVICE_STATUS_HANDLE,
129 BOOL (WINAPI *StartServiceCtrlDispatcherA_fn)(
130 const SERVICE_TABLE_ENTRYA* lpServiceTable);
132 BOOL (WINAPI *StartServiceA_fn)(
134 DWORD dwNumServiceArgs,
135 LPCSTR* lpServiceArgVectors);
137 BOOL (WINAPI *LookupAccountNameA_fn)(
139 LPCSTR lpAccountName,
142 LPTSTR ReferencedDomainName,
143 LPDWORD cchReferencedDomainName,
144 PSID_NAME_USE peUse);
147 NULL, NULL, NULL, NULL, NULL, NULL,
148 NULL, NULL, NULL, NULL, NULL, NULL,
154nt_service_loadlibrary(
void)
159 if (service_fns.loaded)
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.");
172#define LOAD(f) STMT_BEGIN \
173 if (!(fn = GetProcAddress(library, #f))) { \
175 "Couldn't find %s in advapi32.dll! We probably got the " \
176 "name wrong.", #f); \
179 service_fns.f ## _fn = fn; \
183 LOAD(ChangeServiceConfig2A);
184 LOAD(CloseServiceHandle);
185 LOAD(ControlService);
186 LOAD(CreateServiceA);
188 LOAD(OpenSCManagerA);
190 LOAD(QueryServiceStatus);
191 LOAD(RegisterServiceCtrlHandlerA);
192 LOAD(SetServiceStatus);
193 LOAD(StartServiceCtrlDispatcherA);
195 LOAD(LookupAccountNameA);
197 service_fns.loaded = 1;
201 printf(
"Unable to load library support for NT services: exiting.\n");
210nt_service_is_stopping(
void)
214 if (!service_fns.loaded)
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);
222 }
else if (service_status.dwCurrentState == SERVICE_STOPPED) {
230nt_service_set_state(DWORD state)
232 service_status.dwCurrentState = state;
238nt_service_control(DWORD request)
240 static struct timeval exit_now;
242 exit_now.tv_usec = 0;
244 nt_service_loadlibrary();
247 case SERVICE_CONTROL_STOP:
248 case SERVICE_CONTROL_SHUTDOWN:
250 "Got stop/shutdown request; shutting down cleanly.");
251 service_status.dwCurrentState = SERVICE_STOP_PENDING;
256 service_fns.SetServiceStatus_fn(hStatus, &service_status);
264nt_service_body(
int argc,
char **argv)
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);
287 r =
tor_init(backup_argc, backup_argv);
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);
303 service_status.dwCurrentState = SERVICE_RUNNING;
304 service_fns.SetServiceStatus_fn(hStatus, &service_status);
315 SERVICE_TABLE_ENTRYA table[2];
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;
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);
331 if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
332 if (
tor_init(backup_argc, backup_argv))
346 log_err(
LD_CONFIG,
"Unsupported command (--list-fingerprint, "
347 "--hash-password, --keygen, --dump-config, --verify-config, "
348 "or --key-expiration) in NT service.");
353 log_err(
LD_CONFIG,
"Illegal command number %d: internal error.",
364nt_service_open_scm(
void)
366 SC_HANDLE hSCManager;
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);
382nt_service_open(SC_HANDLE hSCManager)
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);
399nt_service_start(SC_HANDLE hService)
403 nt_service_loadlibrary();
405 service_fns.QueryServiceStatus_fn(hService, &service_status);
406 if (service_status.dwCurrentState == SERVICE_RUNNING) {
407 printf(
"Service is already running\n");
411 if (service_fns.StartServiceA_fn(hService, 0, NULL)) {
413 while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
414 (service_status.dwCurrentState == SERVICE_START_PENDING)) {
419 if (service_status.dwCurrentState == SERVICE_RUNNING) {
420 printf(
"Service started successfully\n");
423 errmsg = format_win32_error(service_status.dwWin32ExitCode);
424 printf(
"Service failed to start : %s\n", errmsg);
428 errmsg = format_win32_error(GetLastError());
429 printf(
"StartService() failed : %s\n", errmsg);
438nt_service_stop(SC_HANDLE hService)
441#define MAX_SERVICE_WAIT_TIME 10
444 nt_service_loadlibrary();
446 service_fns.QueryServiceStatus_fn(hService, &service_status);
447 if (service_status.dwCurrentState == SERVICE_STOPPED) {
448 printf(
"Service is already stopped\n");
452 if (service_fns.ControlService_fn(hService, SERVICE_CONTROL_STOP,
455 while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
456 (service_status.dwCurrentState != SERVICE_STOPPED) &&
457 (wait_time < MAX_SERVICE_WAIT_TIME)) {
461 if (service_status.dwCurrentState == SERVICE_STOPPED) {
462 printf(
"Service stopped successfully\n");
464 }
else if (wait_time == MAX_SERVICE_WAIT_TIME) {
465 printf(
"Service did not stop within %d seconds.\n", wait_time);
467 errmsg = format_win32_error(GetLastError());
468 printf(
"QueryServiceStatus() failed : %s\n",errmsg);
472 errmsg = format_win32_error(GetLastError());
473 printf(
"ControlService() failed : %s\n", errmsg);
485nt_service_command_line(
int *using_default_torrc)
487 TCHAR tor_exe[MAX_PATH+1];
488 char tor_exe_ascii[MAX_PATH*2+1];
489 char *
command=NULL, *options=NULL;
492 *using_default_torrc = 1;
495 if (0 == GetModuleFileName(NULL, tor_exe, MAX_PATH))
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;
511 if (smartlist_len(sl))
516 wcstombs(tor_exe_ascii, tor_exe,
sizeof(tor_exe_ascii));
517 tor_exe_ascii[
sizeof(tor_exe_ascii)-1] =
'\0';
519 strlcpy(tor_exe_ascii, tor_exe,
sizeof(tor_exe_ascii));
526 tor_exe_ascii, options);
539nt_service_install(
int argc,
char **argv)
549 SC_HANDLE hSCManager = NULL;
550 SC_HANDLE hService = NULL;
551 SERVICE_DESCRIPTIONA sdBuff;
554 const char *user_acct = NULL;
555 const char *password =
"";
557 OSVERSIONINFOEX info;
559 DWORD sidLen = 0, domainLen = 0;
560 int is_win2k_or_worse = 0;
561 int using_default_torrc = 0;
563 nt_service_loadlibrary();
566 if ((hSCManager = nt_service_open_scm()) == NULL)
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);
575 for (i=1; i < argc; ++i) {
576 if (!strcmp(argv[i],
"--user") && i+1<argc) {
577 user_acct = argv[i+1];
580 if (!strcmp(argv[i],
"--password") && i+1<argc) {
581 password = argv[i+1];
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;
593 if (info.dwMajorVersion < 5 ||
594 (info.dwMajorVersion == 5 && info.dwMinorVersion == 0))
595 is_win2k_or_worse = 1;
599 if (is_win2k_or_worse) {
602 printf(
"Running on Win2K or earlier, so the LocalService account "
603 "doesn't exist. Falling back to SYSTEM account.\n");
610 printf(
"Running on a Post-Win2K OS, so we'll assume that the "
611 "LocalService account exists.\n");
612 user_acct = GENSRV_USERACCT;
614 }
else if (0 && service_fns.LookupAccountNameA_fn(NULL,
620 printf(
"User \"%s\" doesn't seem to exist.\n", user_acct);
624 printf(
"Will try to install service as user \"%s\".\n", user_acct);
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>");
636 if ((hService = service_fns.CreateServiceA_fn(hSCManager, GENSRV_SERVICENAME,
638 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
639 SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
641 user_acct, password)) == NULL) {
642 errmsg = format_win32_error(GetLastError());
643 printf(
"CreateService() failed : %s\n", errmsg);
644 service_fns.CloseServiceHandle_fn(hSCManager);
649 printf(
"Done with CreateService.\n");
652 sdBuff.lpDescription = (
char*)GENSRV_DESCRIPTION;
653 service_fns.ChangeServiceConfig2A_fn(hService, SERVICE_CONFIG_DESCRIPTION,
655 printf(
"Service installed successfully\n");
658 nt_service_start(hService);
660 service_fns.CloseServiceHandle_fn(hService);
661 service_fns.CloseServiceHandle_fn(hSCManager);
670nt_service_remove(
void)
672 SC_HANDLE hSCManager = NULL;
673 SC_HANDLE hService = NULL;
676 nt_service_loadlibrary();
677 if ((hSCManager = nt_service_open_scm()) == NULL)
679 if ((hService = nt_service_open(hSCManager)) == NULL) {
680 service_fns.CloseServiceHandle_fn(hSCManager);
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);
689 service_fns.CloseServiceHandle_fn(hService);
690 service_fns.CloseServiceHandle_fn(hSCManager);
694 service_fns.CloseServiceHandle_fn(hService);
695 service_fns.CloseServiceHandle_fn(hSCManager);
696 printf(
"Service removed successfully\n");
703nt_service_cmd_start(
void)
705 SC_HANDLE hSCManager;
709 if ((hSCManager = nt_service_open_scm()) == NULL)
711 if ((hService = nt_service_open(hSCManager)) == NULL) {
712 service_fns.CloseServiceHandle_fn(hSCManager);
716 start = nt_service_start(hService);
717 service_fns.CloseServiceHandle_fn(hService);
718 service_fns.CloseServiceHandle_fn(hSCManager);
725nt_service_cmd_stop(
void)
727 SC_HANDLE hSCManager;
731 if ((hSCManager = nt_service_open_scm()) == NULL)
733 if ((hService = nt_service_open(hSCManager)) == NULL) {
734 service_fns.CloseServiceHandle_fn(hSCManager);
738 stop = nt_service_stop(hService);
739 service_fns.CloseServiceHandle_fn(hService);
740 service_fns.CloseServiceHandle_fn(hSCManager);
746nt_service_parse_options(
int argc,
char **argv,
int *should_exit)
753 (!strcmp(argv[1],
"-service") || !strcmp(argv[1],
"--service"))) {
754 nt_service_loadlibrary();
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]);
768 if (!strcmp(argv[1],
"-nt-service") || !strcmp(argv[1],
"--nt-service")) {
769 nt_service_loadlibrary();
776 if (!strcmp(argv[1],
"-install") || !strcmp(argv[1],
"--install")) {
777 nt_service_loadlibrary();
779 "The %s option is deprecated; use \"--service install\" instead.",
782 return nt_service_install(argc, argv);
784 if (!strcmp(argv[1],
"-remove") || !strcmp(argv[1],
"--remove")) {
785 nt_service_loadlibrary();
787 "The %s option is deprecated; use \"--service remove\" instead.",
790 return nt_service_remove();
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)
tor_cmdline_mode_t command
Header file for config.c.
int tor_init(int argc, char *argv[])
void pubsub_install(void)
void pubsub_connect(void)
Header file for mainloop.c.
Header file for ntmain.c.
Master header file for Tor-specific functionality.
int tor_asprintf(char **strp, const char *fmt,...)
Header file for shutdown.c.
char * smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, size_t *len_out)
smartlist_t * smartlist_new(void)
void smartlist_add(smartlist_t *sl, void *element)