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
45 static SERVICE_STATUS service_status;
46 static SERVICE_STATUS_HANDLE hStatus;
52 static char **backup_argv;
53 static int backup_argc;
55 static void nt_service_control(DWORD request);
56 static void nt_service_body(
int argc,
char **argv);
57 static void nt_service_main(
void);
58 static SC_HANDLE nt_service_open_scm(
void);
59 static SC_HANDLE nt_service_open(SC_HANDLE hSCManager);
60 static int nt_service_start(SC_HANDLE hService);
61 static int nt_service_stop(SC_HANDLE hService);
62 static int nt_service_install(
int argc,
char **argv);
63 static int nt_service_remove(
void);
64 static int nt_service_cmd_start(
void);
65 static int nt_service_cmd_stop(
void);
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,
154 nt_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");
210 nt_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) {
230 nt_service_set_state(DWORD state)
232 service_status.dwCurrentState = state;
238 nt_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);
264 nt_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);
313 nt_service_main(
void)
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))
345 log_err(
LD_CONFIG,
"Unsupported command (--list-fingerprint, "
346 "--hash-password, --keygen, --dump-config, --verify-config, "
347 "or --key-expiration) in NT service.");
352 log_err(
LD_CONFIG,
"Illegal command number %d: internal error.",
363 nt_service_open_scm(
void)
365 SC_HANDLE hSCManager;
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);
381 nt_service_open(SC_HANDLE hSCManager)
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);
398 nt_service_start(SC_HANDLE hService)
402 nt_service_loadlibrary();
404 service_fns.QueryServiceStatus_fn(hService, &service_status);
405 if (service_status.dwCurrentState == SERVICE_RUNNING) {
406 printf(
"Service is already running\n");
410 if (service_fns.StartServiceA_fn(hService, 0, NULL)) {
412 while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
413 (service_status.dwCurrentState == SERVICE_START_PENDING)) {
418 if (service_status.dwCurrentState == SERVICE_RUNNING) {
419 printf(
"Service started successfully\n");
422 errmsg = format_win32_error(service_status.dwWin32ExitCode);
423 printf(
"Service failed to start : %s\n", errmsg);
427 errmsg = format_win32_error(GetLastError());
428 printf(
"StartService() failed : %s\n", errmsg);
437 nt_service_stop(SC_HANDLE hService)
440 #define MAX_SERVICE_WAIT_TIME 10
443 nt_service_loadlibrary();
445 service_fns.QueryServiceStatus_fn(hService, &service_status);
446 if (service_status.dwCurrentState == SERVICE_STOPPED) {
447 printf(
"Service is already stopped\n");
451 if (service_fns.ControlService_fn(hService, SERVICE_CONTROL_STOP,
454 while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
455 (service_status.dwCurrentState != SERVICE_STOPPED) &&
456 (wait_time < MAX_SERVICE_WAIT_TIME)) {
460 if (service_status.dwCurrentState == SERVICE_STOPPED) {
461 printf(
"Service stopped successfully\n");
463 }
else if (wait_time == MAX_SERVICE_WAIT_TIME) {
464 printf(
"Service did not stop within %d seconds.\n", wait_time);
466 errmsg = format_win32_error(GetLastError());
467 printf(
"QueryServiceStatus() failed : %s\n",errmsg);
471 errmsg = format_win32_error(GetLastError());
472 printf(
"ControlService() failed : %s\n", errmsg);
484 nt_service_command_line(
int *using_default_torrc)
486 TCHAR tor_exe[MAX_PATH+1];
487 char tor_exe_ascii[MAX_PATH*2+1];
488 char *
command=NULL, *options=NULL;
491 *using_default_torrc = 1;
494 if (0 == GetModuleFileName(NULL, tor_exe, MAX_PATH))
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;
510 if (smartlist_len(sl))
515 wcstombs(tor_exe_ascii, tor_exe,
sizeof(tor_exe_ascii));
516 tor_exe_ascii[
sizeof(tor_exe_ascii)-1] =
'\0';
518 strlcpy(tor_exe_ascii, tor_exe,
sizeof(tor_exe_ascii));
525 tor_exe_ascii, options);
538 nt_service_install(
int argc,
char **argv)
548 SC_HANDLE hSCManager = NULL;
549 SC_HANDLE hService = NULL;
550 SERVICE_DESCRIPTIONA sdBuff;
553 const char *user_acct = NULL;
554 const char *password =
"";
556 OSVERSIONINFOEX info;
558 DWORD sidLen = 0, domainLen = 0;
559 int is_win2k_or_worse = 0;
560 int using_default_torrc = 0;
562 nt_service_loadlibrary();
565 if ((hSCManager = nt_service_open_scm()) == NULL)
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);
574 for (i=1; i < argc; ++i) {
575 if (!strcmp(argv[i],
"--user") && i+1<argc) {
576 user_acct = argv[i+1];
579 if (!strcmp(argv[i],
"--password") && i+1<argc) {
580 password = argv[i+1];
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;
592 if (info.dwMajorVersion < 5 ||
593 (info.dwMajorVersion == 5 && info.dwMinorVersion == 0))
594 is_win2k_or_worse = 1;
598 if (is_win2k_or_worse) {
601 printf(
"Running on Win2K or earlier, so the LocalService account "
602 "doesn't exist. Falling back to SYSTEM account.\n");
609 printf(
"Running on a Post-Win2K OS, so we'll assume that the "
610 "LocalService account exists.\n");
611 user_acct = GENSRV_USERACCT;
613 }
else if (0 && service_fns.LookupAccountNameA_fn(NULL,
619 printf(
"User \"%s\" doesn't seem to exist.\n", user_acct);
623 printf(
"Will try to install service as user \"%s\".\n", user_acct);
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>");
635 if ((hService = service_fns.CreateServiceA_fn(hSCManager, GENSRV_SERVICENAME,
637 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
638 SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
640 user_acct, password)) == NULL) {
641 errmsg = format_win32_error(GetLastError());
642 printf(
"CreateService() failed : %s\n", errmsg);
643 service_fns.CloseServiceHandle_fn(hSCManager);
648 printf(
"Done with CreateService.\n");
651 sdBuff.lpDescription = (
char*)GENSRV_DESCRIPTION;
652 service_fns.ChangeServiceConfig2A_fn(hService, SERVICE_CONFIG_DESCRIPTION,
654 printf(
"Service installed successfully\n");
657 nt_service_start(hService);
659 service_fns.CloseServiceHandle_fn(hService);
660 service_fns.CloseServiceHandle_fn(hSCManager);
669 nt_service_remove(
void)
671 SC_HANDLE hSCManager = NULL;
672 SC_HANDLE hService = NULL;
675 nt_service_loadlibrary();
676 if ((hSCManager = nt_service_open_scm()) == NULL)
678 if ((hService = nt_service_open(hSCManager)) == NULL) {
679 service_fns.CloseServiceHandle_fn(hSCManager);
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);
688 service_fns.CloseServiceHandle_fn(hService);
689 service_fns.CloseServiceHandle_fn(hSCManager);
693 service_fns.CloseServiceHandle_fn(hService);
694 service_fns.CloseServiceHandle_fn(hSCManager);
695 printf(
"Service removed successfully\n");
702 nt_service_cmd_start(
void)
704 SC_HANDLE hSCManager;
708 if ((hSCManager = nt_service_open_scm()) == NULL)
710 if ((hService = nt_service_open(hSCManager)) == NULL) {
711 service_fns.CloseServiceHandle_fn(hSCManager);
715 start = nt_service_start(hService);
716 service_fns.CloseServiceHandle_fn(hService);
717 service_fns.CloseServiceHandle_fn(hSCManager);
724 nt_service_cmd_stop(
void)
726 SC_HANDLE hSCManager;
730 if ((hSCManager = nt_service_open_scm()) == NULL)
732 if ((hService = nt_service_open(hSCManager)) == NULL) {
733 service_fns.CloseServiceHandle_fn(hSCManager);
737 stop = nt_service_stop(hService);
738 service_fns.CloseServiceHandle_fn(hService);
739 service_fns.CloseServiceHandle_fn(hSCManager);
745 nt_service_parse_options(
int argc,
char **argv,
int *should_exit)
752 (!strcmp(argv[1],
"-service") || !strcmp(argv[1],
"--service"))) {
753 nt_service_loadlibrary();
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]);
767 if (!strcmp(argv[1],
"-nt-service") || !strcmp(argv[1],
"--nt-service")) {
768 nt_service_loadlibrary();
775 if (!strcmp(argv[1],
"-install") || !strcmp(argv[1],
"--install")) {
776 nt_service_loadlibrary();
778 "The %s option is deprecated; use \"--service install\" instead.",
781 return nt_service_install(argc, argv);
783 if (!strcmp(argv[1],
"-remove") || !strcmp(argv[1],
"--remove")) {
784 nt_service_loadlibrary();
786 "The %s option is deprecated; use \"--service remove\" instead.",
789 return nt_service_remove();
struct event_base * tor_libevent_get_base(void)
void tor_libevent_exit_loop_after_delay(struct event_base *base, const struct timeval *delay)
Header for compat_libevent.c.
void set_main_thread(void)
const or_options_t * get_options(void)
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)