In routerlist_assert_ok(), check r2 before taking &(r2->cache_info)
[tor.git] / src / or / ntmain.c
blobe848314043decc7b9d7b92600d4244227a8264ea
1 /* Copyright (c) 2001-2004, Roger Dingledine.
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2013, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
6 #include "or.h"
7 #include "config.h"
8 #include "main.h"
9 #include "ntmain.h"
11 #ifdef HAVE_EVENT2_EVENT_H
12 #include <event2/event.h>
13 #else
14 #include <event.h>
15 #endif
17 #include <windows.h>
18 #define GENSRV_SERVICENAME "tor"
19 #define GENSRV_DISPLAYNAME "Tor Win32 Service"
20 #define GENSRV_DESCRIPTION \
21 "Provides an anonymous Internet communication system"
22 #define GENSRV_USERACCT "NT AUTHORITY\\LocalService"
24 // Cheating: using the pre-defined error codes, tricks Windows into displaying
25 // a semi-related human-readable error message if startup fails as
26 // opposed to simply scaring people with Error: 0xffffffff
27 #define NT_SERVICE_ERROR_TORINIT_FAILED ERROR_EXCEPTION_IN_SERVICE
29 static SERVICE_STATUS service_status;
30 static SERVICE_STATUS_HANDLE hStatus;
32 /* XXXX This 'backup argv' and 'backup argc' business is an ugly hack. This
33 * is a job for arguments, not globals. Alas, some of the functions that
34 * use them use them need to have fixed signatures, so they can be passed
35 * to the NT service functions. */
36 static char **backup_argv;
37 static int backup_argc;
39 static void nt_service_control(DWORD request);
40 static void nt_service_body(int argc, char **argv);
41 static void nt_service_main(void);
42 static SC_HANDLE nt_service_open_scm(void);
43 static SC_HANDLE nt_service_open(SC_HANDLE hSCManager);
44 static int nt_service_start(SC_HANDLE hService);
45 static int nt_service_stop(SC_HANDLE hService);
46 static int nt_service_install(int argc, char **argv);
47 static int nt_service_remove(void);
48 static int nt_service_cmd_start(void);
49 static int nt_service_cmd_stop(void);
51 /** Struct to hold dynamically loaded NT-service related function pointers.
53 struct service_fns {
54 int loaded;
56 /** @{ */
57 /** Function pointers for Windows API functions related to service
58 * management. These are NULL, or they point to the . They're set by
59 * calling the LOAD macro below. */
61 BOOL (WINAPI *ChangeServiceConfig2A_fn)(
62 SC_HANDLE hService,
63 DWORD dwInfoLevel,
64 LPVOID lpInfo);
66 BOOL (WINAPI *CloseServiceHandle_fn)(
67 SC_HANDLE hSCObject);
69 BOOL (WINAPI *ControlService_fn)(
70 SC_HANDLE hService,
71 DWORD dwControl,
72 LPSERVICE_STATUS lpServiceStatus);
74 SC_HANDLE (WINAPI *CreateServiceA_fn)(
75 SC_HANDLE hSCManager,
76 LPCSTR lpServiceName,
77 LPCSTR lpDisplayName,
78 DWORD dwDesiredAccess,
79 DWORD dwServiceType,
80 DWORD dwStartType,
81 DWORD dwErrorControl,
82 LPCSTR lpBinaryPathName,
83 LPCSTR lpLoadOrderGroup,
84 LPDWORD lpdwTagId,
85 LPCSTR lpDependencies,
86 LPCSTR lpServiceStartName,
87 LPCSTR lpPassword);
89 BOOL (WINAPI *DeleteService_fn)(
90 SC_HANDLE hService);
92 SC_HANDLE (WINAPI *OpenSCManagerA_fn)(
93 LPCSTR lpMachineName,
94 LPCSTR lpDatabaseName,
95 DWORD dwDesiredAccess);
97 SC_HANDLE (WINAPI *OpenServiceA_fn)(
98 SC_HANDLE hSCManager,
99 LPCSTR lpServiceName,
100 DWORD dwDesiredAccess);
102 BOOL (WINAPI *QueryServiceStatus_fn)(
103 SC_HANDLE hService,
104 LPSERVICE_STATUS lpServiceStatus);
106 SERVICE_STATUS_HANDLE (WINAPI *RegisterServiceCtrlHandlerA_fn)(
107 LPCSTR lpServiceName,
108 LPHANDLER_FUNCTION lpHandlerProc);
110 BOOL (WINAPI *SetServiceStatus_fn)(SERVICE_STATUS_HANDLE,
111 LPSERVICE_STATUS);
113 BOOL (WINAPI *StartServiceCtrlDispatcherA_fn)(
114 const SERVICE_TABLE_ENTRYA* lpServiceTable);
116 BOOL (WINAPI *StartServiceA_fn)(
117 SC_HANDLE hService,
118 DWORD dwNumServiceArgs,
119 LPCSTR* lpServiceArgVectors);
121 BOOL (WINAPI *LookupAccountNameA_fn)(
122 LPCSTR lpSystemName,
123 LPCSTR lpAccountName,
124 PSID Sid,
125 LPDWORD cbSid,
126 LPTSTR ReferencedDomainName,
127 LPDWORD cchReferencedDomainName,
128 PSID_NAME_USE peUse);
129 /** @} */
130 } service_fns = { 0,
131 NULL, NULL, NULL, NULL, NULL, NULL,
132 NULL, NULL, NULL, NULL, NULL, NULL,
133 NULL};
135 /** Loads functions used by NT services. Returns on success, or prints a
136 * complaint to stdout and exits on error. */
137 static void
138 nt_service_loadlibrary(void)
140 HMODULE library = 0;
141 void *fn;
143 if (service_fns.loaded)
144 return;
146 if (!(library = load_windows_system_library(TEXT("advapi32.dll")))) {
147 log_err(LD_GENERAL, "Couldn't open advapi32.dll. Are you trying to use "
148 "NT services on Windows 98? That doesn't work.");
149 goto err;
152 /* Helper macro: try to load a function named <b>f</b> from "library" into
153 * service_functions.<b>f</b>_fn. On failure, log an error message, and goto
154 * err.
156 #define LOAD(f) STMT_BEGIN \
157 if (!(fn = GetProcAddress(library, #f))) { \
158 log_err(LD_BUG, \
159 "Couldn't find %s in advapi32.dll! We probably got the " \
160 "name wrong.", #f); \
161 goto err; \
162 } else { \
163 service_fns.f ## _fn = fn; \
165 STMT_END
167 LOAD(ChangeServiceConfig2A);
168 LOAD(CloseServiceHandle);
169 LOAD(ControlService);
170 LOAD(CreateServiceA);
171 LOAD(DeleteService);
172 LOAD(OpenSCManagerA);
173 LOAD(OpenServiceA);
174 LOAD(QueryServiceStatus);
175 LOAD(RegisterServiceCtrlHandlerA);
176 LOAD(SetServiceStatus);
177 LOAD(StartServiceCtrlDispatcherA);
178 LOAD(StartServiceA);
179 LOAD(LookupAccountNameA);
181 service_fns.loaded = 1;
183 return;
184 err:
185 printf("Unable to load library support for NT services: exiting.\n");
186 exit(1);
189 /** If we're compiled to run as an NT service, and the service wants to
190 * shut down, then change our current status and return 1. Else
191 * return 0.
194 nt_service_is_stopping(void)
196 /* If we haven't loaded the function pointers, we can't possibly be an NT
197 * service trying to shut down. */
198 if (!service_fns.loaded)
199 return 0;
201 if (service_status.dwCurrentState == SERVICE_STOP_PENDING) {
202 service_status.dwWin32ExitCode = 0;
203 service_status.dwCurrentState = SERVICE_STOPPED;
204 service_fns.SetServiceStatus_fn(hStatus, &service_status);
205 return 1;
206 } else if (service_status.dwCurrentState == SERVICE_STOPPED) {
207 return 1;
209 return 0;
212 /** Set the dwCurrentState field for our service to <b>state</b>. */
213 void
214 nt_service_set_state(DWORD state)
216 service_status.dwCurrentState = state;
219 /** Handles service control requests, such as stopping or starting the
220 * Tor service. */
221 static void
222 nt_service_control(DWORD request)
224 static struct timeval exit_now;
225 exit_now.tv_sec = 0;
226 exit_now.tv_usec = 0;
228 nt_service_loadlibrary();
230 switch (request) {
231 case SERVICE_CONTROL_STOP:
232 case SERVICE_CONTROL_SHUTDOWN:
233 log_notice(LD_GENERAL,
234 "Got stop/shutdown request; shutting down cleanly.");
235 service_status.dwCurrentState = SERVICE_STOP_PENDING;
236 event_base_loopexit(tor_libevent_get_base(), &exit_now);
237 return;
239 service_fns.SetServiceStatus_fn(hStatus, &service_status);
242 /** Called when the service is started via the system's service control
243 * manager. This calls tor_init() and starts the main event loop. If
244 * tor_init() fails, the service will be stopped and exit code set to
245 * NT_SERVICE_ERROR_TORINIT_FAILED. */
246 static void
247 nt_service_body(int argc, char **argv)
249 int r;
250 (void) argc; /* unused */
251 (void) argv; /* unused */
252 nt_service_loadlibrary();
253 service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
254 service_status.dwCurrentState = SERVICE_START_PENDING;
255 service_status.dwControlsAccepted =
256 SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
257 service_status.dwWin32ExitCode = 0;
258 service_status.dwServiceSpecificExitCode = 0;
259 service_status.dwCheckPoint = 0;
260 service_status.dwWaitHint = 1000;
261 hStatus = service_fns.RegisterServiceCtrlHandlerA_fn(GENSRV_SERVICENAME,
262 (LPHANDLER_FUNCTION) nt_service_control);
264 if (hStatus == 0) {
265 /* Failed to register the service control handler function */
266 return;
269 r = tor_init(backup_argc, backup_argv);
270 if (r) {
271 /* Failed to start the Tor service */
272 r = NT_SERVICE_ERROR_TORINIT_FAILED;
273 service_status.dwCurrentState = SERVICE_STOPPED;
274 service_status.dwWin32ExitCode = r;
275 service_status.dwServiceSpecificExitCode = r;
276 service_fns.SetServiceStatus_fn(hStatus, &service_status);
277 return;
280 /* Set the service's status to SERVICE_RUNNING and start the main
281 * event loop */
282 service_status.dwCurrentState = SERVICE_RUNNING;
283 service_fns.SetServiceStatus_fn(hStatus, &service_status);
284 do_main_loop();
285 tor_cleanup();
288 /** Main service entry point. Starts the service control dispatcher and waits
289 * until the service status is set to SERVICE_STOPPED. */
290 static void
291 nt_service_main(void)
293 SERVICE_TABLE_ENTRYA table[2];
294 DWORD result = 0;
295 char *errmsg;
296 nt_service_loadlibrary();
297 table[0].lpServiceName = (char*)GENSRV_SERVICENAME;
298 table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTIONA)nt_service_body;
299 table[1].lpServiceName = NULL;
300 table[1].lpServiceProc = NULL;
302 if (!service_fns.StartServiceCtrlDispatcherA_fn(table)) {
303 result = GetLastError();
304 errmsg = format_win32_error(result);
305 printf("Service error %d : %s\n", (int) result, errmsg);
306 tor_free(errmsg);
307 if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
308 if (tor_init(backup_argc, backup_argv) < 0)
309 return;
310 switch (get_options()->command) {
311 case CMD_RUN_TOR:
312 do_main_loop();
313 break;
314 case CMD_LIST_FINGERPRINT:
315 case CMD_HASH_PASSWORD:
316 case CMD_VERIFY_CONFIG:
317 case CMD_DUMP_CONFIG:
318 log_err(LD_CONFIG, "Unsupported command (--list-fingerprint, "
319 "--hash-password, or --verify-config) in NT service.");
320 break;
321 case CMD_RUN_UNITTESTS:
322 default:
323 log_err(LD_CONFIG, "Illegal command number %d: internal error.",
324 get_options()->command);
326 tor_cleanup();
331 /** Return a handle to the service control manager on success, or NULL on
332 * failure. */
333 static SC_HANDLE
334 nt_service_open_scm(void)
336 SC_HANDLE hSCManager;
337 char *errmsg = NULL;
339 nt_service_loadlibrary();
340 if ((hSCManager = service_fns.OpenSCManagerA_fn(
341 NULL, NULL, SC_MANAGER_CREATE_SERVICE)) == NULL) {
342 errmsg = format_win32_error(GetLastError());
343 printf("OpenSCManager() failed : %s\n", errmsg);
344 tor_free(errmsg);
346 return hSCManager;
349 /** Open a handle to the Tor service using <b>hSCManager</b>. Return NULL
350 * on failure. */
351 static SC_HANDLE
352 nt_service_open(SC_HANDLE hSCManager)
354 SC_HANDLE hService;
355 char *errmsg = NULL;
356 nt_service_loadlibrary();
357 if ((hService = service_fns.OpenServiceA_fn(hSCManager, GENSRV_SERVICENAME,
358 SERVICE_ALL_ACCESS)) == NULL) {
359 errmsg = format_win32_error(GetLastError());
360 printf("OpenService() failed : %s\n", errmsg);
361 tor_free(errmsg);
363 return hService;
366 /** Start the Tor service. Return 0 if the service is started or was
367 * previously running. Return -1 on error. */
368 static int
369 nt_service_start(SC_HANDLE hService)
371 char *errmsg = NULL;
373 nt_service_loadlibrary();
375 service_fns.QueryServiceStatus_fn(hService, &service_status);
376 if (service_status.dwCurrentState == SERVICE_RUNNING) {
377 printf("Service is already running\n");
378 return 0;
381 if (service_fns.StartServiceA_fn(hService, 0, NULL)) {
382 /* Loop until the service has finished attempting to start */
383 while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
384 (service_status.dwCurrentState == SERVICE_START_PENDING)) {
385 Sleep(500);
388 /* Check if it started successfully or not */
389 if (service_status.dwCurrentState == SERVICE_RUNNING) {
390 printf("Service started successfully\n");
391 return 0;
392 } else {
393 errmsg = format_win32_error(service_status.dwWin32ExitCode);
394 printf("Service failed to start : %s\n", errmsg);
395 tor_free(errmsg);
397 } else {
398 errmsg = format_win32_error(GetLastError());
399 printf("StartService() failed : %s\n", errmsg);
400 tor_free(errmsg);
402 return -1;
405 /** Stop the Tor service. Return 0 if the service is stopped or was not
406 * previously running. Return -1 on error. */
407 static int
408 nt_service_stop(SC_HANDLE hService)
410 /** Wait at most 10 seconds for the service to stop. */
411 #define MAX_SERVICE_WAIT_TIME 10
412 int wait_time;
413 char *errmsg = NULL;
414 nt_service_loadlibrary();
416 service_fns.QueryServiceStatus_fn(hService, &service_status);
417 if (service_status.dwCurrentState == SERVICE_STOPPED) {
418 printf("Service is already stopped\n");
419 return 0;
422 if (service_fns.ControlService_fn(hService, SERVICE_CONTROL_STOP,
423 &service_status)) {
424 wait_time = 0;
425 while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
426 (service_status.dwCurrentState != SERVICE_STOPPED) &&
427 (wait_time < MAX_SERVICE_WAIT_TIME)) {
428 Sleep(1000);
429 wait_time++;
431 if (service_status.dwCurrentState == SERVICE_STOPPED) {
432 printf("Service stopped successfully\n");
433 return 0;
434 } else if (wait_time == MAX_SERVICE_WAIT_TIME) {
435 printf("Service did not stop within %d seconds.\n", wait_time);
436 } else {
437 errmsg = format_win32_error(GetLastError());
438 printf("QueryServiceStatus() failed : %s\n",errmsg);
439 tor_free(errmsg);
441 } else {
442 errmsg = format_win32_error(GetLastError());
443 printf("ControlService() failed : %s\n", errmsg);
444 tor_free(errmsg);
446 return -1;
449 /** Build a formatted command line used for the NT service. Return a
450 * pointer to the formatted string on success, or NULL on failure. Set
451 * *<b>using_default_torrc</b> to true if we're going to use the default
452 * location to torrc, or 1 if an option was specified on the command line.
454 static char *
455 nt_service_command_line(int *using_default_torrc)
457 TCHAR tor_exe[MAX_PATH+1];
458 char tor_exe_ascii[MAX_PATH*2+1];
459 char *command=NULL, *options=NULL;
460 smartlist_t *sl;
461 int i;
462 *using_default_torrc = 1;
464 /* Get the location of tor.exe */
465 if (0 == GetModuleFileName(NULL, tor_exe, MAX_PATH))
466 return NULL;
468 /* Get the service arguments */
469 sl = smartlist_new();
470 for (i = 1; i < backup_argc; ++i) {
471 if (!strcmp(backup_argv[i], "--options") ||
472 !strcmp(backup_argv[i], "-options")) {
473 while (++i < backup_argc) {
474 if (!strcmp(backup_argv[i], "-f"))
475 *using_default_torrc = 0;
476 smartlist_add(sl, backup_argv[i]);
480 if (smartlist_len(sl))
481 options = smartlist_join_strings(sl,"\" \"",0,NULL);
482 smartlist_free(sl);
484 #ifdef UNICODE
485 wcstombs(tor_exe_ascii, tor_exe, sizeof(tor_exe_ascii));
486 tor_exe_ascii[sizeof(tor_exe_ascii)-1] = '\0';
487 #else
488 strlcpy(tor_exe_ascii, tor_exe, sizeof(tor_exe_ascii));
489 #endif
491 /* Allocate a string for the NT service command line and */
492 /* Format the service command */
493 if (options) {
494 tor_asprintf(&command, "\"%s\" --nt-service \"%s\"",
495 tor_exe_ascii, options);
496 } else { /* ! options */
497 tor_asprintf(&command, "\"%s\" --nt-service", tor_exe_ascii);
500 tor_free(options);
501 return command;
504 /** Creates a Tor NT service, set to start on boot. The service will be
505 * started if installation succeeds. Returns 0 on success, or -1 on
506 * failure. */
507 static int
508 nt_service_install(int argc, char **argv)
510 /* Notes about developing NT services:
512 * 1. Don't count on your CWD. If an absolute path is not given, the
513 * fopen() function goes wrong.
514 * 2. The parameters given to the nt_service_body() function differ
515 * from those given to main() function.
518 SC_HANDLE hSCManager = NULL;
519 SC_HANDLE hService = NULL;
520 SERVICE_DESCRIPTIONA sdBuff;
521 char *command;
522 char *errmsg;
523 const char *user_acct = NULL;
524 const char *password = "";
525 int i;
526 OSVERSIONINFOEX info;
527 SID_NAME_USE sidUse;
528 DWORD sidLen = 0, domainLen = 0;
529 int is_win2k_or_worse = 0;
530 int using_default_torrc = 0;
532 nt_service_loadlibrary();
534 /* Open the service control manager so we can create a new service */
535 if ((hSCManager = nt_service_open_scm()) == NULL)
536 return -1;
537 /* Build the command line used for the service */
538 if ((command = nt_service_command_line(&using_default_torrc)) == NULL) {
539 printf("Unable to build service command line.\n");
540 service_fns.CloseServiceHandle_fn(hSCManager);
541 return -1;
544 for (i=1; i < argc; ++i) {
545 if (!strcmp(argv[i], "--user") && i+1<argc) {
546 user_acct = argv[i+1];
547 ++i;
549 if (!strcmp(argv[i], "--password") && i+1<argc) {
550 password = argv[i+1];
551 ++i;
555 /* Compute our version and see whether we're running win2k or earlier. */
556 memset(&info, 0, sizeof(info));
557 info.dwOSVersionInfoSize = sizeof(info);
558 if (! GetVersionEx((LPOSVERSIONINFO)&info)) {
559 printf("Call to GetVersionEx failed.\n");
560 is_win2k_or_worse = 1;
561 } else {
562 if (info.dwMajorVersion < 5 ||
563 (info.dwMajorVersion == 5 && info.dwMinorVersion == 0))
564 is_win2k_or_worse = 1;
567 if (!user_acct) {
568 if (is_win2k_or_worse) {
569 /* On Win2k, there is no LocalService account, so we actually need to
570 * fall back on NULL (the system account). */
571 printf("Running on Win2K or earlier, so the LocalService account "
572 "doesn't exist. Falling back to SYSTEM account.\n");
573 } else {
574 /* Genericity is apparently _so_ last year in Redmond, where some
575 * accounts are accounts that you can look up, and some accounts
576 * are magic and undetectable via the security subsystem. See
577 * http://msdn2.microsoft.com/en-us/library/ms684188.aspx
579 printf("Running on a Post-Win2K OS, so we'll assume that the "
580 "LocalService account exists.\n");
581 user_acct = GENSRV_USERACCT;
583 } else if (0 && service_fns.LookupAccountNameA_fn(NULL, // On this system
584 user_acct,
585 NULL, &sidLen, // Don't care about the SID
586 NULL, &domainLen, // Don't care about the domain
587 &sidUse) == 0) {
588 /* XXXX For some reason, the above test segfaults. Fix that. */
589 printf("User \"%s\" doesn't seem to exist.\n", user_acct);
590 return -1;
591 } else {
592 printf("Will try to install service as user \"%s\".\n", user_acct);
594 /* XXXX This warning could be better about explaining how to resolve the
595 * situation. */
596 if (using_default_torrc)
597 printf("IMPORTANT NOTE:\n"
598 " The Tor service will run under the account \"%s\". This means\n"
599 " that Tor will look for its configuration file under that\n"
600 " account's Application Data directory, which is probably not\n"
601 " the same as yours.\n", user_acct?user_acct:"<local system>");
603 /* Create the Tor service, set to auto-start on boot */
604 if ((hService = service_fns.CreateServiceA_fn(hSCManager, GENSRV_SERVICENAME,
605 GENSRV_DISPLAYNAME,
606 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
607 SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
608 command, NULL, NULL, NULL,
609 user_acct, password)) == NULL) {
610 errmsg = format_win32_error(GetLastError());
611 printf("CreateService() failed : %s\n", errmsg);
612 service_fns.CloseServiceHandle_fn(hSCManager);
613 tor_free(errmsg);
614 tor_free(command);
615 return -1;
617 printf("Done with CreateService.\n");
619 /* Set the service's description */
620 sdBuff.lpDescription = (char*)GENSRV_DESCRIPTION;
621 service_fns.ChangeServiceConfig2A_fn(hService, SERVICE_CONFIG_DESCRIPTION,
622 &sdBuff);
623 printf("Service installed successfully\n");
625 /* Start the service initially */
626 nt_service_start(hService);
628 service_fns.CloseServiceHandle_fn(hService);
629 service_fns.CloseServiceHandle_fn(hSCManager);
630 tor_free(command);
632 return 0;
635 /** Removes the Tor NT service. Returns 0 if the service was successfully
636 * removed, or -1 on error. */
637 static int
638 nt_service_remove(void)
640 SC_HANDLE hSCManager = NULL;
641 SC_HANDLE hService = NULL;
642 char *errmsg;
644 nt_service_loadlibrary();
645 if ((hSCManager = nt_service_open_scm()) == NULL)
646 return -1;
647 if ((hService = nt_service_open(hSCManager)) == NULL) {
648 service_fns.CloseServiceHandle_fn(hSCManager);
649 return -1;
652 nt_service_stop(hService);
653 if (service_fns.DeleteService_fn(hService) == FALSE) {
654 errmsg = format_win32_error(GetLastError());
655 printf("DeleteService() failed : %s\n", errmsg);
656 tor_free(errmsg);
657 service_fns.CloseServiceHandle_fn(hService);
658 service_fns.CloseServiceHandle_fn(hSCManager);
659 return -1;
662 service_fns.CloseServiceHandle_fn(hService);
663 service_fns.CloseServiceHandle_fn(hSCManager);
664 printf("Service removed successfully\n");
666 return 0;
669 /** Starts the Tor service. Returns 0 on success, or -1 on error. */
670 static int
671 nt_service_cmd_start(void)
673 SC_HANDLE hSCManager;
674 SC_HANDLE hService;
675 int start;
677 if ((hSCManager = nt_service_open_scm()) == NULL)
678 return -1;
679 if ((hService = nt_service_open(hSCManager)) == NULL) {
680 service_fns.CloseServiceHandle_fn(hSCManager);
681 return -1;
684 start = nt_service_start(hService);
685 service_fns.CloseServiceHandle_fn(hService);
686 service_fns.CloseServiceHandle_fn(hSCManager);
688 return start;
691 /** Stops the Tor service. Returns 0 on success, or -1 on error. */
692 static int
693 nt_service_cmd_stop(void)
695 SC_HANDLE hSCManager;
696 SC_HANDLE hService;
697 int stop;
699 if ((hSCManager = nt_service_open_scm()) == NULL)
700 return -1;
701 if ((hService = nt_service_open(hSCManager)) == NULL) {
702 service_fns.CloseServiceHandle_fn(hSCManager);
703 return -1;
706 stop = nt_service_stop(hService);
707 service_fns.CloseServiceHandle_fn(hService);
708 service_fns.CloseServiceHandle_fn(hSCManager);
710 return stop;
714 nt_service_parse_options(int argc, char **argv, int *should_exit)
716 backup_argv = argv;
717 backup_argc = argc;
718 *should_exit = 0;
720 if ((argc >= 3) &&
721 (!strcmp(argv[1], "-service") || !strcmp(argv[1], "--service"))) {
722 nt_service_loadlibrary();
723 *should_exit = 1;
724 if (!strcmp(argv[2], "install"))
725 return nt_service_install(argc, argv);
726 if (!strcmp(argv[2], "remove"))
727 return nt_service_remove();
728 if (!strcmp(argv[2], "start"))
729 return nt_service_cmd_start();
730 if (!strcmp(argv[2], "stop"))
731 return nt_service_cmd_stop();
732 printf("Unrecognized service command '%s'\n", argv[2]);
733 return 1;
735 if (argc >= 2) {
736 if (!strcmp(argv[1], "-nt-service") || !strcmp(argv[1], "--nt-service")) {
737 nt_service_loadlibrary();
738 nt_service_main();
739 *should_exit = 1;
740 return 0;
742 // These values have been deprecated since 0.1.1.2-alpha; we've warned
743 // about them since 0.1.2.7-alpha.
744 if (!strcmp(argv[1], "-install") || !strcmp(argv[1], "--install")) {
745 nt_service_loadlibrary();
746 fprintf(stderr,
747 "The %s option is deprecated; use \"--service install\" instead.",
748 argv[1]);
749 *should_exit = 1;
750 return nt_service_install(argc, argv);
752 if (!strcmp(argv[1], "-remove") || !strcmp(argv[1], "--remove")) {
753 nt_service_loadlibrary();
754 fprintf(stderr,
755 "The %s option is deprecated; use \"--service remove\" instead.",
756 argv[1]);
757 *should_exit = 1;
758 return nt_service_remove();
761 *should_exit = 0;
762 return 0;