version 2.0.0

This commit is contained in:
ston1th 2018-09-19 21:12:43 +02:00
commit de6a48c088
10 changed files with 84 additions and 108 deletions

1
.gitignore vendored
View file

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

View file

@ -2,28 +2,27 @@ package main
import (
"fmt"
"log"
"net"
"net/http"
"os"
"git.giftfish.de/ston1th/godrop"
"git.giftfish.de/ston1th/godrop/v2"
)
func main() {
cfg := godrop.Config{
User: "nobody",
Group: "nobody",
Foreground: true,
}
err := godrop.Drop(cfg, func() (net.Listener, error) { return net.Listen("tcp", ":80") })
if err != nil {
fmt.Println(err)
log.Fatal(err)
}
l, err := godrop.GetListener()
if err != nil {
fmt.Println("Failed to listen on FD 3:", err)
os.Exit(1)
log.Fatal("Failed to listen on FD 3:", err)
}
_, port, _ := net.SplitHostPort(l.Addr().String())

View file

@ -2,11 +2,12 @@ package main
import (
"fmt"
"log"
"net"
"net/http"
"os"
"git.giftfish.de/ston1th/godrop"
"git.giftfish.de/ston1th/godrop/v2"
)
func main() {
@ -24,23 +25,23 @@ func main() {
return []net.Listener{l1, l2}, err
})
if err != nil {
fmt.Println(err)
log.Fatal(err)
}
l1, err := godrop.GetListener()
if err != nil {
fmt.Println("Failed to listen on FD 3:", err)
os.Exit(1)
log.Fatal("Failed to listen on FD 3:", err)
}
_, port1, _ := net.SplitHostPort(l1.Addr().String())
l2, err := godrop.GetListenerFd(4)
if err != nil {
fmt.Println("Failed to listen on FD 4:", err)
os.Exit(1)
log.Fatal("Failed to listen on FD 4:", err)
}
_, port2, _ := net.SplitHostPort(l2.Addr().String())
fmt.Printf("port1 %s\nport2 %s\npid %d\nuid %d\ngid %d\n", port1, port2, os.Getpid(), os.Getuid(), os.Getgid())
go func() {
http.Serve(l1, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "port %s\npid %d\nuid %d\ngid %d", port1, os.Getpid(), os.Getuid(), os.Getgid())

35
example/port80fg.go Normal file
View file

@ -0,0 +1,35 @@
package main
import (
"fmt"
"log"
"net"
"net/http"
"os"
"git.giftfish.de/ston1th/godrop/v2"
)
func main() {
cfg := godrop.Config{
User: "nobody",
Group: "nobody",
Foreground: true,
}
err := godrop.Drop(cfg, func() (net.Listener, error) { return net.Listen("tcp", ":80") })
if err != nil {
log.Fatal(err)
}
l, err := godrop.GetListener()
if err != nil {
log.Fatal("Failed to listen on FD 3:", err)
}
_, port, _ := net.SplitHostPort(l.Addr().String())
fmt.Printf("port %s\npid %d\nuid %d\ngid %d\n", port, os.Getpid(), os.Getuid(), os.Getgid())
http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "port %s\npid %d\nuid %d\ngid %d", port, os.Getpid(), os.Getuid(), os.Getgid())
}))
}

1
go.mod Normal file
View file

@ -0,0 +1 @@
module git.giftfish.de/ston1th/godrop/v2

View file

