From ab3263502a3eb2ba008e7aab61709cb11c8aac1e Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 25 Feb 2019 18:47:03 +0100 Subject: service: introduce base of services --- service/install.go | 196 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 service/install.go (limited to 'service/install.go') diff --git a/service/install.go b/service/install.go new file mode 100644 index 00000000..32131f94 --- /dev/null +++ b/service/install.go @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package service + +import ( + "errors" + "golang.org/x/sys/windows" + "golang.org/x/sys/windows/svc" + svcdbg "golang.org/x/sys/windows/svc/debug" + "golang.org/x/sys/windows/svc/mgr" + "golang.zx2c4.com/wireguard/windows/conf" + "os" + "time" +) + +var cachedServiceManager *mgr.Mgr + +func serviceManager() (*mgr.Mgr, error) { + if cachedServiceManager != nil { + return cachedServiceManager, nil + } + m, err := mgr.Connect() + if err != nil { + return nil, err + } + cachedServiceManager = m + return cachedServiceManager, nil +} + +func InstallManager() error { + m, err := serviceManager() + if err != nil { + return err + } + path, err := os.Executable() + if err != nil { + return nil + } + + //TODO: Do we want to bail if executable isn't being run from the right location? + + serviceName := "WireGuard Manager" + service, err := m.OpenService(serviceName) + if err == nil { + status, err := service.Query() + if err != nil { + service.Close() + return err + } + if status.State != svc.Stopped { + service.Close() + return errors.New("Manager already installed and running") + } + err = service.Delete() + service.Close() + if err != nil { + return err + } + for { + service, err = m.OpenService(serviceName) + if err != nil { + break + } + service.Close() + time.Sleep(time.Second) + } + } + + config := mgr.Config{ + ServiceType: windows.SERVICE_WIN32_OWN_PROCESS, + StartType: mgr.StartAutomatic, + ErrorControl: mgr.ErrorNormal, + DisplayName: serviceName, + } + + service, err = m.CreateService(serviceName, path, config, "/managerservice") + if err != nil { + return err + } + service.Start() + return service.Close() +} + +func UninstallManager() error { + m, err := serviceManager() + if err != nil { + return err + } + serviceName := "WireGuard Manager" + service, err := m.OpenService(serviceName) + if err != nil { + return err + } + service.Control(svc.Stop) + err = service.Delete() + err2 := service.Close() + if err != nil { + return err + } + return err2 +} + +func RunManager() error { + return svc.Run("WireGuard Manager", &managerService{}) +} + +func InstallTunnel(configPath string) error { + m, err := serviceManager() + if err != nil { + return err + } + path, err := os.Executable() + if err != nil { + return nil + } + + name, err := conf.NameFromPath(configPath) + if err != nil { + return err + } + + serviceName := "WireGuard Tunnel: " + name + service, err := m.OpenService(serviceName) + if err == nil { + status, err := service.Query() + if err != nil { + service.Close() + return err + } + if status.State != svc.Stopped { + service.Close() + return errors.New("Tunnel already installed and running") + } + err = service.Delete() + service.Close() + if err != nil { + return err + } + for { + service, err = m.OpenService(serviceName) + if err != nil { + break + } + service.Close() + time.Sleep(time.Second) + } + } + + config := mgr.Config{ + ServiceType: windows.SERVICE_WIN32_OWN_PROCESS, + StartType: mgr.StartAutomatic, + ErrorControl: mgr.ErrorNormal, + DisplayName: serviceName, + } + + service, err = m.CreateService(serviceName, path, config, "/tunnelservice", configPath) + if err != nil { + return err + } + service.Start() + return service.Close() +} + +func UninstallTunnel(name string) error { + m, err := serviceManager() + if err != nil { + return err + } + serviceName := "WireGuard Tunnel: " + name + service, err := m.OpenService(serviceName) + if err != nil { + return err + } + service.Control(svc.Stop) + err = service.Delete() + err2 := service.Close() + if err != nil { + return err + } + return err2 +} + +func RunTunnel(confPath string, debug bool) error { + name, err := conf.NameFromPath(confPath) + if err != nil { + return err + } + if debug { + return svcdbg.Run("WireGuard Tunnel: "+name, &tunnelService{confPath, true}) + } else { + return svc.Run("WireGuard Tunnel: "+name, &tunnelService{confPath, false}) + } +} -- cgit v1.2.3-59-g8ed1b