improve drop root code and move it to a separate file

This commit is contained in:
nervuri 2023-02-15 14:44:59 +00:00
parent 8cf7b02e1b
commit 0f48c7479f
2 changed files with 106 additions and 49 deletions

105
drop_privileges.go Normal file
View File

@ -0,0 +1,105 @@
package main
import (
"fmt"
"os"
"os/user"
"strconv"
"syscall"
)
// Drop root privileges.
func dropPrivileges(userToSwitchTo string) {
// Check if we have root privileges.
var rootUser = false
var rootPrimaryGroup = false
var rootSupplementaryGroup = false
// Check UID and EUID.
if syscall.Getuid() == 0 || syscall.Geteuid() == 0 {
rootUser = true
}
// Check GID and EGID.
if syscall.Getgid() == 0 || syscall.Getegid() == 0 {
rootPrimaryGroup = true
}
// Check supplementary groups.
groups, err := syscall.Getgroups()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
for _, groupID := range groups {
if groupID == 0 {
rootSupplementaryGroup = true
break
}
}
if userToSwitchTo == "" {
if rootUser {
fmt.Println("When running as root, use the -u option to switch to an unprivileged user.")
os.Exit(1)
} else if rootPrimaryGroup || rootSupplementaryGroup {
fmt.Println("The user running the program is in the root group;")
fmt.Println("use the -u option to switch to an unprivileged user.")
os.Exit(1)
}
} else { // userToSwitchTo != ""
// Get user and group IDs for the user we want to switch to.
userInfo, err := user.Lookup(userToSwitchTo)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// Convert group id and user id from string to int.
gid, err := strconv.Atoi(userInfo.Gid)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
uid, err := strconv.Atoi(userInfo.Uid)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// If the user we want to switch to has root privileges, stop execution.
if uid == 0 || gid == 0 {
fmt.Println("Running as root is not allowed.")
os.Exit(1)
}
// Unset supplementary group IDs.
err = syscall.Setgroups([]int{})
if err != nil {
fmt.Println("Failed to unset supplementary group IDs: " + err.Error())
if rootSupplementaryGroup {
fmt.Println("Failed to drop root privileges. Exiting...")
os.Exit(1)
}
}
// Set group ID (real and effective).
err = syscall.Setgid(gid)
if err != nil {
fmt.Println("Failed to set group ID: " + err.Error())
if rootPrimaryGroup {
fmt.Println("Failed to drop root privileges. Exiting...")
os.Exit(1)
}
}
// Set user ID (real and effective).
err = syscall.Setuid(uid)
if err != nil {
fmt.Println("Failed to set user ID: " + err.Error())
if rootUser {
fmt.Println("Failed to drop root privileges. Exiting...")
os.Exit(1)
}
}
}
}

View File

@ -14,11 +14,7 @@ import (
"log"
"net"
"net/url"
"os"
"os/user"
"strconv"
"strings"
"syscall"
"time"
)
@ -304,51 +300,7 @@ func main() {
}
defer ln.Close()
// Drop root
if syscall.Getuid() == 0 { // running as root
if userToSwitchTo == "" {
fmt.Println("When running as root, use the -u option to switch to an unprivileged user.")
os.Exit(1)
}
// Get user and group IDs for the user we want to switch to.
userInfo, err := user.Lookup(userToSwitchTo)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// Convert group id and user id from string to int.
gid, err := strconv.Atoi(userInfo.Gid)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
uid, err := strconv.Atoi(userInfo.Uid)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if uid == 0 {
fmt.Println("WARNING: running as root is not recommended!")
}
// Unset supplementary group IDs.
err = syscall.Setgroups([]int{})
if err != nil {
fmt.Println("Failed to unset supplementary group IDs: " + err.Error())
os.Exit(1)
}
// Set group ID.
err = syscall.Setgid(gid)
if err != nil {
fmt.Println("Failed to set group ID: " + err.Error())
os.Exit(1)
}
// Set user ID.
err = syscall.Setuid(uid)
if err != nil {
fmt.Println("Failed to set user ID: " + err.Error())
os.Exit(1)
}
}
dropPrivileges(userToSwitchTo)
log.Println("Server started")