<weasel> tortls.c: In function `tor_tls_client_is_using_v2_ciphers':
[tor.git] / src / or / ntmain.c
blob06d0af4e00e095e8b90cffef4858ee9a3fbccb92
1 /* Copyright (c) 2001-2004, Roger Dingledine.
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2008, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
5 /* $Id$ */
7 #define MAIN_PRIVATE
8 #include "or.h"
10 const char ntmain_c_id[] =
11 "$Id$";
13 #include <tchar.h>
14 #define GENSRV_SERVICENAME TEXT("tor")
15 #define GENSRV_DISPLAYNAME TEXT("Tor Win32 Service")
16 #define GENSRV_DESCRIPTION \
17 TEXT("Provides an anonymous Internet communication system")
18 #define GENSRV_USERACCT TEXT("NT AUTHORITY\\LocalService")
20 // Cheating: using the pre-defined error codes, tricks Windows into displaying
21 // a semi-related human-readable error message if startup fails as
22 // opposed to simply scaring people with Error: 0xffffffff
23 #define NT_SERVICE_ERROR_TORINIT_FAILED ERROR_EXCEPTION_IN_SERVICE
25 static SERVICE_STATUS service_status;
26 static SERVICE_STATUS_HANDLE hStatus;
28 /* XXXX This 'backup argv' and 'backup argc' business is an ugly hack. This
29 * is a job for arguments, not globals. Alas, some of the functions that
30 * use them use them need to have fixed signatures, so they can be passed
31 * to the NT service functions. */
32 static char **backup_argv;
33 static int backup_argc;
34 static char* nt_strerror(uint32_t errnum);
36 static void nt_service_control(DWORD request);
37 static void nt_service_body(int argc, char **argv);
38 static void nt_service_main(void);
39 static SC_HANDLE nt_service_open_scm(void);
40 static SC_HANDLE nt_service_open(SC_HANDLE hSCManager);
41 static int nt_service_start(SC_HANDLE hService);
42 static int nt_service_stop(SC_HANDLE hService);
43 static int nt_service_install(int argc, char **argv);
44 static int nt_service_remove(void);
45 static int nt_service_cmd_start(void);
46 static int nt_service_cmd_stop(void);
48 /** Struct to hold dynamically loaded NT-service related function pointers.
50 struct service_fns {
51 int loaded;
53 BOOL (WINAPI *ChangeServiceConfig2A_fn)(
54 SC_HANDLE hService,
55 DWORD dwInfoLevel,
56 LPVOID lpInfo);
58 BOOL (WINAPI *CloseServiceHandle_fn)(
59 SC_HANDLE hSCObject);
61 BOOL (WINAPI *ControlService_fn)(
62 SC_HANDLE hService,
63 DWORD dwControl,
64 LPSERVICE_STATUS lpServiceStatus);
66 SC_HANDLE (WINAPI *CreateServiceA_fn)(
67 SC_HANDLE hSCManager,
68 LPCTSTR lpServiceName,
69 LPCTSTR lpDisplayName,
70 DWORD dwDesiredAccess,
71 DWORD dwServiceType,
72 DWORD dwStartType,
73 DWORD dwErrorControl,
74 LPCTSTR lpBinaryPathName,
75 LPCTSTR lpLoadOrderGroup,
76 LPDWORD lpdwTagId,
77 LPCTSTR lpDependencies,
78 LPCTSTR lpServiceStartName,
79 LPCTSTR lpPassword);
81 BOOL (WINAPI *DeleteService_fn)(
82 SC_HANDLE hService);
84 SC_HANDLE (WINAPI *OpenSCManagerA_fn)(
85 LPCTSTR lpMachineName,
86 LPCTSTR lpDatabaseName,
87 DWORD dwDesiredAccess);
89 SC_HANDLE (WINAPI *OpenServiceA_fn)(
90 SC_HANDLE hSCManager,
91 LPCTSTR lpServiceName,
92 DWORD dwDesiredAccess);
94 BOOL (WINAPI *QueryServiceStatus_fn)(
95 SC_HANDLE hService,
96 LPSERVICE_STATUS lpServiceStatus);
98 SERVICE_STATUS_HANDLE (WINAPI *RegisterServiceCtrlHandlerA_fn)(
99 LPCTSTR lpServiceName,
100 LPHANDLER_FUNCTION lpHandlerProc);
102 BOOL (WINAPI *SetServiceStatus_fn)(SERVICE_STATUS_HANDLE,
103 LPSERVICE_STATUS);
105 BOOL (WINAPI *StartServiceCtrlDispatcherA_fn)(
106 const SERVICE_TABLE_ENTRY* lpServiceTable);
108 BOOL (WINAPI *StartServiceA_fn)(
109 SC_HANDLE hService,
110 DWORD dwNumServiceArgs,
111 LPCTSTR* lpServiceArgVectors);
113 BOOL (WINAPI *LookupAccountNameA_fn)(
114 LPCTSTR lpSystemName,
115 LPCTSTR lpAccountName,
116 PSID Sid,
117 LPDWORD cbSid,
118 LPTSTR ReferencedDomainName,
119 LPDWORD cchReferencedDomainName,
120 PSID_NAME_USE peUse);
121 } service_fns = { 0,
122 NULL, NULL, NULL, NULL, NULL, NULL,
123 NULL, NULL, NULL, NULL, NULL, NULL,
124 NULL};
126 /** Loads functions used by NT services. Returns on success, or prints a
127 * complaint to stdout and exits on error. */
128 static void
129 nt_service_loadlibrary(void)
131 HMODULE library = 0;
132 void *fn;
134 if (service_fns.loaded)
135 return;
137 /* XXXX Possibly, we should hardcode the location of this DLL. */
138 if (!(library = LoadLibrary("advapi32.dll"))) {
139 log_err(LD_GENERAL, "Couldn't open advapi32.dll. Are you trying to use "
140 "NT services on Windows 98? That doesn't work.");
141 goto err;
144 #define LOAD(f) STMT_BEGIN \
145 if (!(fn = GetProcAddress(library, #f))) { \
146 log_err(LD_BUG, \
147 "Couldn't find %s in advapi32.dll! We probably got the " \
148 "name wrong.", #f); \
149 goto err; \
150 } else { \
151 service_fns.f ## _fn = fn; \
153 STMT_END
155 LOAD(ChangeServiceConfig2A);
156 LOAD(CloseServiceHandle);
157 LOAD(ControlService);
158 LOAD(CreateServiceA);
159 LOAD(DeleteService);
160 LOAD(OpenSCManagerA);
161 LOAD(OpenServiceA);
162 LOAD(QueryServiceStatus);
163 LOAD(RegisterServiceCtrlHandlerA);
164 LOAD(SetServiceStatus);
165 LOAD(StartServiceCtrlDispatcherA);
166 LOAD(StartServiceA);
167 LOAD(LookupAccountNameA);
169 service_fns.loaded = 1;
171 return;
172 err:
173 printf("Unable to load library support for NT services: exiting.\n");
174 exit(1);
177 /** If we're compiled to run as an NT service, and the service wants to
178 * shut down, then change our current status and return 1. Else
179 * return 0.
182 nt_service_is_stopping(void)
183 /* XXXX this function would probably _love_ to be inline, in 0.2.0. */
185 /* If we haven't loaded the function pointers, we can't possibly be an NT
186 * service trying to shut down. */
187 if (!service_fns.loaded)
188 return 0;
190 if (service_status.dwCurrentState == SERVICE_STOP_PENDING) {
191 service_status.dwWin32ExitCode = 0;
192 service_status.dwCurrentState = SERVICE_STOPPED;
193 service_fns.SetServiceStatus_fn(hStatus, &service_status);
194 return 1;
195 } else if (service_status.dwCurrentState == SERVICE_STOPPED) {
196 return 1;
198 return 0;
201 /** Set the dwCurrentState field for our service to <b>state</b>. */
202 void
203 nt_service_set_state(DWORD state)
205 service_status.dwCurrentState = state;
208 /** Handles service control requests, such as stopping or starting the
209 * Tor service. */
210 static void
211 nt_service_control(DWORD request)
213 static struct timeval exit_now;
214 exit_now.tv_sec = 0;
215 exit_now.tv_usec = 0;
217 nt_service_loadlibrary();
219 switch (request) {
220 case SERVICE_CONTROL_STOP:
221 case SERVICE_CONTROL_SHUTDOWN:
222 log_notice(LD_GENERAL,
223 "Got stop/shutdown request; shutting down cleanly.");
224 service_status.dwCurrentState = SERVICE_STOP_PENDING;
225 event_loopexit(&exit_now);
226 return;
228 service_fns.SetServiceStatus_fn(hStatus, &service_status);
231 /** Called when the service is started via the system's service control
232 * manager. This calls tor_init() and starts the main event loop. If
233 * tor_init() fails, the service will be stopped and exit code set to
234 * NT_SERVICE_ERROR_TORINIT_FAILED. */
235 static void
236 nt_service_body(int argc, char **argv)
238 int r;
239 (void) argc; /* unused */
240 (void) argv; /* unused */
241 nt_service_loadlibrary();
242 service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
243 service_status.dwCurrentState = SERVICE_START_PENDING;
244 service_status.dwControlsAccepted =
245 SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
246 service_status.dwWin32ExitCode = 0;
247 service_status.dwServiceSpecificExitCode = 0;
248 service_status.dwCheckPoint = 0;
249 service_status.dwWaitHint = 1000;
250 hStatus = service_fns.RegisterServiceCtrlHandlerA_fn(GENSRV_SERVICENAME,
251 (LPHANDLER_FUNCTION) nt_service_control);
253 if (hStatus == 0) {
254 /* Failed to register the service control handler function */
255 return;
258 r = tor_init(backup_argc, backup_argv);
259 if (r) {
260 /* Failed to start the Tor service */
261 r = NT_SERVICE_ERROR_TORINIT_FAILED;
262 service_status.dwCurrentState = SERVICE_STOPPED;
263 service_status.dwWin32ExitCode = r;
264 service_status.dwServiceSpecificExitCode = r;
265 service_fns.SetServiceStatus_fn(hStatus, &service_status);
266 return;
269 /* Set the service's status to SERVICE_RUNNING and start the main
270 * event loop */
271 service_status.dwCurrentState = SERVICE_RUNNING;
272 service_fns.SetServiceStatus_fn(hStatus, &service_status);
273 do_main_loop();
274 tor_cleanup();
277 /** Main service entry point. Starts the service control dispatcher and waits
278 * until the service status is set to SERVICE_STOPPED. */
279 static void
280 nt_service_main(void)
282 SERVICE_TABLE_ENTRY table[2];
283 DWORD result = 0;
284 char *errmsg;
285 nt_service_loadlibrary();
286 table[0].lpServiceName = (char*)GENSRV_SERVICENAME;
287 table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)nt_service_body;
288 table[1].lpServiceName = NULL;
289 table[1].lpServiceProc = NULL;
291 if (!service_fns.StartServiceCtrlDispatcherA_fn(table)) {
292 result = GetLastError();
293 errmsg = nt_strerror(result);
294 printf("Service error %d : %s\n", (int) result, errmsg);
295 LocalFree(errmsg);
296 if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
297 if (tor_init(backup_argc, backup_argv) < 0)
298 return;
299 switch (get_options()->command) {
300 case CMD_RUN_TOR:
301 do_main_loop();
302 break;
303 case CMD_LIST_FINGERPRINT:
304 do_list_fingerprint();
305 break;
306 case CMD_HASH_PASSWORD:
307 do_hash_password();
308 break;
309 case CMD_VERIFY_CONFIG:
310 printf("Configuration was valid\n");
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 = nt_strerror(GetLastError());
334 printf("OpenSCManager() failed : %s\n", errmsg);
335 LocalFree(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 = nt_strerror(GetLastError());
351 printf("OpenService() failed : %s\n", errmsg);
352 LocalFree(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 = nt_strerror(service_status.dwWin32ExitCode);
385 printf("Service failed to start : %s\n", errmsg);
386 LocalFree(errmsg);
388 } else {
389 errmsg = nt_strerror(GetLastError());
390 printf("StartService() failed : %s\n", errmsg);
391 LocalFree(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 = nt_strerror(GetLastError());
429 printf("QueryServiceStatus() failed : %s\n",errmsg);
430 LocalFree(errmsg);
432 } else {
433 errmsg = nt_strerror(GetLastError());
434 printf("ControlService() failed : %s\n", errmsg);
435 LocalFree(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 *command, *options=NULL;
450 smartlist_t *sl;
451 int i, cmdlen;
452 *using_default_torrc = 1;
454 /* Get the location of tor.exe */
455 if (0 == GetModuleFileName(NULL, tor_exe, MAX_PATH))
456 return NULL;
458 /* Get the service arguments */
459 sl = smartlist_create();
460 for (i = 1; i < backup_argc; ++i) {
461 if (!strcmp(backup_argv[i], "--options") ||
462 !strcmp(backup_argv[i], "-options")) {
463 while (++i < backup_argc) {
464 if (!strcmp(backup_argv[i], "-f"))
465 *using_default_torrc = 0;
466 smartlist_add(sl, backup_argv[i]);
470 if (smartlist_len(sl))
471 options = smartlist_join_strings(sl,"\" \"",0,NULL);
472 smartlist_free(sl);
474 /* Allocate a string for the NT service command line */
475 cmdlen = strlen(tor_exe) + (options?strlen(options):0) + 32;
476 command = tor_malloc(cmdlen);
478 /* Format the service command */
479 if (options) {
480 if (tor_snprintf(command, cmdlen, "\"%s\" --nt-service \"%s\"",
481 tor_exe, options)<0) {
482 tor_free(command); /* sets command to NULL. */
484 } else { /* ! options */
485 if (tor_snprintf(command, cmdlen, "\"%s\" --nt-service", tor_exe)<0) {
486 tor_free(command); /* sets command to NULL. */
490 tor_free(options);
491 return command;
494 /** Creates a Tor NT service, set to start on boot. The service will be
495 * started if installation succeeds. Returns 0 on success, or -1 on
496 * failure. */
497 static int
498 nt_service_install(int argc, char **argv)
500 /* Notes about developing NT services:
502 * 1. Don't count on your CWD. If an absolute path is not given, the
503 * fopen() function goes wrong.
504 * 2. The parameters given to the nt_service_body() function differ
505 * from those given to main() function.
508 SC_HANDLE hSCManager = NULL;
509 SC_HANDLE hService = NULL;
510 SERVICE_DESCRIPTION sdBuff;
511 char *command;
512 char *errmsg;
513 const char *user_acct = GENSRV_USERACCT;
514 const char *password = "";
515 int i;
516 OSVERSIONINFOEX info;
517 SID_NAME_USE sidUse;
518 DWORD sidLen = 0, domainLen = 0;
519 int is_win2k_or_worse = 0;
520 int using_default_torrc = 0;
522 nt_service_loadlibrary();
524 /* Open the service control manager so we can create a new service */
525 if ((hSCManager = nt_service_open_scm()) == NULL)
526 return -1;
527 /* Build the command line used for the service */
528 if ((command = nt_service_command_line(&using_default_torrc)) == NULL) {
529 printf("Unable to build service command line.\n");
530 service_fns.CloseServiceHandle_fn(hSCManager);
531 return -1;
534 for (i=1; i < argc; ++i) {
535 if (!strcmp(argv[i], "--user") && i+1<argc) {
536 user_acct = argv[i+1];
537 ++i;
539 if (!strcmp(argv[i], "--password") && i+1<argc) {
540 password = argv[i+1];
541 ++i;
545 /* Compute our version and see whether we're running win2k or earlier. */
546 memset(&info, 0, sizeof(info));
547 info.dwOSVersionInfoSize = sizeof(info);
548 if (! GetVersionEx((LPOSVERSIONINFO)&info)) {
549 printf("Call to GetVersionEx failed.\n");
550 is_win2k_or_worse = 1;
551 } else {
552 if (info.dwMajorVersion < 5 ||
553 (info.dwMajorVersion == 5 && info.dwMinorVersion == 0))
554 is_win2k_or_worse = 1;
557 if (user_acct == GENSRV_USERACCT) {
558 if (is_win2k_or_worse) {
559 /* On Win2k, there is no LocalService account, so we actually need to
560 * fall back on NULL (the system account). */
561 printf("Running on Win2K or earlier, so the LocalService account "
562 "doesn't exist. Falling back to SYSTEM account.\n");
563 user_acct = NULL;
564 } else {
565 /* Genericity is apparently _so_ last year in Redmond, where some
566 * accounts are accounts that you can look up, and some accounts
567 * are magic and undetectable via the security subsystem. See
568 * http://msdn2.microsoft.com/en-us/library/ms684188.aspx
570 printf("Running on a Post-Win2K OS, so we'll assume that the "
571 "LocalService account exists.\n");
573 } else if (0 && service_fns.LookupAccountNameA_fn(NULL, // On this system
574 user_acct,
575 NULL, &sidLen, // Don't care about the SID
576 NULL, &domainLen, // Don't care about the domain
577 &sidUse) == 0) {
578 /* XXXX For some reason, the above test segfaults. Fix that. */
579 printf("User \"%s\" doesn't seem to exist.\n", user_acct);
580 return -1;
581 } else {
582 printf("Will try to install service as user \"%s\".\n", user_acct);
584 /* XXXX This warning could be better about explaining how to resolve the
585 * situation. */
586 if (using_default_torrc)
587 printf("IMPORTANT NOTE:\n"
588 " The Tor service will run under the account \"%s\". This means\n"
589 " that Tor will look for its configuration file under that\n"
590 " account's Application Data directory, which is probably not\n"
591 " the same as yours.\n", user_acct?user_acct:"<local system>");
593 /* Create the Tor service, set to auto-start on boot */
594 if ((hService = service_fns.CreateServiceA_fn(hSCManager, GENSRV_SERVICENAME,
595 GENSRV_DISPLAYNAME,
596 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
597 SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
598 command, NULL, NULL, NULL,
599 user_acct, password)) == NULL) {
600 errmsg = nt_strerror(GetLastError());
601 printf("CreateService() failed : %s\n", errmsg);
602 service_fns.CloseServiceHandle_fn(hSCManager);
603 LocalFree(errmsg);
604 tor_free(command);
605 return -1;
607 printf("Done with CreateService.\n");
609 /* Set the service's description */
610 sdBuff.lpDescription = (char*)GENSRV_DESCRIPTION;
611 service_fns.ChangeServiceConfig2A_fn(hService, SERVICE_CONFIG_DESCRIPTION,
612 &sdBuff);
613 printf("Service installed successfully\n");
615 /* Start the service initially */
616 nt_service_start(hService);
618 service_fns.CloseServiceHandle_fn(hService);
619 service_fns.CloseServiceHandle_fn(hSCManager);
620 tor_free(command);
622 return 0;
625 /** Removes the Tor NT service. Returns 0 if the service was successfully
626 * removed, or -1 on error. */
627 static int
628 nt_service_remove(void)
630 SC_HANDLE hSCManager = NULL;
631 SC_HANDLE hService = NULL;
632 char *errmsg;
634 nt_service_loadlibrary();
635 if ((hSCManager = nt_service_open_scm()) == NULL)
636 return -1;
637 if ((hService = nt_service_open(hSCManager)) == NULL) {
638 service_fns.CloseServiceHandle_fn(hSCManager);
639 return -1;
642 nt_service_stop(hService);
643 if (service_fns.DeleteService_fn(hService) == FALSE) {
644 errmsg = nt_strerror(GetLastError());
645 printf("DeleteService() failed : %s\n", errmsg);
646 LocalFree(errmsg);
647 service_fns.CloseServiceHandle_fn(hService);
648 service_fns.CloseServiceHandle_fn(hSCManager);
649 return -1;
652 service_fns.CloseServiceHandle_fn(hService);
653 service_fns.CloseServiceHandle_fn(hSCManager);
654 printf("Service removed successfully\n");
656 return 0;
659 /** Starts the Tor service. Returns 0 on success, or -1 on error. */
660 static int
661 nt_service_cmd_start(void)
663 SC_HANDLE hSCManager;
664 SC_HANDLE hService;
665 int start;
667 if ((hSCManager = nt_service_open_scm()) == NULL)
668 return -1;
669 if ((hService = nt_service_open(hSCManager)) == NULL) {
670 service_fns.CloseServiceHandle_fn(hSCManager);
671 return -1;
674 start = nt_service_start(hService);
675 service_fns.CloseServiceHandle_fn(hService);
676 service_fns.CloseServiceHandle_fn(hSCManager);
678 return start;
681 /** Stops the Tor service. Returns 0 on success, or -1 on error. */
682 static int
683 nt_service_cmd_stop(void)
685 SC_HANDLE hSCManager;
686 SC_HANDLE hService;
687 int stop;
689 if ((hSCManager = nt_service_open_scm()) == NULL)
690 return -1;
691 if ((hService = nt_service_open(hSCManager)) == NULL) {
692 service_fns.CloseServiceHandle_fn(hSCManager);
693 return -1;
696 stop = nt_service_stop(hService);
697 service_fns.CloseServiceHandle_fn(hService);
698 service_fns.CloseServiceHandle_fn(hSCManager);
700 return stop;
703 /** Given a Win32 error code, this attempts to make Windows
704 * return a human-readable error message. The char* returned
705 * is allocated by Windows, but should be freed with LocalFree()
706 * when finished with it. */
707 static char*
708 nt_strerror(uint32_t errnum)
710 char *msgbuf;
711 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
712 NULL, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
713 (LPSTR)&msgbuf, 0, NULL);
714 return msgbuf;
718 nt_service_parse_options(int argc, char **argv, int *should_exit)
720 backup_argv = argv;
721 backup_argc = argc;
722 *should_exit = 0;
724 if ((argc >= 3) &&
725 (!strcmp(argv[1], "-service") || !strcmp(argv[1], "--service"))) {
726 nt_service_loadlibrary();
727 if (!strcmp(argv[2], "install"))
728 return nt_service_install(argc, argv);
729 if (!strcmp(argv[2], "remove"))
730 return nt_service_remove();
731 if (!strcmp(argv[2], "start"))
732 return nt_service_cmd_start();
733 if (!strcmp(argv[2], "stop"))
734 return nt_service_cmd_stop();
735 printf("Unrecognized service command '%s'\n", argv[2]);
736 *should_exit = 1;
737 return 1;
739 if (argc >= 2) {
740 if (!strcmp(argv[1], "-nt-service") || !strcmp(argv[1], "--nt-service")) {
741 nt_service_loadlibrary();
742 nt_service_main();
743 *should_exit = 1;
744 return 0;
746 // These values have been deprecated since 0.1.1.2-alpha; we've warned
747 // about them since 0.1.2.7-alpha.
748 if (!strcmp(argv[1], "-install") || !strcmp(argv[1], "--install")) {
749 nt_service_loadlibrary();
750 fprintf(stderr,
751 "The %s option is deprecated; use \"--service install\" instead.",
752 argv[1]);
753 *should_exit = 1;
754 return nt_service_install(argc, argv);
756 if (!strcmp(argv[1], "-remove") || !strcmp(argv[1], "--remove")) {
757 nt_service_loadlibrary();
758 fprintf(stderr,
759 "The %s option is deprecated; use \"--service remove\" instead.",
760 argv[1]);
761 *should_exit = 1;
762 return nt_service_remove();
765 *should_exit = 0;
766 return 0;