user3378687 user3378687 - 11 months ago 47
C++ Question

Can't query, run or stop a Windows Service

I have created my first Windows service following this instruction. I can start or stop my service from the Service panel in Manage-> My computer without problem.
The service account is "LocalSystem" so, I think, I'm ok with privileges.
Now I want to communicate with my service from another app, but first of all I want to stop or start my service.

Following this example I Write this code:

SC_HANDLE schSCManager;
SC_HANDLE schService;
LPCWSTR szSvcName = _T("MyNewService");

// Get a handle to the SCM database.

schSCManager = OpenSCManager(
NULL, // local computer
NULL, // ServicesActive database
SC_MANAGER_ALL_ACCESS); // full access rights
if (NULL == schSCManager)
printf("OpenSCManager failed (%d)\n", GetLastError());

// Get a handle to the service.
schService = OpenService(
schSCManager, // SCM database
szSvcName, // name of service
SERVICE_CHANGE_CONFIG); // need change config access
if (schService == NULL)
printf("OpenService failed (%d)\n", GetLastError());
//OK until now

// Check the status in case the service is not stopped.
DWORD dwBytesNeeded;

if (!QueryServiceStatusEx(
schService, // handle to service
SC_STATUS_PROCESS_INFO, // information level
(LPBYTE) &ssStatus, // address of structure
sizeof(SERVICE_STATUS_PROCESS), // size of structure
&dwBytesNeeded ) ) // size needed if buffer is too small
//printf("QueryServiceStatusEx failed (%d)\n", GetLastError());
CString str;
str.Format(_T("QueryServiceStatusEx failed (%d)\n"), GetLastError()); //ERROR 5: ERROR_ACCESS_DENIED

// Check if the service is already running. It would be possible
// to stop the service here, but for simplicity this example just returns.

if(ssStatus.dwCurrentState != SERVICE_STOPPED && ssStatus.dwCurrentState != SERVICE_STOP_PENDING)
printf("Cannot start the service because it is already running\n");

In any case I get the error number 5, that is "ERROR_ACCESS_DENIED: The handle does not have the SERVICE_QUERY_STATUS access right", but I'm not sure where is the problem. The service has LocalSystem account option that means all privileges and I'm the admin of my computer.. what's wrong?

I also tried with ControlService trying to start or stop the service but I get the same error about rights

BOOL success = ::ControlService(schService, SERVICE_CONTROL_STOP, &ss);

I'm on Visual Studio 2013 Update 2.
Thank you

Answer Source

You seem to be a little bit confused about terms "privileges" and "access rights". You are quite right that the LocalSystem account is really a privileged one, at least for actions on the local computer. However, even a privileged user must know how to take advantage if her privileges (how things work).

When an application wants to work with an object (e.g. a service), it has to declare its intention to the Windows kernel (done via OpenSCManager and OpenService in your code). The application identifies the object (e.g. by service name) and also informs the kernel what sorts of things it plans to do with it. These "sorts of things" are called "access rights" and the kenrel decides whether the application is privileged enough to obtain the access rights it is requesting. In your code, you are requesting all access rights (SC_MANAGER_ALL_ACCESS) for the SC manager and an access right to change configuration of your service (SERVICE_CHANGE_CONFIG). Then, you attempt to query status of your service, but you did not declare this intention to the kernel when requesting access to the service (the OpenService call). That's why you get the "access denied" error.

Here is a list of access rights defined for services and SC manager(s): The document also contains information about which access rights you need to perform which actions.

To open a service, you need only the SC_MANAGER_CONNECT access right to its SC manager. To query service status, the SERVICE-QUERY_STATUS access right is required. To stop the service, request the SERVICE_STOP right.

So, the short version is: specify SERVICE_STOP | SERVICE_QUERY_STATUS desired access mask when calling OpenService, and optionally SC_MANAGER_CONNECT in the OpenSCManager call.