New consensus params "bwconnrate" and "bwconnburst"
[tor/rransom.git] / src / or / ntmain.c
blobe5a855eec4b2139551142dd594973929fe19d20e
1 /* Copyright (c) 2001-2004, Roger Dingledine.
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2009, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
6 #define MAIN_PRIVATE
7 #include "or.h"
9 #ifdef HAVE_EVENT2_EVENT_H
10 #include <event2/event.h>
11 #else
12 #include <event.h>
13 #endif
15 #include <tchar.h>
16 #define GENSRV_SERVICENAME TEXT("tor")
17 #define GENSRV_DISPLAYNAME TEXT("Tor Win32 Service")
18 #define GENSRV_DESCRIPTION \
19 TEXT("Provides an anonymous Internet communication system")
20 #define GENSRV_USERACCT TEXT("NT AUTHORITY\\LocalService")
22 // Cheating: using the pre-defined error codes, tricks Windows into displaying
23 // a semi-related human-readable error message if startup fails as
24 // opposed to simply scaring people with Error: 0xffffffff
25 #define NT_SERVICE_ERROR_TORINIT_FAILED ERROR_EXCEPTION_IN_SERVICE
27 static SERVICE_STATUS service_status;
28 static SERVICE_STATUS_HANDLE hStatus;
30 /* XXXX This 'backup argv' and 'backup argc' business is an ugly hack. This
31 * is a job for arguments, not globals. Alas, some of the functions that
32 * use them use them need to have fixed signatures, so they can be passed
33 * to the NT service functions. */
34 static char **backup_argv;
35 static int backup_argc;
36 static char* nt_strerror(uint32_t errnum);
38 static void nt_service_control(DWORD request);
39 static void nt_service_body(int argc, char **argv);
40 static void nt_service_main(void);
41 static SC_HANDLE nt_service_open_scm(void);
42 static SC_HANDLE nt_service_open(SC_HANDLE hSCManager);
43 static int nt_service_start(SC_HANDLE hService);
44 static int nt_service_stop(SC_HANDLE hService);
45 static int nt_service_install(int argc, char **argv);
46 static int nt_service_remove(void);
47 static int nt_service_cmd_start(void);
48 static int nt_service_cmd_stop(void);
50 /** Struct to hold dynamically loaded NT-service related function pointers.
52 struct service_fns {
53 int loaded;
55 BOOL (WINAPI *ChangeServiceConfig2A_fn)(
56 SC_HANDLE hService,
57 DWORD dwInfoLevel,
58 LPVOID lpInfo);
60 BOOL (WINAPI *CloseServiceHandle_fn)(
61 SC_HANDLE hSCObject);
63 BOOL (WINAPI *ControlService_fn)(
64 SC_HANDLE hService,
65 DWORD dwControl,
66 LPSERVICE_STATUS lpServiceStatus);
68 SC_HANDLE (WINAPI *CreateServiceA_fn)(
69 SC_HANDLE hSCManager,
70 LPCTSTR lpServiceName,
71 LPCTSTR lpDisplayName,
72 DWORD dwDesiredAccess,
73 DWORD dwServiceType,
74 DWORD dwStartType,
75 DWORD dwErrorControl,
76 LPCTSTR lpBinaryPathName,
77 LPCTSTR lpLoadOrderGroup,
78 LPDWORD lpdwTagId,
79 LPCTSTR lpDependencies,
80 LPCTSTR lpServiceStartName,
81 LPCTSTR lpPassword);
83 BOOL (WINAPI *DeleteService_fn)(
84 SC_HANDLE hService);
86 SC_HANDLE (WINAPI *OpenSCManagerA_fn)(
87 LPCTSTR lpMachineName,
88 LPCTSTR lpDatabaseName,
89 DWORD dwDesiredAccess);
91 SC_HANDLE (WINAPI *OpenServiceA_fn)(
92 SC_HANDLE hSCManager,
93 LPCTSTR lpServiceName,
94 DWORD dwDesiredAccess);
96 BOOL (WINAPI *QueryServiceStatus_fn)(
97 SC_HANDLE hService,
98 LPSERVICE_STATUS lpServiceStatus);
100 SERVICE_STATUS_HANDLE (WINAPI *RegisterServiceCtrlHandlerA_fn)(
101 LPCTSTR lpServiceName,
102 LPHANDLER_FUNCTION lpHandlerProc);
104 BOOL (WINAPI *SetServiceStatus_fn)(SERVICE_STATUS_HANDLE,
105 LPSERVICE_STATUS);
107 BOOL (WINAPI *StartServiceCtrlDispatcherA_fn)(
108 const SERVICE_TABLE_ENTRY* lpServiceTable);
110 BOOL (WINAPI *StartServiceA_fn)(
111 SC_HANDLE hService,
112 DWORD dwNumServiceArgs,
113 LPCTSTR* lpServiceArgVectors);
115 BOOL (WINAPI *LookupAccountNameA_fn)(
116 LPCTSTR lpSystemName,
117 LPCTSTR lpAccountName,
118 PSID Sid,
119 LPDWORD cbSid,
120 LPTSTR ReferencedDomainName,
121 LPDWORD cchReferencedDomainName,
122 PSID_NAME_USE peUse);
123 } service_fns = { 0,
124 NULL, NULL, NULL, NULL, NULL, NULL,
125 NULL, NULL, NULL, NULL, NULL, NULL,
126 NULL};
128 /** Loads functions used by NT services. Returns on success, or prints a
129 * complaint to stdout and exits on error. */
130 static void
131 nt_service_loadlibrary(void)
133 HMODULE library = 0;
134 void *fn;
136 if (service_fns.loaded)
137 return;
139 /* XXXX Possibly, we should hardcode the location of this DLL. */
140 if (!(library = LoadLibrary("advapi32.dll"))) {
141 log_err(LD_GENERAL, "Couldn't open advapi32.dll. Are you trying to use "
142 "NT services on Windows 98? That doesn't work.");
143 goto err;
146 #define LOAD(f) STMT_BEGIN \
147 if (!(fn = GetProcAddress(library, #f))) { \
148 log_err(LD_BUG, \
149 "Couldn't find %s in advapi32.dll! We probably got the " \
150 "name wrong.", #f); \
151 goto err; \
152 } else { \
153 service_fns.f ## _fn = fn; \
155 STMT_END
157 LOAD(ChangeServiceConfig2A);
158 LOAD(CloseServiceHandle);
159 LOAD(ControlService);
160 LOAD(CreateServiceA);
161 LOAD(DeleteService);
162 LOAD(OpenSCManagerA);
163 LOAD(OpenServiceA);
164 LOAD(QueryServiceStatus);
165 LOAD(RegisterServiceCtrlHandlerA);
166 LOAD(SetServiceStatus);
167 LOAD(StartServiceCtrlDispatcherA);
168 LOAD(StartServiceA);
169 LOAD(LookupAccountNameA);
171 service_fns.loaded = 1;
173 return;
174 err:
175 printf("Unable to load library support for NT services: exiting.\n");
176 exit(1);
179 /** If we're compiled to run as an NT service, and the service wants to
180 * shut down, then change our current status and return 1. Else
181 * return 0.
184 nt_service_is_stopping(void)
185 /* XXXX this function would probably _love_ to be inline, in 0.2.0. */
187 /* If we haven't loaded the function pointers, we can't possibly be an NT
188 * service trying to shut down. */
189 if (!service_fns.loaded)
190 return 0;
192 if (service_status.dwCurrentState == SERVICE_STOP_PENDING) {
193 service_status.dwWin32ExitCode = 0;
194 service_status.dwCurrentState = SERVICE_STOPPED;
195 service_fns.SetServiceStatus_fn(hStatus, &service_status);
196 return 1;
197 } else if (service_status.dwCurrentState == SERVICE_STOPPED) {
198 return 1;
200 return 0;
203 /** Set the dwCurrentState field for our service to <b>state</b>. */
204 void
205 nt_service_set_state(DWORD state)
207 service_status.dwCurrentState = state;
210 /** Handles service control requests, such as stopping or starting the
211 * Tor service. */
212 static void
213 nt_service_control(DWORD request)
215 static struct timeval exit_now;
216 exit_now.tv_sec = 0;
217 exit_now.tv_usec = 0;
219 nt_service_loadlibrary();
221 switch (request) {
222 case SERVICE_CONTROL_STOP:
223 case SERVICE_CONTROL_SHUTDOWN:
224 log_notice(LD_GENERAL,
225 "Got stop/shutdown request; shutting down cleanly.");
226 service_status.dwCurrentState = SERVICE_STOP_PENDING;
227 event_base_loopexit(tor_libevent_get_base(), &exit_now);
228 return;
230 service_fns.SetServiceStatus_fn(hStatus, &service_status);
233 /** Called when the service is started via the system's service control
234 * manager. This calls tor_init() and starts the main event loop. If
235 * tor_init() fails, the service will be stopped and exit code set to
236 * NT_SERVICE_ERROR_TORINIT_FAILED. */
237 static void
238 nt_service_body(int argc, char **argv)
240 int r;
241 (void) argc; /* unused */
242 (void) argv; /* unused */
243 nt_service_loadlibrary();
244 service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
245 service_status.dwCurrentState = SERVICE_START_PENDING;
246 service_status.dwControlsAccepted =
247 SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
248 service_status.dwWin32ExitCode = 0;
249 service_status.dwServiceSpecificExitCode = 0;
250 service_status.dwCheckPoint = 0;
251 service_status.dwWaitHint = 1000;
252 hStatus = service_fns.RegisterServiceCtrlHandlerA_fn(GENSRV_SERVICENAME,
253 (LPHANDLER_FUNCTION) nt_service_control);
255 if (hStatus == 0) {
256 /* Failed to register the service control handler function */
257 return;
260 r = tor_init(backup_argc, backup_argv);
261 if (r) {
262 /* Failed to start the Tor service */
263 r = NT_SERVICE_ERROR_TORINIT_FAILED;
264 service_status.dwCurrentState = SERVICE_STOPPED;
265 service_status.dwWin32ExitCode = r;
266 service_status.dwServiceSpecificExitCode = r;
267 service_fns.SetServiceStatus_fn(hStatus, &service_status);
268 return;
271 /* Set the service's status to SERVICE_RUNNING and start the main
272 * event loop */
273 service_status.dwCurrentState = SERVICE_RUNNING;
274 service_fns.SetServiceStatus_fn(hStatus, &service_status);
275 do_main_loop();
276 tor_cleanup();
279 /** Main service entry point. Starts the service control dispatcher and waits
280 * until the service status is set to SERVICE_STOPPED. */
281 static void
282 nt_service_main(void)
284 SERVICE_TABLE_ENTRY table[2];
285 DWORD result = 0;
286 char *errmsg;
287 nt_service_loadlibrary();
288 table[0].lpServiceName = (char*)GENSRV_SERVICENAME;
289 table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)nt_service_body;
290 table[1].lpServiceName = NULL;
291 table[1].lpServiceProc = NULL;
293 if (!service_fns.StartServiceCtrlDispatcherA_fn(table)) {
294 result = GetLastError();
295 errmsg = nt_strerror(result);
296 printf("Service error %d : %s\n", (int) result, errmsg);
297 LocalFree(errmsg);
298 if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
299 if (tor_init(backup_argc, backup_argv) < 0)
300 return;
301 switch (get_options()->command) {
302 case CMD_RUN_TOR:
303 do_main_loop();
304 break;
305 case CMD_LIST_FINGERPRINT:
306 case CMD_HASH_PASSWORD:
307 case CMD_VERIFY_CONFIG:
308 log_err(LD_CONFIG, "Unsupported command (--list-fingerprint, "
309 "--hash-password, or --verify-config) in NT service.");
310 break;
311 case CMD_RUN_UNITTESTS:
312 default:
313 log_err(LD_CONFIG, "Illegal command number %d: internal error.",
314 get_options()->command);
316 tor_cleanup();
321 /** Return a handle to the service control manager on success, or NULL on
322 * failure. */
323 static SC_HANDLE
324 nt_service_open_scm(void)
326 SC_HANDLE hSCManager;
327 char *errmsg = NULL;
329 nt_service_loadlibrary();
330 if ((hSCManager = service_fns.OpenSCManagerA_fn(
331 NULL, NULL, SC_MANAGER_CREATE_SERVICE)) == NULL) {
332 errmsg = nt_strerror(GetLastError());
333 printf("OpenSCManager() failed : %s\n", errmsg);
334 LocalFree(errmsg);
336 return hSCManager;
339 /** Open a handle to the Tor service using <b>hSCManager</b>. Return NULL
340 * on failure. */
341 static SC_HANDLE
342 nt_service_open(SC_HANDLE hSCManager)
344 SC_HANDLE hService;
345 char *errmsg = NULL;
346 nt_service_loadlibrary();
347 if ((hService = service_fns.OpenServiceA_fn(hSCManager, GENSRV_SERVICENAME,
348 SERVICE_ALL_ACCESS)) == NULL) {
349 errmsg = nt_strerror(GetLastError());
350 printf("OpenService() failed : %s\n", errmsg);
351 LocalFree(errmsg);
353 return hService;
356 /** Start the Tor service. Return 0 if the service is started or was
357 * previously running. Return -1 on error. */
358 static int
359 nt_service_start(SC_HANDLE hService)
361 char *errmsg = NULL;
363 nt_service_loadlibrary();
365 service_fns.QueryServiceStatus_fn(hService, &service_status);
366 if (service_status.dwCurrentState == SERVICE_RUNNING) {
367 printf("Service is already running\n");
368 return 0;
371 if (service_fns.StartServiceA_fn(hService, 0, NULL)) {
372 /* Loop until the service has finished attempting to start */
373 while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
374 (service_status.dwCurrentState == SERVICE_START_PENDING)) {
375 Sleep(500);
378 /* Check if it started successfully or not */
379 if (service_status.dwCurrentState == SERVICE_RUNNING) {
380 printf("Service started successfully\n");
381 return 0;
382 } else {
383 errmsg = nt_strerror(service_status.dwWin32ExitCode);
384 printf("Service failed to start : %s\n", errmsg);
385 LocalFree(errmsg);
387 } else {
388 errmsg = nt_strerror(GetLastError());
389 printf("StartService() failed : %s\n", errmsg);
390 LocalFree(errmsg);
392 return -1;
395 /** Stop the Tor service. Return 0 if the service is stopped or was not
396 * previously running. Return -1 on error. */
397 static int
398 nt_service_stop(SC_HANDLE hService)
400 /** Wait at most 10 seconds for the service to stop. */
401 #define MAX_SERVICE_WAIT_TIME 10
402 int wait_time;
403 char *errmsg = NULL;
404 nt_service_loadlibrary();
406 service_fns.QueryServiceStatus_fn(hService, &service_status);
407 if (service_status.dwCurrentState == SERVICE_STOPPED) {
408 printf("Service is already stopped\n");
409 return 0;
412 if (service_fns.ControlService_fn(hService, SERVICE_CONTROL_STOP,
413 &service_status)) {
414 wait_time = 0;
415 while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
416 (service_status.dwCurrentState != SERVICE_STOPPED) &&
417 (wait_time < MAX_SERVICE_WAIT_TIME)) {
418 Sleep(1000);
419 wait_time++;
421 if (service_status.dwCurrentState == SERVICE_STOPPED) {
422 printf("Service stopped successfully\n");
423 return 0;
424 } else if (wait_time == MAX_SERVICE_WAIT_TIME) {
425 printf("Service did not stop within %d seconds.\n", wait_time);
426 } else {
427 errmsg = nt_strerror(GetLastError());
428 printf("QueryServiceStatus() failed : %s\n",errmsg);
429 LocalFree(errmsg);
431 } else {
432 errmsg = nt_strerror(GetLastError());
433 printf("ControlService() failed : %s\n", errmsg);
434 LocalFree(errmsg);
436 return -1;
439 /** Build a formatted command line used for the NT service. Return a
440 * pointer to the formatted string on success, or NULL on failure. Set
441 * *<b>using_default_torrc</b> to true if we're going to use the default
442 * location to torrc, or 1 if an option was specified on the command line.
444 static char *
445 nt_service_command_line(int *using_default_torrc)
447 TCHAR tor_exe[MAX_PATH+1];
448 char *command, *options=NULL;
449 smartlist_t *sl;
450 int i, cmdlen;
451 *using_default_torrc = 1;
453 /* Get the location of tor.exe */
454 if (0 == GetModuleFileName(NULL, tor_exe, MAX_PATH))
455 return NULL;
457 /* Get the service arguments */
458 sl = smartlist_create();
459 for (i = 1; i < backup_argc; ++i) {
460 if (!strcmp(backup_argv[i], "--options") ||
461 !strcmp(backup_argv[i], "-options")) {
462 while (++i < backup_argc) {
463 if (!strcmp(backup_argv[i], "-f"))
464 *using_default_torrc = 0;
465 smartlist_add(sl, backup_argv[i]);
469 if (smartlist_len(sl))
470 options = smartlist_join_strings(sl,"\" \"",0,NULL);
471 smartlist_free(sl);
473 /* Allocate a string for the NT service command line */
474 cmdlen = strlen(tor_exe) + (options?strlen(options):0) + 32;
475 command = tor_malloc(cmdlen);
477 /* Format the service command */
478 if (options) {
479 if (tor_snprintf(command, cmdlen, "\"%s\" --nt-service \"%s\"",
480 tor_exe, options)<0) {
481 tor_free(command); /* sets command to NULL. */
483 } else { /* ! options */
484 if (tor_snprintf(command, cmdlen, "\"%s\" --nt-service", tor_exe)<0) {
485 tor_free(command); /* sets command to NULL. */
489 tor_free(options);
490 return command;
493 /** Creates a Tor NT service, set to start on boot. The service will be
494 * started if installation succeeds. Returns 0 on success, or -1 on
495 * failure. */
496 static int
497 nt_service_install(int argc, char **argv)
499 /* Notes about developing NT services:
501 * 1. Don't count on your CWD. If an absolute path is not given, the
502 * fopen() function goes wrong.
503 * 2. The parameters given to the nt_service_body() function differ
504 * from those given to main() function.
507 SC_HANDLE hSCManager = NULL;
508 SC_HANDLE hService = NULL;
509 SERVICE_DESCRIPTION sdBuff;
510 char *command;
511 char *errmsg;
512 const char *user_acct = GENSRV_USERACCT;
513 const char *password = "";
514 int i;
515 OSVERSIONINFOEX info;
516 SID_NAME_USE sidUse;
517 DWORD sidLen = 0, domainLen = 0;
518 int is_win2k_or_worse = 0;
519 int using_default_torrc = 0;
521 nt_service_loadlibrary();
523 /* Open the service control manager so we can create a new service */
524 if ((hSCManager = nt_service_open_scm()) == NULL)
525 return -1;
526 /* Build the command line used for the service */
527 if ((command = nt_service_command_line(&using_default_torrc)) == NULL) {
528 printf("Unable to build service command line.\n");
529 service_fns.CloseServiceHandle_fn(hSCManager);
530 return -1;
533 for (i=1; i < argc; ++i) {
534 if (!strcmp(argv[i], "--user") && i+1<argc) {
535 user_acct = argv[i+1];
536 ++i;
538 if (!strcmp(argv[i], "--password") && i+1<argc) {
539 password = argv[i+1];
540 ++i;
544 /* Compute our version and see whether we're running win2k or earlier. */
545 memset(&info, 0, sizeof(info));
546 info.dwOSVersionInfoSize = sizeof(info);
547 if (! GetVersionEx((LPOSVERSIONINFO)&info)) {
548 printf("Call to GetVersionEx failed.\n");
549 is_win2k_or_worse = 1;
550 } else {
551 if (info.dwMajorVersion < 5 ||
552 (info.dwMajorVersion == 5 && info.dwMinorVersion == 0))
553 is_win2k_or_worse = 1;
556 if (user_acct == GENSRV_USERACCT) {
557 if (is_win2k_or_worse) {
558 /* On Win2k, there is no LocalService account, so we actually need to
559 * fall back on NULL (the system account). */
560 printf("Running on Win2K or earlier, so the LocalService account "
561 "doesn't exist. Falling back to SYSTEM account.\n");
562 user_acct = NULL;
563 } else {
564 /* Genericity is apparently _so_ last year in Redmond, where some
565 * accounts are accounts that you can look up, and some accounts
566 * are magic and undetectable via the security subsystem. See
567 * http://msdn2.microsoft.com/en-us/library/ms684188.aspx
569 printf("Running on a Post-Win2K OS, so we'll assume that the "
570 "LocalService account exists.\n");
572 } else if (0 && service_fns.LookupAccountNameA_fn(NULL, // On this system
573 user_acct,
574 NULL, &sidLen, // Don't care about the SID
575 NULL, &domainLen, // Don't care about the domain
576 &sidUse) == 0) {
577 /* XXXX For some reason, the above test segfaults. Fix that. */
578 printf("User \"%s\" doesn't seem to exist.\n", user_acct);
579 return -1;
580 } else {
581 printf("Will try to install service as user \"%s\".\n", user_acct);
583 /* XXXX This warning could be better about explaining how to resolve the
584 * situation. */
585 if (using_default_torrc)
586 printf("IMPORTANT NOTE:\n"
587 " The Tor service will run under the account \"%s\". This means\n"
588 " that Tor will look for its configuration file under that\n"
589 " account's Application Data directory, which is probably not\n"
590 " the same as yours.\n", user_acct?user_acct:"<local system>");
592 /* Create the Tor service, set to auto-start on boot */
593 if ((hService = service_fns.CreateServiceA_fn(hSCManager, GENSRV_SERVICENAME,
594 GENSRV_DISPLAYNAME,
595 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
596 SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
597 command, NULL, NULL, NULL,
598 user_acct, password)) == NULL) {
599 errmsg = nt_strerror(GetLastError());
600 printf("CreateService() failed : %s\n", errmsg);
601 service_fns.CloseServiceHandle_fn(hSCManager);
602 LocalFree(errmsg);
603 tor_free(command);
604 return -1;
606 printf("Done with CreateService.\n");
608 /* Set the service's description */
609 sdBuff.lpDescription = (char*)GENSRV_DESCRIPTION;
610 service_fns.ChangeServiceConfig2A_fn(hService, SERVICE_CONFIG_DESCRIPTION,
611 &sdBuff);
612 printf("Service installed successfully\n");
614 /* Start the service initially */
615 nt_service_start(hService);
617 service_fns.CloseServiceHandle_fn(hService);
618 service_fns.CloseServiceHandle_fn(hSCManager);
619 tor_free(command);
621 return 0;
624 /** Removes the Tor NT service. Returns 0 if the service was successfully
625 * removed, or -1 on error. */
626 static int
627 nt_service_remove(void)
629 SC_HANDLE hSCManager = NULL;
630 SC_HANDLE hService = NULL;
631 char *errmsg;
633 nt_service_loadlibrary();
634 if ((hSCManager = nt_service_open_scm()) == NULL)
635 return -1;
636 if ((hService = nt_service_open(hSCManager)) == NULL) {
637 service_fns.CloseServiceHandle_fn(hSCManager);
638 return -1;
641 nt_service_stop(hService);
642 if (service_fns.DeleteService_fn(hService) == FALSE) {
643 errmsg = nt_strerror(GetLastError());
644 printf("DeleteService() failed : %s\n", errmsg);
645 LocalFree(errmsg);
646 service_fns.CloseServiceHandle_fn(hService);
647 service_fns.CloseServiceHandle_fn(hSCManager);
648 return -1;
651 service_fns.CloseServiceHandle_fn(hService);
652 service_fns.CloseServiceHandle_fn(hSCManager);
653 printf("Service removed successfully\n");
655 return 0;
658 /** Starts the Tor service. Returns 0 on success, or -1 on error. */
659 static int
660 nt_service_cmd_start(void)
662 SC_HANDLE hSCManager;
663 SC_HANDLE hService;
664 int start;
666 if ((hSCManager = nt_service_open_scm()) == NULL)
667 return -1;
668 if ((hService = nt_service_open(hSCManager)) == NULL) {
669 service_fns.CloseServiceHandle_fn(hSCManager);
670 return -1;
673 start = nt_service_start(hService);
674 service_fns.CloseServiceHandle_fn(hService);
675 service_fns.CloseServiceHandle_fn(hSCManager);
677 return start;
680 /** Stops the Tor service. Returns 0 on success, or -1 on error. */
681 static int
682 nt_service_cmd_stop(void)
684 SC_HANDLE hSCManager;
685 SC_HANDLE hService;
686 int stop;
688 if ((hSCManager = nt_service_open_scm()) == NULL)
689 return -1;
690 if ((hService = nt_service_open(hSCManager)) == NULL) {
691 service_fns.CloseServiceHandle_fn(hSCManager);
692 return -1;
695 stop = nt_service_stop(hService);
696 service_fns.CloseServiceHandle_fn(hService);
697 service_fns.CloseServiceHandle_fn(hSCManager);
699 return stop;
702 /** Given a Win32 error code, this attempts to make Windows
703 * return a human-readable error message. The char* returned
704 * is allocated by Windows, but should be freed with LocalFree()
705 * when finished with it. */
706 static char*
707 nt_strerror(uint32_t errnum)
709 char *msgbuf;
710 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
711 NULL, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
712 (LPSTR)&msgbuf, 0, NULL);
713 return msgbuf;
717 nt_service_parse_options(int argc, char **argv, int *should_exit)
719 backup_argv = argv;
720 backup_argc = argc;
721 *should_exit = 0;
723 if ((argc >= 3) &&
724 (!strcmp(argv[1], "-service") || !strcmp(argv[1], "--service"))) {
725 nt_service_loadlibrary();
726 if (!strcmp(argv[2], "install"))
727 return nt_service_install(argc, argv);
728 if (!strcmp(argv[2], "remove"))
729 return nt_service_remove();
730 if (!strcmp(argv[2], "start"))
731 return nt_service_cmd_start();
732 if (!strcmp(argv[2], "stop"))
733 return nt_service_cmd_stop();
734 printf("Unrecognized service command '%s'\n", argv[2]);
735 *should_exit = 1;
736 return 1;
738 if (argc >= 2) {
739 if (!strcmp(argv[1], "-nt-service") || !strcmp(argv[1], "--nt-service")) {
740 nt_service_loadlibrary();
741 nt_service_main();
742 *should_exit = 1;
743 return 0;
745 // These values have been deprecated since 0.1.1.2-alpha; we've warned
746 // about them since 0.1.2.7-alpha.
747 if (!strcmp(argv[1], "-install") || !strcmp(argv[1], "--install")) {
748 nt_service_loadlibrary();
749 fprintf(stderr,
750 "The %s option is deprecated; use \"--service install\" instead.",
751 argv[1]);
752 *should_exit = 1;
753 return nt_service_install(argc, argv);
755 if (!strcmp(argv[1], "-remove") || !strcmp(argv[1], "--remove")) {
756 nt_service_loadlibrary();
757 fprintf(stderr,
758 "The %s option is deprecated; use \"--service remove\" instead.",
759 argv[1]);
760 *should_exit = 1;
761 return nt_service_remove();
764 *should_exit = 0;
765 return 0;