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