Take the 2-minute tour ×

I have a service application created with Delphi, and managed to install it from another Delphi application using elevated privileges.

The service is set to log on as the Local System account (which is default when creating a service application in Delphi).

I have another Delphi application in which an ordinary user is supposed to be able to start or stop the above service.

My question is: Is this allowed by Windows? When I try to start the service using code in Delphi, it just fails with 'Code 5. Access is denied.' How can I prevent this error from occurring? I want to be able to have the normal user running the application (not in Administrator mode and thus not with elevated privileges) to start / stop the service. Is it possible and if so how? Below is my code:

function ServiceStart(sMachine, sService: string): boolean;
  schm, schs: SC_Handle;
  ss: TServiceStatus;
  psTemp: PChar;
  dwChkP: DWord; // check point
  ss.dwCurrentState := 0;
  // connect to the service control manager
  schm := OpenSCManager(PChar(sMachine), nil, SC_MANAGER_CONNECT);
  // if successful...
  if (schm <> 0) then
    // open a handle to the specified service
    // we want to start the service and query service
    // status
    schs := OpenService(schm, PChar(sService), SERVICE_START  or SERVICE_QUERY_STATUS);
    // if successful...
    if (schs <> 0) then
      psTemp := nil;
      if (StartService(schs, 0, psTemp)) then
        // check status
        if (QueryServiceStatus(schs, ss)) then
          while (SERVICE_RUNNING <> ss.dwCurrentState) do
            // dwCheckPoint contains a value that the
            // service increments periodically to
            // report its progress during a
            // lengthy operation. Save current value
            dwChkP := ss.dwCheckPoint;
            // wait a bit before checking status again
            // dwWaitHint is the estimated amount of
            // time the calling program should wait
            // before calling QueryServiceStatus()
            // again. Idle events should be
            // handled here...
            if not QueryServiceStatus(schs, ss) then
              // couldn't check status break from the
              // loop

            if ss.dwCheckPoint < dwChkP then
              // QueryServiceStatus didn't increment
              // dwCheckPoint as it should have.
              // Avoid an infinite loop by breaking

        if MessageDlg('Start Service failed. Do you want remove it?',
          mtWarning, [mbYes, mbNo], 0) = mrYes then


      // close service handle
    end else RaiseLastOSError;
    // close service control manager handle
  // Return TRUE if the service status is running
  Result := SERVICE_RUNNING = ss.dwCurrentState;
share|improve this question
add comment

3 Answers

up vote 7 down vote accepted

By default you need to have admin privileges to start, stop, install and delete services.

You will have to arrange for your service to expose its own Active property, distinct from what Windows terms as running. Arrange that it is running in Windows terms all the time, but inert when its Active property is false.

You'll have to implement a control mechanism for your user app. I've done this with named pipes but the are other IPC methods available.

share|improve this answer
The user that is running the application has Administrator privilege on Windows 7, yet the function call to start the service fails. It only works if the application was started with 'Run as Administrator'. Why is this? –  Steve F Aug 24 '11 at 10:44
Because it needs elevation. You should properly tell the user, see msdn.microsoft.com/en-us/library/aa511445.aspx, and then perform the elavation. –  user160694 Aug 24 '11 at 10:50
Ok understood. Thanks. Can you just confirm one last thing? When I run the Services Control panel from Run dialog with services.msc or when I right click My Computer and click on Manage - does it run elevated even though it does not give a prompt? –  Steve F Aug 24 '11 at 10:55
My Computer -> Manage shows the elevation shield, the whole Computer Management console is run elevated. "Services" doesn't display the shield, but I guess that's a MS mistake, it should. In Windows 7 not every elevation requires a confirmation (in Vista it does, and it's a nightmare :) –  user160694 Aug 24 '11 at 11:04
@idsandon ha, I always dial up the UAC settings so that I know exactly which operations need elevation –  David Heffernan Aug 24 '11 at 11:16
show 1 more comment

Services hava ACLs as other Windows objects. In a domain permissions to start/stop services may be assigned to users using group policies (under Computer Configuration -> Polices -> Windows Settings -> Security Settings -> System Services). AFAIK this node does not appear in gpedit.msc for a local system. sc.exe could be used to set a service security descriptor, but it requires some knowledge of SDDL (Security Descriptor Definition Language, this may help you). Don't know if a template is available to allow gpedit to handle that - it's a bit uncommon a standalone system for which the user has no admin account.

share|improve this answer
Can you grant start/stop rights on individual services? –  David Heffernan Aug 24 '11 at 10:14
Yes. See the link in my answer. –  Mad Hatter Aug 24 '11 at 10:17
add comment

There are several ways to achieve this:

1. Give permissions to the service

This must be done in elevated mode, for example when creating the service.

Beware that Windows access control model is hard to work with. Maybe JEDI Windows Security Library can help you.

Permissions can be granted to individual users, to user groups or to predefined user groups, such as authenticated users.

To do this you need to create an access control list for the service. Services hace several access rights, and for this purpose you need to include SERVICE_START and SERVICE_STOP in the acl.

The acl is applied using SetSecurityDescriptorDacl and SetServiceObjectSecurity api functions. Here is an example in C of how to use them.

The user or group must be specified filling the Trustee variable of the EXPLICIT_ACCESS structure with the desired SID. Here is another example in C showing how to do it.

Note: Microsoft has an utility called SubInACL that can be used to query and set all kind of acls, though I guess it is not redistributable. Here is a mini-tutorial on how to use it.

2. Use a guardian service

You can have another service that respond to commands and controls the main service. This guardian should be running as LocalSystem. LocalSystem has SERVICE_START and SERVICE_STOP privileges, so it's no needed to set any acl for the guardian.

The guardian also allows you to autoupdate the main service, by simply stopping, updating and restarting it.

Beware that LocalSystem is some kind of local administrator, so it is a security risk to use it, as explained here.

3. Implement activate/deactive commands in the service

As David Heffernan says, it is no needed to start and stop the service, as similar behavior can be achieved by exposing commands that instructs it to internally deactivate and activate independently of what windows thinks.

share|improve this answer
You don't need a Guardian service. You can send the commands direct to the real service and get it to behave accordingly without actually starting and stopping. And isn't it bad practice to use LocalSystem? –  David Heffernan Aug 24 '11 at 10:25
@David: The OP explicitly asked for start and stop the service, so I answer to that, though as you say a similar behavior can be obtained with commands to the real service, except if you want to update the service exe. LocalSystem is some kind of local administrator, so you are right in that it can be risky to use it. –  JRL Aug 24 '11 at 10:54
I actually think your answer is the most comprehensive, my comment was just meant to add a couple of hopefully useful angles –  David Heffernan Aug 24 '11 at 11:26
@David: Thanks. I am sorry that I can't post code implementing alternative #1. I've coded it in the past, but I have not access to it and is rather complex to write. –  JRL Aug 24 '11 at 11:46
@ldsandon: No. Alternatives #1 and #2 are mine. Later I add #3 to include David's one. –  JRL Aug 24 '11 at 12:36
show 6 more comments

Your Answer


