Add chroot feature

This commit is contained in:
Felix Niederwanger 2022-02-05 12:15:19 +01:00
parent 5400abb1b1
commit 0324c6a93f
Signed by: phoenix
GPG key ID: 6E77A590E3F6D71C
5 changed files with 51 additions and 20 deletions

3
.gitignore vendored
View file

@ -16,6 +16,7 @@
# Dependency directories (remove the comment below to include it)
vendor/
# Certificates
# Certificates and config files
*.crt
*.key
*.conf

View file

@ -39,6 +39,8 @@ It's recommended to place your certificates in the `/conf` direcory and use the
Certfile = /conf/orion.crt
Keyfile = /conf/orion.key
Note: Use the `chroot` setting in containers for additional security.
## Credits
* This project was inspired by the [titan2](https://gitlab.com/lostleonardo/titan2) minimalistic Gemini server written by lostleonardo.

View file

@ -13,6 +13,7 @@ type Config struct {
Keyfile string // Key file
BindAddr string // Optional binding address
ContentDir string // Gemini content directory to serve
Chroot string // chroot directory, if configured
}
func (cf *Config) SetDefaults() {
@ -53,6 +54,8 @@ func (cf *Config) LoadConfigFile(filename string) error {
cf.BindAddr = value
} else if name == "contentdir" {
cf.ContentDir = value
} else if name == "chroot" {
cf.Chroot = value
} else {
return fmt.Errorf("Unknown setting in line %d", lineCount)
}

View file

@ -10,6 +10,7 @@ import (
"net/http"
"os"
"os/signal"
"runtime"
"strings"
"syscall"
)
@ -40,6 +41,17 @@ func tryLoadConfig(filename string) {
}
}
func chroot(dir string) error {
runtime.LockOSThread()
if err := syscall.Chroot(dir); err != nil {
return err
}
if err := os.Chdir("/"); err != nil {
return err
}
return nil
}
func main() {
config.SetDefaults()
@ -57,6 +69,29 @@ func main() {
tryLoadConfig("./orion.conf")
}
// Load keys before chroot
if !FileExists(config.Keyfile) {
fmt.Fprintf(os.Stderr, "Server key file not found: %s\n", config.Keyfile)
os.Exit(1)
}
if !FileExists(config.CertFile) {
fmt.Fprintf(os.Stderr, "Certificate file not found: %s\n", config.CertFile)
os.Exit(1)
}
cert, err := tls.LoadX509KeyPair(config.CertFile, config.Keyfile)
if err != nil {
fmt.Fprintf(os.Stderr, "certificate error: %s\n", err)
os.Exit(1)
}
// Chroot, if configured to do so
if config.Chroot != "" {
if err := chroot(config.Chroot); err != nil {
fmt.Fprintf(os.Stderr, "chroot failed: %s\n", err)
os.Exit(1)
}
}
// Make the content dir absolute
if !strings.HasPrefix(config.ContentDir, "/") {
workDir, err := os.Getwd()
@ -71,16 +106,6 @@ func main() {
config.ContentDir += "/"
}
// Check settings
if !FileExists(config.Keyfile) {
fmt.Fprintf(os.Stderr, "Server key file not found: %s\n", config.Keyfile)
os.Exit(1)
}
if !FileExists(config.CertFile) {
fmt.Fprintf(os.Stderr, "Certificate file not found: %s\n", config.CertFile)
os.Exit(1)
}
// Content warnings should point user at wrong configuration early in the program
if !DirectoryExists(config.ContentDir) {
fmt.Fprintf(os.Stderr, "WARNING: Content directory does not exist: %s\n", config.ContentDir)
@ -91,11 +116,6 @@ func main() {
}
// Setup gemini server
cert, err := tls.LoadX509KeyPair(config.CertFile, config.Keyfile)
if err != nil {
fmt.Fprintf(os.Stderr, "certificate error: %s\n", err)
os.Exit(1)
}
server, err := CreateGeminiServer(config.Hostname, config.BindAddr, cert)
if err != nil {
fmt.Fprintf(os.Stderr, "server error: %s\n", err)

View file

@ -2,14 +2,19 @@
## Please modify this file to your needs
## lines starting with a '#' are comments and will be ignored
# Server hostname and listen address
# Bind ':1965' will bind to any IP address and port 1965
## Server hostname and listen address
## Bind ':1965' will bind to any IP address and port 1965
Hostname = localhost
Bind = :1965
# TLS certificate
## TLS certificate
## Note: Those files will be loaded before chroot!
Certfile = orion.crt
Keyfile = orion.key
# Content directory
## Content directory
ContentDir = ./gemini/
## Chroot into this directory (uncomment to enable)
## Note: If enabled, the ContentDir needs to be adapted accordingly
# chroot = /srv/gemini/