From 9c368a93b690735bccfdb7c371371f6ec324d81e Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Thu, 12 Dec 2024 20:46:11 -0800 Subject: [PATCH] Split internal idtools functionality Separare idtools functionality that is used internally from the functionlality used by importers. The `pkg/idtools` package is now much smaller and more generic. Signed-off-by: Derek McGowan Signed-off-by: Sebastiaan van Stijn --- .../usergroup/add_linux.go | 2 +- internal/usergroup/add_linux_test.go | 73 +++++++ .../usergroup/add_unsupported.go | 2 +- internal/usergroup/const_windows.go | 10 + internal/usergroup/lookup_unix.go | 188 ++++++++++++++++++ internal/usergroup/lookup_unix_test.go | 26 +++ internal/usergroup/parser.go | 22 ++ internal/usergroup/parser_test.go | 39 ++++ .../usergroup}/utils_unix.go | 2 +- pkg/idtools/idtools.go | 21 +- pkg/idtools/idtools_unix.go | 132 ++---------- pkg/idtools/idtools_unix_test.go | 112 +---------- pkg/idtools/idtools_windows.go | 8 +- 13 files changed, 383 insertions(+), 254 deletions(-) rename pkg/idtools/usergroupadd_linux.go => internal/usergroup/add_linux.go (98%) create mode 100644 internal/usergroup/add_linux_test.go rename pkg/idtools/usergroupadd_unsupported.go => internal/usergroup/add_unsupported.go (85%) create mode 100644 internal/usergroup/const_windows.go create mode 100644 internal/usergroup/lookup_unix.go create mode 100644 internal/usergroup/lookup_unix_test.go create mode 100644 internal/usergroup/parser.go create mode 100644 internal/usergroup/parser_test.go rename {pkg/idtools => internal/usergroup}/utils_unix.go (89%) diff --git a/pkg/idtools/usergroupadd_linux.go b/internal/usergroup/add_linux.go similarity index 98% rename from pkg/idtools/usergroupadd_linux.go rename to internal/usergroup/add_linux.go index 8a9cb65cf7..631ffc1076 100644 --- a/pkg/idtools/usergroupadd_linux.go +++ b/internal/usergroup/add_linux.go @@ -1,4 +1,4 @@ -package idtools // import "github.com/docker/docker/pkg/idtools" +package usergroup import ( "fmt" diff --git a/internal/usergroup/add_linux_test.go b/internal/usergroup/add_linux_test.go new file mode 100644 index 0000000000..9308965d15 --- /dev/null +++ b/internal/usergroup/add_linux_test.go @@ -0,0 +1,73 @@ +package usergroup + +import ( + "os" + "os/exec" + "os/user" + "syscall" + "testing" + + "github.com/docker/docker/pkg/idtools" + "gotest.tools/v3/assert" + is "gotest.tools/v3/assert/cmp" + "gotest.tools/v3/skip" +) + +const ( + tempUser = "tempuser" +) + +func TestNewIDMappings(t *testing.T) { + skip.If(t, os.Getuid() != 0, "skipping test that requires root") + _, _, err := AddNamespaceRangesUser(tempUser) + assert.Check(t, err) + defer delUser(t, tempUser) + + tempUser, err := user.Lookup(tempUser) + assert.Check(t, err) + + idMapping, err := LoadIdentityMapping(tempUser.Username) + assert.Check(t, err) + + rootUID, rootGID, err := idtools.GetRootUIDGID(idMapping.UIDMaps, idMapping.GIDMaps) + assert.Check(t, err) + + dirName, err := os.MkdirTemp("", "mkdirall") + assert.Check(t, err, "Couldn't create temp directory") + defer os.RemoveAll(dirName) + + err = idtools.MkdirAllAndChown(dirName, 0o700, idtools.Identity{UID: rootUID, GID: rootGID}) + assert.Check(t, err, "Couldn't change ownership of file path. Got error") + cmd := exec.Command("ls", "-la", dirName) + cmd.SysProcAttr = &syscall.SysProcAttr{ + Credential: &syscall.Credential{Uid: uint32(rootUID), Gid: uint32(rootGID)}, + } + out, err := cmd.CombinedOutput() + assert.Check(t, err, "Unable to access %s directory with user UID:%d and GID:%d:\n%s", dirName, rootUID, rootGID, string(out)) +} + +func TestLookupUserAndGroup(t *testing.T) { + skip.If(t, os.Getuid() != 0, "skipping test that requires root") + uid, gid, err := AddNamespaceRangesUser(tempUser) + assert.Check(t, err) + defer delUser(t, tempUser) + + fetchedUser, err := LookupUser(tempUser) + assert.Check(t, err) + + fetchedUserByID, err := LookupUID(uid) + assert.Check(t, err) + assert.Check(t, is.DeepEqual(fetchedUserByID, fetchedUser)) + + fetchedGroup, err := LookupGroup(tempUser) + assert.Check(t, err) + + fetchedGroupByID, err := LookupGID(gid) + assert.Check(t, err) + assert.Check(t, is.DeepEqual(fetchedGroupByID, fetchedGroup)) +} + +func delUser(t *testing.T, name string) { + out, err := exec.Command("userdel", name).CombinedOutput() + assert.Check(t, err, out) +} diff --git a/pkg/idtools/usergroupadd_unsupported.go b/internal/usergroup/add_unsupported.go similarity index 85% rename from pkg/idtools/usergroupadd_unsupported.go rename to internal/usergroup/add_unsupported.go index 6a9311c4a7..118bdf0f96 100644 --- a/pkg/idtools/usergroupadd_unsupported.go +++ b/internal/usergroup/add_unsupported.go @@ -1,6 +1,6 @@ //go:build !linux -package idtools // import "github.com/docker/docker/pkg/idtools" +package usergroup import "fmt" diff --git a/internal/usergroup/const_windows.go b/internal/usergroup/const_windows.go new file mode 100644 index 0000000000..fc93b47f6f --- /dev/null +++ b/internal/usergroup/const_windows.go @@ -0,0 +1,10 @@ +package usergroup + +const ( + SeTakeOwnershipPrivilege = "SeTakeOwnershipPrivilege" +) + +const ( + ContainerAdministratorSidString = "S-1-5-93-2-1" + ContainerUserSidString = "S-1-5-93-2-2" +) diff --git a/internal/usergroup/lookup_unix.go b/internal/usergroup/lookup_unix.go new file mode 100644 index 0000000000..79e9535c04 --- /dev/null +++ b/internal/usergroup/lookup_unix.go @@ -0,0 +1,188 @@ +//go:build !windows + +package usergroup + +import ( + "bytes" + "fmt" + "io" + "os/exec" + "strconv" + "syscall" + + "github.com/docker/docker/pkg/idtools" + "github.com/moby/sys/user" +) + +// LookupUser uses traditional local system files lookup (from libcontainer/user) on a username, +// followed by a call to `getent` for supporting host configured non-files passwd and group dbs +func LookupUser(name string) (user.User, error) { + // first try a local system files lookup using existing capabilities + usr, err := user.LookupUser(name) + if err == nil { + return usr, nil + } + // local files lookup failed; attempt to call `getent` to query configured passwd dbs + usr, err = getentUser(name) + if err != nil { + return user.User{}, err + } + return usr, nil +} + +// LookupUID uses traditional local system files lookup (from libcontainer/user) on a uid, +// followed by a call to `getent` for supporting host configured non-files passwd and group dbs +func LookupUID(uid int) (user.User, error) { + // first try a local system files lookup using existing capabilities + usr, err := user.LookupUid(uid) + if err == nil { + return usr, nil + } + // local files lookup failed; attempt to call `getent` to query configured passwd dbs + return getentUser(strconv.Itoa(uid)) +} + +func getentUser(name string) (user.User, error) { + reader, err := callGetent("passwd", name) + if err != nil { + return user.User{}, err + } + users, err := user.ParsePasswd(reader) + if err != nil { + return user.User{}, err + } + if len(users) == 0 { + return user.User{}, fmt.Errorf("getent failed to find passwd entry for %q", name) + } + return users[0], nil +} + +// LookupGroup uses traditional local system files lookup (from libcontainer/user) on a group name, +// followed by a call to `getent` for supporting host configured non-files passwd and group dbs +func LookupGroup(name string) (user.Group, error) { + // first try a local system files lookup using existing capabilities + group, err := user.LookupGroup(name) + if err == nil { + return group, nil + } + // local files lookup failed; attempt to call `getent` to query configured group dbs + return getentGroup(name) +} + +// LookupGID uses traditional local system files lookup (from libcontainer/user) on a group ID, +// followed by a call to `getent` for supporting host configured non-files passwd and group dbs +func LookupGID(gid int) (user.Group, error) { + // first try a local system files lookup using existing capabilities + group, err := user.LookupGid(gid) + if err == nil { + return group, nil + } + // local files lookup failed; attempt to call `getent` to query configured group dbs + return getentGroup(strconv.Itoa(gid)) +} + +func getentGroup(name string) (user.Group, error) { + reader, err := callGetent("group", name) + if err != nil { + return user.Group{}, err + } + groups, err := user.ParseGroup(reader) + if err != nil { + return user.Group{}, err + } + if len(groups) == 0 { + return user.Group{}, fmt.Errorf("getent failed to find groups entry for %q", name) + } + return groups[0], nil +} + +func callGetent(database, key string) (io.Reader, error) { + getentCmd, err := resolveBinary("getent") + // if no `getent` command within the execution environment, can't do anything else + if err != nil { + return nil, fmt.Errorf("unable to find getent command: %w", err) + } + command := exec.Command(getentCmd, database, key) + // we run getent within container filesystem, but without /dev so /dev/null is not available for exec to mock stdin + command.Stdin = io.NopCloser(bytes.NewReader(nil)) + out, err := command.CombinedOutput() + if err != nil { + exitCode, errC := getExitCode(err) + if errC != nil { + return nil, err + } + switch exitCode { + case 1: + return nil, fmt.Errorf("getent reported invalid parameters/database unknown") + case 2: + return nil, fmt.Errorf("getent unable to find entry %q in %s database", key, database) + case 3: + return nil, fmt.Errorf("getent database doesn't support enumeration") + default: + return nil, err + } + } + return bytes.NewReader(out), nil +} + +// getExitCode returns the ExitStatus of the specified error if its type is +// exec.ExitError, returns 0 and an error otherwise. +func getExitCode(err error) (int, error) { + exitCode := 0 + if exiterr, ok := err.(*exec.ExitError); ok { + if procExit, ok := exiterr.Sys().(syscall.WaitStatus); ok { + return procExit.ExitStatus(), nil + } + } + return exitCode, fmt.Errorf("failed to get exit code") +} + +// LoadIdentityMapping takes a requested username and +// using the data from /etc/sub{uid,gid} ranges, creates the +// proper uid and gid remapping ranges for that user/group pair +func LoadIdentityMapping(name string) (idtools.IdentityMapping, error) { + usr, err := LookupUser(name) + if err != nil { + return idtools.IdentityMapping{}, fmt.Errorf("could not get user for username %s: %v", name, err) + } + + subuidRanges, err := lookupSubRangesFile("/etc/subuid", usr) + if err != nil { + return idtools.IdentityMapping{}, err + } + subgidRanges, err := lookupSubRangesFile("/etc/subgid", usr) + if err != nil { + return idtools.IdentityMapping{}, err + } + + return idtools.IdentityMapping{ + UIDMaps: subuidRanges, + GIDMaps: subgidRanges, + }, nil +} + +func lookupSubRangesFile(path string, usr user.User) ([]idtools.IDMap, error) { + uidstr := strconv.Itoa(usr.Uid) + rangeList, err := user.ParseSubIDFileFilter(path, func(sid user.SubID) bool { + return sid.Name == usr.Name || sid.Name == uidstr + }) + if err != nil { + return nil, err + } + if len(rangeList) == 0 { + return nil, fmt.Errorf("no subuid ranges found for user %q", usr.Name) + } + + idMap := []idtools.IDMap{} + + containerID := 0 + for _, idrange := range rangeList { + idMap = append(idMap, idtools.IDMap{ + ContainerID: containerID, + HostID: int(idrange.SubID), + Size: int(idrange.Count), + }) + containerID = containerID + int(idrange.Count) + } + return idMap, nil +} diff --git a/internal/usergroup/lookup_unix_test.go b/internal/usergroup/lookup_unix_test.go new file mode 100644 index 0000000000..362228a93e --- /dev/null +++ b/internal/usergroup/lookup_unix_test.go @@ -0,0 +1,26 @@ +//go:build !windows + +package usergroup + +import ( + "testing" + + "gotest.tools/v3/assert" + is "gotest.tools/v3/assert/cmp" +) + +func TestLookupUserAndGroupThatDoesNotExist(t *testing.T) { + fakeUser := "fakeuser" + _, err := LookupUser(fakeUser) + assert.Check(t, is.Error(err, `getent unable to find entry "fakeuser" in passwd database`)) + + _, err = LookupUID(-1) + assert.Check(t, is.ErrorContains(err, "")) + + fakeGroup := "fakegroup" + _, err = LookupGroup(fakeGroup) + assert.Check(t, is.Error(err, `getent unable to find entry "fakegroup" in group database`)) + + _, err = LookupGID(-1) + assert.Check(t, is.ErrorContains(err, "")) +} diff --git a/internal/usergroup/parser.go b/internal/usergroup/parser.go new file mode 100644 index 0000000000..ab799869b3 --- /dev/null +++ b/internal/usergroup/parser.go @@ -0,0 +1,22 @@ +package usergroup + +import ( + "github.com/moby/sys/user" +) + +const ( + subuidFileName = "/etc/subuid" + subgidFileName = "/etc/subgid" +) + +func parseSubuid(username string) ([]user.SubID, error) { + return user.ParseSubIDFileFilter(subuidFileName, func(sid user.SubID) bool { + return sid.Name == username + }) +} + +func parseSubgid(username string) ([]user.SubID, error) { + return user.ParseSubIDFileFilter(subgidFileName, func(sid user.SubID) bool { + return sid.Name == username + }) +} diff --git a/internal/usergroup/parser_test.go b/internal/usergroup/parser_test.go new file mode 100644 index 0000000000..42c91737ef --- /dev/null +++ b/internal/usergroup/parser_test.go @@ -0,0 +1,39 @@ +package usergroup + +import ( + "os" + "path/filepath" + "testing" + + "github.com/moby/sys/user" +) + +func TestParseSubidFileWithNewlinesAndComments(t *testing.T) { + tmpDir, err := os.MkdirTemp("", "parsesubid") + if err != nil { + t.Fatal(err) + } + fnamePath := filepath.Join(tmpDir, "testsubuid") + fcontent := `tss:100000:65536 +# empty default subuid/subgid file + +dockremap:231072:65536` + if err := os.WriteFile(fnamePath, []byte(fcontent), 0o644); err != nil { + t.Fatal(err) + } + ranges, err := user.ParseSubIDFileFilter(fnamePath, func(sid user.SubID) bool { + return sid.Name == "dockremap" + }) + if err != nil { + t.Fatal(err) + } + if len(ranges) != 1 { + t.Fatalf("wanted 1 element in ranges, got %d instead", len(ranges)) + } + if ranges[0].SubID != 231072 { + t.Fatalf("wanted 231072, got %d instead", ranges[0].SubID) + } + if ranges[0].Count != 65536 { + t.Fatalf("wanted 65536, got %d instead", ranges[0].Count) + } +} diff --git a/pkg/idtools/utils_unix.go b/internal/usergroup/utils_unix.go similarity index 89% rename from pkg/idtools/utils_unix.go rename to internal/usergroup/utils_unix.go index 517a2f52ca..eb90b45b88 100644 --- a/pkg/idtools/utils_unix.go +++ b/internal/usergroup/utils_unix.go @@ -1,6 +1,6 @@ //go:build !windows -package idtools // import "github.com/docker/docker/pkg/idtools" +package usergroup import ( "fmt" diff --git a/pkg/idtools/idtools.go b/pkg/idtools/idtools.go index 0bd364605b..d2fbd943a6 100644 --- a/pkg/idtools/idtools.go +++ b/pkg/idtools/idtools.go @@ -1,10 +1,8 @@ -package idtools // import "github.com/docker/docker/pkg/idtools" +package idtools import ( "fmt" "os" - - "github.com/moby/sys/user" ) // IDMap contains a single entry for user namespace range remapping. An array @@ -16,11 +14,6 @@ type IDMap struct { Size int `json:"size"` } -const ( - subuidFileName = "/etc/subuid" - subgidFileName = "/etc/subgid" -) - // MkdirAllAndChown creates a directory (include any along the path) and then modifies // ownership to the requested uid/gid. If the directory already exists, this // function will still change ownership and permissions. @@ -150,18 +143,6 @@ func (i IdentityMapping) Empty() bool { return len(i.UIDMaps) == 0 && len(i.GIDMaps) == 0 } -func parseSubuid(username string) ([]user.SubID, error) { - return user.ParseSubIDFileFilter(subuidFileName, func(sid user.SubID) bool { - return sid.Name == username - }) -} - -func parseSubgid(username string) ([]user.SubID, error) { - return user.ParseSubIDFileFilter(subgidFileName, func(sid user.SubID) bool { - return sid.Name == username - }) -} - // CurrentIdentity returns the identity of the current process func CurrentIdentity() Identity { return Identity{UID: os.Getuid(), GID: os.Getegid()} diff --git a/pkg/idtools/idtools_unix.go b/pkg/idtools/idtools_unix.go index e045338387..1f11fe4740 100644 --- a/pkg/idtools/idtools_unix.go +++ b/pkg/idtools/idtools_unix.go @@ -1,13 +1,10 @@ //go:build !windows -package idtools // import "github.com/docker/docker/pkg/idtools" +package idtools import ( - "bytes" "fmt" - "io" "os" - "os/exec" "path/filepath" "strconv" "syscall" @@ -72,127 +69,25 @@ func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting return nil } -// LookupUser uses traditional local system files lookup (from libcontainer/user) on a username, -// followed by a call to `getent` for supporting host configured non-files passwd and group dbs +// LookupUser uses traditional local system files lookup (from libcontainer/user) on a username +// +// Deprecated: use [user.LookupUser] instead func LookupUser(name string) (user.User, error) { - // first try a local system files lookup using existing capabilities - usr, err := user.LookupUser(name) - if err == nil { - return usr, nil - } - // local files lookup failed; attempt to call `getent` to query configured passwd dbs - usr, err = getentUser(name) - if err != nil { - return user.User{}, err - } - return usr, nil + return user.LookupUser(name) } -// LookupUID uses traditional local system files lookup (from libcontainer/user) on a uid, -// followed by a call to `getent` for supporting host configured non-files passwd and group dbs +// LookupUID uses traditional local system files lookup (from libcontainer/user) on a uid +// +// Deprecated: use [user.LookupUid] instead func LookupUID(uid int) (user.User, error) { - // first try a local system files lookup using existing capabilities - usr, err := user.LookupUid(uid) - if err == nil { - return usr, nil - } - // local files lookup failed; attempt to call `getent` to query configured passwd dbs - return getentUser(strconv.Itoa(uid)) -} - -func getentUser(name string) (user.User, error) { - reader, err := callGetent("passwd", name) - if err != nil { - return user.User{}, err - } - users, err := user.ParsePasswd(reader) - if err != nil { - return user.User{}, err - } - if len(users) == 0 { - return user.User{}, fmt.Errorf("getent failed to find passwd entry for %q", name) - } - return users[0], nil + return user.LookupUid(uid) } // LookupGroup uses traditional local system files lookup (from libcontainer/user) on a group name, -// followed by a call to `getent` for supporting host configured non-files passwd and group dbs +// +// Deprecated: use [user.LookupGroup] instead func LookupGroup(name string) (user.Group, error) { - // first try a local system files lookup using existing capabilities - group, err := user.LookupGroup(name) - if err == nil { - return group, nil - } - // local files lookup failed; attempt to call `getent` to query configured group dbs - return getentGroup(name) -} - -// LookupGID uses traditional local system files lookup (from libcontainer/user) on a group ID, -// followed by a call to `getent` for supporting host configured non-files passwd and group dbs -func LookupGID(gid int) (user.Group, error) { - // first try a local system files lookup using existing capabilities - group, err := user.LookupGid(gid) - if err == nil { - return group, nil - } - // local files lookup failed; attempt to call `getent` to query configured group dbs - return getentGroup(strconv.Itoa(gid)) -} - -func getentGroup(name string) (user.Group, error) { - reader, err := callGetent("group", name) - if err != nil { - return user.Group{}, err - } - groups, err := user.ParseGroup(reader) - if err != nil { - return user.Group{}, err - } - if len(groups) == 0 { - return user.Group{}, fmt.Errorf("getent failed to find groups entry for %q", name) - } - return groups[0], nil -} - -func callGetent(database, key string) (io.Reader, error) { - getentCmd, err := resolveBinary("getent") - // if no `getent` command within the execution environment, can't do anything else - if err != nil { - return nil, fmt.Errorf("unable to find getent command: %w", err) - } - command := exec.Command(getentCmd, database, key) - // we run getent within container filesystem, but without /dev so /dev/null is not available for exec to mock stdin - command.Stdin = io.NopCloser(bytes.NewReader(nil)) - out, err := command.CombinedOutput() - if err != nil { - exitCode, errC := getExitCode(err) - if errC != nil { - return nil, err - } - switch exitCode { - case 1: - return nil, fmt.Errorf("getent reported invalid parameters/database unknown") - case 2: - return nil, fmt.Errorf("getent unable to find entry %q in %s database", key, database) - case 3: - return nil, fmt.Errorf("getent database doesn't support enumeration") - default: - return nil, err - } - } - return bytes.NewReader(out), nil -} - -// getExitCode returns the ExitStatus of the specified error if its type is -// exec.ExitError, returns 0 and an error otherwise. -func getExitCode(err error) (int, error) { - exitCode := 0 - if exiterr, ok := err.(*exec.ExitError); ok { - if procExit, ok := exiterr.Sys().(syscall.WaitStatus); ok { - return procExit.ExitStatus(), nil - } - } - return exitCode, fmt.Errorf("failed to get exit code") + return user.LookupGroup(name) } // setPermissions performs a chown/chmod only if the uid/gid don't match what's requested @@ -223,7 +118,8 @@ func setPermissions(p string, mode os.FileMode, owner Identity, stat os.FileInfo // using the data from /etc/sub{uid,gid} ranges, creates the // proper uid and gid remapping ranges for that user/group pair func LoadIdentityMapping(name string) (IdentityMapping, error) { - usr, err := LookupUser(name) + // TODO: Consider adding support for calling out to "getent" + usr, err := user.LookupUser(name) if err != nil { return IdentityMapping{}, fmt.Errorf("could not get user for username %s: %v", name, err) } diff --git a/pkg/idtools/idtools_unix_test.go b/pkg/idtools/idtools_unix_test.go index 7ec219f67b..381a1d7a62 100644 --- a/pkg/idtools/idtools_unix_test.go +++ b/pkg/idtools/idtools_unix_test.go @@ -1,26 +1,17 @@ //go:build !windows -package idtools // import "github.com/docker/docker/pkg/idtools" +package idtools import ( "fmt" "os" - "os/exec" - stduser "os/user" "path/filepath" - "syscall" "testing" "golang.org/x/sys/unix" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" "gotest.tools/v3/skip" - - "github.com/moby/sys/user" -) - -const ( - tempUser = "tempuser" ) type node struct { @@ -327,41 +318,6 @@ func compareTrees(left, right map[string]node) error { return nil } -func delUser(t *testing.T, name string) { - out, err := exec.Command("userdel", name).CombinedOutput() - assert.Check(t, err, out) -} - -func TestParseSubidFileWithNewlinesAndComments(t *testing.T) { - tmpDir, err := os.MkdirTemp("", "parsesubid") - if err != nil { - t.Fatal(err) - } - fnamePath := filepath.Join(tmpDir, "testsubuid") - fcontent := `tss:100000:65536 -# empty default subuid/subgid file - -dockremap:231072:65536` - if err := os.WriteFile(fnamePath, []byte(fcontent), 0o644); err != nil { - t.Fatal(err) - } - ranges, err := user.ParseSubIDFileFilter(fnamePath, func(sid user.SubID) bool { - return sid.Name == "dockremap" - }) - if err != nil { - t.Fatal(err) - } - if len(ranges) != 1 { - t.Fatalf("wanted 1 element in ranges, got %d instead", len(ranges)) - } - if ranges[0].SubID != 231072 { - t.Fatalf("wanted 231072, got %d instead", ranges[0].SubID) - } - if ranges[0].Count != 65536 { - t.Fatalf("wanted 65536, got %d instead", ranges[0].Count) - } -} - func TestGetRootUIDGID(t *testing.T) { uidMap := []IDMap{ { @@ -408,72 +364,6 @@ func TestToContainer(t *testing.T) { assert.Check(t, is.Equal(uidMap[0].ContainerID, containerID)) } -func TestNewIDMappings(t *testing.T) { - RequiresRoot(t) - _, _, err := AddNamespaceRangesUser(tempUser) - assert.Check(t, err) - defer delUser(t, tempUser) - - tempUser, err := stduser.Lookup(tempUser) - assert.Check(t, err) - - idMapping, err := LoadIdentityMapping(tempUser.Username) - assert.Check(t, err) - - rootUID, rootGID, err := GetRootUIDGID(idMapping.UIDMaps, idMapping.GIDMaps) - assert.Check(t, err) - - dirName, err := os.MkdirTemp("", "mkdirall") - assert.Check(t, err, "Couldn't create temp directory") - defer os.RemoveAll(dirName) - - err = MkdirAllAndChown(dirName, 0o700, Identity{UID: rootUID, GID: rootGID}) - assert.Check(t, err, "Couldn't change ownership of file path. Got error") - cmd := exec.Command("ls", "-la", dirName) - cmd.SysProcAttr = &syscall.SysProcAttr{ - Credential: &syscall.Credential{Uid: uint32(rootUID), Gid: uint32(rootGID)}, - } - out, err := cmd.CombinedOutput() - assert.Check(t, err, "Unable to access %s directory with user UID:%d and GID:%d:\n%s", dirName, rootUID, rootGID, string(out)) -} - -func TestLookupUserAndGroup(t *testing.T) { - RequiresRoot(t) - uid, gid, err := AddNamespaceRangesUser(tempUser) - assert.Check(t, err) - defer delUser(t, tempUser) - - fetchedUser, err := LookupUser(tempUser) - assert.Check(t, err) - - fetchedUserByID, err := LookupUID(uid) - assert.Check(t, err) - assert.Check(t, is.DeepEqual(fetchedUserByID, fetchedUser)) - - fetchedGroup, err := LookupGroup(tempUser) - assert.Check(t, err) - - fetchedGroupByID, err := LookupGID(gid) - assert.Check(t, err) - assert.Check(t, is.DeepEqual(fetchedGroupByID, fetchedGroup)) -} - -func TestLookupUserAndGroupThatDoesNotExist(t *testing.T) { - fakeUser := "fakeuser" - _, err := LookupUser(fakeUser) - assert.Check(t, is.Error(err, `getent unable to find entry "fakeuser" in passwd database`)) - - _, err = LookupUID(-1) - assert.Check(t, is.ErrorContains(err, "")) - - fakeGroup := "fakegroup" - _, err = LookupGroup(fakeGroup) - assert.Check(t, is.Error(err, `getent unable to find entry "fakegroup" in group database`)) - - _, err = LookupGID(-1) - assert.Check(t, is.ErrorContains(err, "")) -} - // TestMkdirIsNotDir checks that mkdirAs() function (used by MkdirAll...) // returns a correct error in case a directory which it is about to create // already exists but is a file (rather than a directory). diff --git a/pkg/idtools/idtools_windows.go b/pkg/idtools/idtools_windows.go index 5b7c2ad771..43702f7f3a 100644 --- a/pkg/idtools/idtools_windows.go +++ b/pkg/idtools/idtools_windows.go @@ -1,16 +1,20 @@ -package idtools // import "github.com/docker/docker/pkg/idtools" +package idtools import ( "os" ) const ( + // Deprecated: copy value locally SeTakeOwnershipPrivilege = "SeTakeOwnershipPrivilege" ) const ( + // Deprecated: copy value locally ContainerAdministratorSidString = "S-1-5-93-2-1" - ContainerUserSidString = "S-1-5-93-2-2" + + // Deprecated: copy value locally + ContainerUserSidString = "S-1-5-93-2-2" ) // This is currently a wrapper around [os.MkdirAll] since currently