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  }