github.com/crowdsecurity/crowdsec@v1.6.1/cmd/crowdsec/win_service.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 main
     8  
     9  import (
    10  	"fmt"
    11  	"syscall"
    12  	"time"
    13  
    14  	log "github.com/sirupsen/logrus"
    15  	"golang.org/x/sys/windows"
    16  	"golang.org/x/sys/windows/svc"
    17  	"golang.org/x/sys/windows/svc/eventlog"
    18  
    19  	"github.com/crowdsecurity/crowdsec/pkg/csconfig"
    20  )
    21  
    22  type crowdsec_winservice struct {
    23  	config *csconfig.Config
    24  }
    25  
    26  func (m *crowdsec_winservice) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (bool, uint32) {
    27  	const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown
    28  	changes <- svc.Status{State: svc.StartPending}
    29  	tick := time.Tick(500 * time.Millisecond)
    30  	changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
    31  
    32  	go func() {
    33  	loop:
    34  		for {
    35  			select {
    36  			case <-tick:
    37  
    38  			case c := <-r:
    39  				switch c.Cmd {
    40  				case svc.Interrogate:
    41  					changes <- c.CurrentStatus
    42  				case svc.Stop, svc.Shutdown:
    43  					changes <- svc.Status{State: svc.StopPending}
    44  					err := shutdown(nil, m.config)
    45  					if err != nil {
    46  						log.Errorf("Error while shutting down: %s", err)
    47  						// don't return, we still want to notify windows that we are stopped ?
    48  					}
    49  					break loop
    50  				default:
    51  					log.Errorf("unexpected control request #%d", c)
    52  				}
    53  			}
    54  		}
    55  	}()
    56  
    57  	err := WindowsRun()
    58  	changes <- svc.Status{State: svc.Stopped}
    59  	if err != nil {
    60  		log.Fatal(err)
    61  	}
    62  
    63  	return false, 0
    64  }
    65  
    66  func runService(name string) error {
    67  	// All the calls to logging before the logger is configured are pretty much useless, but we keep them for clarity
    68  	err := eventlog.InstallAsEventCreate("CrowdSec", eventlog.Error|eventlog.Warning|eventlog.Info)
    69  	if err != nil {
    70  		if errno, ok := err.(syscall.Errno); ok {
    71  			if errno == windows.ERROR_ACCESS_DENIED {
    72  				log.Warnf("Access denied when installing event source, running as non-admin ?")
    73  			} else {
    74  				log.Warnf("Failed to install event log: %s (%d)", err, errno)
    75  			}
    76  		} else {
    77  			log.Warnf("Failed to install event log: %s", err)
    78  		}
    79  	}
    80  
    81  	// Let's use our source even if we could not install it:
    82  	// - It could have been created earlier
    83  	// - No permission to create it (e.g. running as non-admin when working on crowdsec)
    84  	// It will still work, windows will just display some additional errors in the event log
    85  	evtlog, err := eventlog.Open("CrowdSec")
    86  
    87  	if err == nil {
    88  		// Send panic and fatal to event log, as they can happen before the logger is configured.
    89  		log.AddHook(&EventLogHook{
    90  			LogLevels: []log.Level{
    91  				log.PanicLevel,
    92  				log.FatalLevel,
    93  			},
    94  			evtlog: evtlog,
    95  		})
    96  	} else {
    97  		log.Warnf("Failed to open event log: %s", err)
    98  	}
    99  
   100  	cConfig, err := LoadConfig(flags.ConfigFile, flags.DisableAgent, flags.DisableAPI, false)
   101  	if err != nil {
   102  		return err
   103  	}
   104  
   105  	log.Infof("starting %s service", name)
   106  	winsvc := crowdsec_winservice{config: cConfig}
   107  
   108  	if err := svc.Run(name, &winsvc); err != nil {
   109  		return fmt.Errorf("%s service failed: %w", name, err)
   110  	}
   111  
   112  	log.Infof("%s service stopped", name)
   113  	return nil
   114  }