Report only the top 10 ports in exit-port stats.
[tor/rransom.git] / src / or / ntmain.c
blob46e7afb78b01e90820d84b5c14dc1d6e4bd2a329
1 /* Copyright (c) 2001-2004, Roger Dingledine.
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2010, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
6 #define MAIN_PRIVATE
7 #include "or.h"
8 #include "config.h"
9 #include "main.h"
10 #include "ntmain.h"
12 #ifdef HAVE_EVENT2_EVENT_H
13 #include <event2/event.h>
14 #else
15 #include <event.h>
16 #endif
18 #include <windows.h>
19 #define GENSRV_SERVICENAME "tor"
20 #define GENSRV_DISPLAYNAME "Tor Win32 Service"
21 #define GENSRV_DESCRIPTION \
22 "Provides an anonymous Internet communication system"
23 #define GENSRV_USERACCT "NT AUTHORITY\\LocalService"
25 // Cheating: using the pre-defined error codes, tricks Windows into displaying
26 // a semi-related human-readable error message if startup fails as
27 // opposed to simply scaring people with Error: 0xffffffff
28 #define NT_SERVICE_ERROR_TORINIT_FAILED ERROR_EXCEPTION_IN_SERVICE
30 static SERVICE_STATUS service_status;
31 static SERVICE_STATUS_HANDLE hStatus;
33 /* XXXX This 'backup argv' and 'backup argc' business is an ugly hack. This
34 * is a job for arguments, not globals. Alas, some of the functions that
35 * use them use them need to have fixed signatures, so they can be passed
36 * to the NT service functions. */
37 static char **backup_argv;
38 static int backup_argc;
40 static void nt_service_control(DWORD request);
41 static void nt_service_body(int argc, char **argv);
42 static void nt_service_main(void);
43 static SC_HANDLE nt_service_open_scm(void);
44 static SC_HANDLE nt_service_open(SC_HANDLE hSCManager);
45 static int nt_service_start(SC_HANDLE hService);
46 static int nt_service_stop(SC_HANDLE hService);
47 static int nt_service_install(int argc, char **argv);
48 static int nt_service_remove(void);
49 static int nt_service_cmd_start(void);
50 static int nt_service_cmd_stop(void);
52 /** Struct to hold dynamically loaded NT-service related function pointers.
54 struct service_fns {
55 int loaded;
57 BOOL (WINAPI *ChangeServiceConfig2A_fn)(
58 SC_HANDLE hService,
59 DWORD dwInfoLevel,
60 LPVOID lpInfo);
62 BOOL (WINAPI *CloseServiceHandle_fn)(
63 SC_HANDLE hSCObject);
65 BOOL (WINAPI *ControlService_fn)(
66 SC_HANDLE hService,
67 DWORD dwControl,
68 LPSERVICE_STATUS lpServiceStatus);
70 SC_HANDLE (WINAPI *CreateServiceA_fn)(
71 SC_HANDLE hSCManager,
72 LPCSTR lpServiceName,
73 LPCSTR lpDisplayName,
74 DWORD dwDesiredAccess,
75 DWORD dwServiceType,
76 DWORD dwStartType,
77 DWORD dwErrorControl,
78 LPCSTR lpBinaryPathName,
79 LPCSTR lpLoadOrderGroup,
80 LPDWORD lpdwTagId,
81 LPCSTR lpDependencies,
82 LPCSTR lpServiceStartName,
83 LPCSTR lpPassword);
85 BOOL (WINAPI *DeleteService_fn)(
86 SC_HANDLE hService);
88 SC_HANDLE (WINAPI *OpenSCManagerA_fn)(
89 LPCSTR lpMachineName,
90 LPCSTR lpDatabaseName,
91 DWORD dwDesiredAccess);
93 SC_HANDLE (WINAPI *OpenServiceA_fn)(
94 SC_HANDLE hSCManager,
95 LPCSTR lpServiceName,
96 DWORD dwDesiredAccess);
98 BOOL (WINAPI *QueryServiceStatus_fn)(
99 SC_HANDLE hService,
100 LPSERVICE_STATUS lpServiceStatus);
102 SERVICE_STATUS_HANDLE (WINAPI *RegisterServiceCtrlHandlerA_fn)(
103 LPCSTR lpServiceName,
104 LPHANDLER_FUNCTION lpHandlerProc);
106 BOOL (WINAPI *SetServiceStatus_fn)(SERVICE_STATUS_HANDLE,
107 LPSERVICE_STATUS);
109 BOOL (WINAPI *StartServiceCtrlDispatcherA_fn)(
110 const SERVICE_TABLE_ENTRYA* lpServiceTable);
112 BOOL (WINAPI *StartServiceA_fn)(
113 SC_HANDLE hService,
114 DWORD dwNumServiceArgs,
115 LPCSTR* lpServiceArgVectors);
117 BOOL (WINAPI *LookupAccountNameA_fn)(
118 LPCSTR lpSystemName,
119 LPCSTR lpAccountName,
120 PSID Sid,
121 LPDWORD cbSid,
122 LPTSTR ReferencedDomainName,
123 LPDWORD cchReferencedDomainName,
124 PSID_NAME_USE peUse);
125 } service_fns = { 0,
126 NULL, NULL, NULL, NULL, NULL, NULL,
127 NULL, NULL, NULL, NULL, NULL, NULL,
128 NULL};
130 /** Loads functions used by NT services. Returns on success, or prints a
131 * complaint to stdout and exits on error. */
132 static void
133 nt_service_loadlibrary(void)
135 HMODULE library = 0;
136 void *fn;
138 if (service_fns.loaded)
139 return;
141 if (!(library = load_windows_system_library(TEXT("advapi32.dll")))) {
142 log_err(LD_GENERAL, "Couldn't open advapi32.dll. Are you trying to use "
143 "NT services on Windows 98? That doesn't work.");
144 goto err;
147 #define LOAD(f) STMT_BEGIN \
148 if (!(fn = GetProcAddress(library, #f))) { \
149 log_err(LD_BUG, \
150 "Couldn't find %s in advapi32.dll! We probably got the " \
151 "name wrong.", #f); \
152 goto err; \
153 } else { \
154 service_fns.f ## _fn = fn; \
156 STMT_END
158 LOAD(ChangeServiceConfig2A);
159 LOAD(CloseServiceHandle);
160 LOAD(ControlService);
161 LOAD(CreateServiceA);
162 LOAD(DeleteService);
163 LOAD(OpenSCManagerA);
164 LOAD(OpenServiceA);
165 LOAD(QueryServiceStatus);
166 LOAD(RegisterServiceCtrlHandlerA);
167 LOAD(SetServiceStatus);
168 LOAD(StartServiceCtrlDispatcherA);
169 LOAD(StartServiceA);
170 LOAD(LookupAccountNameA);
172 service_fns.loaded = 1;
174 return;
175 err:
176 printf("Unable to load library support for NT services: exiting.\n");
177 exit(1);
180 /** If we're compiled to run as an NT service, and the service wants to
181 * shut down, then change our current status and return 1. Else
182 * return 0.
185 nt_service_is_stopping(void)
186 /* XXXX this function would probably _love_ to be inline, in 0.2.0. */
188 /* If we haven't loaded the function pointers, we can't possibly be an NT
189 * service trying to shut down. */
190 if (!service_fns.loaded)
191 return 0;
193 if (service_status.dwCurrentState == SERVICE_STOP_PENDING) {
194 service_status.dwWin32ExitCode = 0;
195 service_status.dwCurrentState = SERVICE_STOPPED;
196 service_fns.SetServiceStatus_fn(hStatus, &service_status);
197 return 1;
198 } else if (service_status.dwCurrentState == SERVICE_STOPPED) {
199 return 1;
201 return 0;
204 /** Set the dwCurrentState field for our service to <b>state</b>. */
205 void
206 nt_service_set_state(DWORD state)
208 service_status.dwCurrentState = state;
211 /** Handles service control requests, such as stopping or starting the
212 * Tor service. */
213 static void
214 nt_service_control(DWORD request)
216 static struct timeval exit_now;
217 exit_now.tv_sec = 0;
218 exit_now.tv_usec = 0;
220 nt_service_loadlibrary();
222 switch (request) {
223 case SERVICE_CONTROL_STOP:
224 case SERVICE_CONTROL_SHUTDOWN:
225 log_notice(LD_GENERAL,
226 "Got stop/shutdown request; shutting down cleanly.");
227 service_status.dwCurrentState = SERVICE_STOP_PENDING;
228 event_base_loopexit(tor_libevent_get_base(), &exit_now);
229 return;
231 service_fns.SetServiceStatus_fn(hStatus, &service_status);
234 /** Called when the service is started via the system's service control
235 * manager. This calls tor_init() and starts the main event loop. If
236 * tor_init() fails, the service will be stopped and exit code set to
237 * NT_SERVICE_ERROR_TORINIT_FAILED. */
238 static void
239 nt_service_body(int argc, char **argv)
241 int r;
242 (void) argc; /* unused */
243 (void) argv; /* unused */
244 nt_service_loadlibrary();
245 service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
246 service_status.dwCurrentState = SERVICE_START_PENDING;
247 service_status.dwControlsAccepted =
248 SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
249 service_status.dwWin32ExitCode = 0;
250 service_status.dwServiceSpecificExitCode = 0;
251 service_status.dwCheckPoint = 0;
252 service_status.dwWaitHint = 1000;
253 hStatus = service_fns.RegisterServiceCtrlHandlerA_fn(GENSRV_SERVICENAME,
254 (LPHANDLER_FUNCTION) nt_service_control);
256 if (hStatus == 0) {
257 /* Failed to register the service control handler function */
258 return;
261 r = tor_init(backup_argc, backup_argv);
262 if (r) {
263 /* Failed to start the Tor service */
264 r = NT_SERVICE_ERROR_TORINIT_FAILED;
265 service_status.dwCurrentState = SERVICE_STOPPED;
266 service_status.dwWin32ExitCode = r;
267 service_status.dwServiceSpecificExitCode = r;
268 service_fns.SetServiceStatus_fn(hStatus, &service_status);
269 return;
272 /* Set the service's status to SERVICE_RUNNING and start the main
273 * event loop */
274 service_status.dwCurrentState = SERVICE_RUNNING;
275 service_fns.SetServiceStatus_fn(hStatus, &service_status);
276 do_main_loop();
277 tor_cleanup();
280 /** Main service entry point. Starts the service control dispatcher and waits
281 * until the service status is set to SERVICE_STOPPED. */
282 static void
283 nt_service_main(void)
285 SERVICE_TABLE_ENTRYA table[2];
286 DWORD result = 0;
287 char *errmsg;
288 nt_service_loadlibrary();
289 table[0].lpServiceName = (char*)GENSRV_SERVICENAME;
290 table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTIONA)nt_service_body;
291 table[1].lpServiceName = NULL;
292 table[1].lpServiceProc = NULL;
294 if (!service_fns.StartServiceCtrlDispatcherA_fn(table)) {
295 result = GetLastError();
296 errmsg = format_win32_error(result);
297 printf("Service error %d : %s\n", (int) result, errmsg);
298 tor_free(errmsg);
299 if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
300 if (tor_init(backup_argc, backup_argv) < 0)
301 return;
302 switch (get_options()->command) {
303 case CMD_RUN_TOR:
304 do_main_loop();
305 break;
306 case CMD_LIST_FINGERPRINT:
307 case CMD_HASH_PASSWORD:
308 case CMD_VERIFY_CONFIG:
309 log_err(LD_CONFIG, "Unsupported command (--list-fingerprint, "
310 "--hash-password, or --verify-config) in NT service.");
311 break;
312 case CMD_RUN_UNITTESTS:
313 default:
314 log_err(LD_CONFIG, "Illegal command number %d: internal error.",
315 get_options()->command);
317 tor_cleanup();
322 /** Return a handle to the service control manager on success, or NULL on
323 * failure. */
324 static SC_HANDLE
325 nt_service_open_scm(void)
327 SC_HANDLE hSCManager;
328 char *errmsg = NULL;
330 nt_service_loadlibrary();
331 if ((hSCManager = service_fns.OpenSCManagerA_fn(
332 NULL, NULL, SC_MANAGER_CREATE_SERVICE)) == NULL) {
333 errmsg = format_win32_error(GetLastError());
334 printf("OpenSCManager() failed : %s\n", errmsg);
335 tor_free(errmsg);
337 return hSCManager;
340 /** Open a handle to the Tor service using <b>hSCManager</b>. Return NULL
341 * on failure. */
342 static SC_HANDLE
343 nt_service_open(SC_HANDLE hSCManager)
345 SC_HANDLE hService;
346 char *errmsg = NULL;
347 nt_service_loadlibrary();
348 if ((hService = service_fns.OpenServiceA_fn(hSCManager, GENSRV_SERVICENAME,
349 SERVICE_ALL_ACCESS)) == NULL) {
350 errmsg = format_win32_error(GetLastError());
351 printf("OpenService() failed : %s\n", errmsg);
352 tor_free(errmsg);
354 return hService;
357 /** Start the Tor service. Return 0 if the service is started or was
358 * previously running. Return -1 on error. */
359 static int
360 nt_service_start(SC_HANDLE hService)
362 char *errmsg = NULL;
364 nt_service_loadlibrary();
366 service_fns.QueryServiceStatus_fn(hService, &service_status);
367 if (service_status.dwCurrentState == SERVICE_RUNNING) {
368 printf("Service is already running\n");
369 return 0;
372 if (service_fns.StartServiceA_fn(hService, 0, NULL)) {
373 /* Loop until the service has finished attempting to start */
374 while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
375 (service_status.dwCurrentState == SERVICE_START_PENDING)) {
376 Sleep(500);
379 /* Check if it started successfully or not */
380 if (service_status.dwCurrentState == SERVICE_RUNNING) {
381 printf("Service started successfully\n");
382 return 0;
383 } else {
384 errmsg = format_win32_error(service_status.dwWin32ExitCode);
385 printf("Service failed to start : %s\n", errmsg);
386 tor_free(errmsg);
388 } else {
389 errmsg = format_win32_error(GetLastError());
390 printf("StartService() failed : %s\n", errmsg);
391 tor_free(errmsg);
393 return -1;
396 /** Stop the Tor service. Return 0 if the service is stopped or was not
397 * previously running. Return -1 on error. */
398 static int
399 nt_service_stop(SC_HANDLE hService)
401 /** Wait at most 10 seconds for the service to stop. */
402 #define MAX_SERVICE_WAIT_TIME 10
403 int wait_time;
404 char *errmsg = NULL;
405 nt_service_loadlibrary();
407 service_fns.QueryServiceStatus_fn(hService, &service_status);
408 if (service_status.dwCurrentState == SERVICE_STOPPED) {
409 printf("Service is already stopped\n");
410 return 0;
413 if (service_fns.ControlService_fn(hService, SERVICE_CONTROL_STOP,
414 &service_status)) {
415 wait_time = 0;
416 while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
417 (service_status.dwCurrentState != SERVICE_STOPPED) &&
418 (wait_time < MAX_SERVICE_WAIT_TIME)) {
419 Sleep(1000);
420 wait_time++;
422 if (service_status.dwCurrentState == SERVICE_STOPPED) {
423 printf("Service stopped successfully\n");
424 return 0;
425 } else if (wait_time == MAX_SERVICE_WAIT_TIME) {
426 printf("Service did not stop within %d seconds.\n", wait_time);
427 } else {
428 errmsg = format_win32_error(GetLastError());
429 printf("QueryServiceStatus() failed : %s\n",errmsg);
430 tor_free(errmsg);
432 } else {
433 errmsg = format_win32_error(GetLastError());
434 printf("ControlService() failed : %s\n", errmsg);
435 tor_free(errmsg);
437 return -1;
440 /** Build a formatted command line used for the NT service. Return a
441 * pointer to the formatted string on success, or NULL on failure. Set
442 * *<b>using_default_torrc</b> to true if we're going to use the default
443 * location to torrc, or 1 if an option was specified on the command line.
445 static char *
446 nt_service_command_line(int *using_default_torrc)
448 TCHAR tor_exe[MAX_PATH+1];
449 char tor_exe_ascii[MAX_PATH+1];
450 char *command, *options=NULL;
451 smartlist_t *sl;
452 int i, cmdlen;
453 *using_default_torrc = 1;
455 /* Get the location of tor.exe */
456 if (0 == GetModuleFileName(NULL, tor_exe, MAX_PATH))
457 return NULL;
459 /* Get the service arguments */
460 sl = smartlist_create();
461 for (i = 1; i < backup_argc; ++i) {
462 if (!strcmp(backup_argv[i], "--options") ||
463 !strcmp(backup_argv[i], "-options")) {
464 while (++i < backup_argc) {
465 if (!strcmp(backup_argv[i], "-f"))
466 *using_default_torrc = 0;
467 smartlist_add(sl, backup_argv[i]);
471 if (smartlist_len(sl))
472 options = smartlist_join_strings(sl,"\" \"",0,NULL);
473 smartlist_free(sl);
475 #ifdef UNICODE
476 wcstombs(tor_exe_ascii, tor_exe, sizeof(tor_exe_ascii));
477 #else
478 strlcpy(tor_exe_ascii, tor_exe, sizeof(tor_exe_ascii));
479 #endif
481 /* Allocate a string for the NT service command line */
482 cmdlen = strlen(tor_exe_ascii) + (options?strlen(options):0) + 32;
483 command = tor_malloc(cmdlen);
485 /* Format the service command */
486 if (options) {
487 if (tor_snprintf(command, cmdlen, "\"%s\" --nt-service \"%s\"",
488 tor_exe_ascii, options)<0) {
489 tor_free(command); /* sets command to NULL. */
491 } else { /* ! options */
492 if (tor_snprintf(command, cmdlen, "\"%s\" --nt-service",
493 tor_exe_ascii)<0) {
494 tor_free(command); /* sets command to NULL. */
498 tor_free(options);
499 return command;
502 /** Creates a Tor NT service, set to start on boot. The service will be
503 * started if installation succeeds. Returns 0 on success, or -1 on
504 * failure. */
505 static int
506 nt_service_install(int argc, char **argv)
508 /* Notes about developing NT services:
510 * 1. Don't count on your CWD. If an absolute path is not given, the
511 * fopen() function goes wrong.
512 * 2. The parameters given to the nt_service_body() function differ
513 * from those given to main() function.
516 SC_HANDLE hSCManager = NULL;
517 SC_HANDLE hService = NULL;
518 SERVICE_DESCRIPTIONA sdBuff;
519 char *command;
520 char *errmsg;
521 const char *user_acct = GENSRV_USERACCT;
522 const char *password = "";
523 int i;
524 OSVERSIONINFOEX info;
525 SID_NAME_USE sidUse;
526 DWORD sidLen = 0, domainLen = 0;
527 int is_win2k_or_worse = 0;
528 int using_default_torrc = 0;
530 nt_service_loadlibrary();
532 /* Open the service control manager so we can create a new service */
533 if ((hSCManager = nt_service_open_scm()) == NULL)
534 return -1;
535 /* Build the command line used for the service */
536 if ((command = nt_service_command_line(&using_default_torrc)) == NULL) {
537 printf("Unable to build service command line.\n");
538 service_fns.CloseServiceHandle_fn(hSCManager);
539 return -1;
542 for (i=1; i < argc; ++i) {
543 if (!strcmp(argv[i], "--user") && i+1<argc) {
544 user_acct = argv[i+1];
545 ++i;
547 if (!strcmp(argv[i], "--password") && i+1<argc) {
548 password = argv[i+1];
549 ++i;
553 /* Compute our version and see whether we're running win2k or earlier. */
554 memset(&info, 0, sizeof(info));
555 info.dwOSVersionInfoSize = sizeof(info);
556 if (! GetVersionEx((LPOSVERSIONINFO)&info)) {
557 printf("Call to GetVersionEx failed.\n");
558 is_win2k_or_worse = 1;
559 } else {
560 if (info.dwMajorVersion < 5 ||
561 (info.dwMajorVersion == 5 && info.dwMinorVersion == 0))
562 is_win2k_or_worse = 1;
565 if (user_acct == GENSRV_USERACCT) {
566 if (is_win2k_or_worse) {
567 /* On Win2k, there is no LocalService account, so we actually need to
568 * fall back on NULL (the system account). */
569 printf("Running on Win2K or earlier, so the LocalService account "
570 "doesn't exist. Falling back to SYSTEM account.\n");
571 user_acct = NULL;
572 } else {
573 /* Genericity is apparently _so_ last year in Redmond, where some
574 * accounts are accounts that you can look up, and some accounts
575 * are magic and undetectable via the security subsystem. See
576 * http://msdn2.microsoft.com/en-us/library/ms684188.aspx
578 printf("Running on a Post-Win2K OS, so we'll assume that the "
579 "LocalService account exists.\n");
581 } else if (0 && service_fns.LookupAccountNameA_fn(NULL, // On this system
582 user_acct,
583 NULL, &sidLen, // Don't care about the SID
584 NULL, &domainLen, // Don't care about the domain
585 &sidUse) == 0) {
586 /* XXXX For some reason, the above test segfaults. Fix that. */
587 printf("User \"%s\" doesn't seem to exist.\n", user_acct);
588 return -1;
589 } else {
590 printf("Will try to install service as user \"%s\".\n", user_acct);
592 /* XXXX This warning could be better about explaining how to resolve the
593 * situation. */
594 if (using_default_torrc)
595 printf("IMPORTANT NOTE:\n"
596 " The Tor service will run under the account \"%s\". This means\n"
597 " that Tor will look for its configuration file under that\n"
598 " account's Application Data directory, which is probably not\n"
599 " the same as yours.\n", user_acct?user_acct:"<local system>");
601 /* Create the Tor service, set to auto-start on boot */
602 if ((hService = service_fns.CreateServiceA_fn(hSCManager, GENSRV_SERVICENAME,
603 GENSRV_DISPLAYNAME,
604 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
605 SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
606 command, NULL, NULL, NULL,
607 user_acct, password)) == NULL) {
608 errmsg = format_win32_error(GetLastError());
609 printf("CreateService() failed : %s\n", errmsg);
610 service_fns.CloseServiceHandle_fn(hSCManager);
611 tor_free(errmsg);
612 tor_free(command);
613 return -1;
615 printf("Done with CreateService.\n");
617 /* Set the service's description */
618 sdBuff.lpDescription = (char*)GENSRV_DESCRIPTION;
619 service_fns.ChangeServiceConfig2A_fn(hService, SERVICE_CONFIG_DESCRIPTION,
620 &sdBuff);
621 printf("Service installed successfully\n");
623 /* Start the service initially */
624 nt_service_start(hService);
626 service_fns.CloseServiceHandle_fn(hService);
627 service_fns.CloseServiceHandle_fn(hSCManager);
628 tor_free(command);
630 return 0;
633 /** Removes the Tor NT service. Returns 0 if the service was successfully
634 * removed, or -1 on error. */
635 static int
636 nt_service_remove(void)
638 SC_HANDLE hSCManager = NULL;
639 SC_HANDLE hService = NULL;
640 char *errmsg;
642 nt_service_loadlibrary();
643 if ((hSCManager = nt_service_open_scm()) == NULL)
644 return -1;
645 if ((hService = nt_service_open(hSCManager)) == NULL) {
646 service_fns.CloseServiceHandle_fn(hSCManager);
647 return -1;
650 nt_service_stop(hService);
651 if (service_fns.DeleteService_fn(hService) == FALSE) {
652 errmsg = format_win32_error(GetLastError());
653 printf("DeleteService() failed : %s\n", errmsg);
654 tor_free(errmsg);
655 service_fns.CloseServiceHandle_fn(hService);
656 service_fns.CloseServiceHandle_fn(hSCManager);
657 return -1;
660 service_fns.CloseServiceHandle_fn(hService);
661 service_fns.CloseServiceHandle_fn(hSCManager);
662 printf("Service removed successfully\n");
664 return 0;
667 /** Starts the Tor service. Returns 0 on success, or -1 on error. */
668 static int
669 nt_service_cmd_start(void)
671 SC_HANDLE hSCManager;
672 SC_HANDLE hService;
673 int start;
675 if ((hSCManager = nt_service_open_scm()) == NULL)
676 return -1;
677 if ((hService = nt_service_open(hSCManager)) == NULL) {
678 service_fns.CloseServiceHandle_fn(hSCManager);
679 return -1;
682 start = nt_service_start(hService);
683 service_fns.CloseServiceHandle_fn(hService);
684 service_fns.CloseServiceHandle_fn(hSCManager);
686 return start;
689 /** Stops the Tor service. Returns 0 on success, or -1 on error. */
690 static int
691 nt_service_cmd_stop(void)
693 SC_HANDLE hSCManager;
694 SC_HANDLE hService;
695 int stop;
697 if ((hSCManager = nt_service_open_scm()) == NULL)
698 return -1;
699 if ((hService = nt_service_open(hSCManager)) == NULL) {
700 service_fns.CloseServiceHandle_fn(hSCManager);
701 return -1;
704 stop = nt_service_stop(hService);
705 service_fns.CloseServiceHandle_fn(hService);
706 service_fns.CloseServiceHandle_fn(hSCManager);
708 return stop;
712 nt_service_parse_options(int argc, char **argv, int *should_exit)
714 backup_argv = argv;
715 backup_argc = argc;
716 *should_exit = 0;
718 if ((argc >= 3) &&
719 (!strcmp(argv[1], "-service") || !strcmp(argv[1], "--service"))) {
720 nt_service_loadlibrary();
721 if (!strcmp(argv[2], "install"))
722 return nt_service_install(argc, argv);
723 if (!strcmp(argv[2], "remove"))
724 return nt_service_remove();
725 if (!strcmp(argv[2], "start"))
726 return nt_service_cmd_start();
727 if (!strcmp(argv[2], "stop"))
728 return nt_service_cmd_stop();
729 printf("Unrecognized service command '%s'\n", argv[2]);
730 *should_exit = 1;
731 return 1;
733 if (argc >= 2) {
734 if (!strcmp(argv[1], "-nt-service") || !strcmp(argv[1], "--nt-service")) {
735 nt_service_loadlibrary();
736 nt_service_main();
737 *should_exit = 1;
738 return 0;
740 // These values have been deprecated since 0.1.1.2-alpha; we've warned
741 // about them since 0.1.2.7-alpha.
742 if (!strcmp(argv[1], "-install") || !strcmp(argv[1], "--install")) {
743 nt_service_loadlibrary();
744 fprintf(stderr,
745 "The %s option is deprecated; use \"--service install\" instead.",
746 argv[1]);
747 *should_exit = 1;
748 return nt_service_install(argc, argv);
750 if (!strcmp(argv[1], "-remove") || !strcmp(argv[1], "--remove")) {
751 nt_service_loadlibrary();
752 fprintf(stderr,
753 "The %s option is deprecated; use \"--service remove\" instead.",
754 argv[1]);
755 *should_exit = 1;
756 return nt_service_remove();
759 *should_exit = 0;
760 return 0;