Browse Source

Open services with minimal privileges.

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.
Iain Patterson 8 years ago
parent
commit
6d0e202157
3 changed files with 40 additions and 18 deletions
  1. 1 1
      console.cpp
  2. 37 15
      service.cpp
  3. 2 2
      service.h

+ 1 - 1
console.cpp

@@ -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);

+ 37 - 15
service.cpp

@@ -253,8 +253,8 @@ static unsigned long WINAPI shutdown_service(void *arg) {
 }
 
 /* Connect to the service manager */
-SC_HANDLE open_service_manager() {
-  SC_HANDLE ret = OpenSCManager(0, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
+SC_HANDLE open_service_manager(unsigned long access) {
+  SC_HANDLE ret = OpenSCManager(0, SERVICES_ACTIVE_DATABASE, access);
   if (! ret) {
     if (is_admin) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OPENSCMANAGER_FAILED, 0);
     return 0;
@@ -264,8 +264,8 @@ SC_HANDLE open_service_manager() {
 }
 
 /* Open a service by name or display name. */
-SC_HANDLE open_service(SC_HANDLE services, TCHAR *service_name, TCHAR *canonical_name, unsigned long canonical_namelen) {
-  SC_HANDLE service_handle = OpenService(services, service_name, SERVICE_ALL_ACCESS);
+SC_HANDLE open_service(SC_HANDLE services, TCHAR *service_name, unsigned long access, TCHAR *canonical_name, unsigned long canonical_namelen) {
+  SC_HANDLE service_handle = OpenService(services, service_name, access);
   if (service_handle) {
     if (canonical_name && canonical_name != service_name) {
       if (_sntprintf_s(canonical_name, canonical_namelen, _TRUNCATE, _T("%s"), service_name) < 0) {
@@ -331,7 +331,7 @@ SC_HANDLE open_service(SC_HANDLE services, TCHAR *service_name, TCHAR *canonical
         }
 
         HeapFree(GetProcessHeap(), 0, status);
-        return open_service(services, canonical_name, 0, 0);
+        return open_service(services, canonical_name, access, 0, 0);
       }
     }
 
@@ -339,7 +339,7 @@ SC_HANDLE open_service(SC_HANDLE services, TCHAR *service_name, TCHAR *canonical
   }
 
   /* Recurse so we can get an error message. */
-  return open_service(services, service_name, 0, 0);
+  return open_service(services, service_name, access, 0, 0);
 }
 
 QUERY_SERVICE_CONFIG *query_service_config(const TCHAR *service_name, SC_HANDLE service_handle) {
@@ -657,14 +657,16 @@ int pre_edit_service(int argc, TCHAR **argv) {
   _sntprintf_s(service->name, _countof(service->name), _TRUNCATE, _T("%s"), service_name);
 
   /* Open service manager */
-  SC_HANDLE services = open_service_manager();
+  SC_HANDLE services = open_service_manager(SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
   if (! services) {
     print_message(stderr, NSSM_MESSAGE_OPEN_SERVICE_MANAGER_FAILED);
     return 2;
   }
 
   /* Try to open the service */
-  service->handle = open_service(services, service->name, service->name, _countof(service->name));
+  unsigned long access = SERVICE_QUERY_CONFIG;
+  if (mode != MODE_GETTING) access |= SERVICE_CHANGE_CONFIG;
+  service->handle = open_service(services, service->name, access, service->name, _countof(service->name));
   if (! service->handle) {
     CloseServiceHandle(services);
     return 3;
@@ -867,7 +869,7 @@ int install_service(nssm_service_t *service) {
   if (! service) return 1;
 
   /* Open service manager */
-  SC_HANDLE services = open_service_manager();
+  SC_HANDLE services = open_service_manager(SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
   if (! services) {
     print_message(stderr, NSSM_MESSAGE_OPEN_SERVICE_MANAGER_FAILED);
     cleanup_nssm_service(service);
@@ -986,13 +988,33 @@ int control_service(unsigned long control, int argc, TCHAR **argv) {
   TCHAR *service_name = argv[0];
   TCHAR canonical_name[SERVICE_NAME_LENGTH];
 
-  SC_HANDLE services = open_service_manager();
+  SC_HANDLE services = open_service_manager(SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
   if (! services) {
     print_message(stderr, NSSM_MESSAGE_OPEN_SERVICE_MANAGER_FAILED);
     return 2;
   }
 
-  SC_HANDLE service_handle = open_service(services, service_name, canonical_name, _countof(canonical_name));
+  unsigned long access = SERVICE_QUERY_STATUS;
+  switch (control) {
+    case NSSM_SERVICE_CONTROL_START:
+      access |= SERVICE_START;
+    break;
+
+    case SERVICE_CONTROL_CONTINUE:
+    case SERVICE_CONTROL_PAUSE:
+      access |= SERVICE_PAUSE_CONTINUE;
+      break;
+
+    case SERVICE_CONTROL_STOP:
+      access |= SERVICE_STOP;
+      break;
+
+    case NSSM_SERVICE_CONTROL_ROTATE:
+      access |= SERVICE_USER_DEFINED_CONTROL;
+      break;
+  }
+
+  SC_HANDLE service_handle = open_service(services, service_name, access, canonical_name, _countof(canonical_name));
   if (! service_handle) {
     CloseServiceHandle(services);
     return 3;
@@ -1090,14 +1112,14 @@ int remove_service(nssm_service_t *service) {
   if (! service) return 1;
 
   /* Open service manager */
-  SC_HANDLE services = open_service_manager();
+  SC_HANDLE services = open_service_manager(SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
   if (! services) {
     print_message(stderr, NSSM_MESSAGE_OPEN_SERVICE_MANAGER_FAILED);
     return 2;
   }
 
   /* Try to open the service */
-  service->handle = open_service(services, service->name, service->name, _countof(service->name));
+  service->handle = open_service(services, service->name, DELETE, service->name, _countof(service->name));
   if (! service->handle) {
     CloseServiceHandle(services);
     return 3;
@@ -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 */
     create_exit_action(service->name, exit_action_strings[0], false);
 
-    SC_HANDLE services = open_service_manager();
+    SC_HANDLE services = open_service_manager(SC_MANAGER_CONNECT);
     if (services) {
-      service->handle = OpenService(services, service->name, SC_MANAGER_ALL_ACCESS);
+      service->handle = open_service(services, service->name, SERVICE_CHANGE_CONFIG, 0, 0);
       set_service_recovery(service);
       CloseServiceHandle(services);
     }

+ 2 - 2
service.h

@@ -116,8 +116,8 @@ unsigned long priority_index_to_constant(int);
 nssm_service_t *alloc_nssm_service();
 void set_nssm_service_defaults(nssm_service_t *);
 void cleanup_nssm_service(nssm_service_t *);
-SC_HANDLE open_service_manager();
-SC_HANDLE open_service(SC_HANDLE, TCHAR *, TCHAR *, unsigned long);
+SC_HANDLE open_service_manager(unsigned long);
+SC_HANDLE open_service(SC_HANDLE, TCHAR *, unsigned long, TCHAR *, unsigned long);
 QUERY_SERVICE_CONFIG *query_service_config(const TCHAR *, SC_HANDLE);
 int set_service_description(const TCHAR *, SC_HANDLE, TCHAR *);
 int get_service_description(const TCHAR *, SC_HANDLE, unsigned long, TCHAR *);