从没有管理员权限的应用程序启动Windows服务(c ++)

时间:2011-12-05 00:16:54

标签: c++ windows service

我写了一个Windows服务(运行正常)。现在我有一个单独的应用程序,我想从中启动此服务,但似乎没有管理员权限这是不可能的。

正确的解决方案如何看起来像用户可以启动/停止服务(例如从托盘或应用程序)

恕我直言,必须始终以管理员权限启动应用程序。

3 个答案:

答案 0 :(得分:9)

您只需更改服务对象的权限,最好在安装时同时更改。

wchar_t sddl[] = L"D:"
  L"(A;;CCLCSWRPWPDTLOCRRC;;;SY)"           // default permissions for local system
  L"(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)"   // default permissions for administrators
  L"(A;;CCLCSWLOCRRC;;;AU)"                 // default permissions for authenticated users
  L"(A;;CCLCSWRPWPDTLOCRRC;;;PU)"           // default permissions for power users
  L"(A;;RP;;;IU)"                           // added permission: start service for interactive users
  ;

PSECURITY_DESCRIPTOR sd;

if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddl, SDDL_REVISION_1, &sd, NULL))
{
   fail();
}

if (!SetServiceObjectSecurity(service, DACL_SECURITY_INFORMATION, sd))
{
   fail();
}

我假设你已经打开了服务句柄。您需要WRITE_DAC权限。

如果您还希望非管理员用户能够停止服务,请添加WP权利,即

L"(A;;RPWP;;;IU)"                           
  // added permissions: start service, stop service for interactive users

服务权利的SDDL代码可以在Wayne Martin的博客文章Service Control Manager Security for non-admins中找到。

答案 1 :(得分:0)

使用StartService函数以编程方式启动服务。标题starting a service下还提供了一个综合的用法示例,其中还说明了如何:

  • 检测到服务因某种原因关闭
  • 等待服务处于稳定状态(已启动/已停止)
  • 以编程方式启动服务

至于管理员权限,这是必要的,因为如果几乎任何应用程序都可以关闭服务(或者更重要的是,安装并启动新服务),那么就会出现非常严重的安全问题

答案 2 :(得分:0)

@Harry Johnston对我很好,以防有人想在C#中这样做:

[DllImport("advapi32.dll", SetLastError = true)]
static extern bool SetServiceObjectSecurity(SafeHandle serviceHandle,
    UInt32 secInfos,
    IntPtr lpSecDesrBuf);

[DllImport("advapi32.dll", EntryPoint = "ConvertStringSecurityDescriptorToSecurityDescriptorW", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern Boolean ConvertStringSecurityDescriptorToSecurityDescriptor(
    [MarshalAs(UnmanagedType.LPWStr)] String strSecurityDescriptor,
    UInt32 sDRevision,
    ref IntPtr securityDescriptor,
    ref UInt32 securityDescriptorSize);

public static void SetServicePermissions(string service)
{
    System.ServiceProcess.ServiceController sc = new System.ServiceProcess.ServiceController(service);
    bool ok;
    IntPtr pSD = IntPtr.Zero;
    uint securityDescriptorSize = 0;
    string secDesc = "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;PU)(A;;RPWP;;;IU)";

    ok = ConvertStringSecurityDescriptorToSecurityDescriptor(secDesc, 1, ref pSD, ref securityDescriptorSize);
    if (!ok)
    {
        throw new ApplicationException("error calling ConvertStringSecurityDescriptorToSecurityDescriptor(): error code=" + Marshal.GetLastWin32Error());
    }

    ok = SetServiceObjectSecurity(sc.ServiceHandle, 4 , pSD);
    if (!ok)
    {
        throw new ApplicationException("error calling SetServiceObjectSecurity(); error code=" + Marshal.GetLastWin32Error());
    }
}