-
Notifications
You must be signed in to change notification settings - Fork 15
/
main.go
108 lines (88 loc) · 2.34 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package main
import (
"log"
"os"
"os/exec"
"os/user"
"path/filepath"
"runtime"
"strings"
"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 main() {
log.SetFlags(0) // no timestamps on our logs
// Args that we pass to sudo
var args []string
var shell string
var ext string
// The command that was executed
cmd := os.Args[0]
ext = strings.TrimLeft(filepath.Ext(cmd), ".")
// If no extension, default to bash
if ext == "" {
ext = "bash"
}
// Resolve extension to a shell
shellFound, shellPathErr := exec.LookPath(ext)
if shellPathErr != nil {
log.Fatalf("error: find to find shell %v: %v", ext, shellPathErr)
}
shell = shellFound
// Shell is always launched as current user
username := ""
// user.Current() may not be implemented on some linux distros (e.g. alpine)
user, userErr := user.Current()
if userErr == nil {
username = user.Username
}
// Fallback to fetching the `LOGNAME` env
if username == "" {
username = os.Getenv("LOGNAME")
}
// Fallback to fetching the `USER` env
if username == "" {
username = os.Getenv("USER")
}
// Fallback to fetching `USERNAME` env
if username == "" {
username = os.Getenv("USERNAME")
}
// Fallback to calling `whoami` command
if username == "" {
whoami := exec.Command("whoami")
whoamiStdout, whoamiErr := whoami.Output()
if whoamiErr != nil {
log.Fatalf("error: unable to determine current user: %v", whoamiErr)
}
username = strings.TrimSpace(string(whoamiStdout))
}
// Give up
if username == "" {
log.Fatalf("error: unable to determine current user: %v", userErr)
}
// Set default shell (do not set to `sudosh`; it may cause infinite loops)
os.Setenv("SHELL", shell)
// Fetch environment
env := os.Environ()
// Lookup path for `sudo`
binary, sudoPathErr := exec.LookPath("sudo")
if sudoPathErr != nil {
log.Fatalf("error: find to find sudo: %v", sudoPathErr)
}
// Prepare `sudo` args
if len(os.Args) < 2 {
args = []string{"sudo", "-E", "-u", username, shell, "-l"}
} else {
args = append([]string{"sudo", "-E", "-u", username, shell}, os.Args[1:]...)
}
execErr := syscall.Exec(binary, args, env)
if execErr != nil {
log.Fatalf("error: exec failed: %v", execErr)
}
}