forked from yext/edward
/
sudo.go
91 lines (78 loc) · 1.9 KB
/
sudo.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
package cmd
import (
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
"os/user"
"strings"
"syscall"
"github.com/pkg/errors"
"github.com/yext/edward/services"
)
func checkNotSudo() error {
user, err := user.Current()
if err != nil {
return errors.WithStack(err)
}
if user.Uid == "0" {
return errors.New("edward should not be fun with sudo")
}
return nil
}
func ensureSudoAble() error {
fmt.Println("One or more services use sudo. You may be prompted for your password.")
var buffer bytes.Buffer
buffer.WriteString("#!/bin/bash\n")
buffer.WriteString("sudo echo Test > /dev/null\n")
buffer.WriteString("ISCHILD=YES ")
buffer.WriteString(strings.Join(os.Args, " "))
buffer.WriteString("\n")
log.Printf("Writing sudoAbility script\n")
file, err := createScriptFile("sudoAbility", buffer.String())
if err != nil {
return errors.WithStack(err)
}
log.Printf("Launching sudoAbility script: %v\n", file.Name())
err = syscall.Exec(file.Name(), []string{file.Name()}, os.Environ())
if err != nil {
return errors.WithStack(err)
}
return nil
}
func prepareForSudo() error {
err := checkNotSudo()
if err != nil {
return errors.WithStack(err)
}
isChild := os.Getenv("ISCHILD")
if isChild == "" {
return errors.WithStack(ensureSudoAble())
}
log.Println("Child process, sudo should be available")
return nil
}
func sudoIfNeeded(sgs []services.ServiceOrGroup) error {
for _, sg := range sgs {
if sg.IsSudo(services.OperationConfig{}) {
log.Printf("sudo required for %v\n", sg.GetName())
return errors.WithStack(prepareForSudo())
}
}
log.Printf("sudo not required for any services/groups\n")
return nil
}
func createScriptFile(suffix string, content string) (*os.File, error) {
file, err := ioutil.TempFile(os.TempDir(), suffix)
if err != nil {
return nil, err
}
file.WriteString(content)
file.Close()
err = os.Chmod(file.Name(), 0777)
if err != nil {
return nil, err
}
return file, nil
}