@ -1,20 +1,20 @@
// Copyright (C) 2017 Marius Schellenberger
// Copyright (C) 2018 Marius Schellenberger
// +build go1.11
// Package godrop provides a simple privileges dropping library
package godrop
import (
"errors"
"fmt"
"net"
"os"
"os/exec"
"os/signal"
"syscall"
)
func errf(err error) error {
return fmt.Errorf("godrop: %s", err)
func errf(i interface{}) error {
return fmt.Errorf("godrop: %s", i)
}
// Config represents the drop config
@ -45,7 +45,7 @@ func MultiDrop(c Config, f func() ([]net.Listener, error)) error {
return errf(err)
}
if uid == 0 {
return errf(errors.New("unable to drop privileges to uid 0 (root)"))
return errf("unable to drop privileges to uid 0 (root)")
}
gid, err := groupID(c.Group)
if err != nil {
@ -68,20 +68,14 @@ func MultiDrop(c Config, f func() ([]net.Listener, error)) error {
f, err = l.File()
l.Close()
default:
return errf(fmt.Errorf("index: %d listener is not type of either *net.TCPListener or *net.UnixListener", i))
return errf(fmt.Sprintf("index %d listener is not type of either *net.TCPListener or *net.UnixListener", i))
}
if err != nil {
return errf(fmt.Errorf("index: %d %s", i, err))
return errf(fmt.Sprintf("index %d %s", i, err))
}
cmd.ExtraFiles = append(cmd.ExtraFiles, f)
}
if c.Foreground {
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
}
cmd.SysProcAttr = &syscall.SysProcAttr{
Chroot: c.Chroot,
Credential: &syscall.Credential{
@ -91,17 +85,20 @@ func MultiDrop(c Config, f func() ([]net.Listener, error)) error {
Setsid: true,
}
if c.Foreground {
cmd.SysProcAttr.Setctty = true
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
} else {
cmd.SysProcAttr.Noctty = true
}
if err := cmd.Start(); err != nil {
return errf(err)
}
if c.Foreground {
go func() {
sigs := make(chan os.Signal)
signal.Notify(sigs, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
sig := <-sigs
cmd.Process.Signal(sig)
}()
_ = cmd.Wait()
os.Exit(int(cmd.ProcessState.Sys().(syscall.WaitStatus)))
}
@ -110,7 +107,7 @@ func MultiDrop(c Config, f func() ([]net.Listener, error)) error {
case uid:
return nil
}
return errf(errors.New("dropping priviledges failed"))
return errf("dropping priviledges failed")
}
// GetListener returns the listener socket of file descriptor 3
@ -120,6 +117,9 @@ func GetListener() (net.Listener, error) {
// GetListenerFd returns the listener socket of the given file descriptor
func GetListenerFd(fd int) (net.Listener, error) {
if fd < 3 {
return nil, errf("fd is less than 3")
}
f := os.NewFile(uintptr(fd), "")
defer f.Close()
return net.FileListener(f)

View file

@ -1,8 +1,13 @@
// Copyright (C) 2017 Marius Schellenberger
// Copyright (C) 2018 Marius Schellenberger
// +build go1.11
package godrop
import "strconv"
import (
"os/user"
"strconv"
)
func atoi(a string) (int, error) {
i, err := strconv.Atoi(a)
@ -12,18 +17,18 @@ func atoi(a string) (int, error) {
return i, nil
}
func userID(username string) (uid int, err error) {
id, err := lookupUID(username)
func userID(username string) (int, error) {
u, err := user.Lookup(username)
if err != nil {
return -1, err
}
return atoi(id)
return atoi(u.Uid)
}
func groupID(name string) (int, error) {
id, err := lookupGID(name)
g, err := user.LookupGroup(name)
if err != nil {
return -1, err
}
return atoi(id)
return atoi(g.Gid)
}

View file

@ -1,23 +0,0 @@
// Copyright (C) 2017 Marius Schellenberger
// +build cgo
package godrop
import "os/user"
func lookupUID(username string) (string, error) {
u, err := user.Lookup(username)
if err != nil {
return "", err
}
return u.Uid, err
}
func lookupGID(name string) (string, error) {
g, err := user.LookupGroup(name)
if err != nil {
return "", err
}
return g.Gid, err
}

View file

@ -1,43 +0,0 @@
// Copyright (C) 2017 Marius Schellenberger
// +build darwin dragonfly freebsd android linux netbsd openbsd solaris
// +build !cgo
package godrop
import (
"io/ioutil"
"os"
"regexp"
)
func readFile(name, file string) (id string, err error) {
id = "-1"
if name == "" {
return
}
f, err := os.Open(file)
if err != nil {
return
}
b, err := ioutil.ReadAll(f)
if err != nil {
return
}
r := regexp.MustCompile(name + `:.*?:(\d+):`)
m := r.FindAllStringSubmatch(string(b), 1)
if len(m) == 1 {
if len(m[0]) == 2 {
return m[0][1], nil
}
}
return
}
func lookupUID(username string) (string, error) {
return readFile(username, "/etc/passwd")
}
func lookupGID(name string) (string, error) {
return readFile(name, "/etc/group")
}

View file

@ -1,4 +1,4 @@
// Copyright (C) 2017 Marius Schellenberger
// Copyright (C) 2018 Marius Schellenberger
package godrop