3

I have a service that I need to be able to start and stop with a button. I am using a ServiceController in a seperate program and everything works as intended when I run this seperate program as an administrator. However, I need to be able to control this service as anyone. How can I set the permissions for my service so that everyone has full control of it? This needs to be done programatically as either part of the service, or the install. It is a localservice written in vb.net.

damian
  • 1,419
  • 1
  • 22
  • 41

2 Answers2

3

You have a few options:

1) You can require that your application runs as an administrator. Every time your application starts, you will be prompted with the UAC (on Windows 7 and Vista) and your application will be elevated to the required level.

Run .NET application as administrator

2) Your application can request an elevation when the action is required to stop and start the service. It would do this by starting another application at a higher level and this other application will do the actual start and stop.

How to elevate privileges only when required?

3) Preferred option, IMHO - You should build your service to run all of the time but just not do anything other than listen for requests via TCP/IP, Named Pipes or some other communication mechanism. Your service can then start or stop a thread that performs the real work.

4) You can modify the service rights. Here are some posts that give some information on this (I would still prefer option 3):

Start / Stop a Windows Service from a non-Administrator user account

http://msmvps.com/blogs/erikr/archive/2007/09/26/set-permissions-on-a-specific-service-windows.aspx

http://fstaal01.home.xs4all.nl/swsc-us.html

Update

I have changed some text and added option 4 based on Harry's comment. It seems that there are ways of tweaking the permissions. These require administrator rights initially but if you bundle something like swsc (third link) with your installation, you could use it to set the rights for you. I am not sure if there are any license implications for doing this. Alternatively, you could use a variant of the code he pasted.

Community
  • 1
  • 1
Graymatter
  • 6,529
  • 2
  • 30
  • 50
  • This is wrong. You can change a service ACL, it isn't even particularly difficult. – Harry Johnston Jul 24 '12 at 22:22
  • I disagree with your suggestion that it is preferable for the service to be running at all times. To be fair, it depends on the context, which the OP hasn't provided, but as a general rule it is better to start services only when needed. Even when idling, they're still using system resources. – Harry Johnston Jul 24 '12 at 22:44
  • The problem is that it does depend a lot on the context. While services do consume resources, there is a fair amount of risk associated with giving all users permission to stop or start your service at will. For example, the application that starts or stops the service could make the assumption that the service is running when in fact it has been stopped through other means. The service is also running at an elevated permission which could provide additional risk. – Graymatter Jul 24 '12 at 22:51
2

The code I have is in C, but it shouldn't be too hard to adapt to VB - or you could put it in a DLL. Alternatively, you could launch a command shell and use the sc sdset command.

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
  ;

DWORD InstallService() 
{
  SC_HANDLE manager, service;
  PSECURITY_DESCRIPTOR sd;
  DWORD err;

  wchar_t apppath[MAX_PATH + 2];

  // Note: because this is only called from main() which exits
  // immediately afterwards, no attempt is made to close the
  // handles generated.

  if (!ConvertStringSecurityDescriptorToSecurityDescriptor(sddl, 
      SDDL_REVISION_1, &sd, NULL))
  {
    err = GetLastError();
    printf("Error %u creating security descriptor.\n", err);
    return err;
  }

  if (!GetModuleFileName(0, apppath, MAX_PATH + 1)) 
  {
    err = GetLastError();
    printf("Error %u fetching module name.\n", err);
    return err;
  }

  if (_wcsicmp(apppath + wcslen(apppath) - wcslen(exename), exename) != 0) 
  {
    printf("Application name mismatch: %ls\n", 
      apppath + wcslen(apppath) - wcslen(exename));
    return ERROR_INVALID_FUNCTION;
  }

  manager = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);

  if (!manager) 
  {
    err = GetLastError();
    printf("Error %u connecting to service manager.\n", err);
    return err;
  }

  service = CreateService(manager,
    servicename,
    displayname,
    WRITE_DAC,
    SERVICE_WIN32_OWN_PROCESS,
    SERVICE_DEMAND_START,
    SERVICE_ERROR_NORMAL,
    apppath,
    0,
    0,
    NULL,
    NULL,
    NULL);

  if (!service) 
  {
    err = GetLastError();
    printf("Error %u installing service.\n", err);
    return err;
  }

  if (!SetServiceObjectSecurity(service, DACL_SECURITY_INFORMATION, sd))
  {
    err = GetLastError();
    printf("Error %u setting service security.\n", err);
    return err;
  }

  printf("Service successfully installed.\n");
  return 0;
}
Harry Johnston
  • 35,639
  • 6
  • 68
  • 158