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. # testuser1 with the default home created by useradd.
RUN groupadd testgroup && \ 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 USER alice:testgroup
RUN touch $HOME/hello 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 // for testing
var ( var (
userLookup = user.Lookup userLookup = user.Lookup
userLookupId = user.LookupId
) )
func (r *RunCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error { 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 cmd.Stderr = os.Stderr
replacementEnvs := buildArgs.ReplacementEnvs(config.Env) replacementEnvs := buildArgs.ReplacementEnvs(config.Env)
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} 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 specified, run the command as a specific user
if config.User != "" { if userStr != "" {
userStr = config.User uid, gid, err := util.GetUIDAndGIDFromString(userStr, true)
uid, gid, err := util.GetUIDAndGIDFromString(config.User, true)
if err != nil { if err != nil {
return err return err
} }
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uid, Gid: gid} 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 { if err := cmd.Start(); err != nil {
return errors.Wrap(err, "starting command") 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 // 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 { for _, env := range envs {
split := strings.SplitN(env, "=", 2) split := strings.SplitN(env, "=", 2)
if split[0] == constants.HOME { if split[0] == constants.HOME {
return envs return envs, nil
} }
} }
// If user isn't set, set default value of HOME // If user isn't set, set default value of HOME
if u == "" || u == constants.RootUser { 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} // If user is set to username, set value of HOME to /home/${user}
// Otherwise the user is set to uid and HOME is / // Otherwise the user is set to uid and HOME is /
home := "/"
userObj, err := userLookup(u) userObj, err := userLookup(u)
if err == nil { if err == nil {
if userObj.HomeDir != "" { if uo, e := userLookupId(u); e == nil {
home = userObj.HomeDir userObj = uo
} else { } 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 // String returns some information about the command for the image config

View File

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