diff --git a/INSTALL.md b/INSTALL.md index f5f63bd..21cc0e0 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -2,10 +2,10 @@ ## Install -Start by installing Go, Git, GCC and glibc (the program is written in Go, but a tiny bit of C code is used to drop privileges when running as root). On Debian, run: +Start by installing Go and Git. On Debian, run: ``` -apt install golang git gcc libc6-dev +apt install golang git ``` Then fetch and build the program: @@ -66,7 +66,7 @@ systemctl start client-hello-mirror.service ## Drop root -A standard web-facing setup involves using a CA-signed certificate and binding to privileged port 443. For security reasons, the program will drop root privileges imediately after loading the certificate and binding to the specified port. Use the `-u` option to select a user to switch to; the default is `www-data`. +A standard web-facing setup involves using a CA-signed certificate and binding to privileged port 443. For security reasons, the program will drop root privileges imediately after loading the certificate and binding to the specified port. Use the `-u` option to select a user to switch to. If you really want to run as root, set `-u root` (not recommended). ## Redirect http:// to https:// diff --git a/server.go b/server.go index 0714515..f945636 100644 --- a/server.go +++ b/server.go @@ -14,6 +14,7 @@ import ( "log" "net" "net/url" + "os" "os/user" "strconv" "strings" @@ -21,12 +22,6 @@ import ( "time" ) -import ( - //#include - //#include - "C" -) - type tlsConnectionInfo struct { TlsVersion uint16 `json:"tls_version"` CipherSuite uint16 `json:"cipher_suite"` @@ -280,11 +275,11 @@ func main() { // Parse arguments flag.StringVar(&certFile, "c", "", "path to certificate file") flag.StringVar(&keyFile, "k", "", "path to private key file") - flag.StringVar(&userToSwitchTo, "u", "www-data", "user to switch to, if running as root") + flag.StringVar(&userToSwitchTo, "u", "", "user to switch to, if running as root") flag.Parse() hostAndPort = flag.Arg(0) if certFile == "" || keyFile == "" || hostAndPort == "" { - fmt.Println("usage: client-hello-mirror -c cert.pem -k key.pem host:port") + fmt.Println("usage: client-hello-mirror -c cert.pem -k key.pem [-u user] host:port") return } @@ -310,36 +305,48 @@ func main() { defer ln.Close() // Drop root - if syscall.Getuid() == 0 { + if syscall.Getuid() == 0 { // running as root if userToSwitchTo == "" { - fmt.Println("Running as root. Please specify an unprivileged user to switch to, using the -u flag") - return + 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) - if userToSwitchTo == "www-data" { - fmt.Println("Running as root. Please specify an unprivileged user to switch to, using the -u flag") - } - return + os.Exit(1) } - uid, err := strconv.ParseInt(userInfo.Uid, 10, 32) + // Convert group id and user id from string to int. + gid, err := strconv.Atoi(userInfo.Gid) if err != nil { fmt.Println(err) - return + os.Exit(1) } - gid, err := strconv.ParseInt(userInfo.Gid, 10, 32) + uid, err := strconv.Atoi(userInfo.Uid) if err != nil { fmt.Println(err) - return + os.Exit(1) } - cerr, errno := C.setgid(C.__gid_t(gid)) - if cerr != 0 { - log.Fatalln("Unable to set GID due to error:", errno) + if uid == 0 { + fmt.Println("WARNING: running as root is not recommended!") } - cerr, errno = C.setuid(C.__uid_t(uid)) - if cerr != 0 { - log.Fatalln("Unable to set UID due to error:", errno) + // 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) } }