Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 从没有管理员权限(c+;+;)的应用程序启动Windows服务_C++_Windows_Service - Fatal编程技术网

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

C++ 从没有管理员权限(c+;+;)的应用程序启动Windows服务,c++,windows,service,C++,Windows,Service,我编写了一个windows服务(运行良好)。现在我有一个单独的应用程序,我想从中启动这项服务,但似乎这是不可能没有管理员权限 用户可以启动/停止服务(例如,从托盘或应用程序)的适当解决方案是什么样的 我认为应用程序必须始终以管理员权限启动是不好的。以编程方式启动服务是通过函数完成的。标题下还提供了一个综合使用示例,该示例还显示了如何: 检测到服务因某种原因正在关闭 等待服务处于稳定状态(已启动/已停止) 以编程方式启动服务 至于管理员权限,这是必要的,因为如果几乎任何应用程序都可以关闭服务(

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

用户可以启动/停止服务(例如,从托盘或应用程序)的适当解决方案是什么样的


我认为应用程序必须始终以管理员权限启动是不好的。

以编程方式启动服务是通过函数完成的。标题下还提供了一个综合使用示例,该示例还显示了如何:

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

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

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

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();
}
我假设您已经打开了服务句柄。您需要写入DAC权限

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

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

服务权限的SDDL代码可以在Wayne Martin的博客条目中找到。

@Harry Johnston,以及回复

这里是C++ Builder示例。

void __fastcall TService1::ServiceAfterInstall(TService *Sender)
{
 wchar_t lpBuffer[256];
 long errorCode;
 SC_HANDLE hSCManager,hService;

 hSCManager  = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
 if (hSCManager == NULL)
 {
   errorCode = GetLastError();
   FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), lpBuffer, 256, NULL);
   LogMessage("OpenSCManager Error "+AnsiString(lpBuffer), EVENTLOG_ERROR_TYPE);
   return;
 }


 hService = OpenService(hSCManager, this->Name.c_str(), READ_CONTROL | WRITE_DAC);
 if (hService == NULL)
 {
   errorCode = GetLastError();
   FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), lpBuffer, 256, NULL);
   LogMessage("OpenService Error "+AnsiString(lpBuffer), EVENTLOG_ERROR_TYPE);
   CloseServiceHandle(hSCManager);
 }

 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(AnsiString(sddl).c_str(), SDDL_REVISION_1, &sd, NULL))
  {
    errorCode = GetLastError();
    FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), lpBuffer, 256, NULL);
    LogMessage("ConvertStringSecurityDescriptorToSecurityDescriptor Error "+AnsiString(lpBuffer), EVENTLOG_ERROR_TYPE);
  }

  if (!SetServiceObjectSecurity(hService, DACL_SECURITY_INFORMATION, sd))
  {
    errorCode = GetLastError();
    FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), lpBuffer, 256, NULL);
    LogMessage("SetServiceObjectSecurity Error "+AnsiString(lpBuffer), EVENTLOG_ERROR_TYPE);
  }

  CloseServiceHandle(hService);
  CloseServiceHandle(hSCManager);
}

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


结构
AnsiString(sddl).c#u str()
是多余的:因为
sddl
只使用一次,您可以将定义更改为
char
,并在必要时使用窄字符串。正如我所写的,这是这个答案的c#等价物:它在最新的windows 10上仍然有效吗?
[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());
    }
}