molly-brown/security_dropprivs.go

120 lines
2.5 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
if ui.root_supp_group {
err := syscall.Setgroups([]int{})
if err != nil {
log.Println("Could not unset supplementary groups: " + err.Error())
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
}