开发者

Can a service be started by normal user on Windows?

开发者 https://www.devze.com 2023-03-30 02:15 出处:网络
I have a service application created with Delphi, and managed to install it from another Delphi application using elevated privileges.

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;
var
  schm, schs: SC_Handle;
  ss: TServiceStatus;
  psTemp: PChar;
  dwChkP: DWord; // check point
begin
  ss.dwCurrentState := 0;
  // connect to the service control manager
  schm := OpenSCManager(PChar(sMachine), nil, SC_MANAGER_CONNECT);
  // if successful...
  if (schm <> 0) then
  begin
    // 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
    begin
      psTemp := nil;
      if (StartService(schs, 0, psTemp)) then
      begin
        // check status
        if (QueryServiceStatus(schs, ss)) then
        begin
          while (SERVICE_RUNNING <> ss.dwCurrentState) do
          begin
            // 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开发者_C百科 program should wait
            // before calling QueryServiceStatus()
            // again. Idle events should be
            // handled here...
            Sleep(ss.dwWaitHint);
            if not QueryServiceStatus(schs, ss) then
            begin
              // couldn't check status break from the
              // loop
              break;
            end;

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

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

      end;

      // close service handle
      CloseServiceHandle(schs);
    end else RaiseLastOSError;
    // close service control manager handle
    CloseServiceHandle(schm);
  end;
  // Return TRUE if the service status is running
  Result := SERVICE_RUNNING = ss.dwCurrentState;
end;


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.


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号