run: user LookupId

Signed-off-by: Yoan Blanc <yoan@dosimple.ch>
This commit is contained in:
Yoan Blanc 2020-03-05 16:44:55 +01:00
parent c553184416
commit c7028c6d2f
No known key found for this signature in database
GPG Key ID: 6058CF4574298812
3 changed files with 58 additions and 44 deletions

View File

@ -20,8 +20,16 @@ RUN touch $HOME/hello
# testuser1 with the default home created by useradd.
RUN groupadd testgroup && \
useradd --create-home --gid testgroup alice
useradd --create-home --gid testgroup alice && \
useradd --create-home --uid 1111 --home-dir /home/john --gid testgroup bob
USER alice:testgroup
RUN touch $HOME/hello
USER bob
RUN touch $HOME/hello
USER root
USER 1111
RUN touch $HOME/world

View File

@ -40,7 +40,8 @@ type RunCommand struct {
// for testing
var (
userLookup = user.Lookup
userLookup = user.Lookup
userLookupId = user.LookupId
)
func (r *RunCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
@ -68,18 +69,29 @@ func (r *RunCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.Bui
cmd.Stderr = os.Stderr
replacementEnvs := buildArgs.ReplacementEnvs(config.Env)
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
var userStr string
u := config.User
userAndGroup := strings.Split(u, ":")
userStr, err := util.ResolveEnvironmentReplacement(userAndGroup[0], replacementEnvs, false)
if err != nil {
return errors.Wrapf(err, "resolving user %s", userAndGroup[0])
}
// If specified, run the command as a specific user
if config.User != "" {
userStr = config.User
uid, gid, err := util.GetUIDAndGIDFromString(config.User, true)
if userStr != "" {
uid, gid, err := util.GetUIDAndGIDFromString(userStr, true)
if err != nil {
return err
}
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid}
}
cmd.Env = addDefaultHOME(userStr, replacementEnvs)
env, err := addDefaultHOME(userStr, replacementEnvs)
if err != nil {
return errors.Wrap(err, "adding default HOME variable")
}
cmd.Env = env
if err := cmd.Start(); err != nil {
return errors.Wrap(err, "starting command")
@ -102,32 +114,31 @@ func (r *RunCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.Bui
}
// addDefaultHOME adds the default value for HOME if it isn't already set
func addDefaultHOME(u string, envs []string) []string {
func addDefaultHOME(u string, envs []string) ([]string, error) {
for _, env := range envs {
split := strings.SplitN(env, "=", 2)
if split[0] == constants.HOME {
return envs
return envs, nil
}
}
// If user isn't set, set default value of HOME
if u == "" || u == constants.RootUser {
return append(envs, fmt.Sprintf("%s=%s", constants.HOME, constants.DefaultHOMEValue))
return append(envs, fmt.Sprintf("%s=%s", constants.HOME, constants.DefaultHOMEValue)), nil
}
// If user is set to username, set value of HOME to /home/${user}
// Otherwise the user is set to uid and HOME is /
home := "/"
userObj, err := userLookup(u)
if err == nil {
if userObj.HomeDir != "" {
home = userObj.HomeDir
if uo, e := userLookupId(u); e == nil {
userObj = uo
} else {
home = fmt.Sprintf("/home/%s", userObj.Username)
return nil, err
}
}
return append(envs, fmt.Sprintf("%s=%s", constants.HOME, home))
return append(envs, fmt.Sprintf("%s=%s", constants.HOME, userObj.HomeDir)), nil
}
// String returns some information about the command for the image config

View File

@ -18,6 +18,7 @@ package commands
import (
"archive/tar"
"bytes"
"errors"
"io"
"io/ioutil"
"log"
@ -33,11 +34,13 @@ import (
func Test_addDefaultHOME(t *testing.T) {
tests := []struct {
name string
user string
mockUser *user.User
initial []string
expected []string
name string
user string
mockUser *user.User
lookupError error
mockUserId *user.User
initial []string
expected []string
}{
{
name: "HOME already set",
@ -78,31 +81,19 @@ func Test_addDefaultHOME(t *testing.T) {
},
},
{
name: "HOME not set and user set",
user: "www-add",
mockUser: &user.User{
Username: "www-add",
name: "USER is set using the UID",
user: "newuser",
lookupError: errors.New("User not found"),
mockUserId: &user.User{
Username: "user",
HomeDir: "/home/user",
},
initial: []string{
"PATH=/something/else",
},
expected: []string{
"PATH=/something/else",
"HOME=/home/www-add",
},
},
{
name: "HOME not set and user is set",
user: "newuser",
mockUser: &user.User{
Username: "newuser",
},
initial: []string{
"PATH=/something/else",
},
expected: []string{
"PATH=/something/else",
"HOME=/home/newuser",
"HOME=/home/user",
},
},
{
@ -122,10 +113,14 @@ func Test_addDefaultHOME(t *testing.T) {
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
userLookup = func(username string) (*user.User, error) { return test.mockUser, nil }
defer func() { userLookup = user.Lookup }()
actual := addDefaultHOME(test.user, test.initial)
testutil.CheckErrorAndDeepEqual(t, false, nil, test.expected, actual)
userLookup = func(username string) (*user.User, error) { return test.mockUser, test.lookupError }
userLookupId = func(username string) (*user.User, error) { return test.mockUserId, nil }
defer func() {
userLookup = user.Lookup
userLookupId = user.LookupId
}()
actual, err := addDefaultHOME(test.user, test.initial)
testutil.CheckErrorAndDeepEqual(t, false, err, test.expected, actual)
})
}
}