implemented pledge and unveil on openbsd

This commit is contained in:
ston1th 2022-10-08 17:48:16 +02:00
commit 0c4376ec32
205 changed files with 19126 additions and 4610 deletions

View file

@ -0,0 +1,3 @@
port80
port80fg
port80and443

View file

@ -0,0 +1,24 @@
Copyright (C) 2022 Marius Schellenberger
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of the authors and/or contributors may not be used to
endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL ston1th BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -0,0 +1,5 @@
# godrop - drop privileges
Godrop is a simple library to drop privileges on Linux and OpenBSD.
See the examples directory on how to use the `Drop` and `MultiDrop` functions.

View file

@ -0,0 +1,137 @@
// Copyright (C) 2022 Marius Schellenberger
//go:build go1.11
// +build go1.11
// Package godrop provides a simple library to drop privileges on Linux and OpenBSD.
package godrop
import (
"errors"
"fmt"
"net"
"os"
"os/exec"
"os/signal"
"syscall"
)
// Config represents the drop config
type Config struct {
// User is the user to drop privileges to.
User string
// Group is the group to drop privileges to.
Group string
// Chroot is the directory to chroot into. Leave this emptry for no chroot.
// When compiling without cgo, make sure the chroot directory contains the /etc/passwd and /etc/group files.
Chroot string
// Set to true, to run the process in the foreground.
Foreground bool
}
// Drop will spawn a new process and hand over the listening socket file descriptor
func Drop(c Config, f func() (net.Listener, error)) error {
return MultiDrop(c, func() ([]net.Listener, error) {
l, err := f()
return []net.Listener{l}, err
})
}
// MultiDrop will spawn a new process and hand over the all listening sockets
func MultiDrop(c Config, f func() ([]net.Listener, error)) error {
uid, err := userID(c.User)
if err != nil {
return errors.New("godrop: " + err.Error())
}
if uid == 0 {
return fmt.Errorf("godrop: you can't drop privileges to uid 0 (%s)", c.User)
}
gid, err := groupID(c.Group)
if err != nil {
return errors.New("godrop: " + err.Error())
}
switch os.Getuid() {
case 0:
cmd := exec.Command(os.Args[0], os.Args[1:]...)
ln, err := f()
if err != nil {
return errors.New("godrop: " + err.Error())
}
for i, v := range ln {
var f *os.File
switch l := v.(type) {
case *net.TCPListener:
f, err = l.File()
l.Close()
case *net.UnixListener:
f, err = l.File()
l.Close()
default:
return fmt.Errorf("godrop: index %d listener is not type of either *net.TCPListener or *net.UnixListener", i)
}
if err != nil {
return fmt.Errorf("godrop: index %d %s", i, err)
}
cmd.ExtraFiles = append(cmd.ExtraFiles, f)
}
cmd.SysProcAttr = &syscall.SysProcAttr{
Chroot: c.Chroot,
Credential: &syscall.Credential{
Uid: uint32(uid),
Gid: uint32(gid),
},
Setsid: true,
}
if c.Foreground {
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
}
if err := cmd.Start(); err != nil {
return errors.New("godrop: " + err.Error())
}
if c.Foreground {
go func() {
term := make(chan os.Signal)
signal.Notify(term, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
sigs := make(chan os.Signal)
signal.Notify(sigs, syscall.SIGSTOP, syscall.SIGCONT, syscall.SIGUSR1, syscall.SIGUSR2)
for {
select {
case sig := <-term:
cmd.Process.Signal(sig)
return
case sig := <-sigs:
cmd.Process.Signal(sig)
}
}
}()
_ = cmd.Wait()
os.Exit(int(cmd.ProcessState.Sys().(syscall.WaitStatus)))
}
cmd.Process.Release()
os.Exit(0)
case uid:
return nil
}
return errors.New("godrop: dropping priviledges failed")
}
// GetListener returns the listener socket of file descriptor 3
func GetListener() (net.Listener, error) {
return GetListenerFd(3)
}
// GetListenerFd returns the listener socket of the given file descriptor
func GetListenerFd(fd int) (net.Listener, error) {
if fd < 3 {
return nil, errors.New("godrop: fd is less than 3")
}
f := os.NewFile(uintptr(fd), "")
defer f.Close()
return net.FileListener(f)
}

View file

@ -0,0 +1,35 @@
// Copyright (C) 2022 Marius Schellenberger
//go:build go1.11
// +build go1.11
package godrop
import (
"os/user"
"strconv"
)
func atoi(a string) (int, error) {
i, err := strconv.Atoi(a)
if err != nil {
return -1, err
}
return i, nil
}
func userID(username string) (int, error) {
u, err := user.Lookup(username)
if err != nil {
return -1, err
}
return atoi(u.Uid)
}
func groupID(name string) (int, error) {
g, err := user.LookupGroup(name)
if err != nil {
return -1, err
}
return atoi(g.Gid)
}

View file

@ -0,0 +1,15 @@
// Copyright (C) 2022 Marius Schellenberger
//go:build !openbsd
// +build !openbsd
package godrop
// Pledge is currently only supported on OpenBSD.
func Pledge(promises, execpromises string) error { return nil }
// PledgePromises is currently only supported on OpenBSD.
func PledgePromises(promises string) error { return nil }
// PledgeExecPromises is currently only supported on OpenBSD.
func PledgeExecpromises(execpromises string) error { return nil }

View file

@ -0,0 +1,44 @@
// Copyright (C) 2022 Marius Schellenberger
//go:build openbsd
// +build openbsd
package godrop
import (
"errors"
"golang.org/x/sys/unix"
)
// Pledge is a wrapper for x/sys/unix Pledge.
//
// See https://go.googlesource.com/sys/+/master/unix/openbsd_pledge.go for usage.
func Pledge(promises, execpromises string) (err error) {
err = unix.Pledge(promises, execpromises)
if err != nil {
err = errors.New("pledge: " + err.Error())
}
return
}
// PledgePromises is a wrapper for x/sys/unix PledgePromises.
//
// See https://go.googlesource.com/sys/+/master/unix/openbsd_pledge.go for usage.
func PledgePromises(promises string) (err error) {
err = unix.PledgePromises(promises)
if err != nil {
err = errors.New("pledge: " + err.Error())
}
return
}
// PledgeExecpromises is a wrapper for x/sys/unix PledgeExecpromises.
//
// See https://go.googlesource.com/sys/+/master/unix/openbsd_pledge.go for usage.
func PledgeExecpromises(execpromises string) (err error) {
err = unix.PledgeExecpromises(execpromises)
if err != nil {
err = errors.New("pledge: " + err.Error())
}
return
}

View file

@ -0,0 +1,12 @@
// Copyright (C) 2022 Marius Schellenberger
//go:build !openbsd
// +build !openbsd
package godrop
// Unveil is currently only supported on OpenBSD.
func Unveil(path, flags string) error { return nil }
// UnveilBlock is currently only supported on OpenBSD.
func UnveilBlock() error { return nil }

View file

@ -0,0 +1,33 @@
// Copyright (C) 2022 Marius Schellenberger
//go:build openbsd
// +build openbsd
package godrop
import (
"errors"
"golang.org/x/sys/unix"
)
// Unveil is a wrapper for x/sys/unix Unveil.
//
// See https://go.googlesource.com/sys/+/master/unix/openbsd_unveil.go for usage.
func Unveil(path, flags string) (err error) {
err = unix.Unveil(path, flags)
if err != nil {
err = errors.New("unveil: " + err.Error())
}
return
}
// UnveilBlock is a wrapper for x/sys/unix UnveilBlock.
//
// See https://go.googlesource.com/sys/+/master/unix/openbsd_unveil.go for usage.
func UnveilBlock() (err error) {
err = unix.UnveilBlock()
if err != nil {
err = errors.New("unveil: " + err.Error())
}
return
}