mirror of
https://github.com/tianon/gosu.git
synced 2025-04-18 19:04:06 +03:00
88 lines
2.7 KiB
Go
88 lines
2.7 KiB
Go
package main // import "github.com/tianon/gosu"
|
|
|
|
import (
|
|
"os"
|
|
"os/exec"
|
|
"runtime"
|
|
"syscall"
|
|
)
|
|
|
|
func init() {
|
|
// make sure we only have one process and that it runs on the main thread (so that ideally, when we Exec, we keep our user switches and stuff)
|
|
runtime.GOMAXPROCS(1)
|
|
runtime.LockOSThread()
|
|
}
|
|
|
|
func version() string {
|
|
// 1.17 (go1.18.2 on linux/amd64; gc)
|
|
return Version + ` (` + runtime.Version() + ` on ` + runtime.GOOS + `/` + runtime.GOARCH + `; ` + runtime.Compiler + `)`
|
|
}
|
|
|
|
func usage() string {
|
|
self := os.Args[0]
|
|
v := version()
|
|
t := `
|
|
Usage: ` + self + ` user-spec command [args]
|
|
eg: ` + self + ` tianon bash
|
|
` + self + ` nobody:root bash -c 'whoami && id'
|
|
` + self + ` 1000:1 id
|
|
|
|
` + self + ` version: ` + v + `
|
|
` + self + ` license: Apache-2.0 (full text at https://github.com/tianon/gosu)
|
|
`
|
|
return t[1:]
|
|
}
|
|
|
|
func exit(code int, w *os.File, ss ...string) {
|
|
for i, s := range ss {
|
|
if i > 0 {
|
|
w.Write([]byte{' '})
|
|
}
|
|
w.Write([]byte(s))
|
|
}
|
|
w.Write([]byte{'\n'})
|
|
os.Exit(code)
|
|
}
|
|
|
|
func main() {
|
|
if ok := os.Getenv("GOSU_PLEASE_LET_ME_BE_COMPLETELY_INSECURE_I_GET_TO_KEEP_ALL_THE_PIECES"); ok != "I've seen things you people wouldn't believe. Attack ships on fire off the shoulder of Orion. I watched C-beams glitter in the dark near the Tannhäuser Gate. All those moments will be lost in time, like tears in rain. Time to die." {
|
|
if fi, err := os.Stat("/proc/self/exe"); err != nil {
|
|
exit(1, os.Stderr, "error:", err.Error())
|
|
} else if mode := fi.Mode(); mode&os.ModeSetuid != 0 {
|
|
// ... oh no
|
|
exit(1, os.Stderr, "error:", os.Args[0], "appears to be installed with the 'setuid' bit set, which is an *extremely* insecure and completely unsupported configuration! (what you want instead is likely 'sudo' or 'su')")
|
|
} else if mode&os.ModeSetgid != 0 {
|
|
// ... oh no
|
|
exit(1, os.Stderr, "error:", os.Args[0], "appears to be installed with the 'setgid' bit set, which is not quite *as* insecure as 'setuid', but still not great, and definitely a completely unsupported configuration! (what you want instead is likely 'sudo' or 'su')")
|
|
}
|
|
}
|
|
|
|
if len(os.Args) >= 2 {
|
|
switch os.Args[1] {
|
|
case "--help", "-h", "-?":
|
|
exit(0, os.Stdout, usage())
|
|
case "--version", "-v":
|
|
exit(0, os.Stdout, version())
|
|
}
|
|
}
|
|
if len(os.Args) <= 2 {
|
|
exit(1, os.Stderr, usage())
|
|
}
|
|
|
|
// clear HOME so that SetupUser will set it
|
|
os.Unsetenv("HOME")
|
|
|
|
if err := SetupUser(os.Args[1]); err != nil {
|
|
exit(1, os.Stderr, "error: failed switching to '"+os.Args[1]+"':", err.Error())
|
|
}
|
|
|
|
name, err := exec.LookPath(os.Args[2])
|
|
if err != nil {
|
|
exit(1, os.Stderr, "error:", err.Error())
|
|
}
|
|
|
|
if err = syscall.Exec(name, os.Args[2:], os.Environ()); err != nil {
|
|
exit(1, os.Stderr, "error: exec failed:", err.Error())
|
|
}
|
|
}
|