/
sys.go
144 lines (118 loc) · 2.95 KB
/
sys.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package utils
import (
"bytes"
"fmt"
"os"
"os/exec"
"os/user"
"strconv"
"strings"
"syscall"
"github.com/pkg/errors"
)
// GourdID holds the system's IDs for the gourd group and user
type GourdID struct {
// GID is the system gourd group id
GID int
// UID is the system gourd user id
UID int
}
// OsInfo represents data about the host machine's operating system
type OsInfo struct {
KernelName string `json:"kernel_name"`
NodeName string `json:"node_name"`
KernelRelease string `json:"kernel_release"`
Machine string `json:"machine"`
OperatingSystem string `json:"operating_system"`
}
var osInfo OsInfo
var gourdID GourdID = GourdID{
GID: -1,
UID: -1,
}
// GetGourdID returns the IDs for the gourd user and group
func GetGourdID() (GourdID, error) {
if gourdID.UID != -1 {
return gourdID, nil
}
grp, err := user.LookupGroup("gourd")
if err != nil {
return GourdID{-1, -1}, err
}
usr, err := user.Lookup("gourd")
if err != nil {
return GourdID{-1, -1}, err
}
gid, err := strconv.Atoi(grp.Gid)
if err != nil {
return GourdID{-1, -1}, err
}
uid, err := strconv.Atoi(usr.Uid)
if err != nil {
return GourdID{-1, -1}, err
}
IDs := GourdID{GID: gid, UID: uid}
gourdID = IDs
return IDs, nil
}
// Os returns OsInfo about the host machine.
func Os() (OsInfo, error) {
if osInfo.KernelName != "" {
return osInfo, nil
}
var host OsInfo
var out bytes.Buffer
cmd := exec.Command("uname", "-snrmo")
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
return host, err
}
sysinfo := strings.Split(out.String(), " ")
osInfo = OsInfo{
KernelName: sysinfo[0],
NodeName: sysinfo[1],
KernelRelease: sysinfo[2],
Machine: sysinfo[3],
OperatingSystem: sysinfo[4],
}
return osInfo, err
}
// Exec provides a thin wrapper over exec.Command
func Exec(name string, arg ...string) error {
cmd := exec.Command(name, arg...)
cmd.Stderr = os.Stdout
cmd.Stdout = os.Stderr
return cmd.Run()
}
// UserCanExec checks to see if a file can be executed by the current $USER
func UserCanExec(path string) (bool, error) {
info, err := os.Stat(path)
if err != nil {
return false, errors.Wrapf(err, "Failed to stat the following file: %s", path)
}
userInfo, err := user.Current()
if err != nil {
return false, errors.Wrapf(err, "Failed to find information about the current user")
}
mode := info.Mode()
ox := mode & 1
or := mode & 4
if ox == 1 && or == 4 {
return true, nil
}
ux := mode & 64
ur := mode & 256
gx := mode & 8
gr := mode & 32
fileUID := info.Sys().(*syscall.Stat_t).Uid
fileGID := info.Sys().(*syscall.Stat_t).Gid
userUID, _ := strconv.ParseUint(userInfo.Uid, 10, 32)
userGID, _ := strconv.ParseUint(userInfo.Gid, 10, 32)
if uint32(userUID) == fileUID && ux == 64 && ur == 256 {
return true, nil
} else if uint32(userGID) == fileGID && gx == 8 && gr == 32 {
return true, nil
}
return false, fmt.Errorf("the current user does not have permission to execute: %s", path)
}