mirror of
https://tildegit.org/solderpunk/molly-brown
synced 2024-11-15 16:30:06 +01:00
Avoid use of log.Fatal() or os.Exit() in main so defers are guaranteed to run.
This commit is contained in:
parent
7fad754ff2
commit
072669a167
37
main.go
37
main.go
@ -41,15 +41,26 @@ func main() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Run server and exit
|
||||
os.Exit(do_main(config))
|
||||
}
|
||||
|
||||
func do_main(config Config) int {
|
||||
|
||||
// If we are running as root, find the UID of the "nobody" user, before a
|
||||
// chroot() possibly stops seeing /etc/passwd
|
||||
privInfo := getUserInfo(config)
|
||||
privInfo, err := getUserInfo(config)
|
||||
if err != nil {
|
||||
errorLog.Println("Exiting due to failure to apply security restrictions.")
|
||||
return 1
|
||||
}
|
||||
|
||||
// Chroot, if asked
|
||||
if config.ChrootDir != "" {
|
||||
err := syscall.Chroot(config.ChrootDir)
|
||||
if err != nil {
|
||||
log.Fatal("Could not chroot to " + config.ChrootDir + ": " + err.Error())
|
||||
log.Println("Could not chroot to " + config.ChrootDir + ": " + err.Error())
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,7 +71,8 @@ func main() {
|
||||
} else {
|
||||
errorLogFile, err = os.OpenFile(config.ErrorLog, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.Println(err)
|
||||
return 1
|
||||
}
|
||||
defer errorLogFile.Close()
|
||||
}
|
||||
@ -73,7 +85,8 @@ func main() {
|
||||
accessLogFile, err = os.OpenFile(config.AccessLog, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
errorLog.Println("Error opening access log file: " + err.Error())
|
||||
log.Fatal(err)
|
||||
log.Println(err)
|
||||
return 1
|
||||
}
|
||||
defer accessLogFile.Close()
|
||||
}
|
||||
@ -83,16 +96,16 @@ func main() {
|
||||
info, err := os.Stat(config.KeyPath)
|
||||
if err != nil {
|
||||
errorLog.Println("Error opening TLS key file: " + err.Error())
|
||||
log.Fatal(err)
|
||||
return 1
|
||||
}
|
||||
if uint64(info.Mode().Perm())&0444 == 0444 {
|
||||
errorLog.Println("Refusing to use world-readable TLS key file " + config.KeyPath)
|
||||
os.Exit(0)
|
||||
return 1
|
||||
}
|
||||
cert, err := tls.LoadX509KeyPair(config.CertPath, config.KeyPath)
|
||||
if err != nil {
|
||||
errorLog.Println("Error loading TLS keypair: " + err.Error())
|
||||
log.Fatal(err)
|
||||
return 1
|
||||
}
|
||||
tlscfg := &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
@ -108,13 +121,17 @@ func main() {
|
||||
}
|
||||
|
||||
// Apply security restrictions
|
||||
enableSecurityRestrictions(config, privInfo, errorLog)
|
||||
err = enableSecurityRestrictions(config, privInfo, errorLog)
|
||||
if err != nil {
|
||||
errorLog.Println("Exiting due to failure to apply security restrictions.")
|
||||
return 1
|
||||
}
|
||||
|
||||
// Create TLS listener
|
||||
listener, err := tls.Listen("tcp", ":"+strconv.Itoa(config.Port), tlscfg)
|
||||
if err != nil {
|
||||
errorLog.Println("Error creating TLS listener: " + err.Error())
|
||||
log.Fatal(err)
|
||||
return 1
|
||||
}
|
||||
defer listener.Close()
|
||||
|
||||
@ -164,4 +181,6 @@ func main() {
|
||||
wg.Wait()
|
||||
errorLog.Println("Exiting.")
|
||||
|
||||
// Exit successfully
|
||||
return 0
|
||||
}
|
||||
|
@ -10,5 +10,5 @@ import (
|
||||
// This is intended to be called immediately prior to accepting client
|
||||
// connections and may be used to establish a security "jail" for the molly
|
||||
// brown executable.
|
||||
func enableSecurityRestrictions(config Config, errorLog *log.Logger) {
|
||||
func enableSecurityRestrictions(config Config, ui userInfo, errorLog *log.Logger) error {
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ type userInfo struct {
|
||||
unpriv_gid int
|
||||
}
|
||||
|
||||
func getUserInfo(config Config) userInfo {
|
||||
func getUserInfo(config Config) (userInfo, error) {
|
||||
var ui userInfo
|
||||
ui.uid = os.Getuid()
|
||||
ui.euid = os.Geteuid()
|
||||
@ -34,7 +34,8 @@ func getUserInfo(config Config) userInfo {
|
||||
ui.egid = os.Getegid()
|
||||
supp_groups, err := os.Getgroups()
|
||||
if err != nil {
|
||||
log.Fatal("Could not get supplementary groups: ", err.Error())
|
||||
log.Println("Could not get supplementary groups: ", err.Error())
|
||||
return ui, err
|
||||
}
|
||||
ui.supp_groups = supp_groups
|
||||
ui.unpriv_uid = -1
|
||||
@ -55,22 +56,24 @@ func getUserInfo(config Config) userInfo {
|
||||
if ui.need_drop {
|
||||
nobody_user, err := user.Lookup(config.UnprivUsername)
|
||||
if err != nil {
|
||||
log.Fatal("Running as root but could not lookup UID for user " + config.UnprivUsername + ": " + err.Error())
|
||||
log.Println("Running as root but could not lookup UID for user " + config.UnprivUsername + ": " + 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.Fatal("Running as root but could not lookup UID for user " + config.UnprivUsername + ": " + err.Error())
|
||||
log.Println("Running as root but could not lookup UID for user " + config.UnprivUsername + ": " + err.Error())
|
||||
return ui, err
|
||||
}
|
||||
}
|
||||
|
||||
return ui
|
||||
return ui, nil
|
||||
}
|
||||
func DropPrivs(ui userInfo, errorLog *log.Logger) {
|
||||
func DropPrivs(ui userInfo, errorLog *log.Logger) error {
|
||||
|
||||
// If we're already unprivileged, all good
|
||||
if !ui.need_drop {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// Drop supplementary groups
|
||||
@ -78,7 +81,7 @@ func DropPrivs(ui userInfo, errorLog *log.Logger) {
|
||||
err := syscall.Setgroups([]int{})
|
||||
if err != nil {
|
||||
errorLog.Println("Could not unset supplementary groups: " + err.Error())
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,7 +90,7 @@ func DropPrivs(ui userInfo, errorLog *log.Logger) {
|
||||
err := syscall.Setgid(ui.unpriv_gid)
|
||||
if err != nil {
|
||||
errorLog.Println("Could not setgid to " + strconv.Itoa(ui.unpriv_gid) + ": " + err.Error())
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,8 +99,9 @@ func DropPrivs(ui userInfo, errorLog *log.Logger) {
|
||||
err := syscall.Setuid(ui.unpriv_uid)
|
||||
if err != nil {
|
||||
errorLog.Println("Could not setuid to " + strconv.Itoa(ui.unpriv_uid) + ": " + err.Error())
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func enableSecurityRestrictions(config Config, errorLog *log.Logger) {
|
||||
func enableSecurityRestrictions(config Config, ui userInfo, errorLog *log.Logger) error {
|
||||
|
||||
// Prior to Go 1.6, setuid did not work reliably on Linux
|
||||
// So, absolutely refuse to run as root
|
||||
@ -16,6 +16,8 @@ func enableSecurityRestrictions(config Config, errorLog *log.Logger) {
|
||||
if uid == 0 || euid == 0 {
|
||||
setuid_err := "Refusing to run with root privileges when setuid() will not work!"
|
||||
errorLog.Println(setuid_err)
|
||||
log.Fatal(setuid_err)
|
||||
return error.New(setuid_err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -11,17 +11,20 @@ import (
|
||||
// operations available to the molly brown executable. Please note that (S)CGI
|
||||
// processes that molly brown spawns or communicates with are unrestricted
|
||||
// and should pledge their own restrictions and unveil their own files.
|
||||
func enableSecurityRestrictions(config Config, ui userInfo, errorLog *log.Logger) {
|
||||
func enableSecurityRestrictions(config Config, ui userInfo, errorLog *log.Logger) error {
|
||||
|
||||
// Setuid to an unprivileged user
|
||||
DropPrivs(ui, errorLog)
|
||||
err := DropPrivs(ui, errorLog)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Unveil the configured document base as readable.
|
||||
log.Println("Unveiling \"" + config.DocBase + "\" as readable.")
|
||||
err := unix.Unveil(config.DocBase, "r")
|
||||
if err != nil {
|
||||
errorLog.Println("Could not unveil DocBase: " + err.Error())
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Unveil cgi path globs as executable.
|
||||
@ -32,7 +35,7 @@ func enableSecurityRestrictions(config Config, ui userInfo, errorLog *log.Logger
|
||||
err = unix.Unveil(cgiGlobbedPath, "rx")
|
||||
if err != nil {
|
||||
errorLog.Println("Could not unveil CGIPaths: " + err.Error())
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -41,6 +44,9 @@ func enableSecurityRestrictions(config Config, ui userInfo, errorLog *log.Logger
|
||||
for _, scgiSocket := range config.SCGIPaths {
|
||||
log.Println("Unveiling \"" + scgiSocket + "\" as read/write.")
|
||||
err = unix.Unveil(scgiSocket, "rw")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Finalize the unveil list.
|
||||
@ -48,7 +54,7 @@ func enableSecurityRestrictions(config Config, ui userInfo, errorLog *log.Logger
|
||||
err = unix.UnveilBlock()
|
||||
if err != nil {
|
||||
errorLog.Println("Could not block unveil: " + err.Error())
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Pledge to only use stdio, inet, and rpath syscalls.
|
||||
@ -64,6 +70,6 @@ func enableSecurityRestrictions(config Config, ui userInfo, errorLog *log.Logger
|
||||
err = unix.PledgePromises(promises)
|
||||
if err != nil {
|
||||
errorLog.Println("Could not pledge: " + err.Error())
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,9 @@ import (
|
||||
"log"
|
||||
)
|
||||
|
||||
func enableSecurityRestrictions(config Config, ui userInfo, errorLog *log.Logger) {
|
||||
func enableSecurityRestrictions(config Config, ui userInfo, errorLog *log.Logger) error {
|
||||
|
||||
// Setuid to an unprivileged user
|
||||
DropPrivs(ui, errorLog)
|
||||
return DropPrivs(ui, errorLog)
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user