diff options
-rw-r--r-- | libpod/container_internal.go | 7 | ||||
-rw-r--r-- | pkg/chrootuser/user.go | 19 | ||||
-rw-r--r-- | pkg/chrootuser/user_linux.go | 6 | ||||
-rw-r--r-- | test/e2e/run_test.go | 21 |
4 files changed, 46 insertions, 7 deletions
diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 62960fa0f..561b8853d 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -9,7 +9,6 @@ import ( "os" "path/filepath" "regexp" - "strconv" "strings" "syscall" "time" @@ -956,17 +955,17 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { return nil, errors.Wrapf(ErrCtrStateInvalid, "container %s must be mounted in order to add additional groups", c.ID()) } for _, group := range c.config.Groups { - _, gid, err := chrootuser.GetUser(c.state.Mountpoint, strconv.Itoa(int(g.Spec().Process.User.UID))+":"+group) + gid, err := chrootuser.GetGroup(c.state.Mountpoint, group) if err != nil { return nil, err } - g.AddProcessAdditionalGid(uint32(gid)) + g.AddProcessAdditionalGid(gid) } } // Look up and add groups the user belongs to groups, err := chrootuser.GetAdditionalGroupsForUser(c.state.Mountpoint, uint64(g.Spec().Process.User.UID)) - if err != nil { + if err != nil && err != chrootuser.ErrNoSuchUser { return nil, err } for _, gid := range groups { diff --git a/pkg/chrootuser/user.go b/pkg/chrootuser/user.go index 22ba5ff8a..54917b843 100644 --- a/pkg/chrootuser/user.go +++ b/pkg/chrootuser/user.go @@ -37,8 +37,8 @@ func GetUser(rootdir, userspec string) (uint32, uint32, error) { userspec = name } else { // Leave userspec alone, but swallow the error and just - // use GID 0. - gid64 = 0 + // use GID == UID. + gid64 = uid64 gerr = nil } } @@ -70,6 +70,21 @@ func GetUser(rootdir, userspec string) (uint32, uint32, error) { return 0, 0, err } +// GetGroup returns the gid by looking it up in the /etc/passwd file +// groupspec format [ group | gid ] +func GetGroup(rootdir, groupspec string) (uint32, error) { + gid64, gerr := strconv.ParseUint(groupspec, 10, 32) + if gerr != nil { + // The group couldn't be parsed as a number, so look up + // the group's GID. + gid64, gerr = lookupGroupInContainer(rootdir, groupspec) + } + if gerr != nil { + return 0, errors.Wrapf(gerr, "error looking up group for gid %q", groupspec) + } + return uint32(gid64), nil +} + // GetAdditionalGroupsForUser returns a list of gids that userid is associated with func GetAdditionalGroupsForUser(rootdir string, userid uint64) ([]uint32, error) { return lookupAdditionalGroupsForUIDInContainer(rootdir, userid) diff --git a/pkg/chrootuser/user_linux.go b/pkg/chrootuser/user_linux.go index 64ff7cef6..d48a1c7c2 100644 --- a/pkg/chrootuser/user_linux.go +++ b/pkg/chrootuser/user_linux.go @@ -4,6 +4,7 @@ package chrootuser import ( "bufio" + "errors" "flag" "fmt" "io" @@ -78,6 +79,9 @@ func openChrootedFile(rootdir, filename string) (*exec.Cmd, io.ReadCloser, error var ( lookupUser, lookupGroup sync.Mutex + // ErrNoSuchUser indicates that the user provided by the caller does not + // exist in /etc/passws + ErrNoSuchUser = errors.New("user does not exist in /etc/passwd") ) type lookupPasswdEntry struct { @@ -207,7 +211,7 @@ func lookupGroupForUIDInContainer(rootdir string, userid uint64) (username strin return pwd.name, pwd.gid, nil } - return "", 0, user.UnknownUserError(fmt.Sprintf("error looking up user with UID %d", userid)) + return "", 0, ErrNoSuchUser } func lookupAdditionalGroupsForUIDInContainer(rootdir string, userid uint64) (gid []uint32, err error) { diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index 501434852..cfeabe6a0 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -330,6 +330,27 @@ var _ = Describe("Podman run", func() { Expect(session.OutputToString()).To(Equal("uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),18(audio),20(dialout),26(tape),27(video),777,65533(nogroup)")) }) + It("podman run with user (default)", func() { + session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "id"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(Equal("uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)")) + }) + + It("podman run with user (integer)", func() { + session := podmanTest.Podman([]string{"run", "--rm", "--user=1234", ALPINE, "id"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(Equal("uid=1234 gid=1234")) + }) + + It("podman run with user (username)", func() { + session := podmanTest.Podman([]string{"run", "--rm", "--user=mail", ALPINE, "id"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(Equal("uid=8(mail) gid=12(mail) groups=12(mail)")) + }) + It("podman run with attach stdin outputs container ID", func() { session := podmanTest.Podman([]string{"run", "--attach", "stdin", ALPINE, "printenv"}) session.WaitWithDefaultTimeout() |