Open services with minimal privileges.
[nssm.git] / service.cpp
index d01ece0..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
@@ -472,17 +472,19 @@ int get_service_username(const TCHAR *service_name, const QUERY_SERVICE_CONFIG *
 \r
   if (! qsc) return 1;\r
 \r
-  if (is_localsystem(qsc->lpServiceStartName)) return 0;\r
+  if (qsc->lpServiceStartName[0]) {\r
+    if (is_localsystem(qsc->lpServiceStartName)) return 0;\r
 \r
-  size_t len = _tcslen(qsc->lpServiceStartName);\r
-  *username = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(TCHAR));\r
-  if (! *username) {\r
-    print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("username"), _T("get_service_username()"));\r
-    return 2;\r
-  }\r
+    size_t len = _tcslen(qsc->lpServiceStartName);\r
+    *username = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(TCHAR));\r
+    if (! *username) {\r
+      print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("username"), _T("get_service_username()"));\r
+      return 2;\r
+    }\r
 \r
-  memmove(*username, qsc->lpServiceStartName, (len + 1) * sizeof(TCHAR));\r
-  *usernamelen = len;\r
+    memmove(*username, qsc->lpServiceStartName, (len + 1) * sizeof(TCHAR));\r
+    *usernamelen = len;\r
+  }\r
 \r
   return 0;\r
 }\r
@@ -655,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
@@ -865,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
@@ -934,7 +938,8 @@ int edit_service(nssm_service_t *service, bool editing) {
   }\r
   else if (editing) username = NSSM_LOCALSYSTEM_ACCOUNT;\r
 \r
-  if (requires_password(username)) {\r
+  if (well_known_username(username)) password = _T("");\r
+  else {\r
     if (grant_logon_as_service(username)) {\r
       print_message(stderr, NSSM_MESSAGE_GRANT_LOGON_AS_SERVICE_FAILED, username);\r
       return 5;\r
@@ -983,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
@@ -1087,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
@@ -1164,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