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