|
@@ -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")
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-#define NT_SERVICE_ERROR_TORINIT_FAILED ERROR_EXCEPTION_IN_SERVICE
|
|
|
-
|
|
|
-SERVICE_STATUS service_status;
|
|
|
-SERVICE_STATUS_HANDLE hStatus;
|
|
|
-
|
|
|
- * 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
|
|
|
-
|
|
|
|
|
|
* 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
|
|
|
-
|
|
|
-
|
|
|
- * services? -NM */
|
|
|
-
|
|
|
- * 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};
|
|
|
-
|
|
|
-
|
|
|
- * complaint to stdout and exits on error. */
|
|
|
-static void
|
|
|
-nt_service_loadlibrary(void)
|
|
|
-{
|
|
|
- HMODULE library = 0;
|
|
|
- void *fn;
|
|
|
-
|
|
|
- if (service_fns.loaded)
|
|
|
- return;
|
|
|
-
|
|
|
-
|
|
|
- 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);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * shut down, then change our current status and return 1. Else
|
|
|
- * return 0.
|
|
|
- */
|
|
|
-static int
|
|
|
-nt_service_is_stopping(void)
|
|
|
-
|
|
|
-{
|
|
|
-
|
|
|
- * 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;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * 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);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * 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;
|
|
|
- (void) argv;
|
|
|
- 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) {
|
|
|
-
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- r = tor_init(backup_argc, backup_argv);
|
|
|
- if (r) {
|
|
|
-
|
|
|
- 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;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- * event loop */
|
|
|
- service_status.dwCurrentState = SERVICE_RUNNING;
|
|
|
- service_fns.SetServiceStatus_fn(hStatus, &service_status);
|
|
|
- do_main_loop();
|
|
|
- tor_cleanup();
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * 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();
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * 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;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * 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;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * 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)) {
|
|
|
-
|
|
|
- while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
|
|
|
- (service_status.dwCurrentState == SERVICE_START_PENDING)) {
|
|
|
- Sleep(500);
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- 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;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * previously running. Return -1 on error. */
|
|
|
-int
|
|
|
-nt_service_stop(SC_HANDLE hService)
|
|
|
-{
|
|
|
-
|
|
|
-#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;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * 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;
|
|
|
-
|
|
|
-
|
|
|
- if (0 == GetModuleFileName(NULL, tor_exe, MAX_PATH))
|
|
|
- return NULL;
|
|
|
-
|
|
|
-
|
|
|
- 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);
|
|
|
-
|
|
|
-
|
|
|
- cmdlen = strlen(tor_exe) + (options?strlen(options):0) + 32;
|
|
|
- command = tor_malloc(cmdlen);
|
|
|
-
|
|
|
-
|
|
|
- if (options) {
|
|
|
- if (tor_snprintf(command, cmdlen, "\"%s\" --nt-service \"%s\"",
|
|
|
- tor_exe, options)<0) {
|
|
|
- tor_free(command);
|
|
|
- }
|
|
|
- } else {
|
|
|
- if (tor_snprintf(command, cmdlen, "\"%s\" --nt-service", tor_exe)<0) {
|
|
|
- tor_free(command);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- tor_free(options);
|
|
|
- return command;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * started if installation succeeds. Returns 0 on success, or -1 on
|
|
|
- * failure. */
|
|
|
-int
|
|
|
-nt_service_install(int argc, char **argv)
|
|
|
-{
|
|
|
-
|
|
|
- *
|
|
|
- * 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();
|
|
|
-
|
|
|
-
|
|
|
- if ((hSCManager = nt_service_open_scm()) == NULL)
|
|
|
- return -1;
|
|
|
-
|
|
|
- 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;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- 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) {
|
|
|
-
|
|
|
- * 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 {
|
|
|
-
|
|
|
- * accounts are accounts that you can look up, and some accounts
|
|
|
- * are magic and undetectable via the security subsystem. See
|
|
|
- * http:
|
|
|
- */
|
|
|
- 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,
|
|
|
- user_acct,
|
|
|
- NULL, &sidLen,
|
|
|
- NULL, &domainLen,
|
|
|
- &sidUse) == 0) {
|
|
|
-
|
|
|
- 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);
|
|
|
- }
|
|
|
-
|
|
|
- * 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>");
|
|
|
-
|
|
|
-
|
|
|
- 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");
|
|
|
-
|
|
|
-
|
|
|
- sdBuff.lpDescription = (char*)GENSRV_DESCRIPTION;
|
|
|
- service_fns.ChangeServiceConfig2A_fn(hService, SERVICE_CONFIG_DESCRIPTION,
|
|
|
- &sdBuff);
|
|
|
- printf("Service installed successfully\n");
|
|
|
-
|
|
|
-
|
|
|
- nt_service_start(hService);
|
|
|
-
|
|
|
- service_fns.CloseServiceHandle_fn(hService);
|
|
|
- service_fns.CloseServiceHandle_fn(hSCManager);
|
|
|
- tor_free(command);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * 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;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-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;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-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;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
- * 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;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- 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;
|