Open services with minimal privileges.
authorIain Patterson <me@iain.cx>
Tue, 4 Feb 2014 21:42:45 +0000 (21:42 +0000)
committerIain Patterson <me@iain.cx>
Tue, 4 Feb 2014 22:29:19 +0000 (22:29 +0000)
Ask for the minimal access rights required to manage a service, so
users don't need to be administrators to perform operations permitted by
the service (manager) ACL.

console.cpp
service.cpp
service.h

index 771b69c..0c7afbe 100644 (file)
@@ -51,7 +51,7 @@ void alloc_console(nssm_service_t *service) {
   /* Set a title like "[NSSM] Jenkins" */
   TCHAR displayname[SERVICE_NAME_LENGTH];
   unsigned long len = _countof(displayname);
-  SC_HANDLE services = open_service_manager();
+  SC_HANDLE services = open_service_manager(SC_MANAGER_CONNECT);
   if (services) {
     if (! GetServiceDisplayName(services, service->name, displayname, &len)) ZeroMemory(displayname, sizeof(displayname));
     CloseServiceHandle(services);
index fe67262..898d987 100644 (file)
@@ -253,8 +253,8 @@ static unsigned long WINAPI shutdown_service(void *arg) {
 }\r
 \r
 /* Connect to the service manager */\r
-SC_HANDLE open_service_manager() {\r
-  SC_HANDLE ret = OpenSCManager(0, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);\r
+SC_HANDLE open_service_manager(unsigned long access) {\r
+  SC_HANDLE ret = OpenSCManager(0, SERVICES_ACTIVE_DATABASE, access);\r
   if (! ret) {\r
     if (is_admin) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OPENSCMANAGER_FAILED, 0);\r
     return 0;\r
@@ -264,8 +264,8 @@ SC_HANDLE open_service_manager() {
 }\r
 \r
 /* Open a service by name or display name. */\r
-SC_HANDLE open_service(SC_HANDLE services, TCHAR *service_name, TCHAR *canonical_name, unsigned long canonical_namelen) {\r
-  SC_HANDLE service_handle = OpenService(services, service_name, SERVICE_ALL_ACCESS);\r
+SC_HANDLE open_service(SC_HANDLE services, TCHAR *service_name, unsigned long access, TCHAR *canonical_name, unsigned long canonical_namelen) {\r
+  SC_HANDLE service_handle = OpenService(services, service_name, access);\r
   if (service_handle) {\r
     if (canonical_name && canonical_name != service_name) {\r
       if (_sntprintf_s(canonical_name, canonical_namelen, _TRUNCATE, _T("%s"), service_name) < 0) {\r
@@ -331,7 +331,7 @@ SC_HANDLE open_service(SC_HANDLE services, TCHAR *service_name, TCHAR *canonical
         }\r
 \r
         HeapFree(GetProcessHeap(), 0, status);\r
-        return open_service(services, canonical_name, 0, 0);\r
+        return open_service(services, canonical_name, access, 0, 0);\r
       }\r
     }\r
 \r
@@ -339,7 +339,7 @@ SC_HANDLE open_service(SC_HANDLE services, TCHAR *service_name, TCHAR *canonical
   }\r
 \r
   /* Recurse so we can get an error message. */\r
-  return open_service(services, service_name, 0, 0);\r
+  return open_service(services, service_name, access, 0, 0);\r
 }\r
 \r
 QUERY_SERVICE_CONFIG *query_service_config(const TCHAR *service_name, SC_HANDLE service_handle) {\r
@@ -657,14 +657,16 @@ int pre_edit_service(int argc, TCHAR **argv) {
   _sntprintf_s(service->name, _countof(service->name), _TRUNCATE, _T("%s"), service_name);\r
 \r
   /* Open service manager */\r
-  SC_HANDLE services = open_service_manager();\r
+  SC_HANDLE services = open_service_manager(SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);\r
   if (! services) {\r
     print_message(stderr, NSSM_MESSAGE_OPEN_SERVICE_MANAGER_FAILED);\r
     return 2;\r
   }\r
 \r
   /* Try to open the service */\r
-  service->handle = open_service(services, service->name, service->name, _countof(service->name));\r
+  unsigned long access = SERVICE_QUERY_CONFIG;\r
+  if (mode != MODE_GETTING) access |= SERVICE_CHANGE_CONFIG;\r
+  service->handle = open_service(services, service->name, access, service->name, _countof(service->name));\r
   if (! service->handle) {\r
     CloseServiceHandle(services);\r
     return 3;\r
@@ -867,7 +869,7 @@ int install_service(nssm_service_t *service) {
   if (! service) return 1;\r
 \r
   /* Open service manager */\r
-  SC_HANDLE services = open_service_manager();\r
+  SC_HANDLE services = open_service_manager(SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);\r
   if (! services) {\r
     print_message(stderr, NSSM_MESSAGE_OPEN_SERVICE_MANAGER_FAILED);\r
     cleanup_nssm_service(service);\r
@@ -986,13 +988,33 @@ int control_service(unsigned long control, int argc, TCHAR **argv) {
   TCHAR *service_name = argv[0];\r
   TCHAR canonical_name[SERVICE_NAME_LENGTH];\r
 \r
-  SC_HANDLE services = open_service_manager();\r
+  SC_HANDLE services = open_service_manager(SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);\r
   if (! services) {\r
     print_message(stderr, NSSM_MESSAGE_OPEN_SERVICE_MANAGER_FAILED);\r
     return 2;\r
   }\r
 \r
-  SC_HANDLE service_handle = open_service(services, service_name, canonical_name, _countof(canonical_name));\r
+  unsigned long access = SERVICE_QUERY_STATUS;\r
+  switch (control) {\r
+    case NSSM_SERVICE_CONTROL_START:\r
+      access |= SERVICE_START;\r
+    break;\r
+\r
+    case SERVICE_CONTROL_CONTINUE:\r
+    case SERVICE_CONTROL_PAUSE:\r
+      access |= SERVICE_PAUSE_CONTINUE;\r
+      break;\r
+\r
+    case SERVICE_CONTROL_STOP:\r
+      access |= SERVICE_STOP;\r
+      break;\r
+\r
+    case NSSM_SERVICE_CONTROL_ROTATE:\r
+      access |= SERVICE_USER_DEFINED_CONTROL;\r
+      break;\r
+  }\r
+\r
+  SC_HANDLE service_handle = open_service(services, service_name, access, canonical_name, _countof(canonical_name));\r
   if (! service_handle) {\r
     CloseServiceHandle(services);\r
     return 3;\r
@@ -1090,14 +1112,14 @@ int remove_service(nssm_service_t *service) {
   if (! service) return 1;\r
 \r
   /* Open service manager */\r
-  SC_HANDLE services = open_service_manager();\r
+  SC_HANDLE services = open_service_manager(SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);\r
   if (! services) {\r
     print_message(stderr, NSSM_MESSAGE_OPEN_SERVICE_MANAGER_FAILED);\r
     return 2;\r
   }\r
 \r
   /* Try to open the service */\r
-  service->handle = open_service(services, service->name, service->name, _countof(service->name));\r
+  service->handle = open_service(services, service->name, DELETE, service->name, _countof(service->name));\r
   if (! service->handle) {\r
     CloseServiceHandle(services);\r
     return 3;\r
@@ -1167,9 +1189,9 @@ void WINAPI service_main(unsigned long argc, TCHAR **argv) {
     /* Try to create the exit action parameters; we don't care if it fails */\r
     create_exit_action(service->name, exit_action_strings[0], false);\r
 \r
-    SC_HANDLE services = open_service_manager();\r
+    SC_HANDLE services = open_service_manager(SC_MANAGER_CONNECT);\r
     if (services) {\r
-      service->handle = OpenService(services, service->name, SC_MANAGER_ALL_ACCESS);\r
+      service->handle = open_service(services, service->name, SERVICE_CHANGE_CONFIG, 0, 0);\r
       set_service_recovery(service);\r
       CloseServiceHandle(services);\r
     }\r
index 68c0147..00428d0 100644 (file)
--- a/service.h
+++ b/service.h
@@ -116,8 +116,8 @@ unsigned long priority_index_to_constant(int);
 nssm_service_t *alloc_nssm_service();\r
 void set_nssm_service_defaults(nssm_service_t *);\r
 void cleanup_nssm_service(nssm_service_t *);\r
-SC_HANDLE open_service_manager();\r
-SC_HANDLE open_service(SC_HANDLE, TCHAR *, TCHAR *, unsigned long);\r
+SC_HANDLE open_service_manager(unsigned long);\r
+SC_HANDLE open_service(SC_HANDLE, TCHAR *, unsigned long, TCHAR *, unsigned long);\r
 QUERY_SERVICE_CONFIG *query_service_config(const TCHAR *, SC_HANDLE);\r
 int set_service_description(const TCHAR *, SC_HANDLE, TCHAR *);\r
 int get_service_description(const TCHAR *, SC_HANDLE, unsigned long, TCHAR *);\r