service
service copied to clipboard
Windows services will only start with the default system account
Steps to reproduce:
- Build a service. The minimal service from example/simple will demonstrate the problem.
- Register the service. Reproducible using
sc.exe create GoServiceExampleSimple binPath= "C:\Test\service.exe"
and via Service.Install(). - The service is now configured to start with the SYSTEM account. It will start without problems.
- Stop the service.
- Configure a different account.
- 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