mirror of
https://github.com/mjl-/mox.git
synced 2024-12-26 16:33:47 +03:00
32d4e9a14c
and give the mox.service permissions to send such signals.
76 lines
1.8 KiB
Go
76 lines
1.8 KiB
Go
//go:build unix
|
|
|
|
package mox
|
|
|
|
import (
|
|
"log/slog"
|
|
"os"
|
|
"os/signal"
|
|
"strings"
|
|
"syscall"
|
|
)
|
|
|
|
// Fork and exec as unprivileged user.
|
|
//
|
|
// We don't use just setuid because it is hard to guarantee that no other
|
|
// privileged go worker processes have been started before we get here. E.g. init
|
|
// functions in packages can start goroutines.
|
|
func ForkExecUnprivileged() {
|
|
prog, err := os.Executable()
|
|
if err != nil {
|
|
pkglog.Fatalx("finding executable for exec", err)
|
|
}
|
|
|
|
files := []*os.File{os.Stdin, os.Stdout, os.Stderr}
|
|
var addrs []string
|
|
for addr, f := range passedListeners {
|
|
files = append(files, f)
|
|
addrs = append(addrs, addr)
|
|
}
|
|
var paths []string
|
|
for path, fl := range passedFiles {
|
|
for _, f := range fl {
|
|
files = append(files, f)
|
|
paths = append(paths, path)
|
|
}
|
|
}
|
|
env := os.Environ()
|
|
env = append(env, "MOX_SOCKETS="+strings.Join(addrs, ","), "MOX_FILES="+strings.Join(paths, ","))
|
|
|
|
p, err := os.StartProcess(prog, os.Args, &os.ProcAttr{
|
|
Env: env,
|
|
Files: files,
|
|
Sys: &syscall.SysProcAttr{
|
|
Credential: &syscall.Credential{
|
|
Uid: Conf.Static.UID,
|
|
Gid: Conf.Static.GID,
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
pkglog.Fatalx("fork and exec", err)
|
|
}
|
|
CleanupPassedFiles()
|
|
|
|
// If we get a interrupt/terminate signal, pass it on to the child. For interrupt,
|
|
// the child probably already got it.
|
|
// todo: see if we tie up child and root process so a kill -9 of the root process
|
|
// kills the child process too.
|
|
sigc := make(chan os.Signal, 1)
|
|
signal.Notify(sigc, os.Interrupt, syscall.SIGTERM)
|
|
go func() {
|
|
for {
|
|
sig := <-sigc
|
|
err := p.Signal(sig)
|
|
pkglog.Check(err, "forwarding signal root to unprivileged process")
|
|
}
|
|
}()
|
|
|
|
st, err := p.Wait()
|
|
if err != nil {
|
|
pkglog.Fatalx("wait", err)
|
|
}
|
|
code := st.ExitCode()
|
|
pkglog.Print("stopping after child exit", slog.Int("exitcode", code))
|
|
os.Exit(code)
|
|
}
|