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);
69typedef struct nt_services {
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);
148static nt_services_t service_fns = { 0,
149 NULL, NULL, NULL, NULL, NULL, NULL,
150 NULL, NULL, NULL, NULL, NULL, NULL,
156nt_service_loadlibrary(
void)
161 if (service_fns.loaded)
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.");
174#define LOAD(f) STMT_BEGIN \
175 if (!(fn = GetProcAddress(library, #f))) { \
177 "Couldn't find %s in advapi32.dll! We probably got the " \
178 "name wrong.", #f); \
181 service_fns.f ## _fn = fn; \
185 LOAD(ChangeServiceConfig2A);
186 LOAD(CloseServiceHandle);
187 LOAD(ControlService);
188 LOAD(CreateServiceA);
190 LOAD(OpenSCManagerA);
192 LOAD(QueryServiceStatus);
193 LOAD(RegisterServiceCtrlHandlerA);
194 LOAD(SetServiceStatus);
195 LOAD(StartServiceCtrlDispatcherA);
197 LOAD(LookupAccountNameA);
199 service_fns.loaded = 1;
203 printf(
"Unable to load library support for NT services: exiting.\n");
212nt_service_is_stopping(
void)
216 if (!service_fns.loaded)
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);
224 }
else if (service_status.dwCurrentState == SERVICE_STOPPED) {
232nt_service_set_state(DWORD state)
234 service_status.dwCurrentState = state;
240nt_service_control(DWORD request)
242 static struct timeval exit_now;
244 exit_now.tv_usec = 0;
246 nt_service_loadlibrary();
249 case SERVICE_CONTROL_STOP:
250 case SERVICE_CONTROL_SHUTDOWN:
252 "Got stop/shutdown request; shutting down cleanly.");
253 service_status.dwCurrentState = SERVICE_STOP_PENDING;
258 service_fns.SetServiceStatus_fn(hStatus, &service_status);
266nt_service_body(
int argc,
char **argv)
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);
289 r =
tor_init(backup_argc, backup_argv);
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);
305 service_status.dwCurrentState = SERVICE_RUNNING;
306 service_fns.SetServiceStatus_fn(hStatus, &service_status);
317 SERVICE_TABLE_ENTRYA table[2];
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;
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);
333 if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
334 if (
tor_init(backup_argc, backup_argv))
348 log_err(
LD_CONFIG,
"Unsupported command (--list-fingerprint, "
349 "--hash-password, --keygen, --dump-config, --verify-config, "
350 "or --key-expiration) in NT service.");
355 log_err(
LD_CONFIG,
"Illegal command number %d: internal error.",
366nt_service_open_scm(
void)
368 SC_HANDLE hSCManager;
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);
384nt_service_open(SC_HANDLE hSCManager)
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);
401nt_service_start(SC_HANDLE hService)
405 nt_service_loadlibrary();
407 service_fns.QueryServiceStatus_fn(hService, &service_status);
408 if (service_status.dwCurrentState == SERVICE_RUNNING) {
409 printf(
"Service is already running\n");
413 if (service_fns.StartServiceA_fn(hService, 0, NULL)) {
415 while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
416 (service_status.dwCurrentState == SERVICE_START_PENDING)) {
421 if (service_status.dwCurrentState == SERVICE_RUNNING) {
422 printf(
"Service started successfully\n");
425 errmsg = format_win32_error(service_status.dwWin32ExitCode);
426 printf(
"Service failed to start : %s\n", errmsg);
430 errmsg = format_win32_error(GetLastError());
431 printf(
"StartService() failed : %s\n", errmsg);
440nt_service_stop(SC_HANDLE hService)
443#define MAX_SERVICE_WAIT_TIME 10
446 nt_service_loadlibrary();
448 service_fns.QueryServiceStatus_fn(hService, &service_status);
449 if (service_status.dwCurrentState == SERVICE_STOPPED) {
450 printf(
"Service is already stopped\n");
454 if (service_fns.ControlService_fn(hService, SERVICE_CONTROL_STOP,
457 while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
458 (service_status.dwCurrentState != SERVICE_STOPPED) &&
459 (wait_time < MAX_SERVICE_WAIT_TIME)) {
463 if (service_status.dwCurrentState == SERVICE_STOPPED) {
464 printf(
"Service stopped successfully\n");
466 }
else if (wait_time == MAX_SERVICE_WAIT_TIME) {
467 printf(
"Service did not stop within %d seconds.\n", wait_time);
469 errmsg = format_win32_error(GetLastError());
470 printf(
"QueryServiceStatus() failed : %s\n",errmsg);
474 errmsg = format_win32_error(GetLastError());
475 printf(
"ControlService() failed : %s\n", errmsg);
487nt_service_command_line(
int *using_default_torrc)
489 TCHAR tor_exe[MAX_PATH+1];
490 char tor_exe_ascii[MAX_PATH*2+1];
491 char *
command=NULL, *options=NULL;
494 *using_default_torrc = 1;
497 if (0 == GetModuleFileName(NULL, tor_exe, MAX_PATH))
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;
513 if (smartlist_len(sl))
518 wcstombs(tor_exe_ascii, tor_exe,
sizeof(tor_exe_ascii));
519 tor_exe_ascii[
sizeof(tor_exe_ascii)-1] =
'\0';
521 strlcpy(tor_exe_ascii, tor_exe,
sizeof(tor_exe_ascii));
528 tor_exe_ascii, options);
541nt_service_install(
int argc,
char **argv)
551 SC_HANDLE hSCManager = NULL;
552 SC_HANDLE hService = NULL;
553 SERVICE_DESCRIPTIONA sdBuff;
556 const char *user_acct = NULL;
557 const char *password =
"";
559 OSVERSIONINFOEX info;
561 DWORD sidLen = 0, domainLen = 0;
562 int is_win2k_or_worse = 0;
563 int using_default_torrc = 0;
565 nt_service_loadlibrary();
568 if ((hSCManager = nt_service_open_scm()) == NULL)
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);
577 for (i=1; i < argc; ++i) {
578 if (!strcmp(argv[i],
"--user") && i+1<argc) {
579 user_acct = argv[i+1];
582 if (!strcmp(argv[i],
"--password") && i+1<argc) {
583 password = argv[i+1];
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;
595 if (info.dwMajorVersion < 5 ||
596 (info.dwMajorVersion == 5 && info.dwMinorVersion == 0))
597 is_win2k_or_worse = 1;
601 if (is_win2k_or_worse) {
604 printf(
"Running on Win2K or earlier, so the LocalService account "
605 "doesn't exist. Falling back to SYSTEM account.\n");
612 printf(
"Running on a Post-Win2K OS, so we'll assume that the "
613 "LocalService account exists.\n");
614 user_acct = GENSRV_USERACCT;
616 }
else if (0 && service_fns.LookupAccountNameA_fn(NULL,
622 printf(
"User \"%s\" doesn't seem to exist.\n", user_acct);
626 printf(
"Will try to install service as user \"%s\".\n", user_acct);
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>");
638 if ((hService = service_fns.CreateServiceA_fn(hSCManager, GENSRV_SERVICENAME,
640 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
641 SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
643 user_acct, password)) == NULL) {
644 errmsg = format_win32_error(GetLastError());
645 printf(
"CreateService() failed : %s\n", errmsg);
646 service_fns.CloseServiceHandle_fn(hSCManager);
651 printf(
"Done with CreateService.\n");
654 sdBuff.lpDescription = (
char*)GENSRV_DESCRIPTION;
655 service_fns.ChangeServiceConfig2A_fn(hService, SERVICE_CONFIG_DESCRIPTION,
657 printf(
"Service installed successfully\n");
660 nt_service_start(hService);
662 service_fns.CloseServiceHandle_fn(hService);
663 service_fns.CloseServiceHandle_fn(hSCManager);
672nt_service_remove(
void)
674 SC_HANDLE hSCManager = NULL;
675 SC_HANDLE hService = NULL;
678 nt_service_loadlibrary();
679 if ((hSCManager = nt_service_open_scm()) == NULL)
681 if ((hService = nt_service_open(hSCManager)) == NULL) {
682 service_fns.CloseServiceHandle_fn(hSCManager);
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);
691 service_fns.CloseServiceHandle_fn(hService);
692 service_fns.CloseServiceHandle_fn(hSCManager);
696 service_fns.CloseServiceHandle_fn(hService);
697 service_fns.CloseServiceHandle_fn(hSCManager);
698 printf(
"Service removed successfully\n");
705nt_service_cmd_start(
void)
707 SC_HANDLE hSCManager;
711 if ((hSCManager = nt_service_open_scm()) == NULL)
713 if ((hService = nt_service_open(hSCManager)) == NULL) {
714 service_fns.CloseServiceHandle_fn(hSCManager);
718 start = nt_service_start(hService);
719 service_fns.CloseServiceHandle_fn(hService);
720 service_fns.CloseServiceHandle_fn(hSCManager);
727nt_service_cmd_stop(
void)
729 SC_HANDLE hSCManager;
733 if ((hSCManager = nt_service_open_scm()) == NULL)
735 if ((hService = nt_service_open(hSCManager)) == NULL) {
736 service_fns.CloseServiceHandle_fn(hSCManager);
740 stop = nt_service_stop(hService);
741 service_fns.CloseServiceHandle_fn(hService);
742 service_fns.CloseServiceHandle_fn(hSCManager);
748nt_service_parse_options(
int argc,
char **argv,
int *should_exit)
755 (!strcmp(argv[1],
"-service") || !strcmp(argv[1],
"--service"))) {
756 nt_service_loadlibrary();
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]);
770 if (!strcmp(argv[1],
"-nt-service") || !strcmp(argv[1],
"--nt-service")) {
771 nt_service_loadlibrary();
778 if (!strcmp(argv[1],
"-install") || !strcmp(argv[1],
"--install")) {
779 nt_service_loadlibrary();
781 "The %s option is deprecated; use \"--service install\" instead.",
784 return nt_service_install(argc, argv);
786 if (!strcmp(argv[1],
"-remove") || !strcmp(argv[1],
"--remove")) {
787 nt_service_loadlibrary();
789 "The %s option is deprecated; use \"--service remove\" instead.",
792 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)