Start Windows Service From Application without Adm

2019-01-03 10:52发布

I wrote a windows service (and it runs fine). Now i have a separate app where I want to start this service from, but it seems this is not possible without administrator rights.

How would a proper solution look like that a user can start/stop the service (e.g. from a tray or application)

IMHO its bad that the application must always be started with administrator rights.

4条回答
forever°为你锁心
2楼-- · 2019-01-03 11:25

Starting a service programmatically is done with the StartService function. There is a comprehensive usage example also given under the title starting a service, which also shows how to:

  • detect that the service is for some reason shutting down
  • wait until the service is in a stable state (started/stopped)
  • start the service programmatically

As for administrator rights, this is necessary because if just about any application could shut services down (or, more importantly, install and start new services) there would be very real and very serious security issues.

查看更多
混吃等死
3楼-- · 2019-01-03 11:27

You just need to change the permissions on the service object, preferably at the same time you install it.

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();
}

I'm assuming here you've already opened the service handle. You need WRITE_DAC permission.

If you also want non-admin users to be able to stop the service, add the WP right, i.e.,

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

SDDL codes for service rights can be found in Wayne Martin's blog entry, Service Control Manager Security for non-admins.

查看更多
ら.Afraid
4楼-- · 2019-01-03 11:34

@Harry Johnston 's worked fine for me, in case someone wants to do this in 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());
    }
}
查看更多
姐就是有狂的资本
5楼-- · 2019-01-03 11:39

@Harry Johnston, in addition to response.

Here is c++ builder example.

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);
}
查看更多
登录 后发表回答