1
1
Fork 0
mirror of https://tildegit.org/solderpunk/molly-brown synced 2024-05-13 04:26:03 +02:00
molly-brown/security_dropprivs.go
Solderpunk 212c9f79fb A rather extensive refactor.
Basically the function formerly known as do_main() in main.go has
been renamed launch() and moved into launch.go.  Now there are
main.go and main_unix.go files implementing minmial main()
functions which load a config and pass it to launch.  This allows
separating unix-specific security stuff (both the actual system
calls which won't compile on other platforms and the definition
of command line switches) out from the platform agnostic
implementation of the main server logic.  It also simplifies the
interaction of relative paths in config files with chrooting.

Docs still need updating...
2023-02-23 18:49:15 +01:00

122 lines
2.6 KiB
Go

// +build linux,go1.16 aix darwin dragonfly freebsd illumos netbsd openbsd solaris
package main
import (
"log"
"os"
"os/user"
"strconv"
"syscall"
)
type userInfo struct {
uid int
euid int
gid int
egid int
supp_groups []int
is_setuid bool
is_setgid bool
root_user bool
root_prim_group bool
root_supp_group bool
need_drop bool
unpriv_uid int
unpriv_gid int
}
func getUserInfo(unprivUser string) (userInfo, error) {
var ui userInfo
ui.uid = os.Getuid()
ui.euid = os.Geteuid()
ui.gid = os.Getgid()
ui.egid = os.Getegid()
supp_groups, err := os.Getgroups()
if err != nil {
log.Println("Could not get supplementary groups: ", err.Error())
return ui, err
}
ui.supp_groups = supp_groups
ui.unpriv_uid = -1
ui.unpriv_gid = -1
ui.is_setuid = ui.uid != ui.euid
ui.is_setgid = ui.gid != ui.egid
ui.root_user = ui.uid == 0 || ui.euid == 0
ui.root_prim_group = ui.gid == 0 || ui.egid == 0
for _, gid := range ui.supp_groups {
if gid == 0 {
ui.root_supp_group = true
break
}
}
ui.need_drop = ui.is_setuid || ui.is_setgid || ui.root_user || ui.root_prim_group || ui.root_supp_group
if ui.root_user || ui.root_prim_group {
nobody_user, err := user.Lookup(unprivUser)
if err != nil {
log.Println("Running as root but could not lookup UID for user " + unprivUser + ": " + err.Error())
return ui, err
}
ui.unpriv_uid, err = strconv.Atoi(nobody_user.Uid)
ui.unpriv_gid, err = strconv.Atoi(nobody_user.Gid)
if err != nil {
log.Println("Running as root but could not lookup UID for user " + unprivUser + ": " + err.Error())
return ui, err
}
}
return ui, nil
}
func DropPrivs(ui userInfo) error {
// If we're already unprivileged, all good
if !ui.need_drop {
return nil
}
// Drop supplementary groups
err := syscall.Setgroups([]int{})
if err != nil {
// Log failure
log.Println("Could not unset supplementary groups: " + err.Error())
// Make this fatal if root was amongst supplementary groups
if ui.root_supp_group {
return err
}
}
// Setgid()
if ui.root_prim_group || ui.is_setgid {
var target_gid int
if ui.root_prim_group {
target_gid = ui.unpriv_gid
} else {
target_gid = ui.gid
}
err := syscall.Setgid(target_gid)
if err != nil {
log.Println("Could not setgid to " + strconv.Itoa(target_gid) + ": " + err.Error())
return err
}
}
// Setuid()
if ui.root_user || ui.is_setuid {
var target_uid int
if ui.root_user {
target_uid = ui.unpriv_uid
} else {
target_uid = ui.uid
}
err := syscall.Setuid(target_uid)
if err != nil {
log.Println("Could not setuid to " + strconv.Itoa(target_uid) + ": " + err.Error())
return err
}
}
return nil
}