forked from taskcluster/taskcluster
-
Notifications
You must be signed in to change notification settings - Fork 0
/
multiuser_posix.go
202 lines (178 loc) · 6.37 KB
/
multiuser_posix.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
//go:build (multiuser && darwin) || (multiuser && linux)
package main
import (
"fmt"
"log"
"os"
"path/filepath"
"runtime"
"strconv"
"github.com/taskcluster/shell"
"github.com/taskcluster/taskcluster/v47/workers/generic-worker/host"
"github.com/taskcluster/taskcluster/v47/workers/generic-worker/process"
gwruntime "github.com/taskcluster/taskcluster/v47/workers/generic-worker/runtime"
)
func (task *TaskRun) formatCommand(index int) string {
return shell.Escape(task.Payload.Command[index]...)
}
func platformFeatures() []Feature {
return []Feature{
// keep chain of trust as low down as possible, as it checks permissions
// of signing key file, and a feature could change them, so we want these
// checks as late as possible
&ChainOfTrustFeature{},
}
}
func deleteDir(path string) error {
log.Print("Removing directory '" + path + "'...")
err := host.Run("/usr/bin/sudo", "/bin/chmod", "-R", "u+w", path)
if err != nil {
log.Print("WARNING: could not chmod -R u+w '" + path + "'")
log.Printf("%v", err)
}
err = host.Run("/usr/bin/sudo", "/bin/rm", "-rf", path)
if err != nil {
log.Print("WARNING: could not delete directory '" + path + "'")
log.Printf("%v", err)
return err
}
return nil
}
func (task *TaskRun) generateCommand(index int) error {
var err error
task.Commands[index], err = process.NewCommand(task.Payload.Command[index], taskContext.TaskDir, task.EnvVars(), taskContext.pd)
if err != nil {
return err
}
task.logMux.RLock()
defer task.logMux.RUnlock()
task.Commands[index].DirectOutput(task.logWriter)
return nil
}
func (task *TaskRun) prepareCommand(index int) *CommandExecutionError {
return nil
}
// Set an environment variable in each command. This can be called from a feature's
// NewTaskFeature method to set variables for the task.
func (task *TaskRun) setVariable(variable string, value string) error {
for i := range task.Commands {
task.Commands[i].SetEnv(variable, value)
}
return nil
}
func install(arguments map[string]interface{}) (err error) {
return nil
}
func RenameCrossDevice(oldpath, newpath string) (err error) {
// TODO: here we should be able to rename when oldpath and newpath are on
// different partitions - for now this will cover 99% of cases.
return os.Rename(oldpath, newpath)
}
func defaultTasksDir() string {
// assume all user home directories are all in same folder, i.e. the parent
// folder of the current user's home folder
return filepath.Dir(os.Getenv("HOME"))
}
func rebootBetweenTasks() bool {
return true
}
func platformTargets(arguments map[string]interface{}) ExitCode {
log.Print("Internal error - no target found to run, yet command line parsing successful")
return INTERNAL_ERROR
}
// we put this in init() instead of startup() as we want tests to be able to change
// it - note we shouldn't have these nasty global vars, I can only apologise, and
// say taskcluster-worker will be much nicer
func init() {
pwd, err := os.Getwd()
if err != nil {
panic(err)
}
taskContext = &TaskContext{
TaskDir: pwd,
}
}
func (task *TaskRun) EnvVars() []string {
taskEnv := map[string]string{}
taskEnvArray := []string{}
// Defaults that can be overwritten by task payload env
taskEnv["HOME"] = filepath.Join(gwruntime.UserHomeDirectoriesParent(), taskContext.User.Name)
taskEnv["PATH"] = "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
taskEnv["USER"] = taskContext.User.Name
for k, v := range task.Payload.Env {
taskEnv[k] = v
}
// Values that should be overwritten if also set in task definition
taskEnv["TASK_ID"] = task.TaskID
taskEnv["RUN_ID"] = strconv.Itoa(int(task.RunID))
taskEnv["TASKCLUSTER_ROOT_URL"] = config.RootURL
if config.RunTasksAsCurrentUser {
taskEnv["TASK_USER_CREDENTIALS"] = filepath.Join(cwd, "current-task-user.json")
}
if runtime.GOOS == "linux" {
taskEnv["DISPLAY"] = ":0"
}
if config.WorkerLocation != "" {
taskEnv["TASKCLUSTER_WORKER_LOCATION"] = config.WorkerLocation
}
for i, j := range taskEnv {
taskEnvArray = append(taskEnvArray, i+"="+j)
}
log.Printf("Environment: %#v", taskEnvArray)
return taskEnvArray
}
func PreRebootSetup(nextTaskUser *gwruntime.OSUser) {
}
func MkdirAllTaskUser(dir string, perms os.FileMode) (err error) {
cmd, err := process.NewCommand([]string{"mkdir", "-p", dir}, taskContext.TaskDir, []string{}, taskContext.pd)
if err != nil {
return fmt.Errorf("Cannot create process to create directory %v with permissions %v as task user %v from directory %v: %v", dir, perms, taskContext.User.Name, taskContext.TaskDir, err)
}
result := cmd.Execute()
if result.ExitError != nil {
return fmt.Errorf("Cannot create directory %v with permissions %v as task user %v from directory %v: %v", dir, perms, taskContext.User.Name, taskContext.TaskDir, result)
}
return nil
}
func makeFileOrDirReadWritableForUser(recurse bool, fileOrDir string, user *gwruntime.OSUser) error {
// We'll use chown binary rather that os.Chown here since:
// 1) we have user/group names not ids, and can avoid extra code to look up
// their values
// 2) Perhaps we would need a CGO_ENABLED build to call user.Lookup and
// user.LookupGroup (see https://bugzil.la/1566159)
// 3) os.Chown doesn't have a recursive option; maybe a third party library
// does, but that's more bloat to import/maintain, or we'd need to write
// our own
// 4) we get logging of commands run for free
if recurse {
switch runtime.GOOS {
case "darwin":
return host.Run("/usr/sbin/chown", "-R", user.Name+":staff", fileOrDir)
case "linux":
return host.Run("/bin/chown", "-R", user.Name+":"+user.Name, fileOrDir)
}
return fmt.Errorf("Unknown platform: %v", runtime.GOOS)
}
switch runtime.GOOS {
case "darwin":
return host.Run("/usr/sbin/chown", user.Name+":staff", fileOrDir)
case "linux":
return host.Run("/bin/chown", user.Name+":"+user.Name, fileOrDir)
}
return fmt.Errorf("Unknown platform: %v", runtime.GOOS)
}
func makeDirUnreadableForUser(dir string, user *gwruntime.OSUser) error {
// Note, only need to set top directory, not recursively, since without
// access to top directory, nothing inside can be read anyway
var err error
switch runtime.GOOS {
case "darwin":
err = host.Run("/usr/sbin/chown", "0:0", dir)
case "linux":
err = host.Run("/bin/chown", "0:0", dir)
}
if err != nil {
return fmt.Errorf("[mounts] Not able to make directory %v owned by root/root in order to prevent %v from having access: %v", dir, user.Name, err)
}
return os.Chmod(dir, 0700)
}