golang.org/x/sys@v0.20.1-0.20240517151509-673e0f94c16d/windows/svc/mgr/config.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build windows 6 7 package mgr 8 9 import ( 10 "syscall" 11 "unsafe" 12 13 "golang.org/x/sys/windows" 14 ) 15 16 const ( 17 // Service start types. 18 StartManual = windows.SERVICE_DEMAND_START // the service must be started manually 19 StartAutomatic = windows.SERVICE_AUTO_START // the service will start by itself whenever the computer reboots 20 StartDisabled = windows.SERVICE_DISABLED // the service cannot be started 21 22 // The severity of the error, and action taken, 23 // if this service fails to start. 24 ErrorCritical = windows.SERVICE_ERROR_CRITICAL 25 ErrorIgnore = windows.SERVICE_ERROR_IGNORE 26 ErrorNormal = windows.SERVICE_ERROR_NORMAL 27 ErrorSevere = windows.SERVICE_ERROR_SEVERE 28 ) 29 30 // TODO(brainman): Password is not returned by windows.QueryServiceConfig, not sure how to get it. 31 32 type Config struct { 33 ServiceType uint32 34 StartType uint32 35 ErrorControl uint32 36 BinaryPathName string // fully qualified path to the service binary file, can also include arguments for an auto-start service 37 LoadOrderGroup string 38 TagId uint32 39 Dependencies []string 40 ServiceStartName string // name of the account under which the service should run 41 DisplayName string 42 Password string 43 Description string 44 SidType uint32 // one of SERVICE_SID_TYPE, the type of sid to use for the service 45 DelayedAutoStart bool // the service is started after other auto-start services are started plus a short delay 46 } 47 48 func toStringSlice(ps *uint16) []string { 49 r := make([]string, 0) 50 p := unsafe.Pointer(ps) 51 52 for { 53 s := windows.UTF16PtrToString((*uint16)(p)) 54 if len(s) == 0 { 55 break 56 } 57 58 r = append(r, s) 59 offset := unsafe.Sizeof(uint16(0)) * (uintptr)(len(s)+1) 60 p = unsafe.Pointer(uintptr(p) + offset) 61 } 62 63 return r 64 } 65 66 // Config retrieves service s configuration paramteres. 67 func (s *Service) Config() (Config, error) { 68 var p *windows.QUERY_SERVICE_CONFIG 69 n := uint32(1024) 70 for { 71 b := make([]byte, n) 72 p = (*windows.QUERY_SERVICE_CONFIG)(unsafe.Pointer(&b[0])) 73 err := windows.QueryServiceConfig(s.Handle, p, n, &n) 74 if err == nil { 75 break 76 } 77 if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER { 78 return Config{}, err 79 } 80 if n <= uint32(len(b)) { 81 return Config{}, err 82 } 83 } 84 85 b, err := s.queryServiceConfig2(windows.SERVICE_CONFIG_DESCRIPTION) 86 if err != nil { 87 return Config{}, err 88 } 89 p2 := (*windows.SERVICE_DESCRIPTION)(unsafe.Pointer(&b[0])) 90 91 b, err = s.queryServiceConfig2(windows.SERVICE_CONFIG_DELAYED_AUTO_START_INFO) 92 if err != nil { 93 return Config{}, err 94 } 95 p3 := (*windows.SERVICE_DELAYED_AUTO_START_INFO)(unsafe.Pointer(&b[0])) 96 delayedStart := false 97 if p3.IsDelayedAutoStartUp != 0 { 98 delayedStart = true 99 } 100 101 b, err = s.queryServiceConfig2(windows.SERVICE_CONFIG_SERVICE_SID_INFO) 102 if err != nil { 103 return Config{}, err 104 } 105 sidType := *(*uint32)(unsafe.Pointer(&b[0])) 106 107 return Config{ 108 ServiceType: p.ServiceType, 109 StartType: p.StartType, 110 ErrorControl: p.ErrorControl, 111 BinaryPathName: windows.UTF16PtrToString(p.BinaryPathName), 112 LoadOrderGroup: windows.UTF16PtrToString(p.LoadOrderGroup), 113 TagId: p.TagId, 114 Dependencies: toStringSlice(p.Dependencies), 115 ServiceStartName: windows.UTF16PtrToString(p.ServiceStartName), 116 DisplayName: windows.UTF16PtrToString(p.DisplayName), 117 Description: windows.UTF16PtrToString(p2.Description), 118 DelayedAutoStart: delayedStart, 119 SidType: sidType, 120 }, nil 121 } 122 123 func updateDescription(handle windows.Handle, desc string) error { 124 d := windows.SERVICE_DESCRIPTION{Description: toPtr(desc)} 125 return windows.ChangeServiceConfig2(handle, 126 windows.SERVICE_CONFIG_DESCRIPTION, (*byte)(unsafe.Pointer(&d))) 127 } 128 129 func updateSidType(handle windows.Handle, sidType uint32) error { 130 return windows.ChangeServiceConfig2(handle, windows.SERVICE_CONFIG_SERVICE_SID_INFO, (*byte)(unsafe.Pointer(&sidType))) 131 } 132 133 func updateStartUp(handle windows.Handle, isDelayed bool) error { 134 var d windows.SERVICE_DELAYED_AUTO_START_INFO 135 if isDelayed { 136 d.IsDelayedAutoStartUp = 1 137 } 138 return windows.ChangeServiceConfig2(handle, 139 windows.SERVICE_CONFIG_DELAYED_AUTO_START_INFO, (*byte)(unsafe.Pointer(&d))) 140 } 141 142 // UpdateConfig updates service s configuration parameters. 143 func (s *Service) UpdateConfig(c Config) error { 144 err := windows.ChangeServiceConfig(s.Handle, c.ServiceType, c.StartType, 145 c.ErrorControl, toPtr(c.BinaryPathName), toPtr(c.LoadOrderGroup), 146 nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName), 147 toPtr(c.Password), toPtr(c.DisplayName)) 148 if err != nil { 149 return err 150 } 151 err = updateSidType(s.Handle, c.SidType) 152 if err != nil { 153 return err 154 } 155 156 err = updateStartUp(s.Handle, c.DelayedAutoStart) 157 if err != nil { 158 return err 159 } 160 161 return updateDescription(s.Handle, c.Description) 162 } 163 164 // queryServiceConfig2 calls Windows QueryServiceConfig2 with infoLevel parameter and returns retrieved service configuration information. 165 func (s *Service) queryServiceConfig2(infoLevel uint32) ([]byte, error) { 166 n := uint32(1024) 167 for { 168 b := make([]byte, n) 169 err := windows.QueryServiceConfig2(s.Handle, infoLevel, &b[0], n, &n) 170 if err == nil { 171 return b, nil 172 } 173 if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER { 174 return nil, err 175 } 176 if n <= uint32(len(b)) { 177 return nil, err 178 } 179 } 180 }