1//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
 2// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 3
 4// This is an example of binding soft-serve ssh port to a restricted port (<1024) and
 5// then droping root privileges to a different user to run the server.
 6// Make sure you run this as root.
 7
 8package main
 9
10import (
11	"context"
12	"flag"
13	"fmt"
14	"net"
15	"os"
16	"os/signal"
17	"syscall"
18	"time"
19
20	"github.com/charmbracelet/log"
21
22	"github.com/charmbracelet/soft-serve/server"
23	"github.com/charmbracelet/soft-serve/server/config"
24)
25
26var (
27	port = flag.Int("port", 22, "port to listen on")
28	gid  = flag.Int("gid", 1000, "group id to run as")
29	uid  = flag.Int("uid", 1000, "user id to run as")
30)
31
32func main() {
33	flag.Parse()
34	addr := fmt.Sprintf(":%d", *port)
35	// To listen on port 22 we need root privileges
36	ls, err := net.Listen("tcp", addr)
37	if err != nil {
38		log.Fatal("Can't listen", "err", err)
39	}
40	// We don't need root privileges any more
41	if err := syscall.Setgid(*gid); err != nil {
42		log.Fatal("Setgid error", "err", err)
43	}
44	if err := syscall.Setuid(*uid); err != nil {
45		log.Fatal("Setuid error", "err", err)
46	}
47	ctx := context.Background()
48	cfg := config.DefaultConfig()
49	ctx = config.WithContext(ctx, cfg)
50	cfg.SSH.ListenAddr = fmt.Sprintf(":%d", *port)
51	s, err := server.NewServer(ctx)
52	if err != nil {
53		log.Fatal(err)
54	}
55
56	done := make(chan os.Signal, 1)
57	signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
58
59	log.Print("Starting SSH server", "addr", cfg.SSH.ListenAddr)
60	go func() {
61		if err := s.SSHServer.Serve(ls); err != nil {
62			log.Fatal(err)
63		}
64	}()
65
66	<-done
67
68	log.Print("Stopping SSH server", "addr", cfg.SSH.ListenAddr)
69	ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
70	defer func() { cancel() }()
71	if err := s.Shutdown(ctx); err != nil {
72		log.Fatal(err)
73	}
74}