Back to index

tor  0.2.3.18-rc
ntmain.c
Go to the documentation of this file.
00001 /* Copyright (c) 2001-2004, Roger Dingledine.
00002  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
00003  * Copyright (c) 2007-2012, The Tor Project, Inc. */
00004 /* See LICENSE for licensing information */
00005 
00006 #define MAIN_PRIVATE
00007 #include "or.h"
00008 #include "config.h"
00009 #include "main.h"
00010 #include "ntmain.h"
00011 
00012 #ifdef HAVE_EVENT2_EVENT_H
00013 #include <event2/event.h>
00014 #else
00015 #include <event.h>
00016 #endif
00017 
00018 #include <windows.h>
00019 #define GENSRV_SERVICENAME  "tor"
00020 #define GENSRV_DISPLAYNAME  "Tor Win32 Service"
00021 #define GENSRV_DESCRIPTION  \
00022   "Provides an anonymous Internet communication system"
00023 #define GENSRV_USERACCT "NT AUTHORITY\\LocalService"
00024 
00025 // Cheating: using the pre-defined error codes, tricks Windows into displaying
00026 //           a semi-related human-readable error message if startup fails as
00027 //           opposed to simply scaring people with Error: 0xffffffff
00028 #define NT_SERVICE_ERROR_TORINIT_FAILED ERROR_EXCEPTION_IN_SERVICE
00029 
00030 static SERVICE_STATUS service_status;
00031 static SERVICE_STATUS_HANDLE hStatus;
00032 
00033 /* XXXX This 'backup argv' and 'backup argc' business is an ugly hack. This
00034  * is a job for arguments, not globals.  Alas, some of the functions that
00035  * use them use them need to have fixed signatures, so they can be passed
00036  * to the NT service functions. */
00037 static char **backup_argv;
00038 static int backup_argc;
00039 
00040 static void nt_service_control(DWORD request);
00041 static void nt_service_body(int argc, char **argv);
00042 static void nt_service_main(void);
00043 static SC_HANDLE nt_service_open_scm(void);
00044 static SC_HANDLE nt_service_open(SC_HANDLE hSCManager);
00045 static int nt_service_start(SC_HANDLE hService);
00046 static int nt_service_stop(SC_HANDLE hService);
00047 static int nt_service_install(int argc, char **argv);
00048 static int nt_service_remove(void);
00049 static int nt_service_cmd_start(void);
00050 static int nt_service_cmd_stop(void);
00051 
00054 struct service_fns {
00055   int loaded;
00056 
00062   BOOL (WINAPI *ChangeServiceConfig2A_fn)(
00063                              SC_HANDLE hService,
00064                              DWORD dwInfoLevel,
00065                              LPVOID lpInfo);
00066 
00067   BOOL (WINAPI *CloseServiceHandle_fn)(
00068                              SC_HANDLE hSCObject);
00069 
00070   BOOL (WINAPI *ControlService_fn)(
00071                              SC_HANDLE hService,
00072                              DWORD dwControl,
00073                              LPSERVICE_STATUS lpServiceStatus);
00074 
00075   SC_HANDLE (WINAPI *CreateServiceA_fn)(
00076                              SC_HANDLE hSCManager,
00077                              LPCSTR lpServiceName,
00078                              LPCSTR lpDisplayName,
00079                              DWORD dwDesiredAccess,
00080                              DWORD dwServiceType,
00081                              DWORD dwStartType,
00082                              DWORD dwErrorControl,
00083                              LPCSTR lpBinaryPathName,
00084                              LPCSTR lpLoadOrderGroup,
00085                              LPDWORD lpdwTagId,
00086                              LPCSTR lpDependencies,
00087                              LPCSTR lpServiceStartName,
00088                              LPCSTR lpPassword);
00089 
00090   BOOL (WINAPI *DeleteService_fn)(
00091                              SC_HANDLE hService);
00092 
00093   SC_HANDLE (WINAPI *OpenSCManagerA_fn)(
00094                              LPCSTR lpMachineName,
00095                              LPCSTR lpDatabaseName,
00096                              DWORD dwDesiredAccess);
00097 
00098   SC_HANDLE (WINAPI *OpenServiceA_fn)(
00099                              SC_HANDLE hSCManager,
00100                              LPCSTR lpServiceName,
00101                              DWORD dwDesiredAccess);
00102 
00103   BOOL (WINAPI *QueryServiceStatus_fn)(
00104                              SC_HANDLE hService,
00105                              LPSERVICE_STATUS lpServiceStatus);
00106 
00107   SERVICE_STATUS_HANDLE (WINAPI *RegisterServiceCtrlHandlerA_fn)(
00108                              LPCSTR lpServiceName,
00109                              LPHANDLER_FUNCTION lpHandlerProc);
00110 
00111   BOOL (WINAPI *SetServiceStatus_fn)(SERVICE_STATUS_HANDLE,
00112                              LPSERVICE_STATUS);
00113 
00114   BOOL (WINAPI *StartServiceCtrlDispatcherA_fn)(
00115                              const SERVICE_TABLE_ENTRYA* lpServiceTable);
00116 
00117   BOOL (WINAPI *StartServiceA_fn)(
00118                              SC_HANDLE hService,
00119                              DWORD dwNumServiceArgs,
00120                              LPCSTR* lpServiceArgVectors);
00121 
00122   BOOL (WINAPI *LookupAccountNameA_fn)(
00123                              LPCSTR lpSystemName,
00124                              LPCSTR lpAccountName,
00125                              PSID Sid,
00126                              LPDWORD cbSid,
00127                              LPTSTR ReferencedDomainName,
00128                              LPDWORD cchReferencedDomainName,
00129                              PSID_NAME_USE peUse);
00131 } service_fns = { 0,
00132                   NULL, NULL, NULL, NULL, NULL, NULL,
00133                   NULL, NULL, NULL, NULL, NULL, NULL,
00134                   NULL};
00135 
00138 static void
00139 nt_service_loadlibrary(void)
00140 {
00141   HMODULE library = 0;
00142   void *fn;
00143 
00144   if (service_fns.loaded)
00145     return;
00146 
00147   if (!(library = load_windows_system_library(TEXT("advapi32.dll")))) {
00148     log_err(LD_GENERAL, "Couldn't open advapi32.dll.  Are you trying to use "
00149             "NT services on Windows 98? That doesn't work.");
00150     goto err;
00151   }
00152 
00153 /* Helper macro: try to load a function named <b>f</b> from "library" into
00154  * service_functions.<b>f</b>_fn.  On failure, log an error message, and goto
00155  * err.
00156  */
00157 #define LOAD(f) STMT_BEGIN                                              \
00158     if (!(fn = GetProcAddress(library, #f))) {                          \
00159       log_err(LD_BUG,                                                   \
00160               "Couldn't find %s in advapi32.dll! We probably got the "  \
00161               "name wrong.", #f);                                       \
00162       goto err;                                                         \
00163     } else {                                                            \
00164       service_fns.f ## _fn = fn;                                        \
00165     }                                                                   \
00166   STMT_END
00167 
00168   LOAD(ChangeServiceConfig2A);
00169   LOAD(CloseServiceHandle);
00170   LOAD(ControlService);
00171   LOAD(CreateServiceA);
00172   LOAD(DeleteService);
00173   LOAD(OpenSCManagerA);
00174   LOAD(OpenServiceA);
00175   LOAD(QueryServiceStatus);
00176   LOAD(RegisterServiceCtrlHandlerA);
00177   LOAD(SetServiceStatus);
00178   LOAD(StartServiceCtrlDispatcherA);
00179   LOAD(StartServiceA);
00180   LOAD(LookupAccountNameA);
00181 
00182   service_fns.loaded = 1;
00183 
00184   return;
00185  err:
00186   printf("Unable to load library support for NT services: exiting.\n");
00187   exit(1);
00188 }
00189 
00194 int
00195 nt_service_is_stopping(void)
00196 {
00197   /* If we haven't loaded the function pointers, we can't possibly be an NT
00198    * service trying to shut down. */
00199   if (!service_fns.loaded)
00200     return 0;
00201 
00202   if (service_status.dwCurrentState == SERVICE_STOP_PENDING) {
00203     service_status.dwWin32ExitCode = 0;
00204     service_status.dwCurrentState = SERVICE_STOPPED;
00205     service_fns.SetServiceStatus_fn(hStatus, &service_status);
00206     return 1;
00207   } else if (service_status.dwCurrentState == SERVICE_STOPPED) {
00208     return 1;
00209   }
00210   return 0;
00211 }
00212 
00214 void
00215 nt_service_set_state(DWORD state)
00216 {
00217   service_status.dwCurrentState = state;
00218 }
00219 
00222 static void
00223 nt_service_control(DWORD request)
00224 {
00225   static struct timeval exit_now;
00226   exit_now.tv_sec  = 0;
00227   exit_now.tv_usec = 0;
00228 
00229   nt_service_loadlibrary();
00230 
00231   switch (request) {
00232     case SERVICE_CONTROL_STOP:
00233         case SERVICE_CONTROL_SHUTDOWN:
00234           log_notice(LD_GENERAL,
00235                      "Got stop/shutdown request; shutting down cleanly.");
00236           service_status.dwCurrentState = SERVICE_STOP_PENDING;
00237           event_base_loopexit(tor_libevent_get_base(), &exit_now);
00238           return;
00239   }
00240   service_fns.SetServiceStatus_fn(hStatus, &service_status);
00241 }
00242 
00247 static void
00248 nt_service_body(int argc, char **argv)
00249 {
00250   int r;
00251   (void) argc; /* unused */
00252   (void) argv; /* unused */
00253   nt_service_loadlibrary();
00254   service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
00255   service_status.dwCurrentState = SERVICE_START_PENDING;
00256   service_status.dwControlsAccepted =
00257         SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
00258   service_status.dwWin32ExitCode = 0;
00259   service_status.dwServiceSpecificExitCode = 0;
00260   service_status.dwCheckPoint = 0;
00261   service_status.dwWaitHint = 1000;
00262   hStatus = service_fns.RegisterServiceCtrlHandlerA_fn(GENSRV_SERVICENAME,
00263                                    (LPHANDLER_FUNCTION) nt_service_control);
00264 
00265   if (hStatus == 0) {
00266     /* Failed to register the service control handler function */
00267     return;
00268   }
00269 
00270   r = tor_init(backup_argc, backup_argv);
00271   if (r) {
00272     /* Failed to start the Tor service */
00273     r = NT_SERVICE_ERROR_TORINIT_FAILED;
00274     service_status.dwCurrentState = SERVICE_STOPPED;
00275     service_status.dwWin32ExitCode = r;
00276     service_status.dwServiceSpecificExitCode = r;
00277     service_fns.SetServiceStatus_fn(hStatus, &service_status);
00278     return;
00279   }
00280 
00281   /* Set the service's status to SERVICE_RUNNING and start the main
00282    * event loop */
00283   service_status.dwCurrentState = SERVICE_RUNNING;
00284   service_fns.SetServiceStatus_fn(hStatus, &service_status);
00285   do_main_loop();
00286   tor_cleanup();
00287 }
00288 
00291 static void
00292 nt_service_main(void)
00293 {
00294   SERVICE_TABLE_ENTRYA table[2];
00295   DWORD result = 0;
00296   char *errmsg;
00297   nt_service_loadlibrary();
00298   table[0].lpServiceName = (char*)GENSRV_SERVICENAME;
00299   table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTIONA)nt_service_body;
00300   table[1].lpServiceName = NULL;
00301   table[1].lpServiceProc = NULL;
00302 
00303   if (!service_fns.StartServiceCtrlDispatcherA_fn(table)) {
00304     result = GetLastError();
00305     errmsg = format_win32_error(result);
00306     printf("Service error %d : %s\n", (int) result, errmsg);
00307     tor_free(errmsg);
00308     if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
00309       if (tor_init(backup_argc, backup_argv) < 0)
00310         return;
00311       switch (get_options()->command) {
00312       case CMD_RUN_TOR:
00313         do_main_loop();
00314         break;
00315       case CMD_LIST_FINGERPRINT:
00316       case CMD_HASH_PASSWORD:
00317       case CMD_VERIFY_CONFIG:
00318         log_err(LD_CONFIG, "Unsupported command (--list-fingerprint, "
00319                 "--hash-password, or --verify-config) in NT service.");
00320         break;
00321       case CMD_RUN_UNITTESTS:
00322       default:
00323         log_err(LD_CONFIG, "Illegal command number %d: internal error.",
00324                 get_options()->command);
00325       }
00326       tor_cleanup();
00327     }
00328   }
00329 }
00330 
00333 static SC_HANDLE
00334 nt_service_open_scm(void)
00335 {
00336   SC_HANDLE hSCManager;
00337   char *errmsg = NULL;
00338 
00339   nt_service_loadlibrary();
00340   if ((hSCManager = service_fns.OpenSCManagerA_fn(
00341                             NULL, NULL, SC_MANAGER_CREATE_SERVICE)) == NULL) {
00342     errmsg = format_win32_error(GetLastError());
00343     printf("OpenSCManager() failed : %s\n", errmsg);
00344     tor_free(errmsg);
00345   }
00346   return hSCManager;
00347 }
00348 
00351 static SC_HANDLE
00352 nt_service_open(SC_HANDLE hSCManager)
00353 {
00354   SC_HANDLE hService;
00355   char *errmsg = NULL;
00356   nt_service_loadlibrary();
00357   if ((hService = service_fns.OpenServiceA_fn(hSCManager, GENSRV_SERVICENAME,
00358                               SERVICE_ALL_ACCESS)) == NULL) {
00359     errmsg = format_win32_error(GetLastError());
00360     printf("OpenService() failed : %s\n", errmsg);
00361     tor_free(errmsg);
00362   }
00363   return hService;
00364 }
00365 
00368 static int
00369 nt_service_start(SC_HANDLE hService)
00370 {
00371   char *errmsg = NULL;
00372 
00373   nt_service_loadlibrary();
00374 
00375   service_fns.QueryServiceStatus_fn(hService, &service_status);
00376   if (service_status.dwCurrentState == SERVICE_RUNNING) {
00377     printf("Service is already running\n");
00378     return 0;
00379   }
00380 
00381   if (service_fns.StartServiceA_fn(hService, 0, NULL)) {
00382     /* Loop until the service has finished attempting to start */
00383     while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
00384            (service_status.dwCurrentState == SERVICE_START_PENDING)) {
00385       Sleep(500);
00386     }
00387 
00388     /* Check if it started successfully or not */
00389     if (service_status.dwCurrentState == SERVICE_RUNNING) {
00390       printf("Service started successfully\n");
00391       return 0;
00392     } else {
00393       errmsg = format_win32_error(service_status.dwWin32ExitCode);
00394       printf("Service failed to start : %s\n", errmsg);
00395       tor_free(errmsg);
00396     }
00397   } else {
00398     errmsg = format_win32_error(GetLastError());
00399     printf("StartService() failed : %s\n", errmsg);
00400     tor_free(errmsg);
00401   }
00402   return -1;
00403 }
00404 
00407 static int
00408 nt_service_stop(SC_HANDLE hService)
00409 {
00411 #define MAX_SERVICE_WAIT_TIME 10
00412   int wait_time;
00413   char *errmsg = NULL;
00414   nt_service_loadlibrary();
00415 
00416   service_fns.QueryServiceStatus_fn(hService, &service_status);
00417   if (service_status.dwCurrentState == SERVICE_STOPPED) {
00418     printf("Service is already stopped\n");
00419     return 0;
00420   }
00421 
00422   if (service_fns.ControlService_fn(hService, SERVICE_CONTROL_STOP,
00423                                     &service_status)) {
00424     wait_time = 0;
00425     while (service_fns.QueryServiceStatus_fn(hService, &service_status) &&
00426            (service_status.dwCurrentState != SERVICE_STOPPED) &&
00427            (wait_time < MAX_SERVICE_WAIT_TIME)) {
00428       Sleep(1000);
00429       wait_time++;
00430     }
00431     if (service_status.dwCurrentState == SERVICE_STOPPED) {
00432       printf("Service stopped successfully\n");
00433       return 0;
00434     } else if (wait_time == MAX_SERVICE_WAIT_TIME) {
00435       printf("Service did not stop within %d seconds.\n", wait_time);
00436     } else {
00437       errmsg = format_win32_error(GetLastError());
00438       printf("QueryServiceStatus() failed : %s\n",errmsg);
00439       tor_free(errmsg);
00440     }
00441   } else {
00442     errmsg = format_win32_error(GetLastError());
00443     printf("ControlService() failed : %s\n", errmsg);
00444     tor_free(errmsg);
00445   }
00446   return -1;
00447 }
00448 
00454 static char *
00455 nt_service_command_line(int *using_default_torrc)
00456 {
00457   TCHAR tor_exe[MAX_PATH+1];
00458   char tor_exe_ascii[MAX_PATH*2+1];
00459   char *command=NULL, *options=NULL;
00460   smartlist_t *sl;
00461   int i;
00462   *using_default_torrc = 1;
00463 
00464   /* Get the location of tor.exe */
00465   if (0 == GetModuleFileName(NULL, tor_exe, MAX_PATH))
00466     return NULL;
00467 
00468   /* Get the service arguments */
00469   sl = smartlist_new();
00470   for (i = 1; i < backup_argc; ++i) {
00471     if (!strcmp(backup_argv[i], "--options") ||
00472         !strcmp(backup_argv[i], "-options")) {
00473       while (++i < backup_argc) {
00474         if (!strcmp(backup_argv[i], "-f"))
00475           *using_default_torrc = 0;
00476         smartlist_add(sl, backup_argv[i]);
00477       }
00478     }
00479   }
00480   if (smartlist_len(sl))
00481     options = smartlist_join_strings(sl,"\" \"",0,NULL);
00482   smartlist_free(sl);
00483 
00484 #ifdef UNICODE
00485   wcstombs(tor_exe_ascii, tor_exe, sizeof(tor_exe_ascii));
00486   tor_exe_ascii[sizeof(tor_exe_ascii)-1] = '\0';
00487 #else
00488   strlcpy(tor_exe_ascii, tor_exe, sizeof(tor_exe_ascii));
00489 #endif
00490 
00491   /* Allocate a string for the NT service command line and */
00492   /* Format the service command */
00493   if (options) {
00494     tor_asprintf(&command, "\"%s\" --nt-service \"%s\"",
00495                  tor_exe_ascii, options);
00496   } else { /* ! options */
00497     tor_asprintf(&command, "\"%s\" --nt-service", tor_exe_ascii);
00498   }
00499 
00500   tor_free(options);
00501   return command;
00502 }
00503 
00507 static int
00508 nt_service_install(int argc, char **argv)
00509 {
00510   /* Notes about developing NT services:
00511    *
00512    * 1. Don't count on your CWD. If an absolute path is not given, the
00513    *    fopen() function goes wrong.
00514    * 2. The parameters given to the nt_service_body() function differ
00515    *    from those given to main() function.
00516    */
00517 
00518   SC_HANDLE hSCManager = NULL;
00519   SC_HANDLE hService = NULL;
00520   SERVICE_DESCRIPTIONA sdBuff;
00521   char *command;
00522   char *errmsg;
00523   const char *user_acct = NULL;
00524   const char *password = "";
00525   int i;
00526   OSVERSIONINFOEX info;
00527   SID_NAME_USE sidUse;
00528   DWORD sidLen = 0, domainLen = 0;
00529   int is_win2k_or_worse = 0;
00530   int using_default_torrc = 0;
00531 
00532   nt_service_loadlibrary();
00533 
00534   /* Open the service control manager so we can create a new service */
00535   if ((hSCManager = nt_service_open_scm()) == NULL)
00536     return -1;
00537   /* Build the command line used for the service */
00538   if ((command = nt_service_command_line(&using_default_torrc)) == NULL) {
00539     printf("Unable to build service command line.\n");
00540     service_fns.CloseServiceHandle_fn(hSCManager);
00541     return -1;
00542   }
00543 
00544   for (i=1; i < argc; ++i) {
00545     if (!strcmp(argv[i], "--user") && i+1<argc) {
00546       user_acct = argv[i+1];
00547       ++i;
00548     }
00549     if (!strcmp(argv[i], "--password") && i+1<argc) {
00550       password = argv[i+1];
00551       ++i;
00552     }
00553   }
00554 
00555   /* Compute our version and see whether we're running win2k or earlier. */
00556   memset(&info, 0, sizeof(info));
00557   info.dwOSVersionInfoSize = sizeof(info);
00558   if (! GetVersionEx((LPOSVERSIONINFO)&info)) {
00559     printf("Call to GetVersionEx failed.\n");
00560     is_win2k_or_worse = 1;
00561   } else {
00562     if (info.dwMajorVersion < 5 ||
00563         (info.dwMajorVersion == 5 && info.dwMinorVersion == 0))
00564       is_win2k_or_worse = 1;
00565   }
00566 
00567   if (!user_acct) {
00568     if (is_win2k_or_worse) {
00569       /* On Win2k, there is no LocalService account, so we actually need to
00570        * fall back on NULL (the system account). */
00571       printf("Running on Win2K or earlier, so the LocalService account "
00572              "doesn't exist.  Falling back to SYSTEM account.\n");
00573     } else {
00574       /* Genericity is apparently _so_ last year in Redmond, where some
00575        * accounts are accounts that you can look up, and some accounts
00576        * are magic and undetectable via the security subsystem. See
00577        * http://msdn2.microsoft.com/en-us/library/ms684188.aspx
00578        */
00579       printf("Running on a Post-Win2K OS, so we'll assume that the "
00580              "LocalService account exists.\n");
00581       user_acct = GENSRV_USERACCT;
00582     }
00583   } else if (0 && service_fns.LookupAccountNameA_fn(NULL, // On this system
00584                             user_acct,
00585                             NULL, &sidLen, // Don't care about the SID
00586                             NULL, &domainLen, // Don't care about the domain
00587                             &sidUse) == 0) {
00588     /* XXXX For some reason, the above test segfaults. Fix that. */
00589     printf("User \"%s\" doesn't seem to exist.\n", user_acct);
00590     return -1;
00591   } else {
00592     printf("Will try to install service as user \"%s\".\n", user_acct);
00593   }
00594   /* XXXX This warning could be better about explaining how to resolve the
00595    * situation. */
00596   if (using_default_torrc)
00597     printf("IMPORTANT NOTE:\n"
00598         "    The Tor service will run under the account \"%s\".  This means\n"
00599         "    that Tor will look for its configuration file under that\n"
00600         "    account's Application Data directory, which is probably not\n"
00601         "    the same as yours.\n", user_acct?user_acct:"<local system>");
00602 
00603   /* Create the Tor service, set to auto-start on boot */
00604   if ((hService = service_fns.CreateServiceA_fn(hSCManager, GENSRV_SERVICENAME,
00605                                 GENSRV_DISPLAYNAME,
00606                                 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
00607                                 SERVICE_AUTO_START, SERVICE_ERROR_IGNORE,
00608                                 command, NULL, NULL, NULL,
00609                                 user_acct, password)) == NULL) {
00610     errmsg = format_win32_error(GetLastError());
00611     printf("CreateService() failed : %s\n", errmsg);
00612     service_fns.CloseServiceHandle_fn(hSCManager);
00613     tor_free(errmsg);
00614     tor_free(command);
00615     return -1;
00616   }
00617   printf("Done with CreateService.\n");
00618 
00619   /* Set the service's description */
00620   sdBuff.lpDescription = (char*)GENSRV_DESCRIPTION;
00621   service_fns.ChangeServiceConfig2A_fn(hService, SERVICE_CONFIG_DESCRIPTION,
00622                                        &sdBuff);
00623   printf("Service installed successfully\n");
00624 
00625   /* Start the service initially */
00626   nt_service_start(hService);
00627 
00628   service_fns.CloseServiceHandle_fn(hService);
00629   service_fns.CloseServiceHandle_fn(hSCManager);
00630   tor_free(command);
00631 
00632   return 0;
00633 }
00634 
00637 static int
00638 nt_service_remove(void)
00639 {
00640   SC_HANDLE hSCManager = NULL;
00641   SC_HANDLE hService = NULL;
00642   char *errmsg;
00643 
00644   nt_service_loadlibrary();
00645   if ((hSCManager = nt_service_open_scm()) == NULL)
00646     return -1;
00647   if ((hService = nt_service_open(hSCManager)) == NULL) {
00648     service_fns.CloseServiceHandle_fn(hSCManager);
00649     return -1;
00650   }
00651 
00652   nt_service_stop(hService);
00653   if (service_fns.DeleteService_fn(hService) == FALSE) {
00654     errmsg = format_win32_error(GetLastError());
00655     printf("DeleteService() failed : %s\n", errmsg);
00656     tor_free(errmsg);
00657     service_fns.CloseServiceHandle_fn(hService);
00658     service_fns.CloseServiceHandle_fn(hSCManager);
00659     return -1;
00660   }
00661 
00662   service_fns.CloseServiceHandle_fn(hService);
00663   service_fns.CloseServiceHandle_fn(hSCManager);
00664   printf("Service removed successfully\n");
00665 
00666   return 0;
00667 }
00668 
00670 static int
00671 nt_service_cmd_start(void)
00672 {
00673   SC_HANDLE hSCManager;
00674   SC_HANDLE hService;
00675   int start;
00676 
00677   if ((hSCManager = nt_service_open_scm()) == NULL)
00678     return -1;
00679   if ((hService = nt_service_open(hSCManager)) == NULL) {
00680     service_fns.CloseServiceHandle_fn(hSCManager);
00681     return -1;
00682   }
00683 
00684   start = nt_service_start(hService);
00685   service_fns.CloseServiceHandle_fn(hService);
00686   service_fns.CloseServiceHandle_fn(hSCManager);
00687 
00688   return start;
00689 }
00690 
00692 static int
00693 nt_service_cmd_stop(void)
00694 {
00695   SC_HANDLE hSCManager;
00696   SC_HANDLE hService;
00697   int stop;
00698 
00699   if ((hSCManager = nt_service_open_scm()) == NULL)
00700     return -1;
00701   if ((hService = nt_service_open(hSCManager)) == NULL) {
00702     service_fns.CloseServiceHandle_fn(hSCManager);
00703     return -1;
00704   }
00705 
00706   stop = nt_service_stop(hService);
00707   service_fns.CloseServiceHandle_fn(hService);
00708   service_fns.CloseServiceHandle_fn(hSCManager);
00709 
00710   return stop;
00711 }
00712 
00713 int
00714 nt_service_parse_options(int argc, char **argv, int *should_exit)
00715 {
00716   backup_argv = argv;
00717   backup_argc = argc;
00718   *should_exit = 0;
00719 
00720   if ((argc >= 3) &&
00721       (!strcmp(argv[1], "-service") || !strcmp(argv[1], "--service"))) {
00722     nt_service_loadlibrary();
00723     *should_exit = 1;
00724     if (!strcmp(argv[2], "install"))
00725       return nt_service_install(argc, argv);
00726     if (!strcmp(argv[2], "remove"))
00727       return nt_service_remove();
00728     if (!strcmp(argv[2], "start"))
00729       return nt_service_cmd_start();
00730     if (!strcmp(argv[2], "stop"))
00731       return nt_service_cmd_stop();
00732     printf("Unrecognized service command '%s'\n", argv[2]);
00733     return 1;
00734   }
00735   if (argc >= 2) {
00736     if (!strcmp(argv[1], "-nt-service") || !strcmp(argv[1], "--nt-service")) {
00737       nt_service_loadlibrary();
00738       nt_service_main();
00739       *should_exit = 1;
00740       return 0;
00741     }
00742     // These values have been deprecated since 0.1.1.2-alpha; we've warned
00743     // about them since 0.1.2.7-alpha.
00744     if (!strcmp(argv[1], "-install") || !strcmp(argv[1], "--install")) {
00745       nt_service_loadlibrary();
00746       fprintf(stderr,
00747             "The %s option is deprecated; use \"--service install\" instead.",
00748             argv[1]);
00749       *should_exit = 1;
00750       return nt_service_install(argc, argv);
00751     }
00752     if (!strcmp(argv[1], "-remove") || !strcmp(argv[1], "--remove")) {
00753       nt_service_loadlibrary();
00754       fprintf(stderr,
00755             "The %s option is deprecated; use \"--service remove\" instead.",
00756             argv[1]);
00757       *should_exit = 1;
00758       return nt_service_remove();
00759     }
00760   }
00761   *should_exit = 0;
00762   return 0;
00763 }
00764