kardianos / service

Run go programs as a service on major platforms.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Windows services will only start with the default system account

hschletz opened this issue · comments

Steps to reproduce:

  1. Build a service. The minimal service from example/simple will demonstrate the problem.
  2. Register the service. Reproducible using sc.exe create GoServiceExampleSimple binPath= "C:\Test\service.exe" and via Service.Install().
  3. The service is now configured to start with the SYSTEM account. It will start without problems.
  4. Stop the service.
  5. Configure a different account.
  6. Try to start the service.

Startup will now fail with:
Error 1053: The service did not respond to the start or control request in a timely fashion

I believe that the message is incorrect in this case. The Start() method does nothing except launching run() in the background – even doing nothing would not change anything. The message shows up immediately – even a successful start will take longer. According to the event log, the time limit is 30 seconds.

I added a line to the top of the main() function:
os.WriteFile("C:/Windows/Temp/service.txt", []byte("main"), 666)

The file does not get created. ProcessMonitor indicates that the service indeed starts, but seems to abort before main() is even executed.

I tried these types of account:

  • a virtual service account "NT SERVICE\GoServiceExampleSimple"
  • NT AUTHORITY\NetworkService
  • NT AUTHORITY\LocalService
  • a manually created local user account with the permission to start as a service

To isolate the problem and understand startup behavior, I started with the simplest code: a no-op program

package main

func main() {}

and registered it as a service:

sc.exe create TestSvc binPath= "C:\Test\service.exe"

Trying to start this "service" fails immediately with the 1053 message, even for the SYSTEM account. The message is misleading, but technically correct: The service really did not respond to the request in a timely fashion. Not because a timeout was encountered, but because it exited prematurely. Lesson learned: the message can indicate a timeout, OR premature exit.

To keep the program running the simplest way possible, I start an infinite loop:

package main

func main() {
    for {}
}

This behaves as expected: it starts, hogs a CPU thread and ultimately gets killed after 30 seconds. I get a 1053 message again, this time because of the timeout. The key is: This also works with a virtual account "NT SERVICE\TestSvc".

Now I include the package, but don't actually use it. I'm only interested in its side effects.

package main

import _ "github.com/kardianos/service"

func main() {
    for {}
}

Now I get the initially described behavior: it runs with the SYSTEM account (until it times out, but that's not important here), but fails immediately with any other account.

My conclusion: The package and/or some of its dependencies have side effects that cause a premature panic when run as a non-system account, before main() is even encountered.

This is probably a symptom of golang/go/issues/44921 and would be fixed by #362. Workaround:

go get github.com/kardianos/service@804642397ef740ab10846edc26f61fd134d74379