aboutsummaryrefslogtreecommitdiff
path: root/src/daemonizer/windows_service.cpp
diff options
context:
space:
mode:
authorRiccardo Spagni <ric@spagni.net>2015-03-24 08:50:08 +0200
committerRiccardo Spagni <ric@spagni.net>2015-03-24 08:53:05 +0200
commitd7286395c97afd9d33d6170c1cf24f1e38140b37 (patch)
tree5513e1477d68755a44e0b0c7d34542b1c75eb99d /src/daemonizer/windows_service.cpp
parent1c49d6b2d392f67df18cfa8103584957c1bfe562 (diff)
parent8855a32044f53c5aa39feac305cd357a39f90d90 (diff)
downloadmonzero-core-d7286395c97afd9d33d6170c1cf24f1e38140b37.tar.gz
monzero-core-d7286395c97afd9d33d6170c1cf24f1e38140b37.tar.xz
monzero-core-d7286395c97afd9d33d6170c1cf24f1e38140b37.zip
Merge pull request #243
51e3579 Fixed bug in static linking boost on MINGW (Thomas Winget) f78bb00 Hopefully fixes build on Windows for real this time (Thomas Winget) 2b0583b Hopefully fixes build on Windows (Thomas Winget) 9dab105 DNS checkpoint loading for testnet should now be correct (Thomas Winget) 52f9629 sending commands to forked daemon works on testnet now (Thomas Winget) 76289d0 Fix tests building -- function signatures changed (Thomas Winget) db53e19 revert stop_daemon method to use correct exit (Thomas Winget) 96cbecf RPC calls for background daemon added in (Thomas Winget) 9193d6f Daemonize changes pulled in -- daemon builds (Thomas Winget)
Diffstat (limited to 'src/daemonizer/windows_service.cpp')
-rw-r--r--src/daemonizer/windows_service.cpp341
1 files changed, 341 insertions, 0 deletions
diff --git a/src/daemonizer/windows_service.cpp b/src/daemonizer/windows_service.cpp
new file mode 100644
index 000000000..1b0ee2ef4
--- /dev/null
+++ b/src/daemonizer/windows_service.cpp
@@ -0,0 +1,341 @@
+#undef UNICODE
+#undef _UNICODE
+
+#include "common/scoped_message_writer.h"
+#include "daemonizer/windows_service.h"
+#include "string_tools.h"
+#include <chrono>
+#include <iostream>
+#include <utility>
+#include <memory>
+#include <shellapi.h>
+#include <thread>
+#include <windows.h>
+
+namespace windows {
+
+namespace {
+ typedef std::unique_ptr<std::remove_pointer<SC_HANDLE>::type, decltype(&::CloseServiceHandle)> service_handle;
+
+ std::string get_last_error()
+ {
+ LPSTR p_error_text = nullptr;
+
+ FormatMessage(
+ FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_ALLOCATE_BUFFER
+ | FORMAT_MESSAGE_IGNORE_INSERTS
+ , nullptr
+ , GetLastError()
+ , MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)
+ , reinterpret_cast<LPSTR>(&p_error_text)
+ , 0
+ , nullptr
+ );
+
+ if (nullptr == p_error_text)
+ {
+ return "";
+ }
+ else
+ {
+ return std::string{p_error_text};
+ LocalFree(p_error_text);
+ }
+ }
+
+ bool relaunch_as_admin(
+ std::string const & command
+ , std::string const & arguments
+ )
+ {
+ SHELLEXECUTEINFO info{};
+ info.cbSize = sizeof(info);
+ info.lpVerb = "runas";
+ info.lpFile = command.c_str();
+ info.lpParameters = arguments.c_str();
+ info.hwnd = nullptr;
+ info.nShow = SW_SHOWNORMAL;
+ if (!ShellExecuteEx(&info))
+ {
+ tools::fail_msg_writer() << "Admin relaunch failed: " << get_last_error();
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ // When we relaunch as admin, Windows opens a new window. This just pauses
+ // to allow the user to read any output.
+ void pause_to_display_admin_window_messages()
+ {
+ std::chrono::milliseconds how_long{1500};
+ std::this_thread::sleep_for(how_long);
+ }
+}
+
+bool check_admin(bool & result)
+{
+ BOOL is_admin = FALSE;
+ PSID p_administrators_group = nullptr;
+
+ SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY;
+
+ if (!AllocateAndInitializeSid(
+ &nt_authority
+ , 2
+ , SECURITY_BUILTIN_DOMAIN_RID
+ , DOMAIN_ALIAS_RID_ADMINS
+ , 0, 0, 0, 0, 0, 0
+ , &p_administrators_group
+ ))
+ {
+ tools::fail_msg_writer() << "Security Identifier creation failed: " << get_last_error();
+ return false;
+ }
+
+ if (!CheckTokenMembership(
+ nullptr
+ , p_administrators_group
+ , &is_admin
+ ))
+ {
+ tools::fail_msg_writer() << "Permissions check failed: " << get_last_error();
+ return false;
+ }
+
+ result = is_admin ? true : false;
+
+ return true;
+}
+
+bool ensure_admin(
+ std::string const & arguments
+ )
+{
+ bool admin;
+
+ if (!check_admin(admin))
+ {
+ return false;
+ }
+
+ if (admin)
+ {
+ return true;
+ }
+ else
+ {
+ std::string command = epee::string_tools::get_current_module_path();
+ relaunch_as_admin(command, arguments);
+ return false;
+ }
+}
+
+bool install_service(
+ std::string const & service_name
+ , std::string const & arguments
+ )
+{
+ std::string command = epee::string_tools::get_current_module_path();
+ std::string full_command = command + arguments;
+
+ service_handle p_manager{
+ OpenSCManager(
+ nullptr
+ , nullptr
+ , SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE
+ )
+ , &::CloseServiceHandle
+ };
+ if (p_manager == nullptr)
+ {
+ tools::fail_msg_writer() << "Couldn't connect to service manager: " << get_last_error();
+ return false;
+ }
+
+ service_handle p_service{
+ CreateService(
+ p_manager.get()
+ , service_name.c_str()
+ , service_name.c_str()
+ , 0
+ //, GENERIC_EXECUTE | GENERIC_READ
+ , SERVICE_WIN32_OWN_PROCESS
+ , SERVICE_DEMAND_START
+ , SERVICE_ERROR_NORMAL
+ , full_command.c_str()
+ , nullptr
+ , nullptr
+ , ""
+ //, "NT AUTHORITY\\LocalService"
+ , nullptr // Implies LocalSystem account
+ , nullptr
+ )
+ , &::CloseServiceHandle
+ };
+ if (p_service == nullptr)
+ {
+ tools::fail_msg_writer() << "Couldn't create service: " << get_last_error();
+ return false;
+ }
+
+ tools::success_msg_writer() << "Service installed";
+
+ pause_to_display_admin_window_messages();
+
+ return true;
+}
+
+bool start_service(
+ std::string const & service_name
+ )
+{
+ tools::msg_writer() << "Starting service";
+
+ SERVICE_STATUS_PROCESS service_status = {};
+ DWORD unused = 0;
+
+ service_handle p_manager{
+ OpenSCManager(
+ nullptr
+ , nullptr
+ , SC_MANAGER_CONNECT
+ )
+ , &::CloseServiceHandle
+ };
+ if (p_manager == nullptr)
+ {
+ tools::fail_msg_writer() << "Couldn't connect to service manager: " << get_last_error();
+ return false;
+ }
+
+ service_handle p_service{
+ OpenService(
+ p_manager.get()
+ , service_name.c_str()
+ //, SERVICE_START | SERVICE_QUERY_STATUS
+ , SERVICE_START
+ )
+ , &::CloseServiceHandle
+ };
+ if (p_service == nullptr)
+ {
+ tools::fail_msg_writer() << "Couldn't find service: " << get_last_error();
+ return false;
+ }
+
+ if (!StartService(
+ p_service.get()
+ , 0
+ , nullptr
+ ))
+ {
+ tools::fail_msg_writer() << "Service start request failed: " << get_last_error();
+ return false;
+ }
+
+ tools::success_msg_writer() << "Service started";
+
+ pause_to_display_admin_window_messages();
+
+ return true;
+}
+
+bool stop_service(
+ std::string const & service_name
+ )
+{
+ tools::msg_writer() << "Stopping service";
+
+ service_handle p_manager{
+ OpenSCManager(
+ nullptr
+ , nullptr
+ , SC_MANAGER_CONNECT
+ )
+ , &::CloseServiceHandle
+ };
+ if (p_manager == nullptr)
+ {
+ tools::fail_msg_writer() << "Couldn't connect to service manager: " << get_last_error();
+ return false;
+ }
+
+ service_handle p_service{
+ OpenService(
+ p_manager.get()
+ , service_name.c_str()
+ , SERVICE_STOP | SERVICE_QUERY_STATUS
+ )
+ , &::CloseServiceHandle
+ };
+ if (p_service == nullptr)
+ {
+ tools::fail_msg_writer() << "Couldn't find service: " << get_last_error();
+ return false;
+ }
+
+ SERVICE_STATUS status = {};
+ if (!ControlService(p_service.get(), SERVICE_CONTROL_STOP, &status))
+ {
+ tools::fail_msg_writer() << "Couldn't request service stop: " << get_last_error();
+ return false;
+ }
+
+ tools::success_msg_writer() << "Service stopped";
+
+ pause_to_display_admin_window_messages();
+
+ return true;
+}
+
+bool uninstall_service(
+ std::string const & service_name
+ )
+{
+ service_handle p_manager{
+ OpenSCManager(
+ nullptr
+ , nullptr
+ , SC_MANAGER_CONNECT
+ )
+ , &::CloseServiceHandle
+ };
+ if (p_manager == nullptr)
+ {
+ tools::fail_msg_writer() << "Couldn't connect to service manager: " << get_last_error();
+ return false;
+ }
+
+ service_handle p_service{
+ OpenService(
+ p_manager.get()
+ , service_name.c_str()
+ , SERVICE_QUERY_STATUS | DELETE
+ )
+ , &::CloseServiceHandle
+ };
+ if (p_service == nullptr)
+ {
+ tools::fail_msg_writer() << "Couldn't find service: " << get_last_error();
+ return false;
+ }
+
+ SERVICE_STATUS status = {};
+ if (!DeleteService(p_service.get()))
+ {
+ tools::fail_msg_writer() << "Couldn't uninstall service: " << get_last_error();
+ return false;
+ }
+
+ tools::success_msg_writer() << "Service uninstalled";
+
+ pause_to_display_admin_window_messages();
+
+ return true;
+}
+
+} // namespace windows