|  | @@ -86,35 +86,6 @@ static int called_loop_once = 0;
 | 
	
		
			
				|  |  |   * entry to inform the user that Tor is working. */
 | 
	
		
			
				|  |  |  int has_completed_circuit=0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#ifdef MS_WINDOWS
 | 
	
		
			
				|  |  | -#define MS_WINDOWS_SERVICE
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#ifdef MS_WINDOWS_SERVICE
 | 
	
		
			
				|  |  | -#include <tchar.h>
 | 
	
		
			
				|  |  | -#define GENSRV_SERVICENAME  TEXT("tor")
 | 
	
		
			
				|  |  | -#define GENSRV_DISPLAYNAME  TEXT("Tor Win32 Service")
 | 
	
		
			
				|  |  | -#define GENSRV_DESCRIPTION  \
 | 
	
		
			
				|  |  | -  TEXT("Provides an anonymous Internet communication system")
 | 
	
		
			
				|  |  | -#define GENSRV_USERACCT TEXT("NT AUTHORITY\\LocalService")
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -// Cheating: using the pre-defined error codes, tricks Windows into displaying
 | 
	
		
			
				|  |  | -//           a semi-related human-readable error message if startup fails as
 | 
	
		
			
				|  |  | -//           opposed to simply scaring people with Error: 0xffffffff
 | 
	
		
			
				|  |  | -#define NT_SERVICE_ERROR_TORINIT_FAILED ERROR_EXCEPTION_IN_SERVICE
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -SERVICE_STATUS service_status;
 | 
	
		
			
				|  |  | -SERVICE_STATUS_HANDLE hStatus;
 | 
	
		
			
				|  |  | -/* XXXX020 This 'backup argv' and 'backup argc' business is an ugly hack. This
 | 
	
		
			
				|  |  | - * is a job for arguments, not globals. */
 | 
	
		
			
				|  |  | -static char **backup_argv;
 | 
	
		
			
				|  |  | -static int backup_argc;
 | 
	
		
			
				|  |  | -static int nt_service_is_stopping(void);
 | 
	
		
			
				|  |  | -static char* nt_strerror(uint32_t errnum);
 | 
	
		
			
				|  |  | -#else
 | 
	
		
			
				|  |  | -#define nt_service_is_stopping() (0)
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  /** If our router descriptor ever goes this long without being regenerated
 | 
	
		
			
				|  |  |   * because something changed, we force an immediate regenerate-and-upload. */
 | 
	
		
			
				|  |  |  #define FORCE_REGENERATE_DESCRIPTOR_INTERVAL (18*60*60)
 | 
	
	
		
			
				|  | @@ -1909,685 +1880,6 @@ do_hash_password(void)
 | 
	
		
			
				|  |  |    printf("16:%s\n",output);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#ifdef MS_WINDOWS_SERVICE
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/* XXXX can some/all these functions become static? without breaking NT
 | 
	
		
			
				|  |  | - * services? -NM */
 | 
	
		
			
				|  |  | -/* XXXX I'd also like to move much of the NT service stuff into its own
 | 
	
		
			
				|  |  | - * file. -RD */
 | 
	
		
			
				|  |  | -void nt_service_control(DWORD request);
 | 
	
		
			
				|  |  | -void nt_service_body(int argc, char **argv);
 | 
	
		
			
				|  |  | -void nt_service_main(void);
 | 
	
		
			
				|  |  | -SC_HANDLE nt_service_open_scm(void);
 | 
	
		
			
				|  |  | -SC_HANDLE nt_service_open(SC_HANDLE hSCManager);
 | 
	
		
			
				|  |  | -int nt_service_start(SC_HANDLE hService);
 | 
	
		
			
				|  |  | -int nt_service_stop(SC_HANDLE hService);
 | 
	
		
			
				|  |  | -int nt_service_install(int argc, char **argv);
 | 
	
		
			
				|  |  | -int nt_service_remove(void);
 | 
	
		
			
				|  |  | -int nt_service_cmd_start(void);
 | 
	
		
			
				|  |  | -int nt_service_cmd_stop(void);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -struct service_fns {
 | 
	
		
			
				|  |  | -  int loaded;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  BOOL (WINAPI *ChangeServiceConfig2A_fn)(
 | 
	
		
			
				|  |  | -                             SC_HANDLE hService,
 | 
	
		
			
				|  |  | -                             DWORD dwInfoLevel,
 | 
	
		
			
				|  |  | -                             LPVOID lpInfo);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  BOOL (WINAPI *CloseServiceHandle_fn)(
 | 
	
		
			
				|  |  | -                             SC_HANDLE hSCObject);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  BOOL (WINAPI *ControlService_fn)(
 | 
	
		
			
				|  |  | -                             SC_HANDLE hService,
 | 
	
		
			
				|  |  | -                             DWORD dwControl,
 | 
	
		
			
				|  |  | -                             LPSERVICE_STATUS lpServiceStatus);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  SC_HANDLE (WINAPI *CreateServiceA_fn)(
 | 
	
		
			
				|  |  | -                             SC_HANDLE hSCManager,
 | 
	
		
			
				|  |  | -                             LPCTSTR lpServiceName,
 | 
	
		
			
				|  |  | -                             LPCTSTR lpDisplayName,
 | 
	
		
			
				|  |  | -                             DWORD dwDesiredAccess,
 | 
	
		
			
				|  |  | -                             DWORD dwServiceType,
 | 
	
		
			
				|  |  | -                             DWORD dwStartType,
 | 
	
		
			
				|  |  | -                             DWORD dwErrorControl,
 | 
	
		
			
				|  |  | -                             LPCTSTR lpBinaryPathName,
 | 
	
		
			
				|  |  | -                             LPCTSTR lpLoadOrderGroup,
 | 
	
		
			
				|  |  | -                             LPDWORD lpdwTagId,
 | 
	
		
			
				|  |  | -                             LPCTSTR lpDependencies,
 | 
	
		
			
				|  |  | -                             LPCTSTR lpServiceStartName,
 | 
	
		
			
				|  |  | -                             LPCTSTR lpPassword);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  BOOL (WINAPI *DeleteService_fn)(
 | 
	
		
			
				|  |  | -                             SC_HANDLE hService);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  SC_HANDLE (WINAPI *OpenSCManagerA_fn)(
 | 
	
		
			
				|  |  | -                             LPCTSTR lpMachineName,
 | 
	
		
			
				|  |  | -                             LPCTSTR lpDatabaseName,
 | 
	
		
			
				|  |  | -                             DWORD dwDesiredAccess);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  SC_HANDLE (WINAPI *OpenServiceA_fn)(
 | 
	
		
			
				|  |  | -                             SC_HANDLE hSCManager,
 | 
	
		
			
				|  |  | -                             LPCTSTR lpServiceName,
 | 
	
		
			
				|  |  | -                             DWORD dwDesiredAccess);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  BOOL (WINAPI *QueryServiceStatus_fn)(
 | 
	
		
			
				|  |  | -                             SC_HANDLE hService,
 | 
	
		
			
				|  |  | -                             LPSERVICE_STATUS lpServiceStatus);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  SERVICE_STATUS_HANDLE (WINAPI *RegisterServiceCtrlHandlerA_fn)(
 | 
	
		
			
				|  |  | -                             LPCTSTR lpServiceName,
 | 
	
		
			
				|  |  | -                             LPHANDLER_FUNCTION lpHandlerProc);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  BOOL (WINAPI *SetServiceStatus_fn)(SERVICE_STATUS_HANDLE,
 | 
	
		
			
				|  |  | -                             LPSERVICE_STATUS);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  BOOL (WINAPI *StartServiceCtrlDispatcherA_fn)(
 | 
	
		
			
				|  |  | -                             const SERVICE_TABLE_ENTRY* lpServiceTable);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  BOOL (WINAPI *StartServiceA_fn)(
 | 
	
		
			
				|  |  | -                             SC_HANDLE hService,
 | 
	
		
			
				|  |  | -                             DWORD dwNumServiceArgs,
 | 
	
		
			
				|  |  | -                             LPCTSTR* lpServiceArgVectors);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  BOOL (WINAPI *LookupAccountNameA_fn)(
 | 
	
		
			
				|  |  | -                             LPCTSTR lpSystemName,
 | 
	
		
			
				|  |  | -                             LPCTSTR lpAccountName,
 | 
	
		
			
				|  |  | -                             PSID Sid,
 | 
	
		
			
				|  |  | -                             LPDWORD cbSid,
 | 
	
		
			
				|  |  | -                             LPTSTR ReferencedDomainName,
 | 
	
		
			
				|  |  | -                             LPDWORD cchReferencedDomainName,
 | 
	
		
			
				|  |  | -                             PSID_NAME_USE peUse);
 | 
	
		
			
				|  |  | -} service_fns = { 0,
 | 
	
		
			
				|  |  | -                  NULL, NULL, NULL, NULL, NULL, NULL,
 | 
	
		
			
				|  |  | -                  NULL, NULL, NULL, NULL, NULL, NULL,
 | 
	
		
			
				|  |  | -                  NULL};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Loads functions used by NT services. Returns on success, or prints a
 | 
	
		
			
				|  |  | - * complaint to stdout and exits on error. */
 | 
	
		
			
				|  |  | -static void
 | 
	
		
			
				|  |  | -nt_service_loadlibrary(void)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  HMODULE library = 0;
 | 
	
		
			
				|  |  | -  void *fn;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (service_fns.loaded)
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* XXXX Possibly, we should hardcode the location of this DLL. */
 | 
	
		
			
				|  |  | -  if (!(library = LoadLibrary("advapi32.dll"))) {
 | 
	
		
			
				|  |  | -    log_err(LD_GENERAL, "Couldn't open advapi32.dll.  Are you trying to use "
 | 
	
		
			
				|  |  | -            "NT services on Windows 98? That doesn't work.");
 | 
	
		
			
				|  |  | -    goto err;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#define LOAD(f) STMT_BEGIN                                              \
 | 
	
		
			
				|  |  | -    if (!(fn = GetProcAddress(library, #f))) {                          \
 | 
	
		
			
				|  |  | -      log_err(LD_BUG,                                                   \
 | 
	
		
			
				|  |  | -              "Couldn't find %s in advapi32.dll! We probably got the "  \
 | 
	
		
			
				|  |  | -              "name wrong.", #f);                                       \
 | 
	
		
			
				|  |  | -      goto err;                                                         \
 | 
	
		
			
				|  |  | -    } else {                                                            \
 | 
	
		
			
				|  |  | -      service_fns.f ## _fn = fn;                                        \
 | 
	
		
			
				|  |  | -    }                                                                   \
 | 
	
		
			
				|  |  | -  STMT_END
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  LOAD(ChangeServiceConfig2A);
 | 
	
		
			
				|  |  | -  LOAD(CloseServiceHandle);
 | 
	
		
			
				|  |  | -  LOAD(ControlService);
 | 
	
		
			
				|  |  | -  LOAD(CreateServiceA);
 | 
	
		
			
				|  |  | -  LOAD(DeleteService);
 | 
	
		
			
				|  |  | -  LOAD(OpenSCManagerA);
 | 
	
		
			
				|  |  | -  LOAD(OpenServiceA);
 | 
	
		
			
				|  |  | -  LOAD(QueryServiceStatus);
 | 
	
		
			
				|  |  | -  LOAD(RegisterServiceCtrlHandlerA);
 | 
	
		
			
				|  |  | -  LOAD(SetServiceStatus);
 | 
	
		
			
				|  |  | -  LOAD(StartServiceCtrlDispatcherA);
 | 
	
		
			
				|  |  | -  LOAD(StartServiceA);
 | 
	
		
			
				|  |  | -  LOAD(LookupAccountNameA);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  service_fns.loaded = 1;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  return;
 | 
	
		
			
				|  |  | - err:
 | 
	
		
			
				|  |  | -  printf("Unable to load library support for NT services: exiting.\n");
 | 
	
		
			
				|  |  | -  exit(1);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** If we're compiled to run as an NT service, and the service wants to
 | 
	
		
			
				|  |  | - * shut down, then change our current status and return 1.  Else
 | 
	
		
			
				|  |  | - * return 0.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -static int
 | 
	
		
			
				|  |  | -nt_service_is_stopping(void)
 | 
	
		
			
				|  |  | -/* XXXX this function would probably _love_ to be inline, in 0.2.0. */
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  /* If we haven't loaded the function pointers, we can't possibly be an NT
 | 
	
		
			
				|  |  | -   * service trying to shut down. */
 | 
	
		
			
				|  |  | -  if (!service_fns.loaded)
 | 
	
		
			
				|  |  | -    return 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (service_status.dwCurrentState == SERVICE_STOP_PENDING) {
 | 
	
		
			
				|  |  | -    service_status.dwWin32ExitCode = 0;
 | 
	
		
			
				|  |  | -    service_status.dwCurrentState = SERVICE_STOPPED;
 | 
	
		
			
				|  |  | -    service_fns.SetServiceStatus_fn(hStatus, &service_status);
 | 
	
		
			
				|  |  | -    return 1;
 | 
	
		
			
				|  |  | -  } else if (service_status.dwCurrentState == SERVICE_STOPPED) {
 | 
	
		
			
				|  |  | -    return 1;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  return 0;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Handles service control requests, such as stopping or starting the
 | 
	
		
			
				|  |  | - * Tor service. */
 | 
	
		
			
				|  |  | -void
 | 
	
		
			
				|  |  | -nt_service_control(DWORD request)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  static struct timeval exit_now;
 | 
	
		
			
				|  |  | -  exit_now.tv_sec  = 0;
 | 
	
		
			
				|  |  | -  exit_now.tv_usec = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  nt_service_loadlibrary();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  switch (request) {
 | 
	
		
			
				|  |  | -    case SERVICE_CONTROL_STOP:
 | 
	
		
			
				|  |  | -        case SERVICE_CONTROL_SHUTDOWN:
 | 
	
		
			
				|  |  | -          log_notice(LD_GENERAL,
 | 
	
		
			
				|  |  | -                     "Got stop/shutdown request; shutting down cleanly.");
 | 
	
		
			
				|  |  | -          service_status.dwCurrentState = SERVICE_STOP_PENDING;
 | 
	
		
			
				|  |  | -          event_loopexit(&exit_now);
 | 
	
		
			
				|  |  | -          return;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  service_fns.SetServiceStatus_fn(hStatus, &service_status);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Called when the service is started via the system's service control
 | 
	
		
			
				|  |  | - * manager. This calls tor_init() and starts the main event loop. If
 | 
	
		
			
				|  |  | - * tor_init() fails, the service will be stopped and exit code set to
 | 
	
		
			
				|  |  | - * NT_SERVICE_ERROR_TORINIT_FAILED. */
 | 
	
		
			
				|  |  | -void
 | 
	
		
			
				|  |  | -nt_service_body(int argc, char **argv)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  int r;
 | 
	
		
			
				|  |  | -  (void) argc; /* unused */
 | 
	
		
			
				|  |  | -  (void) argv; /* unused */
 | 
	
		
			
				|  |  | -  nt_service_loadlibrary();
 | 
	
		
			
				|  |  | -  service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
 | 
	
		
			
				|  |  | -  service_status.dwCurrentState = SERVICE_START_PENDING;
 | 
	
		
			
				|  |  | -  service_status.dwControlsAccepted =
 | 
	
		
			
				|  |  | -        SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
 | 
	
		
			
				|  |  | -  service_status.dwWin32ExitCode = 0;
 | 
	
		
			
				|  |  | -  service_status.dwServiceSpecificExitCode = 0;
 | 
	
		
			
				|  |  | -  service_status.dwCheckPoint = 0;
 | 
	
		
			
				|  |  | -  service_status.dwWaitHint = 1000;
 | 
	
		
			
				|  |  | -  hStatus = service_fns.RegisterServiceCtrlHandlerA_fn(GENSRV_SERVICENAME,
 | 
	
		
			
				|  |  | -                                   (LPHANDLER_FUNCTION) nt_service_control);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (hStatus == 0) {
 | 
	
		
			
				|  |  | -    /* Failed to register the service control handler function */
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  r = tor_init(backup_argc, backup_argv);
 | 
	
		
			
				|  |  | -  if (r) {
 | 
	
		
			
				|  |  | -    /* Failed to start the Tor service */
 | 
	
		
			
				|  |  | -    r = NT_SERVICE_ERROR_TORINIT_FAILED;
 | 
	
		
			
				|  |  | -    service_status.dwCurrentState = SERVICE_STOPPED;
 | 
	
		
			
				|  |  | -    service_status.dwWin32ExitCode = r;
 | 
	
		
			
				|  |  | -    service_status.dwServiceSpecificExitCode = r;
 | 
	
		
			
				|  |  | -    service_fns.SetServiceStatus_fn(hStatus, &service_status);
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Set the service's status to SERVICE_RUNNING and start the main
 | 
	
		
			
				|  |  | -   * event loop */
 | 
	
		
			
				|  |  | -  service_status.dwCurrentState = SERVICE_RUNNING;
 | 
	
		
			
				|  |  | -  service_fns.SetServiceStatus_fn(hStatus, &service_status);
 | 
	
		
			
				|  |  | -  do_main_loop();
 | 
	
		
			
				|  |  | -  tor_cleanup();
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Main service entry point. Starts the service control dispatcher and waits
 | 
	
		
			
				|  |  | - * until the service status is set to SERVICE_STOPPED. */
 | 
	
		
			
				|  |  | -void
 | 
	
		
			
				|  |  | -nt_service_main(void)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  SERVICE_TABLE_ENTRY table[2];
 | 
	
		
			
				|  |  | -  DWORD result = 0;
 | 
	
		
			
				|  |  | -  char *errmsg;
 | 
	
		
			
				|  |  | -  nt_service_loadlibrary();
 | 
	
		
			
				|  |  | -  table[0].lpServiceName = (char*)GENSRV_SERVICENAME;
 | 
	
		
			
				|  |  | -  table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)nt_service_body;
 | 
	
		
			
				|  |  | -  table[1].lpServiceName = NULL;
 | 
	
		
			
				|  |  | -  table[1].lpServiceProc = NULL;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (!service_fns.StartServiceCtrlDispatcherA_fn(table)) {
 | 
	
		
			
				|  |  | -    result = GetLastError();
 | 
	
		
			
				|  |  | -    errmsg = nt_strerror(result);
 | 
	
		
			
				|  |  | -    printf("Service error %d : %s\n", (int) result, errmsg);
 | 
	
		
			
				|  |  | -    LocalFree(errmsg);
 | 
	
		
			
				|  |  | -    if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
 | 
	
		
			
				|  |  | -      if (tor_init(backup_argc, backup_argv) < 0)
 | 
	
		
			
				|  |  | -        return;
 | 
	
		
			
				|  |  | -      switch (get_options()->command) {
 | 
	
		
			
				|  |  | -      case CMD_RUN_TOR:
 | 
	
		
			
				|  |  | -        do_main_loop();
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -      case CMD_LIST_FINGERPRINT:
 | 
	
		
			
				|  |  | -        do_list_fingerprint();
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -      case CMD_HASH_PASSWORD:
 | 
	
		
			
				|  |  | -        do_hash_password();
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -      case CMD_VERIFY_CONFIG:
 | 
	
		
			
				|  |  | -        printf("Configuration was valid\n");
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -      case CMD_RUN_UNITTESTS:
 | 
	
		
			
				|  |  | -      default:
 | 
	
		
			
				|  |  | -        log_err(LD_CONFIG, "Illegal command number %d: internal error.",
 | 
	
		
			
				|  |  | -                get_options()->command);
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      tor_cleanup();
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Return a handle to the service control manager on success, or NULL on
 | 
	
		
			
				|  |  | - * failure. */
 | 
	
		
			
				|  |  | -SC_HANDLE
 | 
	
		
			
				|  |  | -nt_service_open_scm(void)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  SC_HANDLE hSCManager;
 | 
	
		
			
				|  |  | -  char *errmsg = NULL;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  nt_service_loadlibrary();
 | 
	
		
			
				|  |  | -  if ((hSCManager = service_fns.OpenSCManagerA_fn(
 | 
	
		
			
				|  |  | -                            NULL, NULL, SC_MANAGER_CREATE_SERVICE)) == NULL) {
 | 
	
		
			
				|  |  | -    errmsg = nt_strerror(GetLastError());
 | 
	
		
			
				|  |  | -    printf("OpenSCManager() failed : %s\n", errmsg);
 | 
	
		
			
				|  |  | -    LocalFree(errmsg);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  return hSCManager;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Open a handle to the Tor service using <b>hSCManager</b>. Return NULL
 | 
	
		
			
				|  |  | - * on failure. */
 | 
	
		
			
				|  |  | -SC_HANDLE
 | 
	
		
			
				|  |  | -nt_service_open(SC_HANDLE hSCManager)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  SC_HANDLE hService;
 | 
	
		
			
				|  |  | -  char *errmsg = NULL;
 | 
	
		
			
				|  |  | -  nt_service_loadlibrary();
 | 
	
		
			
				|  |  | -  if ((hService = service_fns.OpenServiceA_fn(hSCManager, GENSRV_SERVICENAME,
 | 
	
		
			
				|  |  | -                              SERVICE_ALL_ACCESS)) == NULL) {
 | 
	
		
			
				|  |  | -    errmsg = nt_strerror(GetLastError());
 | 
	
		
			
				|  |  | -    printf("OpenService() failed : %s\n", errmsg);
 | 
	
		
			
				|  |  | -    LocalFree(errmsg);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  return hService;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Start the Tor service. Return 0 if the service is started or was
 | 
	
		
			
				|  |  | - * previously running. Return -1 on error. */
 | 
	
		
			
				|  |  | -int
 | 
	
		
			
				|  |  | -nt_service_start(SC_HANDLE hService)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  char *errmsg = NULL;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  nt_service_loadlibrary();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  service_fns.QueryServiceStatus_fn(hService, &service_status);
 | 
	
		
			
				|  |  | -  if (service_status.dwCurrentState == SERVICE_RUNNING) {
 | 
	
		
			
				|  |  | -    printf("Service is already running\n");
 | 
	
		
			
				|  |  | -    return 0;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (service_fns.StartServiceA_fn(hService, 0, NULL)) {
 | 
	
		
			
				|  |  | -    /* Loop until the service has finished attempting to start */
 | 
	
		
			
				|  |  | -    while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
 | 
	
		
			
				|  |  | -           (service_status.dwCurrentState == SERVICE_START_PENDING)) {
 | 
	
		
			
				|  |  | -      Sleep(500);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    /* Check if it started successfully or not */
 | 
	
		
			
				|  |  | -    if (service_status.dwCurrentState == SERVICE_RUNNING) {
 | 
	
		
			
				|  |  | -      printf("Service started successfully\n");
 | 
	
		
			
				|  |  | -      return 0;
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      errmsg = nt_strerror(service_status.dwWin32ExitCode);
 | 
	
		
			
				|  |  | -      printf("Service failed to start : %s\n", errmsg);
 | 
	
		
			
				|  |  | -      LocalFree(errmsg);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    errmsg = nt_strerror(GetLastError());
 | 
	
		
			
				|  |  | -    printf("StartService() failed : %s\n", errmsg);
 | 
	
		
			
				|  |  | -    LocalFree(errmsg);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  return -1;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Stop the Tor service. Return 0 if the service is stopped or was not
 | 
	
		
			
				|  |  | - * previously running. Return -1 on error. */
 | 
	
		
			
				|  |  | -int
 | 
	
		
			
				|  |  | -nt_service_stop(SC_HANDLE hService)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -/** Wait at most 10 seconds for the service to stop. */
 | 
	
		
			
				|  |  | -#define MAX_SERVICE_WAIT_TIME 10
 | 
	
		
			
				|  |  | -  int wait_time;
 | 
	
		
			
				|  |  | -  char *errmsg = NULL;
 | 
	
		
			
				|  |  | -  nt_service_loadlibrary();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  service_fns.QueryServiceStatus_fn(hService, &service_status);
 | 
	
		
			
				|  |  | -  if (service_status.dwCurrentState == SERVICE_STOPPED) {
 | 
	
		
			
				|  |  | -    printf("Service is already stopped\n");
 | 
	
		
			
				|  |  | -    return 0;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (service_fns.ControlService_fn(hService, SERVICE_CONTROL_STOP,
 | 
	
		
			
				|  |  | -                                    &service_status)) {
 | 
	
		
			
				|  |  | -    wait_time = 0;
 | 
	
		
			
				|  |  | -    while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
 | 
	
		
			
				|  |  | -           (service_status.dwCurrentState != SERVICE_STOPPED) &&
 | 
	
		
			
				|  |  | -           (wait_time < MAX_SERVICE_WAIT_TIME)) {
 | 
	
		
			
				|  |  | -      Sleep(1000);
 | 
	
		
			
				|  |  | -      wait_time++;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    if (service_status.dwCurrentState == SERVICE_STOPPED) {
 | 
	
		
			
				|  |  | -      printf("Service stopped successfully\n");
 | 
	
		
			
				|  |  | -      return 0;
 | 
	
		
			
				|  |  | -    } else if (wait_time == MAX_SERVICE_WAIT_TIME) {
 | 
	
		
			
				|  |  | -      printf("Service did not stop within %d seconds.\n", wait_time);
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      errmsg = nt_strerror(GetLastError());
 | 
	
		
			
				|  |  | -      printf("QueryServiceStatus() failed : %s\n",errmsg);
 | 
	
		
			
				|  |  | -      LocalFree(errmsg);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    errmsg = nt_strerror(GetLastError());
 | 
	
		
			
				|  |  | -    printf("ControlService() failed : %s\n", errmsg);
 | 
	
		
			
				|  |  | -    LocalFree(errmsg);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  return -1;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Build a formatted command line used for the NT service. Return a
 | 
	
		
			
				|  |  | - * pointer to the formatted string on success, or NULL on failure.  Set
 | 
	
		
			
				|  |  | - * *<b>using_default_torrc</b> to true if we're going to use the default
 | 
	
		
			
				|  |  | - * location to torrc, or 1 if an option was specified on the command line.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -static char *
 | 
	
		
			
				|  |  | -nt_service_command_line(int *using_default_torrc)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  TCHAR tor_exe[MAX_PATH+1];
 | 
	
		
			
				|  |  | -  char *command, *options=NULL;
 | 
	
		
			
				|  |  | -  smartlist_t *sl;
 | 
	
		
			
				|  |  | -  int i, cmdlen;
 | 
	
		
			
				|  |  | -  *using_default_torrc = 1;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Get the location of tor.exe */
 | 
	
		
			
				|  |  | -  if (0 == GetModuleFileName(NULL, tor_exe, MAX_PATH))
 | 
	
		
			
				|  |  | -    return NULL;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Get the service arguments */
 | 
	
		
			
				|  |  | -  sl = smartlist_create();
 | 
	
		
			
				|  |  | -  for (i = 1; i < backup_argc; ++i) {
 | 
	
		
			
				|  |  | -    if (!strcmp(backup_argv[i], "--options") ||
 | 
	
		
			
				|  |  | -        !strcmp(backup_argv[i], "-options")) {
 | 
	
		
			
				|  |  | -      while (++i < backup_argc) {
 | 
	
		
			
				|  |  | -        if (!strcmp(backup_argv[i], "-f"))
 | 
	
		
			
				|  |  | -          *using_default_torrc = 0;
 | 
	
		
			
				|  |  | -        smartlist_add(sl, backup_argv[i]);
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  if (smartlist_len(sl))
 | 
	
		
			
				|  |  | -    options = smartlist_join_strings(sl,"\" \"",0,NULL);
 | 
	
		
			
				|  |  | -  smartlist_free(sl);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Allocate a string for the NT service command line */
 | 
	
		
			
				|  |  | -  cmdlen = strlen(tor_exe) + (options?strlen(options):0) + 32;
 | 
	
		
			
				|  |  | -  command = tor_malloc(cmdlen);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Format the service command */
 | 
	
		
			
				|  |  | -  if (options) {
 | 
	
		
			
				|  |  | -    if (tor_snprintf(command, cmdlen, "\"%s\" --nt-service \"%s\"",
 | 
	
		
			
				|  |  | -                     tor_exe, options)<0) {
 | 
	
		
			
				|  |  | -      tor_free(command); /* sets command to NULL. */
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  } else { /* ! options */
 | 
	
		
			
				|  |  | -    if (tor_snprintf(command, cmdlen, "\"%s\" --nt-service", tor_exe)<0) {
 | 
	
		
			
				|  |  | -      tor_free(command); /* sets command to NULL. */
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  tor_free(options);
 | 
	
		
			
				|  |  | -  return command;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Creates a Tor NT service, set to start on boot. The service will be
 | 
	
		
			
				|  |  | - * started if installation succeeds. Returns 0 on success, or -1 on
 | 
	
		
			
				|  |  | - * failure. */
 | 
	
		
			
				|  |  | -int
 | 
	
		
			
				|  |  | -nt_service_install(int argc, char **argv)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  /* Notes about developing NT services:
 | 
	
		
			
				|  |  | -   *
 | 
	
		
			
				|  |  | -   * 1. Don't count on your CWD. If an absolute path is not given, the
 | 
	
		
			
				|  |  | -   *    fopen() function goes wrong.
 | 
	
		
			
				|  |  | -   * 2. The parameters given to the nt_service_body() function differ
 | 
	
		
			
				|  |  | -   *    from those given to main() function.
 | 
	
		
			
				|  |  | -   */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  SC_HANDLE hSCManager = NULL;
 | 
	
		
			
				|  |  | -  SC_HANDLE hService = NULL;
 | 
	
		
			
				|  |  | -  SERVICE_DESCRIPTION sdBuff;
 | 
	
		
			
				|  |  | -  char *command;
 | 
	
		
			
				|  |  | -  char *errmsg;
 | 
	
		
			
				|  |  | -  const char *user_acct = GENSRV_USERACCT;
 | 
	
		
			
				|  |  | -  const char *password = "";
 | 
	
		
			
				|  |  | -  int i;
 | 
	
		
			
				|  |  | -  OSVERSIONINFOEX info;
 | 
	
		
			
				|  |  | -  SID_NAME_USE sidUse;
 | 
	
		
			
				|  |  | -  DWORD sidLen = 0, domainLen = 0;
 | 
	
		
			
				|  |  | -  int is_win2k_or_worse = 0;
 | 
	
		
			
				|  |  | -  int using_default_torrc = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  nt_service_loadlibrary();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Open the service control manager so we can create a new service */
 | 
	
		
			
				|  |  | -  if ((hSCManager = nt_service_open_scm()) == NULL)
 | 
	
		
			
				|  |  | -    return -1;
 | 
	
		
			
				|  |  | -  /* Build the command line used for the service */
 | 
	
		
			
				|  |  | -  if ((command = nt_service_command_line(&using_default_torrc)) == NULL) {
 | 
	
		
			
				|  |  | -    printf("Unable to build service command line.\n");
 | 
	
		
			
				|  |  | -    service_fns.CloseServiceHandle_fn(hSCManager);
 | 
	
		
			
				|  |  | -    return -1;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  for (i=1; i < argc; ++i) {
 | 
	
		
			
				|  |  | -    if (!strcmp(argv[i], "--user") && i+1<argc) {
 | 
	
		
			
				|  |  | -      user_acct = argv[i+1];
 | 
	
		
			
				|  |  | -      ++i;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    if (!strcmp(argv[i], "--password") && i+1<argc) {
 | 
	
		
			
				|  |  | -      password = argv[i+1];
 | 
	
		
			
				|  |  | -      ++i;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Compute our version and see whether we're running win2k or earlier. */
 | 
	
		
			
				|  |  | -  memset(&info, 0, sizeof(info));
 | 
	
		
			
				|  |  | -  info.dwOSVersionInfoSize = sizeof(info);
 | 
	
		
			
				|  |  | -  if (! GetVersionEx((LPOSVERSIONINFO)&info)) {
 | 
	
		
			
				|  |  | -    printf("Call to GetVersionEx failed.\n");
 | 
	
		
			
				|  |  | -    is_win2k_or_worse = 1;
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    if (info.dwMajorVersion < 5 ||
 | 
	
		
			
				|  |  | -        (info.dwMajorVersion == 5 && info.dwMinorVersion == 0))
 | 
	
		
			
				|  |  | -      is_win2k_or_worse = 1;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (user_acct == GENSRV_USERACCT) {
 | 
	
		
			
				|  |  | -    if (is_win2k_or_worse) {
 | 
	
		
			
				|  |  | -      /* On Win2k, there is no LocalService account, so we actually need to
 | 
	
		
			
				|  |  | -       * fall back on NULL (the system account). */
 | 
	
		
			
				|  |  | -      printf("Running on Win2K or earlier, so the LocalService account "
 | 
	
		
			
				|  |  | -             "doesn't exist.  Falling back to SYSTEM account.\n");
 | 
	
		
			
				|  |  | -      user_acct = NULL;
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      /* Genericity is apparently _so_ last year in Redmond, where some
 | 
	
		
			
				|  |  | -       * accounts are accounts that you can look up, and some accounts
 | 
	
		
			
				|  |  | -       * are magic and undetectable via the security subsystem. See
 | 
	
		
			
				|  |  | -       * http://msdn2.microsoft.com/en-us/library/ms684188.aspx
 | 
	
		
			
				|  |  | -       */
 | 
	
		
			
				|  |  | -      printf("Running on a Post-Win2K OS, so we'll assume that the "
 | 
	
		
			
				|  |  | -             "LocalService account exists.\n");
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  } else if (0 && service_fns.LookupAccountNameA_fn(NULL, // On this system
 | 
	
		
			
				|  |  | -                            user_acct,
 | 
	
		
			
				|  |  | -                            NULL, &sidLen, // Don't care about the SID
 | 
	
		
			
				|  |  | -                            NULL, &domainLen, // Don't care about the domain
 | 
	
		
			
				|  |  | -                            &sidUse) == 0) {
 | 
	
		
			
				|  |  | -    /* XXXX For some reason, the above test segfaults. Fix that. */
 | 
	
		
			
				|  |  | -    printf("User \"%s\" doesn't seem to exist.\n", user_acct);
 | 
	
		
			
				|  |  | -    return -1;
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    printf("Will try to install service as user \"%s\".\n", user_acct);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  /* XXXX This warning could be better about explaining how to resolve the
 | 
	
		
			
				|  |  | -   * situation. */
 | 
	
		
			
				|  |  | -  if (using_default_torrc)
 | 
	
		
			
				|  |  | -    printf("IMPORTANT NOTE:\n"
 | 
	
		
			
				|  |  | -        "    The Tor service will run under the account \"%s\".  This means\n"
 | 
	
		
			
				|  |  | -        "    that Tor will look for its configuration file under that\n"
 | 
	
		
			
				|  |  | -        "    account's Application Data directory, which is probably not\n"
 | 
	
		
			
				|  |  | -        "    the same as yours.\n", user_acct?user_acct:"<local system>");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Create the Tor service, set to auto-start on boot */
 | 
	
		
			
				|  |  | -  if ((hService = service_fns.CreateServiceA_fn(hSCManager, GENSRV_SERVICENAME,
 | 
	
		
			
				|  |  | -                                GENSRV_DISPLAYNAME,
 | 
	
		
			
				|  |  | -                                SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
 | 
	
		
			
				|  |  | -                                SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
 | 
	
		
			
				|  |  | -                                command, NULL, NULL, NULL,
 | 
	
		
			
				|  |  | -                                user_acct, password)) == NULL) {
 | 
	
		
			
				|  |  | -    errmsg = nt_strerror(GetLastError());
 | 
	
		
			
				|  |  | -    printf("CreateService() failed : %s\n", errmsg);
 | 
	
		
			
				|  |  | -    service_fns.CloseServiceHandle_fn(hSCManager);
 | 
	
		
			
				|  |  | -    LocalFree(errmsg);
 | 
	
		
			
				|  |  | -    tor_free(command);
 | 
	
		
			
				|  |  | -    return -1;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  printf("Done with CreateService.\n");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Set the service's description */
 | 
	
		
			
				|  |  | -  sdBuff.lpDescription = (char*)GENSRV_DESCRIPTION;
 | 
	
		
			
				|  |  | -  service_fns.ChangeServiceConfig2A_fn(hService, SERVICE_CONFIG_DESCRIPTION,
 | 
	
		
			
				|  |  | -                                       &sdBuff);
 | 
	
		
			
				|  |  | -  printf("Service installed successfully\n");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  /* Start the service initially */
 | 
	
		
			
				|  |  | -  nt_service_start(hService);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  service_fns.CloseServiceHandle_fn(hService);
 | 
	
		
			
				|  |  | -  service_fns.CloseServiceHandle_fn(hSCManager);
 | 
	
		
			
				|  |  | -  tor_free(command);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  return 0;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Removes the Tor NT service. Returns 0 if the service was successfully
 | 
	
		
			
				|  |  | - * removed, or -1 on error. */
 | 
	
		
			
				|  |  | -int
 | 
	
		
			
				|  |  | -nt_service_remove(void)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  SC_HANDLE hSCManager = NULL;
 | 
	
		
			
				|  |  | -  SC_HANDLE hService = NULL;
 | 
	
		
			
				|  |  | -  char *errmsg;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  nt_service_loadlibrary();
 | 
	
		
			
				|  |  | -  if ((hSCManager = nt_service_open_scm()) == NULL)
 | 
	
		
			
				|  |  | -    return -1;
 | 
	
		
			
				|  |  | -  if ((hService = nt_service_open(hSCManager)) == NULL) {
 | 
	
		
			
				|  |  | -    service_fns.CloseServiceHandle_fn(hSCManager);
 | 
	
		
			
				|  |  | -    return -1;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  nt_service_stop(hService);
 | 
	
		
			
				|  |  | -  if (service_fns.DeleteService_fn(hService) == FALSE) {
 | 
	
		
			
				|  |  | -    errmsg = nt_strerror(GetLastError());
 | 
	
		
			
				|  |  | -    printf("DeleteService() failed : %s\n", errmsg);
 | 
	
		
			
				|  |  | -    LocalFree(errmsg);
 | 
	
		
			
				|  |  | -    service_fns.CloseServiceHandle_fn(hService);
 | 
	
		
			
				|  |  | -    service_fns.CloseServiceHandle_fn(hSCManager);
 | 
	
		
			
				|  |  | -    return -1;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  service_fns.CloseServiceHandle_fn(hService);
 | 
	
		
			
				|  |  | -  service_fns.CloseServiceHandle_fn(hSCManager);
 | 
	
		
			
				|  |  | -  printf("Service removed successfully\n");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  return 0;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Starts the Tor service. Returns 0 on success, or -1 on error. */
 | 
	
		
			
				|  |  | -int
 | 
	
		
			
				|  |  | -nt_service_cmd_start(void)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  SC_HANDLE hSCManager;
 | 
	
		
			
				|  |  | -  SC_HANDLE hService;
 | 
	
		
			
				|  |  | -  int start;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if ((hSCManager = nt_service_open_scm()) == NULL)
 | 
	
		
			
				|  |  | -    return -1;
 | 
	
		
			
				|  |  | -  if ((hService = nt_service_open(hSCManager)) == NULL) {
 | 
	
		
			
				|  |  | -    service_fns.CloseServiceHandle_fn(hSCManager);
 | 
	
		
			
				|  |  | -    return -1;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  start = nt_service_start(hService);
 | 
	
		
			
				|  |  | -  service_fns.CloseServiceHandle_fn(hService);
 | 
	
		
			
				|  |  | -  service_fns.CloseServiceHandle_fn(hSCManager);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  return start;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Stops the Tor service. Returns 0 on success, or -1 on error. */
 | 
	
		
			
				|  |  | -int
 | 
	
		
			
				|  |  | -nt_service_cmd_stop(void)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -  SC_HANDLE hSCManager;
 | 
	
		
			
				|  |  | -  SC_HANDLE hService;
 | 
	
		
			
				|  |  | -  int stop;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if ((hSCManager = nt_service_open_scm()) == NULL)
 | 
	
		
			
				|  |  | -    return -1;
 | 
	
		
			
				|  |  | -  if ((hService = nt_service_open(hSCManager)) == NULL) {
 | 
	
		
			
				|  |  | -    service_fns.CloseServiceHandle_fn(hSCManager);
 | 
	
		
			
				|  |  | -    return -1;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  stop = nt_service_stop(hService);
 | 
	
		
			
				|  |  | -  service_fns.CloseServiceHandle_fn(hService);
 | 
	
		
			
				|  |  | -  service_fns.CloseServiceHandle_fn(hSCManager);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  return stop;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/** Given a Win32 error code, this attempts to make Windows
 | 
	
		
			
				|  |  | - * return a human-readable error message. The char* returned
 | 
	
		
			
				|  |  | - * is allocated by Windows, but should be freed with LocalFree()
 | 
	
		
			
				|  |  | - * when finished with it. */
 | 
	
		
			
				|  |  | -static char*
 | 
	
		
			
				|  |  | -nt_strerror(uint32_t errnum)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -   char *msgbuf;
 | 
	
		
			
				|  |  | -   FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
 | 
	
		
			
				|  |  | -                 NULL, errnum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
 | 
	
		
			
				|  |  | -                 (LPSTR)&msgbuf, 0, NULL);
 | 
	
		
			
				|  |  | -   return msgbuf;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  #ifdef USE_DMALLOC
 | 
	
		
			
				|  |  |  #include <openssl/crypto.h>
 | 
	
		
			
				|  |  |  static void
 | 
	
	
		
			
				|  | @@ -2609,53 +1901,16 @@ tor_main(int argc, char *argv[])
 | 
	
		
			
				|  |  |                                        _tor_dmalloc_free);
 | 
	
		
			
				|  |  |    log_notice(LD_CONFIG, "Set up dmalloc; returned %d", r);
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  | -#ifdef MS_WINDOWS_SERVICE
 | 
	
		
			
				|  |  | -  backup_argv = argv;
 | 
	
		
			
				|  |  | -  backup_argc = argc;
 | 
	
		
			
				|  |  | -  if ((argc >= 3) &&
 | 
	
		
			
				|  |  | -      (!strcmp(argv[1], "-service") || !strcmp(argv[1], "--service"))) {
 | 
	
		
			
				|  |  | -    nt_service_loadlibrary();
 | 
	
		
			
				|  |  | -    if (!strcmp(argv[2], "install"))
 | 
	
		
			
				|  |  | -      return nt_service_install(argc, argv);
 | 
	
		
			
				|  |  | -    if (!strcmp(argv[2], "remove"))
 | 
	
		
			
				|  |  | -      return nt_service_remove();
 | 
	
		
			
				|  |  | -    if (!strcmp(argv[2], "start"))
 | 
	
		
			
				|  |  | -      return nt_service_cmd_start();
 | 
	
		
			
				|  |  | -    if (!strcmp(argv[2], "stop"))
 | 
	
		
			
				|  |  | -      return nt_service_cmd_stop();
 | 
	
		
			
				|  |  | -    printf("Unrecognized service command '%s'\n", argv[2]);
 | 
	
		
			
				|  |  | -    return -1;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  if (argc >= 2) {
 | 
	
		
			
				|  |  | -    if (!strcmp(argv[1], "-nt-service") || !strcmp(argv[1], "--nt-service")) {
 | 
	
		
			
				|  |  | -      nt_service_loadlibrary();
 | 
	
		
			
				|  |  | -      nt_service_main();
 | 
	
		
			
				|  |  | -      return 0;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    // These values have been deprecated since 0.1.1.2-alpha; we've warned
 | 
	
		
			
				|  |  | -    // about them since 0.1.2.7-alpha.
 | 
	
		
			
				|  |  | -    if (!strcmp(argv[1], "-install") || !strcmp(argv[1], "--install")) {
 | 
	
		
			
				|  |  | -      nt_service_loadlibrary();
 | 
	
		
			
				|  |  | -      fprintf(stderr,
 | 
	
		
			
				|  |  | -            "The %s option is deprecated; use \"--service install\" instead.",
 | 
	
		
			
				|  |  | -            argv[1]);
 | 
	
		
			
				|  |  | -      return nt_service_install(argc, argv);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    if (!strcmp(argv[1], "-remove") || !strcmp(argv[1], "--remove")) {
 | 
	
		
			
				|  |  | -      nt_service_loadlibrary();
 | 
	
		
			
				|  |  | -      fprintf(stderr,
 | 
	
		
			
				|  |  | -            "The %s option is deprecated; use \"--service remove\" instead.",
 | 
	
		
			
				|  |  | -            argv[1]);
 | 
	
		
			
				|  |  | -      return nt_service_remove();
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | +#ifdef NT_SERVICE
 | 
	
		
			
				|  |  | +  if ((result = nt_service_parse_options(argv, argc)))
 | 
	
		
			
				|  |  | +    return result;
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |    if (tor_init(argc, argv)<0)
 | 
	
		
			
				|  |  |      return -1;
 | 
	
		
			
				|  |  |    switch (get_options()->command) {
 | 
	
		
			
				|  |  |    case CMD_RUN_TOR:
 | 
	
		
			
				|  |  | -#ifdef MS_WINDOWS_SERVICE
 | 
	
		
			
				|  |  | -    service_status.dwCurrentState = SERVICE_RUNNING;
 | 
	
		
			
				|  |  | +#ifdef NT_SERVICE
 | 
	
		
			
				|  |  | +    nt_service_set_state(SERVICE_RUNNING);
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |      result = do_main_loop();
 | 
	
		
			
				|  |  |      break;
 |