Imported Upstream version 0.3.5
[anytun.git] / src / win32 / winService.cpp
index b6ea67f..fd666d4 100644 (file)
-/*\r
- *  anytun\r
- *\r
- *  The secure anycast tunneling protocol (satp) defines a protocol used\r
- *  for communication between any combination of unicast and anycast\r
- *  tunnel endpoints.  It has less protocol overhead than IPSec in Tunnel\r
- *  mode and allows tunneling of every ETHER TYPE protocol (e.g.\r
- *  ethernet, ip, arp ...). satp directly includes cryptography and\r
- *  message authentication based on the methodes used by SRTP.  It is\r
- *  intended to deliver a generic, scaleable and secure solution for\r
- *  tunneling and relaying of packets of any protocol.\r
- *\r
- *\r
- *  Copyright (C) 2007-2008 Othmar Gsenger, Erwin Nindl, \r
- *                          Christian Pointner <satp@wirdorange.org>\r
- *\r
- *  This file is part of Anytun.\r
- *\r
- *  Anytun is free software: you can redistribute it and/or modify\r
- *  it under the terms of the GNU General Public License version 3 as\r
- *  published by the Free Software Foundation.\r
- *\r
- *  Anytun is distributed in the hope that it will be useful,\r
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- *  GNU General Public License for more details.\r
- *\r
- *  You should have received a copy of the GNU General Public License\r
- *  along with anytun.  If not, see <http://www.gnu.org/licenses/>.\r
- */\r
-\r
-#ifdef WIN_SERVICE\r
-\r
-#include <iostream>\r
-\r
-#include <windows.h>\r
-\r
-#include "winService.h"\r
-#include "../log.h"\r
-#include "../anytunError.h"\r
-#include "../threadUtils.hpp"\r
-\r
-WinService* WinService::inst = NULL;\r
-Mutex WinService::instMutex;\r
-WinService& gWinService = WinService::instance();\r
-\r
-WinService& WinService::instance()\r
-{\r
-       Lock lock(instMutex);\r
-       static instanceCleaner c;\r
-       if(!inst)\r
-               inst = new WinService();\r
-       \r
-       return *inst;\r
-}\r
-\r
-WinService::~WinService()\r
-{\r
-  if(started_)\r
-    CloseHandle(stop_event_);\r
-}\r
-\r
-void WinService::install()\r
-{\r
-  SC_HANDLE schSCManager;\r
-  SC_HANDLE schService;\r
-  char szPath[MAX_PATH];\r
-\r
-  if(!GetModuleFileNameA(NULL, szPath, MAX_PATH))\r
-    AnytunError::throwErr() << "Error on GetModuleFileName: " << AnytunErrno(GetLastError());\r
-\r
-  schSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);\r
-  if(NULL == schSCManager)\r
-    AnytunError::throwErr() << "Error on OpenSCManager: " << AnytunErrno(GetLastError());\r
-\r
-  schService = CreateServiceA(schSCManager, SVC_NAME, SVC_NAME, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, \r
-                              SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, szPath, NULL, NULL, NULL, NULL, NULL);\r
-  if(schService == NULL) {\r
-    CloseServiceHandle(schSCManager);\r
-    AnytunError::throwErr() << "Error on CreateService: " << AnytunErrno(GetLastError());\r
-  }\r
-\r
-  std::cout << "Service installed successfully" << std::endl; \r
-\r
-  CloseServiceHandle(schService); \r
-  CloseServiceHandle(schSCManager);\r
-}\r
-\r
-void WinService::uninstall()\r
-{\r
-  SC_HANDLE schSCManager;\r
-  SC_HANDLE schService;\r
-\r
-  schSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);\r
-  if(NULL == schSCManager)\r
-    AnytunError::throwErr() << "Error on OpenSCManager: " << AnytunErrno(GetLastError());\r
-\r
-  schService = OpenServiceA(schSCManager, SVC_NAME, SERVICE_ALL_ACCESS);\r
-  if(schService == NULL) {\r
-    CloseServiceHandle(schSCManager);\r
-    AnytunError::throwErr() << "Error on CreateService: " << AnytunErrno(GetLastError());\r
-  }\r
-\r
-  if(!DeleteService(schService)) {\r
-    CloseServiceHandle(schService); \r
-    CloseServiceHandle(schSCManager);\r
-    AnytunError::throwErr() << "Error on DeleteService: " << AnytunErrno(GetLastError());\r
-  }\r
-\r
-  std::cout << "Service uninstalled successfully" << std::endl; \r
-\r
-  CloseServiceHandle(schService); \r
-  CloseServiceHandle(schSCManager);\r
-}\r
-\r
-void WinService::start()\r
-{\r
-  SERVICE_TABLE_ENTRY DispatchTable[] = {\r
-    {SVC_NAME, (LPSERVICE_MAIN_FUNCTION)WinService::main },\r
-    {NULL, NULL}\r
-  };\r
-\r
-  if(!StartServiceCtrlDispatcherA(DispatchTable))\r
-    AnytunError::throwErr() << "Error on StartServiceCtrlDispatcher: " << AnytunErrno(GetLastError());\r
-}\r
-\r
-void WinService::waitForStop()\r
-{\r
-  if(!started_)\r
-    AnytunError::throwErr() << "Service not started correctly";\r
-  \r
-  reportStatus(SERVICE_RUNNING, NO_ERROR);\r
-  WaitForSingleObject(stop_event_, INFINITE);\r
-  reportStatus(SERVICE_STOP_PENDING, NO_ERROR);\r
-  cLog.msg(Log::PRIO_NOTICE) << "WinService received stop signal, exitting";\r
-}\r
-\r
-void WinService::stop()\r
-{\r
-  if(!started_)\r
-    AnytunError::throwErr() << "Service not started correctly";\r
-\r
-  reportStatus(SERVICE_STOPPED, NO_ERROR);\r
-}\r
-\r
-int real_main(int argc, char* argv[]);\r
-\r
-VOID WINAPI WinService::main(DWORD dwArgc, LPTSTR *lpszArgv)\r
-{\r
-  if(gWinService.started_) {\r
-    cLog.msg(Log::PRIO_ERROR) << "Service is already running";\r
-    return;\r
-  }\r
-\r
-  gWinService.status_handle_ = RegisterServiceCtrlHandlerA(SVC_NAME, WinService::ctrlHandler);\r
-  if(!gWinService.status_handle_) { \r
-    cLog.msg(Log::PRIO_ERROR) << "Error on RegisterServiceCtrlHandler: " << AnytunErrno(GetLastError());\r
-    return;\r
-  }\r
-  gWinService.status_.dwServiceType = SERVICE_WIN32_OWN_PROCESS; \r
-  gWinService.status_.dwServiceSpecificExitCode = 0;    \r
-  gWinService.reportStatus(SERVICE_START_PENDING, NO_ERROR);\r
-  gWinService.started_ = true;\r
-  \r
-  gWinService.stop_event_ = CreateEvent(NULL, true, false, NULL);\r
-  if(!gWinService.stop_event_) {\r
-    cLog.msg(Log::PRIO_ERROR) << "WinService Error on CreateEvent: " << AnytunErrno(GetLastError());\r
-    gWinService.reportStatus(SERVICE_STOPPED, -1);\r
-    return;\r
-  }\r
-\r
-  real_main(dwArgc, lpszArgv);\r
-}\r
-\r
-VOID WINAPI WinService::ctrlHandler(DWORD dwCtrl)\r
-{\r
-  switch(dwCtrl) {\r
-    case SERVICE_CONTROL_STOP: {\r
-      gWinService.reportStatus(SERVICE_STOP_PENDING, NO_ERROR);\r
-      SetEvent(gWinService.stop_event_);\r
-      return;\r
-    }\r
-    case SERVICE_CONTROL_INTERROGATE: break;\r
-    default: break;\r
-  }\r
-  gWinService.reportStatus(gWinService.status_.dwCurrentState, NO_ERROR);\r
-}\r
-\r
-void WinService::reportStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)\r
-{\r
-  static DWORD dwCheckPoint = 1;\r
-\r
-  status_.dwCurrentState = dwCurrentState;\r
-  status_.dwWin32ExitCode = dwWin32ExitCode;\r
-  status_.dwWaitHint = dwWaitHint;\r
-\r
-  if((dwCurrentState == SERVICE_START_PENDING) ||\r
-     (dwCurrentState == SERVICE_STOP_PENDING))\r
-    status_.dwControlsAccepted = 0;\r
-  else \r
-    status_.dwControlsAccepted = SERVICE_ACCEPT_STOP;\r
-\r
-  if((dwCurrentState == SERVICE_RUNNING) ||\r
-     (dwCurrentState == SERVICE_STOPPED))\r
-    status_.dwCheckPoint = 0;\r
-  else\r
-    status_.dwCheckPoint = dwCheckPoint++;\r
-\r
-  SetServiceStatus(status_handle_, &status_);\r
-}\r
-\r
-#endif\r
+/*
+ *  anytun
+ *
+ *  The secure anycast tunneling protocol (satp) defines a protocol used
+ *  for communication between any combination of unicast and anycast
+ *  tunnel endpoints.  It has less protocol overhead than IPSec in Tunnel
+ *  mode and allows tunneling of every ETHER TYPE protocol (e.g.
+ *  ethernet, ip, arp ...). satp directly includes cryptography and
+ *  message authentication based on the methods used by SRTP.  It is
+ *  intended to deliver a generic, scaleable and secure solution for
+ *  tunneling and relaying of packets of any protocol.
+ *
+ *
+ *  Copyright (C) 2007-2014 Markus Grüneis, Othmar Gsenger, Erwin Nindl,
+ *                          Christian Pointner <satp@wirdorange.org>
+ *
+ *  This file is part of Anytun.
+ *
+ *  Anytun is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  any later version.
+ *
+ *  Anytun is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Anytun.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  In addition, as a special exception, the copyright holders give
+ *  permission to link the code of portions of this program with the
+ *  OpenSSL library under certain conditions as described in each
+ *  individual source file, and distribute linked combinations
+ *  including the two.
+ *  You must obey the GNU General Public License in all respects
+ *  for all of the code used other than OpenSSL.  If you modify
+ *  file(s) with this exception, you may extend this exception to your
+ *  version of the file(s), but you are not obligated to do so.  If you
+ *  do not wish to do so, delete this exception statement from your
+ *  version.  If you delete this exception statement from all source
+ *  files in the program, then also delete it here.
+ */
+
+#ifdef WIN_SERVICE
+
+#include <iostream>
+
+#include <windows.h>
+
+#include "winService.h"
+#include "../log.h"
+#include "../anytunError.h"
+#include "../threadUtils.hpp"
+
+void WinService::install()
+{
+  SC_HANDLE schSCManager;
+  SC_HANDLE schService;
+  char szPath[MAX_PATH];
+
+  if(!GetModuleFileNameA(NULL, szPath, MAX_PATH)) {
+    AnytunError::throwErr() << "Error on GetModuleFileName: " << AnytunErrno(GetLastError());
+  }
+
+  schSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+  if(NULL == schSCManager) {
+    AnytunError::throwErr() << "Error on OpenSCManager: " << AnytunErrno(GetLastError());
+  }
+
+  schService = CreateServiceA(schSCManager, SVC_NAME, SVC_NAME, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
+                              SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, szPath, NULL, NULL, NULL, NULL, NULL);
+  if(schService == NULL) {
+    CloseServiceHandle(schSCManager);
+    AnytunError::throwErr() << "Error on CreateService: " << AnytunErrno(GetLastError());
+  }
+
+  std::cout << "Service installed successfully" << std::endl;
+
+  CloseServiceHandle(schService);
+  CloseServiceHandle(schSCManager);
+}
+
+void WinService::uninstall()
+{
+  SC_HANDLE schSCManager;
+  SC_HANDLE schService;
+
+  schSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+  if(NULL == schSCManager) {
+    AnytunError::throwErr() << "Error on OpenSCManager: " << AnytunErrno(GetLastError());
+  }
+
+  schService = OpenServiceA(schSCManager, SVC_NAME, SERVICE_ALL_ACCESS);
+  if(schService == NULL) {
+    CloseServiceHandle(schSCManager);
+    AnytunError::throwErr() << "Error on CreateService: " << AnytunErrno(GetLastError());
+  }
+
+  if(!DeleteService(schService)) {
+    CloseServiceHandle(schService);
+    CloseServiceHandle(schSCManager);
+    AnytunError::throwErr() << "Error on DeleteService: " << AnytunErrno(GetLastError());
+  }
+
+  std::cout << "Service uninstalled successfully" << std::endl;
+
+  CloseServiceHandle(schService);
+  CloseServiceHandle(schSCManager);
+}
+
+void WinService::start()
+{
+  SERVICE_TABLE_ENTRY DispatchTable[] = {
+    {SVC_NAME, (LPSERVICE_MAIN_FUNCTION)WinService::main },
+    {NULL, NULL}
+  };
+
+  if(!StartServiceCtrlDispatcherA(DispatchTable)) {
+    AnytunError::throwErr() << "Error on StartServiceCtrlDispatcher: " << AnytunErrno(GetLastError());
+  }
+}
+
+int real_main(int argc, char* argv[], WinService& service);
+
+VOID WINAPI WinService::main(DWORD dwArgc, LPTSTR* lpszArgv)
+{
+  WinService service;
+
+  service.status_handle_ = RegisterServiceCtrlHandlerA(SVC_NAME, WinService::ctrlHandler);
+  if(!service.status_handle_) {
+    cLog.msg(Log::PRIO_ERROR) << "Error on RegisterServiceCtrlHandler: " << AnytunErrno(GetLastError());
+    return;
+  }
+  service.status_.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+  service.status_.dwServiceSpecificExitCode = 0;
+  service.reportStatus(SERVICE_START_PENDING, NO_ERROR);
+
+  real_main(dwArgc, lpszArgv, service);
+
+  service.reportStatus(SERVICE_STOPPED, NO_ERROR);
+}
+
+VOID WINAPI WinService::ctrlHandler(DWORD dwCtrl)
+{
+  gSignalController.inject(dwCtrl);
+}
+
+int WinService::handleCtrlSignal(int sig, const std::string& msg)
+{
+  switch(sig) {
+  case SERVICE_CONTROL_STOP: {
+    reportStatus(SERVICE_STOP_PENDING, NO_ERROR);
+    cLog.msg(Log::PRIO_NOTICE) << "received service stop signal, exitting";
+    return 1;
+  }
+  case SERVICE_CONTROL_INTERROGATE:
+    break;
+  default:
+    break;
+  }
+  reportStatus(status_.dwCurrentState, NO_ERROR);
+
+  return 0;
+}
+
+void WinService::reportStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode)
+{
+  static DWORD dwCheckPoint = 1;
+
+  status_.dwCurrentState = dwCurrentState;
+  status_.dwWin32ExitCode = dwWin32ExitCode;
+  status_.dwWaitHint = 0;
+
+  if((dwCurrentState == SERVICE_START_PENDING) ||
+      (dwCurrentState == SERVICE_STOP_PENDING)) {
+    status_.dwControlsAccepted = 0;
+  } else {
+    status_.dwControlsAccepted = SERVICE_ACCEPT_STOP;
+  }
+
+  if((dwCurrentState == SERVICE_RUNNING) ||
+      (dwCurrentState == SERVICE_STOPPED)) {
+    status_.dwCheckPoint = 0;
+  } else {
+    status_.dwCheckPoint = dwCheckPoint++;
+  }
+
+  SetServiceStatus(status_handle_, &status_);
+}
+
+void WinService::initPrivs(std::string const& username, std::string const& groupname)
+{
+  // nothing here
+}
+
+void WinService::dropPrivs()
+{
+  // nothing here
+}
+
+void WinService::chroot(std::string const& dir)
+{
+  // nothing here
+}
+
+void WinService::daemonize()
+{
+  // nothing here
+}
+
+bool WinService::isDaemonized()
+{
+  return true;
+}
+
+#endif