Windows上的普通用户可以启动服务吗?

时间:2011-08-24 09:04:43

标签: delphi windows-7 windows-services

我有一个使用Delphi创建的服务应用程序,并设法使用提升的权限从另一个Delphi应用程序安装它。

该服务设置为以本地系统帐户登录(在Delphi中创建服务应用程序时是默认帐户)。

我有另一个Delphi应用程序,普通用户应该能够启动或停止上述服务。

我的问题是:Windows允许这样做吗?当我尝试使用Delphi中的代码启动服务时,它只是失败了“Code 5. Access被拒绝”。如何防止发生此错误?我希望能够让普通用户运行应用程序(不是在管理员模式下,因此没有提升权限)来启动/停止服务。有可能,如果可能,怎么样?以下是我的代码:

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

3 个答案:

答案 0 :(得分:6)

默认情况下,您需要拥有管理员权限才能启动,停止,安装和删除服务。

您必须安排自己的服务来公开自己的Active属性,这与Windows术语的运行区别不同。安排它一直以Windows术语运行,但在Active属性为false时是惰性的。

您必须为您的用户应用实施控制机制。我已经使用命名管道完成了这项工作,但其他IPC方法也是可用的。

答案 1 :(得分:3)

服务hava ACL作为其他Windows对象。在域中,可以使用组策略向用户分配启动/停止服务的权限(在“计算机配置” - >“策略” - >“Windows设置” - >“安全设置” - >“系统服务”下)。对于本地系统,AFAIK此节点不会出现在gpedit.msc中。 sc.exe可用于设置服务安全描述符,但它需要一些SDDL知识(安全描述符定义语言,this may help you)。不知道是否有一个模板可以让gpedit处理它 - 这个用户没有管理员帐户的独立系统有点不常见。

答案 2 :(得分:2)

有几种方法可以实现这一目标:

1。授予服务

的权限

这必须在提升模式下完成,例如在创建服务时。

请注意Windows access control model很难处理。也许JEDI Windows Security Library可以帮到你。

可以将权限授予单个用户,用户组或预定义的用户组,例如经过身份验证的用户。

要执行此操作,您需要为服务创建access control list。服务有几个access rights,为此您需要在acl中包含 SERVICE_START SERVICE_STOP

使用SetSecurityDescriptorDaclSetServiceObjectSecurity api函数应用acl。以下是how to use them的C中的示例。

必须使用所需Trustee填充EXPLICIT_ACCESS结构的SID变量,以指定用户或组。以下是C中显示how to do it的另一个示例。

注意: Microsoft有一个名为SubInACL的实用程序,可用于查询和设置所有类型的acls,但我猜它不是可再发行的。这是关于how to use it的小型教程。

2。使用监护人服务

您可以使用其他服务来响应命令并控制主服务。该监护人应该以 LocalSystem 的形式运行。 LocalSystem具有 SERVICE_START SERVICE_STOP 权限,因此无需为监护人设置任何acl。

监护人还允许您通过简单地停止,更新和重新启动主服务来进行自动更新。

请注意LocalSystem是某种本地管理员,因此使用它是一种安全风险,如here所述。

3。在服务中实现activate / deactive命令

作为David Heffernan says,不需要启动和停止服务,因为类似的行为可以通过暴露命令来实现,这些命令指示它在内部停用并独立于窗口的思考而激活。