Add ADD/COPY --chown flag support to Windows

This implements chown support on Windows. Built-in accounts as well
as accounts included in the SAM database of the container are supported.

NOTE: IDPair is now named Identity and IDMappings is now named
IdentityMapping.

The following are valid examples:
ADD --chown=Guest . <some directory>
COPY --chown=Administrator . <some directory>
COPY --chown=Guests . <some directory>
COPY --chown=ContainerUser . <some directory>

On Windows an owner is only granted the permission to read the security
descriptor and read/write the discretionary access control list. This
fix also grants read/write and execute permissions to the owner.

Signed-off-by: Salahuddin Khan <salah@docker.com>
This commit is contained in:
Salahuddin Khan 2017-11-15 22:20:33 -08:00
parent 1fd7e4c28d
commit 763d839261
64 changed files with 610 additions and 301 deletions

View file

@ -56,21 +56,21 @@ type SessionGetter interface {
// BuildManager is shared across all Builder objects // BuildManager is shared across all Builder objects
type BuildManager struct { type BuildManager struct {
idMappings *idtools.IDMappings idMapping *idtools.IdentityMapping
backend builder.Backend backend builder.Backend
pathCache pathCache // TODO: make this persistent pathCache pathCache // TODO: make this persistent
sg SessionGetter sg SessionGetter
fsCache *fscache.FSCache fsCache *fscache.FSCache
} }
// NewBuildManager creates a BuildManager // NewBuildManager creates a BuildManager
func NewBuildManager(b builder.Backend, sg SessionGetter, fsCache *fscache.FSCache, idMappings *idtools.IDMappings) (*BuildManager, error) { func NewBuildManager(b builder.Backend, sg SessionGetter, fsCache *fscache.FSCache, identityMapping *idtools.IdentityMapping) (*BuildManager, error) {
bm := &BuildManager{ bm := &BuildManager{
backend: b, backend: b,
pathCache: &syncmap.Map{}, pathCache: &syncmap.Map{},
sg: sg, sg: sg,
idMappings: idMappings, idMapping: identityMapping,
fsCache: fsCache, fsCache: fsCache,
} }
if err := fsCache.RegisterTransport(remotecontext.ClientSessionRemote, NewClientSessionTransport()); err != nil { if err := fsCache.RegisterTransport(remotecontext.ClientSessionRemote, NewClientSessionTransport()); err != nil {
return nil, err return nil, err
@ -111,7 +111,7 @@ func (bm *BuildManager) Build(ctx context.Context, config backend.BuildConfig) (
ProgressWriter: config.ProgressWriter, ProgressWriter: config.ProgressWriter,
Backend: bm.backend, Backend: bm.backend,
PathCache: bm.pathCache, PathCache: bm.pathCache,
IDMappings: bm.idMappings, IDMapping: bm.idMapping,
} }
b, err := newBuilder(ctx, builderOptions) b, err := newBuilder(ctx, builderOptions)
if err != nil { if err != nil {
@ -159,7 +159,7 @@ type builderOptions struct {
Backend builder.Backend Backend builder.Backend
ProgressWriter backend.ProgressWriter ProgressWriter backend.ProgressWriter
PathCache pathCache PathCache pathCache
IDMappings *idtools.IDMappings IDMapping *idtools.IdentityMapping
} }
// Builder is a Dockerfile builder // Builder is a Dockerfile builder
@ -175,7 +175,7 @@ type Builder struct {
docker builder.Backend docker builder.Backend
clientCtx context.Context clientCtx context.Context
idMappings *idtools.IDMappings idMapping *idtools.IdentityMapping
disableCommit bool disableCommit bool
imageSources *imageSources imageSources *imageSources
pathCache pathCache pathCache pathCache
@ -199,7 +199,7 @@ func newBuilder(clientCtx context.Context, options builderOptions) (*Builder, er
Aux: options.ProgressWriter.AuxFormatter, Aux: options.ProgressWriter.AuxFormatter,
Output: options.ProgressWriter.Output, Output: options.ProgressWriter.Output,
docker: options.Backend, docker: options.Backend,
idMappings: options.IDMappings, idMapping: options.IDMapping,
imageSources: newImageSources(clientCtx, options), imageSources: newImageSources(clientCtx, options),
pathCache: options.PathCache, pathCache: options.PathCache,
imageProber: newImageProber(options.Backend, config.CacheFrom, config.NoCache), imageProber: newImageProber(options.Backend, config.CacheFrom, config.NoCache),

View file

@ -451,7 +451,7 @@ func downloadSource(output io.Writer, stdout io.Writer, srcURL string) (remote b
type copyFileOptions struct { type copyFileOptions struct {
decompress bool decompress bool
chownPair idtools.IDPair identity idtools.Identity
archiver Archiver archiver Archiver
} }
@ -481,7 +481,7 @@ func performCopyForInfo(dest copyInfo, source copyInfo, options copyFileOptions)
return errors.Wrapf(err, "source path not found") return errors.Wrapf(err, "source path not found")
} }
if src.IsDir() { if src.IsDir() {
return copyDirectory(archiver, srcEndpoint, destEndpoint, options.chownPair) return copyDirectory(archiver, srcEndpoint, destEndpoint, options.identity)
} }
if options.decompress && isArchivePath(source.root, srcPath) && !source.noDecompress { if options.decompress && isArchivePath(source.root, srcPath) && !source.noDecompress {
return archiver.UntarPath(srcPath, destPath) return archiver.UntarPath(srcPath, destPath)
@ -499,7 +499,7 @@ func performCopyForInfo(dest copyInfo, source copyInfo, options copyFileOptions)
destPath = dest.root.Join(destPath, source.root.Base(source.path)) destPath = dest.root.Join(destPath, source.root.Base(source.path))
destEndpoint = &copyEndpoint{driver: dest.root, path: destPath} destEndpoint = &copyEndpoint{driver: dest.root, path: destPath}
} }
return copyFile(archiver, srcEndpoint, destEndpoint, options.chownPair) return copyFile(archiver, srcEndpoint, destEndpoint, options.identity)
} }
func isArchivePath(driver containerfs.ContainerFS, path string) bool { func isArchivePath(driver containerfs.ContainerFS, path string) bool {
@ -517,7 +517,7 @@ func isArchivePath(driver containerfs.ContainerFS, path string) bool {
return err == nil return err == nil
} }
func copyDirectory(archiver Archiver, source, dest *copyEndpoint, chownPair idtools.IDPair) error { func copyDirectory(archiver Archiver, source, dest *copyEndpoint, identity idtools.Identity) error {
destExists, err := isExistingDirectory(dest) destExists, err := isExistingDirectory(dest)
if err != nil { if err != nil {
return errors.Wrapf(err, "failed to query destination path") return errors.Wrapf(err, "failed to query destination path")
@ -527,17 +527,17 @@ func copyDirectory(archiver Archiver, source, dest *copyEndpoint, chownPair idto
return errors.Wrapf(err, "failed to copy directory") return errors.Wrapf(err, "failed to copy directory")
} }
// TODO: @gupta-ak. Investigate how LCOW permission mappings will work. // TODO: @gupta-ak. Investigate how LCOW permission mappings will work.
return fixPermissions(source.path, dest.path, chownPair, !destExists) return fixPermissions(source.path, dest.path, identity, !destExists)
} }
func copyFile(archiver Archiver, source, dest *copyEndpoint, chownPair idtools.IDPair) error { func copyFile(archiver Archiver, source, dest *copyEndpoint, identity idtools.Identity) error {
if runtime.GOOS == "windows" && dest.driver.OS() == "linux" { if runtime.GOOS == "windows" && dest.driver.OS() == "linux" {
// LCOW // LCOW
if err := dest.driver.MkdirAll(dest.driver.Dir(dest.path), 0755); err != nil { if err := dest.driver.MkdirAll(dest.driver.Dir(dest.path), 0755); err != nil {
return errors.Wrapf(err, "failed to create new directory") return errors.Wrapf(err, "failed to create new directory")
} }
} else { } else {
if err := idtools.MkdirAllAndChownNew(filepath.Dir(dest.path), 0755, chownPair); err != nil { if err := idtools.MkdirAllAndChownNew(filepath.Dir(dest.path), 0755, identity); err != nil {
// Normal containers // Normal containers
return errors.Wrapf(err, "failed to create new directory") return errors.Wrapf(err, "failed to create new directory")
} }
@ -547,7 +547,7 @@ func copyFile(archiver Archiver, source, dest *copyEndpoint, chownPair idtools.I
return errors.Wrapf(err, "failed to copy file") return errors.Wrapf(err, "failed to copy file")
} }
// TODO: @gupta-ak. Investigate how LCOW permission mappings will work. // TODO: @gupta-ak. Investigate how LCOW permission mappings will work.
return fixPermissions(source.path, dest.path, chownPair, false) return fixPermissions(source.path, dest.path, identity, false)
} }
func endsInSlash(driver containerfs.Driver, path string) bool { func endsInSlash(driver containerfs.Driver, path string) bool {

View file

@ -10,7 +10,7 @@ import (
"github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/idtools"
) )
func fixPermissions(source, destination string, rootIDs idtools.IDPair, overrideSkip bool) error { func fixPermissions(source, destination string, identity idtools.Identity, overrideSkip bool) error {
var ( var (
skipChownRoot bool skipChownRoot bool
err error err error
@ -39,7 +39,7 @@ func fixPermissions(source, destination string, rootIDs idtools.IDPair, override
} }
fullpath = filepath.Join(destination, cleaned) fullpath = filepath.Join(destination, cleaned)
return os.Lchown(fullpath, rootIDs.UID, rootIDs.GID) return os.Lchown(fullpath, identity.UID, identity.GID)
}) })
} }

View file

@ -1,11 +1,17 @@
package dockerfile // import "github.com/docker/docker/builder/dockerfile" package dockerfile // import "github.com/docker/docker/builder/dockerfile"
import ( import (
"errors" "fmt"
"os"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/Microsoft/go-winio"
"github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/reexec"
"github.com/docker/docker/pkg/system"
"github.com/pkg/errors"
"golang.org/x/sys/windows"
) )
var pathBlacklist = map[string]bool{ var pathBlacklist = map[string]bool{
@ -13,9 +19,69 @@ var pathBlacklist = map[string]bool{
"c:\\windows": true, "c:\\windows": true,
} }
func fixPermissions(source, destination string, rootIDs idtools.IDPair, overrideSkip bool) error { func init() {
// chown is not supported on Windows reexec.Register("windows-fix-permissions", fixPermissionsReexec)
return nil }
func fixPermissions(source, destination string, identity idtools.Identity, _ bool) error {
if identity.SID == "" {
return nil
}
cmd := reexec.Command("windows-fix-permissions", source, destination, identity.SID)
output, err := cmd.CombinedOutput()
return errors.Wrapf(err, "failed to exec windows-fix-permissions: %s", output)
}
func fixPermissionsReexec() {
err := fixPermissionsWindows(os.Args[1], os.Args[2], os.Args[3])
if err != nil {
fmt.Fprint(os.Stderr, err)
os.Exit(1)
}
}
func fixPermissionsWindows(source, destination, SID string) error {
privileges := []string{winio.SeRestorePrivilege, system.SeTakeOwnershipPrivilege}
err := winio.EnableProcessPrivileges(privileges)
if err != nil {
return err
}
defer winio.DisableProcessPrivileges(privileges)
sid, err := windows.StringToSid(SID)
if err != nil {
return err
}
// Owners on *nix have read/write/delete/read control and write DAC.
// Add an ACE that grants this to the user/group specified with the
// chown option. Currently Windows is not honoring the owner change,
// however, they are aware of this and it should be fixed at some
// point.
sddlString := system.SddlAdministratorsLocalSystem
sddlString += "(A;OICI;GRGWGXRCWDSD;;;" + SID + ")"
securityDescriptor, err := winio.SddlToSecurityDescriptor(sddlString)
if err != nil {
return err
}
var daclPresent uint32
var daclDefaulted uint32
var dacl *byte
err = system.GetSecurityDescriptorDacl(&securityDescriptor[0], &daclPresent, &dacl, &daclDefaulted)
if err != nil {
return err
}
return system.SetNamedSecurityInfo(windows.StringToUTF16Ptr(destination), system.SE_FILE_OBJECT, system.OWNER_SECURITY_INFORMATION|system.DACL_SECURITY_INFORMATION, sid, nil, dacl, nil)
} }
func validateCopySourcePath(imageSource *imageMount, origPath, platform string) error { func validateCopySourcePath(imageSource *imageMount, origPath, platform string) error {

View file

@ -37,7 +37,7 @@ type Archiver interface {
UntarPath(src, dst string) error UntarPath(src, dst string) error
CopyWithTar(src, dst string) error CopyWithTar(src, dst string) error
CopyFileWithTar(src, dst string) error CopyFileWithTar(src, dst string) error
IDMappings() *idtools.IDMappings IdentityMapping() *idtools.IdentityMapping
} }
// The builder will use the following interfaces if the container fs implements // The builder will use the following interfaces if the container fs implements
@ -68,11 +68,11 @@ func tarFunc(i interface{}) containerfs.TarFunc {
func (b *Builder) getArchiver(src, dst containerfs.Driver) Archiver { func (b *Builder) getArchiver(src, dst containerfs.Driver) Archiver {
t, u := tarFunc(src), untarFunc(dst) t, u := tarFunc(src), untarFunc(dst)
return &containerfs.Archiver{ return &containerfs.Archiver{
SrcDriver: src, SrcDriver: src,
DstDriver: dst, DstDriver: dst,
Tar: t, Tar: t,
Untar: u, Untar: u,
IDMappingsVar: b.idMappings, IDMapping: b.idMapping,
} }
} }
@ -185,14 +185,18 @@ func (b *Builder) performCopy(req dispatchRequest, inst copyInstruction) error {
return err return err
} }
chownPair := b.idMappings.RootPair() identity := b.idMapping.RootPair()
// if a chown was requested, perform the steps to get the uid, gid // if a chown was requested, perform the steps to get the uid, gid
// translated (if necessary because of user namespaces), and replace // translated (if necessary because of user namespaces), and replace
// the root pair with the chown pair for copy operations // the root pair with the chown pair for copy operations
if inst.chownStr != "" { if inst.chownStr != "" {
chownPair, err = parseChownFlag(inst.chownStr, destInfo.root.Path(), b.idMappings) identity, err = parseChownFlag(b, state, inst.chownStr, destInfo.root.Path(), b.idMapping)
if err != nil { if err != nil {
return errors.Wrapf(err, "unable to convert uid/gid chown string to host mapping") if b.options.Platform != "windows" {
return errors.Wrapf(err, "unable to convert uid/gid chown string to host mapping")
}
return errors.Wrapf(err, "unable to map container user account name to SID")
} }
} }
@ -200,7 +204,7 @@ func (b *Builder) performCopy(req dispatchRequest, inst copyInstruction) error {
opts := copyFileOptions{ opts := copyFileOptions{
decompress: inst.allowLocalDecompression, decompress: inst.allowLocalDecompression,
archiver: b.getArchiver(info.root, destInfo.root), archiver: b.getArchiver(info.root, destInfo.root),
chownPair: chownPair, identity: identity,
} }
if err := performCopyForInfo(destInfo, info, opts); err != nil { if err := performCopyForInfo(destInfo, info, opts); err != nil {
return errors.Wrapf(err, "failed to copy files") return errors.Wrapf(err, "failed to copy files")

View file

@ -11,11 +11,11 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) { func parseChownFlag(builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping *idtools.IdentityMapping) (idtools.Identity, error) {
var userStr, grpStr string var userStr, grpStr string
parts := strings.Split(chown, ":") parts := strings.Split(chown, ":")
if len(parts) > 2 { if len(parts) > 2 {
return idtools.IDPair{}, errors.New("invalid chown string format: " + chown) return idtools.Identity{}, errors.New("invalid chown string format: " + chown)
} }
if len(parts) == 1 { if len(parts) == 1 {
// if no group specified, use the user spec as group as well // if no group specified, use the user spec as group as well
@ -26,25 +26,25 @@ func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (
passwdPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "passwd"), ctrRootPath) passwdPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "passwd"), ctrRootPath)
if err != nil { if err != nil {
return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/passwd path in container rootfs") return idtools.Identity{}, errors.Wrapf(err, "can't resolve /etc/passwd path in container rootfs")
} }
groupPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "group"), ctrRootPath) groupPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "group"), ctrRootPath)
if err != nil { if err != nil {
return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/group path in container rootfs") return idtools.Identity{}, errors.Wrapf(err, "can't resolve /etc/group path in container rootfs")
} }
uid, err := lookupUser(userStr, passwdPath) uid, err := lookupUser(userStr, passwdPath)
if err != nil { if err != nil {
return idtools.IDPair{}, errors.Wrapf(err, "can't find uid for user "+userStr) return idtools.Identity{}, errors.Wrapf(err, "can't find uid for user "+userStr)
} }
gid, err := lookupGroup(grpStr, groupPath) gid, err := lookupGroup(grpStr, groupPath)
if err != nil { if err != nil {
return idtools.IDPair{}, errors.Wrapf(err, "can't find gid for group "+grpStr) return idtools.Identity{}, errors.Wrapf(err, "can't find gid for group "+grpStr)
} }
// convert as necessary because of user namespaces // convert as necessary because of user namespaces
chownPair, err := idMappings.ToHost(idtools.IDPair{UID: uid, GID: gid}) chownPair, err := identityMapping.ToHost(idtools.Identity{UID: uid, GID: gid})
if err != nil { if err != nil {
return idtools.IDPair{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping") return idtools.Identity{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
} }
return chownPair, nil return chownPair, nil
} }

View file

@ -5,6 +5,7 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/idtools"
"gotest.tools/assert" "gotest.tools/assert"
is "gotest.tools/assert/cmp" is "gotest.tools/assert/cmp"
@ -34,7 +35,7 @@ othergrp:x:6666:
}, },
} }
remapped := idtools.NewIDMappingsFromMaps(idMaps, idMaps) remapped := idtools.NewIDMappingsFromMaps(idMaps, idMaps)
unmapped := &idtools.IDMappings{} unmapped := &idtools.IdentityMapping{}
contextDir, cleanup := createTestTempDir(t, "", "builder-chown-parse-test") contextDir, cleanup := createTestTempDir(t, "", "builder-chown-parse-test")
defer cleanup() defer cleanup()
@ -49,56 +50,72 @@ othergrp:x:6666:
// positive tests // positive tests
for _, testcase := range []struct { for _, testcase := range []struct {
builder *Builder
name string name string
chownStr string chownStr string
idMapping *idtools.IDMappings idMapping *idtools.IdentityMapping
expected idtools.IDPair state *dispatchState
expected idtools.Identity
}{ }{
{ {
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "UIDNoMap", name: "UIDNoMap",
chownStr: "1", chownStr: "1",
idMapping: unmapped, idMapping: unmapped,
expected: idtools.IDPair{UID: 1, GID: 1}, state: &dispatchState{},
expected: idtools.Identity{UID: 1, GID: 1},
}, },
{ {
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "UIDGIDNoMap", name: "UIDGIDNoMap",
chownStr: "0:1", chownStr: "0:1",
idMapping: unmapped, idMapping: unmapped,
expected: idtools.IDPair{UID: 0, GID: 1}, state: &dispatchState{},
expected: idtools.Identity{UID: 0, GID: 1},
}, },
{ {
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "UIDWithMap", name: "UIDWithMap",
chownStr: "0", chownStr: "0",
idMapping: remapped, idMapping: remapped,
expected: idtools.IDPair{UID: 100000, GID: 100000}, state: &dispatchState{},
expected: idtools.Identity{UID: 100000, GID: 100000},
}, },
{ {
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "UIDGIDWithMap", name: "UIDGIDWithMap",
chownStr: "1:33", chownStr: "1:33",
idMapping: remapped, idMapping: remapped,
expected: idtools.IDPair{UID: 100001, GID: 100033}, state: &dispatchState{},
expected: idtools.Identity{UID: 100001, GID: 100033},
}, },
{ {
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "UserNoMap", name: "UserNoMap",
chownStr: "bin:5555", chownStr: "bin:5555",
idMapping: unmapped, idMapping: unmapped,
expected: idtools.IDPair{UID: 1, GID: 5555}, state: &dispatchState{},
expected: idtools.Identity{UID: 1, GID: 5555},
}, },
{ {
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "GroupWithMap", name: "GroupWithMap",
chownStr: "0:unicorn", chownStr: "0:unicorn",
idMapping: remapped, idMapping: remapped,
expected: idtools.IDPair{UID: 100000, GID: 101002}, state: &dispatchState{},
expected: idtools.Identity{UID: 100000, GID: 101002},
}, },
{ {
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "UserOnlyWithMap", name: "UserOnlyWithMap",
chownStr: "unicorn", chownStr: "unicorn",
idMapping: remapped, idMapping: remapped,
expected: idtools.IDPair{UID: 101001, GID: 101002}, state: &dispatchState{},
expected: idtools.Identity{UID: 101001, GID: 101002},
}, },
} { } {
t.Run(testcase.name, func(t *testing.T) { t.Run(testcase.name, func(t *testing.T) {
idPair, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping) idPair, err := parseChownFlag(testcase.builder, testcase.state, testcase.chownStr, contextDir, testcase.idMapping)
assert.NilError(t, err, "Failed to parse chown flag: %q", testcase.chownStr) assert.NilError(t, err, "Failed to parse chown flag: %q", testcase.chownStr)
assert.Check(t, is.DeepEqual(testcase.expected, idPair), "chown flag mapping failure") assert.Check(t, is.DeepEqual(testcase.expected, idPair), "chown flag mapping failure")
}) })
@ -106,32 +123,40 @@ othergrp:x:6666:
// error tests // error tests
for _, testcase := range []struct { for _, testcase := range []struct {
builder *Builder
name string name string
chownStr string chownStr string
idMapping *idtools.IDMappings idMapping *idtools.IdentityMapping
state *dispatchState
descr string descr string
}{ }{
{ {
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "BadChownFlagFormat", name: "BadChownFlagFormat",
chownStr: "bob:1:555", chownStr: "bob:1:555",
idMapping: unmapped, idMapping: unmapped,
state: &dispatchState{},
descr: "invalid chown string format: bob:1:555", descr: "invalid chown string format: bob:1:555",
}, },
{ {
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "UserNoExist", name: "UserNoExist",
chownStr: "bob", chownStr: "bob",
idMapping: unmapped, idMapping: unmapped,
state: &dispatchState{},
descr: "can't find uid for user bob: no such user: bob", descr: "can't find uid for user bob: no such user: bob",
}, },
{ {
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "GroupNoExist", name: "GroupNoExist",
chownStr: "root:bob", chownStr: "root:bob",
idMapping: unmapped, idMapping: unmapped,
state: &dispatchState{},
descr: "can't find gid for group bob: no such group: bob", descr: "can't find gid for group bob: no such group: bob",
}, },
} { } {
t.Run(testcase.name, func(t *testing.T) { t.Run(testcase.name, func(t *testing.T) {
_, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping) _, err := parseChownFlag(testcase.builder, testcase.state, testcase.chownStr, contextDir, testcase.idMapping)
assert.Check(t, is.Error(err, testcase.descr), "Expected error string doesn't match") assert.Check(t, is.Error(err, testcase.descr), "Expected error string doesn't match")
}) })
} }

View file

@ -1,7 +1,120 @@
package dockerfile // import "github.com/docker/docker/builder/dockerfile" package dockerfile // import "github.com/docker/docker/builder/dockerfile"
import "github.com/docker/docker/pkg/idtools" import (
"bytes"
"os"
"path/filepath"
"strings"
func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) { "github.com/containerd/containerd/platforms"
return idMappings.RootPair(), nil "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/pkg/system"
"github.com/pkg/errors"
"golang.org/x/sys/windows"
)
func parseChownFlag(builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping *idtools.IdentityMapping) (idtools.Identity, error) {
if builder.options.Platform == "windows" {
return getAccountIdentity(builder, chown, ctrRootPath, state)
}
return identityMapping.RootPair(), nil
}
func getAccountIdentity(builder *Builder, accountName string, ctrRootPath string, state *dispatchState) (idtools.Identity, error) {
// If this is potentially a string SID then attempt to convert it to verify
// this, otherwise continue looking for the account.
if strings.HasPrefix(accountName, "S-") || strings.HasPrefix(accountName, "s-") {
sid, err := windows.StringToSid(accountName)
if err == nil {
accountSid, err := sid.String()
if err != nil {
return idtools.Identity{SID: ""}, errors.Wrapf(err, "error converting SID to string")
}
return idtools.Identity{SID: accountSid}, nil
}
}
// Attempt to obtain the SID using the name.
sid, _, accType, err := windows.LookupSID("", accountName)
// If this is a SID that is built-in and hence the same across all systems then use that.
if err == nil && (accType == windows.SidTypeAlias || accType == windows.SidTypeWellKnownGroup) {
accountSid, err := sid.String()
if err != nil {
return idtools.Identity{SID: ""}, errors.Wrapf(err, "error converting SID to string")
}
return idtools.Identity{SID: accountSid}, nil
}
// Check if the account name is one unique to containers.
if strings.EqualFold(accountName, "ContainerAdministrator") {
return idtools.Identity{SID: system.ContainerAdministratorSidString}, nil
} else if strings.EqualFold(accountName, "ContainerUser") {
return idtools.Identity{SID: system.ContainerUserSidString}, nil
}
// All other lookups failed, so therefore determine if the account in
// question exists in the container and if so, obtain its SID.
return lookupNTAccount(builder, accountName, state)
}
func lookupNTAccount(builder *Builder, accountName string, state *dispatchState) (idtools.Identity, error) {
source, _ := filepath.Split(os.Args[0])
target := "C:\\Docker"
targetExecutable := target + "\\containerutility.exe"
optionsPlatform, err := platforms.Parse(builder.options.Platform)
if err != nil {
return idtools.Identity{}, err
}
runConfig := copyRunConfig(state.runConfig,
withCmdCommentString("internal run to obtain NT account information.", optionsPlatform.OS))
runConfig.ArgsEscaped = true
runConfig.Cmd = []string{targetExecutable, "getaccountsid", accountName}
hostConfig := &container.HostConfig{Mounts: []mount.Mount{
{
Type: mount.TypeBind,
Source: source,
Target: target,
ReadOnly: true,
},
},
}
container, err := builder.containerManager.Create(runConfig, hostConfig)
if err != nil {
return idtools.Identity{}, err
}
stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
if err := builder.containerManager.Run(builder.clientCtx, container.ID, stdout, stderr); err != nil {
if err, ok := err.(*statusCodeError); ok {
return idtools.Identity{}, &jsonmessage.JSONError{
Message: stderr.String(),
Code: err.StatusCode(),
}
}
return idtools.Identity{}, err
}
accountSid := stdout.String()
return idtools.Identity{SID: accountSid}, nil
} }

View file

@ -267,7 +267,7 @@ func newRouterOptions(config *config.Config, daemon *daemon.Daemon) (routerOptio
return opts, errors.Wrap(err, "failed to create fscache") return opts, errors.Wrap(err, "failed to create fscache")
} }
manager, err := dockerfile.NewBuildManager(daemon.BuilderBackend(), sm, buildCache, daemon.IDMappings()) manager, err := dockerfile.NewBuildManager(daemon.BuilderBackend(), sm, buildCache, daemon.IdentityMapping())
if err != nil { if err != nil {
return opts, err return opts, err
} }

View file

@ -254,7 +254,7 @@ func (container *Container) WriteHostConfig() (*containertypes.HostConfig, error
} }
// SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir // SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir
func (container *Container) SetupWorkingDirectory(rootIDs idtools.IDPair) error { func (container *Container) SetupWorkingDirectory(rootIdentity idtools.Identity) error {
// TODO @jhowardmsft, @gupta-ak LCOW Support. This will need revisiting. // TODO @jhowardmsft, @gupta-ak LCOW Support. This will need revisiting.
// We will need to do remote filesystem operations here. // We will need to do remote filesystem operations here.
if container.OS != runtime.GOOS { if container.OS != runtime.GOOS {
@ -271,7 +271,7 @@ func (container *Container) SetupWorkingDirectory(rootIDs idtools.IDPair) error
return err return err
} }
if err := idtools.MkdirAllAndChownNew(pth, 0755, rootIDs); err != nil { if err := idtools.MkdirAllAndChownNew(pth, 0755, rootIdentity); err != nil {
pthInfo, err2 := os.Stat(pth) pthInfo, err2 := os.Stat(pth)
if err2 == nil && pthInfo != nil && !pthInfo.IsDir() { if err2 == nil && pthInfo != nil && !pthInfo.IsDir() {
return errors.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir) return errors.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir)

View file

@ -9,7 +9,7 @@ import (
func (daemon *Daemon) defaultTarCopyOptions(noOverwriteDirNonDir bool) *archive.TarOptions { func (daemon *Daemon) defaultTarCopyOptions(noOverwriteDirNonDir bool) *archive.TarOptions {
return &archive.TarOptions{ return &archive.TarOptions{
NoOverwriteDirNonDir: noOverwriteDirNonDir, NoOverwriteDirNonDir: noOverwriteDirNonDir,
UIDMaps: daemon.idMappings.UIDs(), UIDMaps: daemon.idMapping.UIDs(),
GIDMaps: daemon.idMappings.GIDs(), GIDMaps: daemon.idMapping.GIDs(),
} }
} }

View file

@ -18,8 +18,10 @@ func (daemon *Daemon) tarCopyOptions(container *container.Container, noOverwrite
return nil, err return nil, err
} }
identity := idtools.Identity{UID: user.Uid, GID: user.Gid}
return &archive.TarOptions{ return &archive.TarOptions{
NoOverwriteDirNonDir: noOverwriteDirNonDir, NoOverwriteDirNonDir: noOverwriteDirNonDir,
ChownOpts: &idtools.IDPair{UID: user.Uid, GID: user.Gid}, ChownOpts: &identity,
}, nil }, nil
} }

View file

@ -132,7 +132,7 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
fallthrough fallthrough
case ipcMode.IsShareable(): case ipcMode.IsShareable():
rootIDs := daemon.idMappings.RootPair() rootIDs := daemon.idMapping.RootPair()
if !c.HasMountFor("/dev/shm") { if !c.HasMountFor("/dev/shm") {
shmPath, err := c.ShmResourcePath() shmPath, err := c.ShmResourcePath()
if err != nil { if err != nil {
@ -179,7 +179,7 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
} }
// retrieve possible remapped range start for root UID, GID // retrieve possible remapped range start for root UID, GID
rootIDs := daemon.idMappings.RootPair() rootIDs := daemon.idMapping.RootPair()
for _, s := range c.SecretReferences { for _, s := range c.SecretReferences {
// TODO (ehazlett): use type switch when more are supported // TODO (ehazlett): use type switch when more are supported
@ -278,7 +278,7 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
// In practice this is using a tmpfs mount and is used for both "configs" and "secrets" // In practice this is using a tmpfs mount and is used for both "configs" and "secrets"
func (daemon *Daemon) createSecretsDir(c *container.Container) error { func (daemon *Daemon) createSecretsDir(c *container.Container) error {
// retrieve possible remapped range start for root UID, GID // retrieve possible remapped range start for root UID, GID
rootIDs := daemon.idMappings.RootPair() rootIDs := daemon.idMapping.RootPair()
dir, err := c.SecretMountPath() dir, err := c.SecretMountPath()
if err != nil { if err != nil {
return errors.Wrap(err, "error getting container secrets dir") return errors.Wrap(err, "error getting container secrets dir")
@ -304,7 +304,7 @@ func (daemon *Daemon) remountSecretDir(c *container.Container) error {
if err := label.Relabel(dir, c.MountLabel, false); err != nil { if err := label.Relabel(dir, c.MountLabel, false); err != nil {
logrus.WithError(err).WithField("dir", dir).Warn("Error while attempting to set selinux label") logrus.WithError(err).WithField("dir", dir).Warn("Error while attempting to set selinux label")
} }
rootIDs := daemon.idMappings.RootPair() rootIDs := daemon.idMapping.RootPair()
tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID) tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
// remount secrets ro // remount secrets ro
@ -407,5 +407,5 @@ func (daemon *Daemon) setupContainerMountsRoot(c *container.Container) error {
if err != nil { if err != nil {
return err return err
} }
return idtools.MkdirAllAndChown(p, 0700, daemon.idMappings.RootPair()) return idtools.MkdirAllAndChown(p, 0700, daemon.idMapping.RootPair())
} }

View file

@ -155,13 +155,14 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (
} }
// Set RWLayer for container after mount labels have been set // Set RWLayer for container after mount labels have been set
rwLayer, err := daemon.imageService.CreateLayer(container, setupInitLayer(daemon.idMappings)) rwLayer, err := daemon.imageService.CreateLayer(container, setupInitLayer(daemon.idMapping))
if err != nil { if err != nil {
return nil, errdefs.System(err) return nil, errdefs.System(err)
} }
container.RWLayer = rwLayer container.RWLayer = rwLayer
rootIDs := daemon.idMappings.RootPair() rootIDs := daemon.idMapping.RootPair()
if err := idtools.MkdirAndChown(container.Root, 0700, rootIDs); err != nil { if err := idtools.MkdirAndChown(container.Root, 0700, rootIDs); err != nil {
return nil, err return nil, err
} }

View file

@ -25,7 +25,7 @@ func (daemon *Daemon) createContainerOSSpecificSettings(container *container.Con
} }
defer daemon.Unmount(container) defer daemon.Unmount(container)
rootIDs := daemon.idMappings.RootPair() rootIDs := daemon.idMapping.RootPair()
if err := container.SetupWorkingDirectory(rootIDs); err != nil { if err := container.SetupWorkingDirectory(rootIDs); err != nil {
return err return err
} }

View file

@ -87,7 +87,7 @@ type Daemon struct {
seccompEnabled bool seccompEnabled bool
apparmorEnabled bool apparmorEnabled bool
shutdown bool shutdown bool
idMappings *idtools.IDMappings idMapping *idtools.IdentityMapping
// TODO: move graphDrivers field to an InfoService // TODO: move graphDrivers field to an InfoService
graphDrivers map[string]string // By operating system graphDrivers map[string]string // By operating system
@ -594,11 +594,11 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
return nil, err return nil, err
} }
idMappings, err := setupRemappedRoot(config) idMapping, err := setupRemappedRoot(config)
if err != nil { if err != nil {
return nil, err return nil, err
} }
rootIDs := idMappings.RootPair() rootIDs := idMapping.RootPair()
if err := setupDaemonProcess(config); err != nil { if err := setupDaemonProcess(config); err != nil {
return nil, err return nil, err
} }
@ -749,7 +749,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
MetadataStorePathTemplate: filepath.Join(config.Root, "image", "%s", "layerdb"), MetadataStorePathTemplate: filepath.Join(config.Root, "image", "%s", "layerdb"),
GraphDriver: gd, GraphDriver: gd,
GraphDriverOptions: config.GraphOptions, GraphDriverOptions: config.GraphOptions,
IDMappings: idMappings, IDMapping: idMapping,
PluginGetter: d.PluginStore, PluginGetter: d.PluginStore,
ExperimentalEnabled: config.Experimental, ExperimentalEnabled: config.Experimental,
OS: operatingSystem, OS: operatingSystem,
@ -856,7 +856,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
d.EventsService = events.New() d.EventsService = events.New()
d.root = config.Root d.root = config.Root
d.idMappings = idMappings d.idMapping = idMapping
d.seccompEnabled = sysInfo.Seccomp d.seccompEnabled = sysInfo.Seccomp
d.apparmorEnabled = sysInfo.AppArmor d.apparmorEnabled = sysInfo.AppArmor
@ -1106,7 +1106,7 @@ func (daemon *Daemon) Subnets() ([]net.IPNet, []net.IPNet) {
// prepareTempDir prepares and returns the default directory to use // prepareTempDir prepares and returns the default directory to use
// for temporary files. // for temporary files.
// If it doesn't exist, it is created. If it exists, its content is removed. // If it doesn't exist, it is created. If it exists, its content is removed.
func prepareTempDir(rootDir string, rootIDs idtools.IDPair) (string, error) { func prepareTempDir(rootDir string, rootIdentity idtools.Identity) (string, error) {
var tmpDir string var tmpDir string
if tmpDir = os.Getenv("DOCKER_TMPDIR"); tmpDir == "" { if tmpDir = os.Getenv("DOCKER_TMPDIR"); tmpDir == "" {
tmpDir = filepath.Join(rootDir, "tmp") tmpDir = filepath.Join(rootDir, "tmp")
@ -1126,7 +1126,7 @@ func prepareTempDir(rootDir string, rootIDs idtools.IDPair) (string, error) {
} }
// We don't remove the content of tmpdir if it's not the default, // We don't remove the content of tmpdir if it's not the default,
// it may hold things that do not belong to us. // it may hold things that do not belong to us.
return tmpDir, idtools.MkdirAllAndChown(tmpDir, 0700, rootIDs) return tmpDir, idtools.MkdirAllAndChown(tmpDir, 0700, rootIdentity)
} }
func (daemon *Daemon) setGenericResources(conf *config.Config) error { func (daemon *Daemon) setGenericResources(conf *config.Config) error {
@ -1274,11 +1274,11 @@ func CreateDaemonRoot(config *config.Config) error {
} }
} }
idMappings, err := setupRemappedRoot(config) idMapping, err := setupRemappedRoot(config)
if err != nil { if err != nil {
return err return err
} }
return setupDaemonRoot(config, realRoot, idMappings.RootPair()) return setupDaemonRoot(config, realRoot, idMapping.RootPair())
} }
// checkpointAndSave grabs a container lock to safely call container.CheckpointTo // checkpointAndSave grabs a container lock to safely call container.CheckpointTo
@ -1304,9 +1304,9 @@ func (daemon *Daemon) GetAttachmentStore() *network.AttachmentStore {
return &daemon.attachmentStore return &daemon.attachmentStore
} }
// IDMappings returns uid/gid mappings for the builder // IdentityMapping returns uid/gid mapping or a SID (in the case of Windows) for the builder
func (daemon *Daemon) IDMappings() *idtools.IDMappings { func (daemon *Daemon) IdentityMapping() *idtools.IdentityMapping {
return daemon.idMappings return daemon.idMapping
} }
// ImageService returns the Daemon's ImageService // ImageService returns the Daemon's ImageService

View file

@ -124,7 +124,7 @@ func TestTmpfsDevShmSizeOverride(t *testing.T) {
mnt := "/dev/shm" mnt := "/dev/shm"
d := Daemon{ d := Daemon{
idMappings: &idtools.IDMappings{}, idMapping: &idtools.IdentityMapping{},
} }
c := &container.Container{ c := &container.Container{
HostConfig: &containertypes.HostConfig{ HostConfig: &containertypes.HostConfig{

View file

@ -118,7 +118,7 @@ func initDaemonWithVolumeStore(tmp string) (*Daemon, error) {
repository: tmp, repository: tmp,
root: tmp, root: tmp,
} }
daemon.volumes, err = volumesservice.NewVolumeService(tmp, nil, idtools.IDPair{UID: 0, GID: 0}, daemon) daemon.volumes, err = volumesservice.NewVolumeService(tmp, nil, idtools.Identity{UID: 0, GID: 0}, daemon)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -1003,9 +1003,9 @@ func removeDefaultBridgeInterface() {
} }
} }
func setupInitLayer(idMappings *idtools.IDMappings) func(containerfs.ContainerFS) error { func setupInitLayer(idMapping *idtools.IdentityMapping) func(containerfs.ContainerFS) error {
return func(initPath containerfs.ContainerFS) error { return func(initPath containerfs.ContainerFS) error {
return initlayer.Setup(initPath, idMappings.RootPair()) return initlayer.Setup(initPath, idMapping.RootPair())
} }
} }
@ -1102,7 +1102,7 @@ func parseRemappedRoot(usergrp string) (string, string, error) {
return username, groupname, nil return username, groupname, nil
} }
func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) { func setupRemappedRoot(config *config.Config) (*idtools.IdentityMapping, error) {
if runtime.GOOS != "linux" && config.RemappedRoot != "" { if runtime.GOOS != "linux" && config.RemappedRoot != "" {
return nil, fmt.Errorf("User namespaces are only supported on Linux") return nil, fmt.Errorf("User namespaces are only supported on Linux")
} }
@ -1118,22 +1118,22 @@ func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) {
// Cannot setup user namespaces with a 1-to-1 mapping; "--root=0:0" is a no-op // Cannot setup user namespaces with a 1-to-1 mapping; "--root=0:0" is a no-op
// effectively // effectively
logrus.Warn("User namespaces: root cannot be remapped with itself; user namespaces are OFF") logrus.Warn("User namespaces: root cannot be remapped with itself; user namespaces are OFF")
return &idtools.IDMappings{}, nil return &idtools.IdentityMapping{}, nil
} }
logrus.Infof("User namespaces: ID ranges will be mapped to subuid/subgid ranges of: %s:%s", username, groupname) logrus.Infof("User namespaces: ID ranges will be mapped to subuid/subgid ranges of: %s:%s", username, groupname)
// update remapped root setting now that we have resolved them to actual names // update remapped root setting now that we have resolved them to actual names
config.RemappedRoot = fmt.Sprintf("%s:%s", username, groupname) config.RemappedRoot = fmt.Sprintf("%s:%s", username, groupname)
mappings, err := idtools.NewIDMappings(username, groupname) mappings, err := idtools.NewIdentityMapping(username, groupname)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Can't create ID mappings") return nil, errors.Wrap(err, "Can't create ID mappings")
} }
return mappings, nil return mappings, nil
} }
return &idtools.IDMappings{}, nil return &idtools.IdentityMapping{}, nil
} }
func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPair) error { func setupDaemonRoot(config *config.Config, rootDir string, rootIdentity idtools.Identity) error {
config.Root = rootDir config.Root = rootDir
// the docker root metadata directory needs to have execute permissions for all users (g+x,o+x) // the docker root metadata directory needs to have execute permissions for all users (g+x,o+x)
// so that syscalls executing as non-root, operating on subdirectories of the graph root // so that syscalls executing as non-root, operating on subdirectories of the graph root
@ -1158,10 +1158,10 @@ func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPa
// a new subdirectory with ownership set to the remapped uid/gid (so as to allow // a new subdirectory with ownership set to the remapped uid/gid (so as to allow
// `chdir()` to work for containers namespaced to that uid/gid) // `chdir()` to work for containers namespaced to that uid/gid)
if config.RemappedRoot != "" { if config.RemappedRoot != "" {
config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootIDs.UID, rootIDs.GID)) config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootIdentity.UID, rootIdentity.GID))
logrus.Debugf("Creating user namespaced daemon root: %s", config.Root) logrus.Debugf("Creating user namespaced daemon root: %s", config.Root)
// Create the root directory if it doesn't exist // Create the root directory if it doesn't exist
if err := idtools.MkdirAllAndChown(config.Root, 0700, rootIDs); err != nil { if err := idtools.MkdirAllAndChown(config.Root, 0700, rootIdentity); err != nil {
return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err) return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err)
} }
// we also need to verify that any pre-existing directories in the path to // we also need to verify that any pre-existing directories in the path to
@ -1174,7 +1174,7 @@ func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPa
if dirPath == "/" { if dirPath == "/" {
break break
} }
if !idtools.CanAccess(dirPath, rootIDs) { if !idtools.CanAccess(dirPath, rootIdentity) {
return fmt.Errorf("a subdirectory in your graphroot path (%s) restricts access to the remapped root uid/gid; please fix by allowing 'o+x' permissions on existing directories", config.Root) return fmt.Errorf("a subdirectory in your graphroot path (%s) restricts access to the remapped root uid/gid; please fix by allowing 'o+x' permissions on existing directories", config.Root)
} }
} }

View file

@ -53,7 +53,7 @@ func parseSecurityOpt(container *container.Container, config *containertypes.Hos
return nil return nil
} }
func setupInitLayer(idMappings *idtools.IDMappings) func(containerfs.ContainerFS) error { func setupInitLayer(idMapping *idtools.IdentityMapping) func(containerfs.ContainerFS) error {
return nil return nil
} }
@ -465,11 +465,11 @@ func (daemon *Daemon) cleanupMounts() error {
return nil return nil
} }
func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) { func setupRemappedRoot(config *config.Config) (*idtools.IdentityMapping, error) {
return &idtools.IDMappings{}, nil return &idtools.IdentityMapping{}, nil
} }
func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPair) error { func setupDaemonRoot(config *config.Config, rootDir string, rootIdentity idtools.Identity) error {
config.Root = rootDir config.Root = rootDir
// Create the root directory if it doesn't exists // Create the root directory if it doesn't exists
if err := system.MkdirAllWithACL(config.Root, 0, system.SddlAdministratorsLocalSystem); err != nil { if err := system.MkdirAllWithACL(config.Root, 0, system.SddlAdministratorsLocalSystem); err != nil {

View file

@ -68,8 +68,8 @@ func (daemon *Daemon) containerExport(container *container.Container) (arch io.R
archive, err := archivePath(basefs, basefs.Path(), &archive.TarOptions{ archive, err := archivePath(basefs, basefs.Path(), &archive.TarOptions{
Compression: archive.Uncompressed, Compression: archive.Uncompressed,
UIDMaps: daemon.idMappings.UIDs(), UIDMaps: daemon.idMapping.UIDs(),
GIDMaps: daemon.idMappings.GIDs(), GIDMaps: daemon.idMapping.GIDs(),
}) })
if err != nil { if err != nil {
rwlayer.Unmount() rwlayer.Unmount()

View file

@ -135,13 +135,13 @@ func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, err return nil, err
} }
// Create the root aufs driver dir // Create the root aufs driver dir
if err := idtools.MkdirAllAndChown(root, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil { if err := idtools.MkdirAllAndChown(root, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return nil, err return nil, err
} }
// Populate the dir structure // Populate the dir structure
for _, p := range paths { for _, p := range paths {
if err := idtools.MkdirAllAndChown(path.Join(root, p), 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil { if err := idtools.MkdirAllAndChown(path.Join(root, p), 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return nil, err return nil, err
} }
} }
@ -289,7 +289,7 @@ func (a *Driver) createDirsFor(id string) error {
// The path of directories are <aufs_root_path>/mnt/<image_id> // The path of directories are <aufs_root_path>/mnt/<image_id>
// and <aufs_root_path>/diff/<image_id> // and <aufs_root_path>/diff/<image_id>
for _, p := range paths { for _, p := range paths {
if err := idtools.MkdirAllAndChown(path.Join(a.rootPath(), p, id), 0755, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil { if err := idtools.MkdirAllAndChown(path.Join(a.rootPath(), p, id), 0755, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return err return err
} }
} }

View file

@ -72,7 +72,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := idtools.MkdirAllAndChown(home, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil { if err := idtools.MkdirAllAndChown(home, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return nil, err return nil, err
} }
@ -502,7 +502,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
if err != nil { if err != nil {
return err return err
} }
if err := idtools.MkdirAllAndChown(subvolumes, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil { if err := idtools.MkdirAllAndChown(subvolumes, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return err return err
} }
if parent == "" { if parent == "" {
@ -537,7 +537,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
if err := d.setStorageSize(path.Join(subvolumes, id), driver); err != nil { if err := d.setStorageSize(path.Join(subvolumes, id), driver); err != nil {
return err return err
} }
if err := idtools.MkdirAllAndChown(quotas, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil { if err := idtools.MkdirAllAndChown(quotas, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return err return err
} }
if err := ioutil.WriteFile(path.Join(quotas, id), []byte(fmt.Sprint(driver.options.size)), 0644); err != nil { if err := ioutil.WriteFile(path.Join(quotas, id), []byte(fmt.Sprint(driver.options.size)), 0644); err != nil {

View file

@ -268,7 +268,7 @@ func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
if err := idtools.MkdirAllAndChown(dirname, 0700, idtools.IDPair{UID: uid, GID: gid}); err != nil { if err := idtools.MkdirAllAndChown(dirname, 0700, idtools.Identity{UID: uid, GID: gid}); err != nil {
return "", err return "", err
} }
@ -1691,7 +1691,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) (retErr error) {
if err != nil { if err != nil {
return err return err
} }
if err := idtools.MkdirAndChown(devices.root, 0700, idtools.IDPair{UID: uid, GID: gid}); err != nil { if err := idtools.MkdirAndChown(devices.root, 0700, idtools.Identity{UID: uid, GID: gid}); err != nil {
return err return err
} }
if err := os.MkdirAll(devices.metadataDir(), 0700); err != nil { if err := os.MkdirAll(devices.metadataDir(), 0700); err != nil {

View file

@ -200,11 +200,11 @@ func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
} }
// Create the target directories if they don't exist // Create the target directories if they don't exist
if err := idtools.MkdirAllAndChown(path.Join(d.home, "mnt"), 0755, idtools.IDPair{UID: uid, GID: gid}); err != nil { if err := idtools.MkdirAllAndChown(path.Join(d.home, "mnt"), 0755, idtools.Identity{UID: uid, GID: gid}); err != nil {
d.ctr.Decrement(mp) d.ctr.Decrement(mp)
return nil, err return nil, err
} }
if err := idtools.MkdirAndChown(mp, 0755, idtools.IDPair{UID: uid, GID: gid}); err != nil && !os.IsExist(err) { if err := idtools.MkdirAndChown(mp, 0755, idtools.Identity{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
d.ctr.Decrement(mp) d.ctr.Decrement(mp)
return nil, err return nil, err
} }
@ -215,7 +215,7 @@ func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
return nil, err return nil, err
} }
if err := idtools.MkdirAllAndChown(rootFs, 0755, idtools.IDPair{UID: uid, GID: gid}); err != nil { if err := idtools.MkdirAllAndChown(rootFs, 0755, idtools.Identity{UID: uid, GID: gid}); err != nil {
d.ctr.Decrement(mp) d.ctr.Decrement(mp)
d.DeviceSet.UnmountDevice(id, mp) d.DeviceSet.UnmountDevice(id, mp)
return nil, err return nil, err

View file

@ -183,17 +183,17 @@ func InitDriver(dataRoot string, options []string, _, _ []idtools.IDMap) (graphd
} }
// Make sure the dataRoot directory is created // Make sure the dataRoot directory is created
if err := idtools.MkdirAllAndChown(dataRoot, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil { if err := idtools.MkdirAllAndChown(dataRoot, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
return nil, fmt.Errorf("%s failed to create '%s': %v", title, dataRoot, err) return nil, fmt.Errorf("%s failed to create '%s': %v", title, dataRoot, err)
} }
// Make sure the cache directory is created under dataRoot // Make sure the cache directory is created under dataRoot
if err := idtools.MkdirAllAndChown(cd, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil { if err := idtools.MkdirAllAndChown(cd, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
return nil, fmt.Errorf("%s failed to create '%s': %v", title, cd, err) return nil, fmt.Errorf("%s failed to create '%s': %v", title, cd, err)
} }
// Make sure the scratch directory is created under dataRoot // Make sure the scratch directory is created under dataRoot
if err := idtools.MkdirAllAndChown(sd, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil { if err := idtools.MkdirAllAndChown(sd, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
return nil, fmt.Errorf("%s failed to create '%s': %v", title, sd, err) return nil, fmt.Errorf("%s failed to create '%s': %v", title, sd, err)
} }

View file

@ -168,7 +168,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, err return nil, err
} }
// Create the driver home dir // Create the driver home dir
if err := idtools.MkdirAllAndChown(home, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil { if err := idtools.MkdirAllAndChown(home, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return nil, err return nil, err
} }
@ -291,7 +291,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr
if err != nil { if err != nil {
return err return err
} }
root := idtools.IDPair{UID: rootUID, GID: rootGID} root := idtools.Identity{UID: rootUID, GID: rootGID}
if err := idtools.MkdirAllAndChown(path.Dir(dir), 0700, root); err != nil { if err := idtools.MkdirAllAndChown(path.Dir(dir), 0700, root); err != nil {
return err return err
@ -413,7 +413,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, err erro
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil { if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return nil, err return nil, err
} }
var ( var (

View file

@ -200,7 +200,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, err return nil, err
} }
// Create the driver home dir // Create the driver home dir
if err := idtools.MkdirAllAndChown(path.Join(home, linkDir), 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil { if err := idtools.MkdirAllAndChown(path.Join(home, linkDir), 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return nil, err return nil, err
} }
@ -378,7 +378,7 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr
if err != nil { if err != nil {
return err return err
} }
root := idtools.IDPair{UID: rootUID, GID: rootGID} root := idtools.Identity{UID: rootUID, GID: rootGID}
if err := idtools.MkdirAllAndChown(path.Dir(dir), 0700, root); err != nil { if err := idtools.MkdirAllAndChown(path.Dir(dir), 0700, root); err != nil {
return err return err
@ -586,7 +586,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil { if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return nil, err return nil, err
} }

View file

@ -27,10 +27,10 @@ func init() {
// This sets the home directory for the driver and returns NaiveDiffDriver. // This sets the home directory for the driver and returns NaiveDiffDriver.
func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
d := &Driver{ d := &Driver{
home: home, home: home,
idMappings: idtools.NewIDMappingsFromMaps(uidMaps, gidMaps), idMapping: idtools.NewIDMappingsFromMaps(uidMaps, gidMaps),
} }
rootIDs := d.idMappings.RootPair() rootIDs := d.idMapping.RootPair()
if err := idtools.MkdirAllAndChown(home, 0700, rootIDs); err != nil { if err := idtools.MkdirAllAndChown(home, 0700, rootIDs); err != nil {
return nil, err return nil, err
} }
@ -46,8 +46,8 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
// Driver must be wrapped in NaiveDiffDriver to be used as a graphdriver.Driver // Driver must be wrapped in NaiveDiffDriver to be used as a graphdriver.Driver
type Driver struct { type Driver struct {
driverQuota driverQuota
home string home string
idMappings *idtools.IDMappings idMapping *idtools.IdentityMapping
} }
func (d *Driver) String() string { func (d *Driver) String() string {
@ -105,7 +105,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
func (d *Driver) create(id, parent string, size uint64) error { func (d *Driver) create(id, parent string, size uint64) error {
dir := d.dir(id) dir := d.dir(id)
rootIDs := d.idMappings.RootPair() rootIDs := d.idMapping.RootPair()
if err := idtools.MkdirAllAndChown(filepath.Dir(dir), 0700, rootIDs); err != nil { if err := idtools.MkdirAllAndChown(filepath.Dir(dir), 0700, rootIDs); err != nil {
return err return err
} }

View file

@ -95,7 +95,7 @@ func InitFilter(home string, options []string, uidMaps, gidMaps []idtools.IDMap)
return nil, fmt.Errorf("%s is on an ReFS volume - ReFS volumes are not supported", home) return nil, fmt.Errorf("%s is on an ReFS volume - ReFS volumes are not supported", home)
} }
if err := idtools.MkdirAllAndChown(home, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil { if err := idtools.MkdirAllAndChown(home, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
return nil, fmt.Errorf("windowsfilter failed to create '%s': %v", home, err) return nil, fmt.Errorf("windowsfilter failed to create '%s': %v", home, err)
} }

View file

@ -106,7 +106,7 @@ func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdri
if err != nil { if err != nil {
return nil, fmt.Errorf("Failed to get root uid/guid: %v", err) return nil, fmt.Errorf("Failed to get root uid/guid: %v", err)
} }
if err := idtools.MkdirAllAndChown(base, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil { if err := idtools.MkdirAllAndChown(base, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return nil, fmt.Errorf("Failed to create '%s': %v", base, err) return nil, fmt.Errorf("Failed to create '%s': %v", base, err)
} }
@ -385,7 +385,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
return nil, err return nil, err
} }
// Create the target directories if they don't exist // Create the target directories if they don't exist
if err := idtools.MkdirAllAndChown(mountpoint, 0755, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil { if err := idtools.MkdirAllAndChown(mountpoint, 0755, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return nil, err return nil, err
} }

View file

@ -162,7 +162,7 @@ func (daemon *Daemon) fillSecurityOptions(v *types.Info, sysInfo *sysinfo.SysInf
if selinuxEnabled() { if selinuxEnabled() {
securityOptions = append(securityOptions, "name=selinux") securityOptions = append(securityOptions, "name=selinux")
} }
if rootIDs := daemon.idMappings.RootPair(); rootIDs.UID != 0 || rootIDs.GID != 0 { if rootIDs := daemon.idMapping.RootPair(); rootIDs.UID != 0 || rootIDs.GID != 0 {
securityOptions = append(securityOptions, "name=userns") securityOptions = append(securityOptions, "name=userns")
} }
v.SecurityOptions = securityOptions v.SecurityOptions = securityOptions

View file

@ -17,7 +17,7 @@ import (
// //
// This extra layer is used by all containers as the top-most ro layer. It protects // This extra layer is used by all containers as the top-most ro layer. It protects
// the container from unwanted side-effects on the rw layer. // the container from unwanted side-effects on the rw layer.
func Setup(initLayerFs containerfs.ContainerFS, rootIDs idtools.IDPair) error { func Setup(initLayerFs containerfs.ContainerFS, rootIdentity idtools.Identity) error {
// Since all paths are local to the container, we can just extract initLayerFs.Path() // Since all paths are local to the container, we can just extract initLayerFs.Path()
initLayer := initLayerFs.Path() initLayer := initLayerFs.Path()
@ -42,12 +42,12 @@ func Setup(initLayerFs containerfs.ContainerFS, rootIDs idtools.IDPair) error {
if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil { if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootIDs); err != nil { if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootIdentity); err != nil {
return err return err
} }
switch typ { switch typ {
case "dir": case "dir":
if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, pth), 0755, rootIDs); err != nil { if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, pth), 0755, rootIdentity); err != nil {
return err return err
} }
case "file": case "file":
@ -55,7 +55,7 @@ func Setup(initLayerFs containerfs.ContainerFS, rootIDs idtools.IDPair) error {
if err != nil { if err != nil {
return err return err
} }
f.Chown(rootIDs.UID, rootIDs.GID) f.Chown(rootIdentity.UID, rootIdentity.GID)
f.Close() f.Close()
default: default:
if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil { if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil {

View file

@ -11,6 +11,6 @@ import (
// //
// This extra layer is used by all containers as the top-most ro layer. It protects // This extra layer is used by all containers as the top-most ro layer. It protects
// the container from unwanted side-effects on the rw layer. // the container from unwanted side-effects on the rw layer.
func Setup(initLayer containerfs.ContainerFS, rootIDs idtools.IDPair) error { func Setup(initLayer containerfs.ContainerFS, rootIDs idtools.Identity) error {
return nil return nil
} }

View file

@ -217,13 +217,13 @@ func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error
userNS := false userNS := false
// user // user
if c.HostConfig.UsernsMode.IsPrivate() { if c.HostConfig.UsernsMode.IsPrivate() {
uidMap := daemon.idMappings.UIDs() uidMap := daemon.idMapping.UIDs()
if uidMap != nil { if uidMap != nil {
userNS = true userNS = true
ns := specs.LinuxNamespace{Type: "user"} ns := specs.LinuxNamespace{Type: "user"}
setNamespace(s, ns) setNamespace(s, ns)
s.Linux.UIDMappings = specMapping(uidMap) s.Linux.UIDMappings = specMapping(uidMap)
s.Linux.GIDMappings = specMapping(daemon.idMappings.GIDs()) s.Linux.GIDMappings = specMapping(daemon.idMapping.GIDs())
} }
} }
// network // network
@ -619,7 +619,7 @@ func setMounts(daemon *Daemon, s *specs.Spec, c *container.Container, mounts []c
// TODO: until a kernel/mount solution exists for handling remount in a user namespace, // TODO: until a kernel/mount solution exists for handling remount in a user namespace,
// we must clear the readonly flag for the cgroups mount (@mrunalp concurs) // we must clear the readonly flag for the cgroups mount (@mrunalp concurs)
if uidMap := daemon.idMappings.UIDs(); uidMap != nil || c.HostConfig.Privileged { if uidMap := daemon.idMapping.UIDs(); uidMap != nil || c.HostConfig.Privileged {
for i, m := range s.Mounts { for i, m := range s.Mounts {
if m.Type == "cgroup" { if m.Type == "cgroup" {
clearReadOnly(&s.Mounts[i]) clearReadOnly(&s.Mounts[i])
@ -642,7 +642,7 @@ func (daemon *Daemon) populateCommonSpec(s *specs.Spec, c *container.Container)
Path: c.BaseFS.Path(), Path: c.BaseFS.Path(),
Readonly: c.HostConfig.ReadonlyRootfs, Readonly: c.HostConfig.ReadonlyRootfs,
} }
if err := c.SetupWorkingDirectory(daemon.idMappings.RootPair()); err != nil { if err := c.SetupWorkingDirectory(daemon.idMapping.RootPair()); err != nil {
return err return err
} }
cwd := c.Config.WorkingDir cwd := c.Config.WorkingDir

View file

@ -21,7 +21,7 @@ func TestTmpfsDevShmNoDupMount(t *testing.T) {
d := Daemon{ d := Daemon{
// some empty structs to avoid getting a panic // some empty structs to avoid getting a panic
// caused by a null pointer dereference // caused by a null pointer dereference
idMappings: &idtools.IDMappings{}, idMapping: &idtools.IdentityMapping{},
configStore: &config.Config{}, configStore: &config.Config{},
} }
c := &container.Container{ c := &container.Container{
@ -58,7 +58,7 @@ func TestIpcPrivateVsReadonly(t *testing.T) {
d := Daemon{ d := Daemon{
// some empty structs to avoid getting a panic // some empty structs to avoid getting a panic
// caused by a null pointer dereference // caused by a null pointer dereference
idMappings: &idtools.IDMappings{}, idMapping: &idtools.IdentityMapping{},
configStore: &config.Config{}, configStore: &config.Config{},
} }
c := &container.Container{ c := &container.Container{

View file

@ -47,7 +47,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er
return nil return nil
} }
path, err := m.Setup(c.MountLabel, daemon.idMappings.RootPair(), checkfunc) path, err := m.Setup(c.MountLabel, daemon.idMapping.RootPair(), checkfunc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -77,7 +77,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er
// if we are going to mount any of the network files from container // if we are going to mount any of the network files from container
// metadata, the ownership must be set properly for potential container // metadata, the ownership must be set properly for potential container
// remapped root (user namespaces) // remapped root (user namespaces)
rootIDs := daemon.idMappings.RootPair() rootIDs := daemon.idMapping.RootPair()
for _, mount := range netMounts { for _, mount := range netMounts {
// we should only modify ownership of network files within our own container // we should only modify ownership of network files within our own container
// metadata repository. If the user specifies a mount path external, it is // metadata repository. If the user specifies a mount path external, it is

View file

@ -24,7 +24,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er
if err := daemon.lazyInitializeVolume(c.ID, mount); err != nil { if err := daemon.lazyInitializeVolume(c.ID, mount); err != nil {
return nil, err return nil, err
} }
s, err := mount.Setup(c.MountLabel, idtools.IDPair{UID: 0, GID: 0}, nil) s, err := mount.Setup(c.MountLabel, idtools.Identity{}, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -16,5 +16,5 @@ func (daemon *Daemon) ContainerCreateWorkdir(cID string) error {
return err return err
} }
defer daemon.Unmount(container) defer daemon.Unmount(container)
return container.SetupWorkingDirectory(daemon.idMappings.RootPair()) return container.SetupWorkingDirectory(daemon.idMapping.RootPair())
} }

View file

@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -e
CONTAINER_UTILITY_COMMIT=e004a1415a433447369e315b9d7df357102be0d2 # v0.9.0
(
git clone https://github.com/docker/windows-container-utility.git "$GOPATH/src/github.com/docker/windows-container-utility"
cd "$GOPATH/src/github.com/docker/windows-container-utility"
git checkout -q "$CONTAINER_UTILITY_COMMIT"
echo Building: ${DEST}/containerutility.exe
(
make
)
mkdir -p ${ABS_DEST}
cp containerutility.exe ${ABS_DEST}/containerutility.exe
)

View file

@ -25,5 +25,7 @@ for platform in $DOCKER_CROSSPLATFORMS; do
mkdir -p "$DEST" mkdir -p "$DEST"
ABS_DEST="$(cd "$DEST" && pwd -P)" ABS_DEST="$(cd "$DEST" && pwd -P)"
source "${MAKEDIR}/binary-daemon" source "${MAKEDIR}/binary-daemon"
source "${MAKEDIR}/cross-platform-dependent"
) )
done done

View file

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -e
if [ $platform == "windows/amd64" ]; then
source "${MAKEDIR}/containerutility"
fi

View file

@ -45,7 +45,7 @@ type StoreOptions struct {
MetadataStorePathTemplate string MetadataStorePathTemplate string
GraphDriver string GraphDriver string
GraphDriverOptions []string GraphDriverOptions []string
IDMappings *idtools.IDMappings IDMapping *idtools.IdentityMapping
PluginGetter plugingetter.PluginGetter PluginGetter plugingetter.PluginGetter
ExperimentalEnabled bool ExperimentalEnabled bool
OS string OS string
@ -56,8 +56,8 @@ func NewStoreFromOptions(options StoreOptions) (Store, error) {
driver, err := graphdriver.New(options.GraphDriver, options.PluginGetter, graphdriver.Options{ driver, err := graphdriver.New(options.GraphDriver, options.PluginGetter, graphdriver.Options{
Root: options.Root, Root: options.Root,
DriverOptions: options.GraphDriverOptions, DriverOptions: options.GraphDriverOptions,
UIDMaps: options.IDMappings.UIDs(), UIDMaps: options.IDMapping.UIDs(),
GIDMaps: options.IDMappings.GIDs(), GIDMaps: options.IDMapping.GIDs(),
ExperimentalEnabled: options.ExperimentalEnabled, ExperimentalEnabled: options.ExperimentalEnabled,
}) })
if err != nil { if err != nil {

View file

@ -58,7 +58,7 @@ func getSpecUser(ociSpec *specs.Spec) (int, int) {
func prepareBundleDir(bundleDir string, ociSpec *specs.Spec) (string, error) { func prepareBundleDir(bundleDir string, ociSpec *specs.Spec) (string, error) {
uid, gid := getSpecUser(ociSpec) uid, gid := getSpecUser(ociSpec)
if uid == 0 && gid == 0 { if uid == 0 && gid == 0 {
return bundleDir, idtools.MkdirAllAndChownNew(bundleDir, 0755, idtools.IDPair{UID: 0, GID: 0}) return bundleDir, idtools.MkdirAllAndChownNew(bundleDir, 0755, idtools.Identity{UID: 0, GID: 0})
} }
p := string(filepath.Separator) p := string(filepath.Separator)
@ -71,7 +71,7 @@ func prepareBundleDir(bundleDir string, ociSpec *specs.Spec) (string, error) {
} }
if os.IsNotExist(err) || fi.Mode()&1 == 0 { if os.IsNotExist(err) || fi.Mode()&1 == 0 {
p = fmt.Sprintf("%s.%d.%d", p, uid, gid) p = fmt.Sprintf("%s.%d.%d", p, uid, gid)
if err := idtools.MkdirAndChown(p, 0700, idtools.IDPair{UID: uid, GID: gid}); err != nil && !os.IsExist(err) { if err := idtools.MkdirAndChown(p, 0700, idtools.Identity{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
return "", err return "", err
} }
} }

View file

@ -52,7 +52,7 @@ type (
NoLchown bool NoLchown bool
UIDMaps []idtools.IDMap UIDMaps []idtools.IDMap
GIDMaps []idtools.IDMap GIDMaps []idtools.IDMap
ChownOpts *idtools.IDPair ChownOpts *idtools.Identity
IncludeSourceDir bool IncludeSourceDir bool
// WhiteoutFormat is the expected on disk format for whiteout files. // WhiteoutFormat is the expected on disk format for whiteout files.
// This format will be converted to the standard format on pack // This format will be converted to the standard format on pack
@ -72,13 +72,13 @@ type (
// this package with a pluggable Untar function. Also, to facilitate the passing of specific id // this package with a pluggable Untar function. Also, to facilitate the passing of specific id
// mappings for untar, an Archiver can be created with maps which will then be passed to Untar operations. // mappings for untar, an Archiver can be created with maps which will then be passed to Untar operations.
type Archiver struct { type Archiver struct {
Untar func(io.Reader, string, *TarOptions) error Untar func(io.Reader, string, *TarOptions) error
IDMappingsVar *idtools.IDMappings IDMapping *idtools.IdentityMapping
} }
// NewDefaultArchiver returns a new Archiver without any IDMappings // NewDefaultArchiver returns a new Archiver without any IdentityMapping
func NewDefaultArchiver() *Archiver { func NewDefaultArchiver() *Archiver {
return &Archiver{Untar: Untar, IDMappingsVar: &idtools.IDMappings{}} return &Archiver{Untar: Untar, IDMapping: &idtools.IdentityMapping{}}
} }
// breakoutError is used to differentiate errors related to breaking out // breakoutError is used to differentiate errors related to breaking out
@ -420,9 +420,9 @@ type tarAppender struct {
Buffer *bufio.Writer Buffer *bufio.Writer
// for hardlink mapping // for hardlink mapping
SeenFiles map[uint64]string SeenFiles map[uint64]string
IDMappings *idtools.IDMappings IdentityMapping *idtools.IdentityMapping
ChownOpts *idtools.IDPair ChownOpts *idtools.Identity
// For packing and unpacking whiteout files in the // For packing and unpacking whiteout files in the
// non standard format. The whiteout files defined // non standard format. The whiteout files defined
@ -431,13 +431,13 @@ type tarAppender struct {
WhiteoutConverter tarWhiteoutConverter WhiteoutConverter tarWhiteoutConverter
} }
func newTarAppender(idMapping *idtools.IDMappings, writer io.Writer, chownOpts *idtools.IDPair) *tarAppender { func newTarAppender(idMapping *idtools.IdentityMapping, writer io.Writer, chownOpts *idtools.Identity) *tarAppender {
return &tarAppender{ return &tarAppender{
SeenFiles: make(map[uint64]string), SeenFiles: make(map[uint64]string),
TarWriter: tar.NewWriter(writer), TarWriter: tar.NewWriter(writer),
Buffer: pools.BufioWriter32KPool.Get(nil), Buffer: pools.BufioWriter32KPool.Get(nil),
IDMappings: idMapping, IdentityMapping: idMapping,
ChownOpts: chownOpts, ChownOpts: chownOpts,
} }
} }
@ -502,14 +502,12 @@ func (ta *tarAppender) addTarFile(path, name string) error {
//handle re-mapping container ID mappings back to host ID mappings before //handle re-mapping container ID mappings back to host ID mappings before
//writing tar headers/files. We skip whiteout files because they were written //writing tar headers/files. We skip whiteout files because they were written
//by the kernel and already have proper ownership relative to the host //by the kernel and already have proper ownership relative to the host
if !isOverlayWhiteout && if !isOverlayWhiteout && !strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) && !ta.IdentityMapping.Empty() {
!strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) &&
!ta.IDMappings.Empty() {
fileIDPair, err := getFileUIDGID(fi.Sys()) fileIDPair, err := getFileUIDGID(fi.Sys())
if err != nil { if err != nil {
return err return err
} }
hdr.Uid, hdr.Gid, err = ta.IDMappings.ToContainer(fileIDPair) hdr.Uid, hdr.Gid, err = ta.IdentityMapping.ToContainer(fileIDPair)
if err != nil { if err != nil {
return err return err
} }
@ -572,7 +570,7 @@ func (ta *tarAppender) addTarFile(path, name string) error {
return nil return nil
} }
func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *idtools.IDPair, inUserns bool) error { func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *idtools.Identity, inUserns bool) error {
// hdr.Mode is in linux format, which we can use for sycalls, // hdr.Mode is in linux format, which we can use for sycalls,
// but for os.Foo() calls we need the mode converted to os.FileMode, // but for os.Foo() calls we need the mode converted to os.FileMode,
// so use hdrInfo.Mode() (they differ for e.g. setuid bits) // so use hdrInfo.Mode() (they differ for e.g. setuid bits)
@ -652,7 +650,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
// Lchown is not supported on Windows. // Lchown is not supported on Windows.
if Lchown && runtime.GOOS != "windows" { if Lchown && runtime.GOOS != "windows" {
if chownOpts == nil { if chownOpts == nil {
chownOpts = &idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid} chownOpts = &idtools.Identity{UID: hdr.Uid, GID: hdr.Gid}
} }
if err := os.Lchown(path, chownOpts.UID, chownOpts.GID); err != nil { if err := os.Lchown(path, chownOpts.UID, chownOpts.GID); err != nil {
return err return err
@ -901,8 +899,8 @@ func Unpack(decompressedArchive io.Reader, dest string, options *TarOptions) err
defer pools.BufioReader32KPool.Put(trBuf) defer pools.BufioReader32KPool.Put(trBuf)
var dirs []*tar.Header var dirs []*tar.Header
idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps) idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
rootIDs := idMappings.RootPair() rootIDs := idMapping.RootPair()
whiteoutConverter := getWhiteoutConverter(options.WhiteoutFormat) whiteoutConverter := getWhiteoutConverter(options.WhiteoutFormat)
// Iterate through the files in the archive. // Iterate through the files in the archive.
@ -981,7 +979,7 @@ loop:
} }
trBuf.Reset(tr) trBuf.Reset(tr)
if err := remapIDs(idMappings, hdr); err != nil { if err := remapIDs(idMapping, hdr); err != nil {
return err return err
} }
@ -1068,8 +1066,8 @@ func (archiver *Archiver) TarUntar(src, dst string) error {
} }
defer archive.Close() defer archive.Close()
options := &TarOptions{ options := &TarOptions{
UIDMaps: archiver.IDMappingsVar.UIDs(), UIDMaps: archiver.IDMapping.UIDs(),
GIDMaps: archiver.IDMappingsVar.GIDs(), GIDMaps: archiver.IDMapping.GIDs(),
} }
return archiver.Untar(archive, dst, options) return archiver.Untar(archive, dst, options)
} }
@ -1082,8 +1080,8 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
} }
defer archive.Close() defer archive.Close()
options := &TarOptions{ options := &TarOptions{
UIDMaps: archiver.IDMappingsVar.UIDs(), UIDMaps: archiver.IDMapping.UIDs(),
GIDMaps: archiver.IDMappingsVar.GIDs(), GIDMaps: archiver.IDMapping.GIDs(),
} }
return archiver.Untar(archive, dst, options) return archiver.Untar(archive, dst, options)
} }
@ -1104,7 +1102,7 @@ func (archiver *Archiver) CopyWithTar(src, dst string) error {
// if this Archiver is set up with ID mapping we need to create // if this Archiver is set up with ID mapping we need to create
// the new destination directory with the remapped root UID/GID pair // the new destination directory with the remapped root UID/GID pair
// as owner // as owner
rootIDs := archiver.IDMappingsVar.RootPair() rootIDs := archiver.IDMapping.RootPair()
// Create dst, copy src's content into it // Create dst, copy src's content into it
logrus.Debugf("Creating dest directory: %s", dst) logrus.Debugf("Creating dest directory: %s", dst)
if err := idtools.MkdirAllAndChownNew(dst, 0755, rootIDs); err != nil { if err := idtools.MkdirAllAndChownNew(dst, 0755, rootIDs); err != nil {
@ -1164,7 +1162,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
hdr.Name = filepath.Base(dst) hdr.Name = filepath.Base(dst)
hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode))) hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
if err := remapIDs(archiver.IDMappingsVar, hdr); err != nil { if err := remapIDs(archiver.IDMapping, hdr); err != nil {
return err return err
} }
@ -1192,13 +1190,13 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
return err return err
} }
// IDMappings returns the IDMappings of the archiver. // IdentityMapping returns the IdentityMapping of the archiver.
func (archiver *Archiver) IDMappings() *idtools.IDMappings { func (archiver *Archiver) IdentityMapping() *idtools.IdentityMapping {
return archiver.IDMappingsVar return archiver.IDMapping
} }
func remapIDs(idMappings *idtools.IDMappings, hdr *tar.Header) error { func remapIDs(idMapping *idtools.IdentityMapping, hdr *tar.Header) error {
ids, err := idMappings.ToHost(idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid}) ids, err := idMapping.ToHost(idtools.Identity{UID: hdr.Uid, GID: hdr.Gid})
hdr.Uid, hdr.Gid = ids.UID, ids.GID hdr.Uid, hdr.Gid = ids.UID, ids.GID
return err return err
} }

View file

@ -755,11 +755,11 @@ func TestTarWithOptionsChownOptsAlwaysOverridesIdPair(t *testing.T) {
expectedUID int expectedUID int
expectedGID int expectedGID int
}{ }{
{&TarOptions{ChownOpts: &idtools.IDPair{UID: 1337, GID: 42}}, 1337, 42}, {&TarOptions{ChownOpts: &idtools.Identity{UID: 1337, GID: 42}}, 1337, 42},
{&TarOptions{ChownOpts: &idtools.IDPair{UID: 100001, GID: 100001}, UIDMaps: idMaps, GIDMaps: idMaps}, 100001, 100001}, {&TarOptions{ChownOpts: &idtools.Identity{UID: 100001, GID: 100001}, UIDMaps: idMaps, GIDMaps: idMaps}, 100001, 100001},
{&TarOptions{ChownOpts: &idtools.IDPair{UID: 0, GID: 0}, NoLchown: false}, 0, 0}, {&TarOptions{ChownOpts: &idtools.Identity{UID: 0, GID: 0}, NoLchown: false}, 0, 0},
{&TarOptions{ChownOpts: &idtools.IDPair{UID: 1, GID: 1}, NoLchown: true}, 1, 1}, {&TarOptions{ChownOpts: &idtools.Identity{UID: 1, GID: 1}, NoLchown: true}, 1, 1},
{&TarOptions{ChownOpts: &idtools.IDPair{UID: 1000, GID: 1000}, NoLchown: true}, 1000, 1000}, {&TarOptions{ChownOpts: &idtools.Identity{UID: 1000, GID: 1000}, NoLchown: true}, 1000, 1000},
} }
for _, testCase := range cases { for _, testCase := range cases {
reader, err := TarWithOptions(filePath, testCase.opts) reader, err := TarWithOptions(filePath, testCase.opts)

View file

@ -68,13 +68,13 @@ func getInodeFromStat(stat interface{}) (inode uint64, err error) {
return return
} }
func getFileUIDGID(stat interface{}) (idtools.IDPair, error) { func getFileUIDGID(stat interface{}) (idtools.Identity, error) {
s, ok := stat.(*syscall.Stat_t) s, ok := stat.(*syscall.Stat_t)
if !ok { if !ok {
return idtools.IDPair{}, errors.New("cannot convert stat value to syscall.Stat_t") return idtools.Identity{}, errors.New("cannot convert stat value to syscall.Stat_t")
} }
return idtools.IDPair{UID: int(s.Uid), GID: int(s.Gid)}, nil return idtools.Identity{UID: int(s.Uid), GID: int(s.Gid)}, nil
} }
// handleTarTypeBlockCharFifo is an OS-specific helper function used by // handleTarTypeBlockCharFifo is an OS-specific helper function used by

View file

@ -61,7 +61,7 @@ func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
return nil return nil
} }
func getFileUIDGID(stat interface{}) (idtools.IDPair, error) { func getFileUIDGID(stat interface{}) (idtools.Identity, error) {
// no notion of file ownership mapping yet on Windows // no notion of file ownership mapping yet on Windows
return idtools.IDPair{UID: 0, GID: 0}, nil return idtools.Identity{UID: 0, GID: 0}, nil
} }

View file

@ -33,7 +33,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
if options.ExcludePatterns == nil { if options.ExcludePatterns == nil {
options.ExcludePatterns = []string{} options.ExcludePatterns = []string{}
} }
idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps) idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
aufsTempdir := "" aufsTempdir := ""
aufsHardlinks := make(map[string]*tar.Header) aufsHardlinks := make(map[string]*tar.Header)
@ -192,7 +192,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
srcData = tmpFile srcData = tmpFile
} }
if err := remapIDs(idMappings, srcHdr); err != nil { if err := remapIDs(idMapping, srcHdr); err != nil {
return 0, err return 0, err
} }

View file

@ -12,13 +12,13 @@ import (
) )
// NewArchiver returns a new Archiver which uses chrootarchive.Untar // NewArchiver returns a new Archiver which uses chrootarchive.Untar
func NewArchiver(idMappings *idtools.IDMappings) *archive.Archiver { func NewArchiver(idMapping *idtools.IdentityMapping) *archive.Archiver {
if idMappings == nil { if idMapping == nil {
idMappings = &idtools.IDMappings{} idMapping = &idtools.IdentityMapping{}
} }
return &archive.Archiver{ return &archive.Archiver{
Untar: Untar, Untar: Untar,
IDMappingsVar: idMappings, IDMapping: idMapping,
} }
} }
@ -49,8 +49,8 @@ func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions
options.ExcludePatterns = []string{} options.ExcludePatterns = []string{}
} }
idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps) idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
rootIDs := idMappings.RootPair() rootIDs := idMapping.RootPair()
dest = filepath.Clean(dest) dest = filepath.Clean(dest)
if _, err := os.Stat(dest); os.IsNotExist(err) { if _, err := os.Stat(dest); os.IsNotExist(err) {

View file

@ -22,11 +22,11 @@ type UntarFunc func(io.Reader, string, *archive.TarOptions) error
// Archiver provides a similar implementation of the archive.Archiver package with the rootfs abstraction // Archiver provides a similar implementation of the archive.Archiver package with the rootfs abstraction
type Archiver struct { type Archiver struct {
SrcDriver Driver SrcDriver Driver
DstDriver Driver DstDriver Driver
Tar TarFunc Tar TarFunc
Untar UntarFunc Untar UntarFunc
IDMappingsVar *idtools.IDMappings IDMapping *idtools.IdentityMapping
} }
// TarUntar is a convenience function which calls Tar and Untar, with the output of one piped into the other. // TarUntar is a convenience function which calls Tar and Untar, with the output of one piped into the other.
@ -39,8 +39,8 @@ func (archiver *Archiver) TarUntar(src, dst string) error {
} }
defer tarArchive.Close() defer tarArchive.Close()
options := &archive.TarOptions{ options := &archive.TarOptions{
UIDMaps: archiver.IDMappingsVar.UIDs(), UIDMaps: archiver.IDMapping.UIDs(),
GIDMaps: archiver.IDMappingsVar.GIDs(), GIDMaps: archiver.IDMapping.GIDs(),
} }
return archiver.Untar(tarArchive, dst, options) return archiver.Untar(tarArchive, dst, options)
} }
@ -53,8 +53,8 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
} }
defer tarArchive.Close() defer tarArchive.Close()
options := &archive.TarOptions{ options := &archive.TarOptions{
UIDMaps: archiver.IDMappingsVar.UIDs(), UIDMaps: archiver.IDMapping.UIDs(),
GIDMaps: archiver.IDMappingsVar.GIDs(), GIDMaps: archiver.IDMapping.GIDs(),
} }
return archiver.Untar(tarArchive, dst, options) return archiver.Untar(tarArchive, dst, options)
} }
@ -75,9 +75,11 @@ func (archiver *Archiver) CopyWithTar(src, dst string) error {
// if this archiver is set up with ID mapping we need to create // if this archiver is set up with ID mapping we need to create
// the new destination directory with the remapped root UID/GID pair // the new destination directory with the remapped root UID/GID pair
// as owner // as owner
rootIDs := archiver.IDMappingsVar.RootPair()
identity := idtools.Identity{UID: archiver.IDMapping.RootPair().UID, GID: archiver.IDMapping.RootPair().GID}
// Create dst, copy src's content into it // Create dst, copy src's content into it
if err := idtools.MkdirAllAndChownNew(dst, 0755, rootIDs); err != nil { if err := idtools.MkdirAllAndChownNew(dst, 0755, identity); err != nil {
return err return err
} }
logrus.Debugf("Calling TarUntar(%s, %s)", src, dst) logrus.Debugf("Calling TarUntar(%s, %s)", src, dst)
@ -150,7 +152,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
hdr.Mode = int64(os.FileMode(hdr.Mode)) hdr.Mode = int64(os.FileMode(hdr.Mode))
} }
if err := remapIDs(archiver.IDMappingsVar, hdr); err != nil { if err := remapIDs(archiver.IDMapping, hdr); err != nil {
return err return err
} }
@ -178,13 +180,13 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
return err return err
} }
// IDMappings returns the IDMappings of the archiver. // IdentityMapping returns the IdentityMapping of the archiver.
func (archiver *Archiver) IDMappings() *idtools.IDMappings { func (archiver *Archiver) IdentityMapping() *idtools.IdentityMapping {
return archiver.IDMappingsVar return archiver.IDMapping
} }
func remapIDs(idMappings *idtools.IDMappings, hdr *tar.Header) error { func remapIDs(idMapping *idtools.IdentityMapping, hdr *tar.Header) error {
ids, err := idMappings.ToHost(idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid}) ids, err := idMapping.ToHost(idtools.Identity{UID: hdr.Uid, GID: hdr.Gid})
hdr.Uid, hdr.Gid = ids.UID, ids.GID hdr.Uid, hdr.Gid = ids.UID, ids.GID
return err return err
} }

View file

@ -37,23 +37,23 @@ const (
// MkdirAllAndChown creates a directory (include any along the path) and then modifies // MkdirAllAndChown creates a directory (include any along the path) and then modifies
// ownership to the requested uid/gid. If the directory already exists, this // ownership to the requested uid/gid. If the directory already exists, this
// function will still change ownership to the requested uid/gid pair. // function will still change ownership to the requested uid/gid pair.
func MkdirAllAndChown(path string, mode os.FileMode, owner IDPair) error { func MkdirAllAndChown(path string, mode os.FileMode, owner Identity) error {
return mkdirAs(path, mode, owner.UID, owner.GID, true, true) return mkdirAs(path, mode, owner, true, true)
} }
// MkdirAndChown creates a directory and then modifies ownership to the requested uid/gid. // MkdirAndChown creates a directory and then modifies ownership to the requested uid/gid.
// If the directory already exists, this function still changes ownership. // If the directory already exists, this function still changes ownership.
// Note that unlike os.Mkdir(), this function does not return IsExist error // Note that unlike os.Mkdir(), this function does not return IsExist error
// in case path already exists. // in case path already exists.
func MkdirAndChown(path string, mode os.FileMode, owner IDPair) error { func MkdirAndChown(path string, mode os.FileMode, owner Identity) error {
return mkdirAs(path, mode, owner.UID, owner.GID, false, true) return mkdirAs(path, mode, owner, false, true)
} }
// MkdirAllAndChownNew creates a directory (include any along the path) and then modifies // MkdirAllAndChownNew creates a directory (include any along the path) and then modifies
// ownership ONLY of newly created directories to the requested uid/gid. If the // ownership ONLY of newly created directories to the requested uid/gid. If the
// directories along the path exist, no change of ownership will be performed // directories along the path exist, no change of ownership will be performed
func MkdirAllAndChownNew(path string, mode os.FileMode, owner IDPair) error { func MkdirAllAndChownNew(path string, mode os.FileMode, owner Identity) error {
return mkdirAs(path, mode, owner.UID, owner.GID, true, false) return mkdirAs(path, mode, owner, true, false)
} }
// GetRootUIDGID retrieves the remapped root uid/gid pair from the set of maps. // GetRootUIDGID retrieves the remapped root uid/gid pair from the set of maps.
@ -102,22 +102,23 @@ func toHost(contID int, idMap []IDMap) (int, error) {
return -1, fmt.Errorf("Container ID %d cannot be mapped to a host ID", contID) return -1, fmt.Errorf("Container ID %d cannot be mapped to a host ID", contID)
} }
// IDPair is a UID and GID pair // Identity is either a UID and GID pair or a SID (but not both)
type IDPair struct { type Identity struct {
UID int UID int
GID int GID int
SID string
} }
// IDMappings contains a mappings of UIDs and GIDs // IdentityMapping contains a mappings of UIDs and GIDs
type IDMappings struct { type IdentityMapping struct {
uids []IDMap uids []IDMap
gids []IDMap gids []IDMap
} }
// NewIDMappings takes a requested user and group name and // NewIdentityMapping takes a requested user and group name and
// using the data from /etc/sub{uid,gid} ranges, creates the // using the data from /etc/sub{uid,gid} ranges, creates the
// proper uid and gid remapping ranges for that user/group pair // proper uid and gid remapping ranges for that user/group pair
func NewIDMappings(username, groupname string) (*IDMappings, error) { func NewIdentityMapping(username, groupname string) (*IdentityMapping, error) {
subuidRanges, err := parseSubuid(username) subuidRanges, err := parseSubuid(username)
if err != nil { if err != nil {
return nil, err return nil, err
@ -133,7 +134,7 @@ func NewIDMappings(username, groupname string) (*IDMappings, error) {
return nil, fmt.Errorf("No subgid ranges found for group %q", groupname) return nil, fmt.Errorf("No subgid ranges found for group %q", groupname)
} }
return &IDMappings{ return &IdentityMapping{
uids: createIDMap(subuidRanges), uids: createIDMap(subuidRanges),
gids: createIDMap(subgidRanges), gids: createIDMap(subgidRanges),
}, nil }, nil
@ -141,21 +142,21 @@ func NewIDMappings(username, groupname string) (*IDMappings, error) {
// NewIDMappingsFromMaps creates a new mapping from two slices // NewIDMappingsFromMaps creates a new mapping from two slices
// Deprecated: this is a temporary shim while transitioning to IDMapping // Deprecated: this is a temporary shim while transitioning to IDMapping
func NewIDMappingsFromMaps(uids []IDMap, gids []IDMap) *IDMappings { func NewIDMappingsFromMaps(uids []IDMap, gids []IDMap) *IdentityMapping {
return &IDMappings{uids: uids, gids: gids} return &IdentityMapping{uids: uids, gids: gids}
} }
// RootPair returns a uid and gid pair for the root user. The error is ignored // RootPair returns a uid and gid pair for the root user. The error is ignored
// because a root user always exists, and the defaults are correct when the uid // because a root user always exists, and the defaults are correct when the uid
// and gid maps are empty. // and gid maps are empty.
func (i *IDMappings) RootPair() IDPair { func (i *IdentityMapping) RootPair() Identity {
uid, gid, _ := GetRootUIDGID(i.uids, i.gids) uid, gid, _ := GetRootUIDGID(i.uids, i.gids)
return IDPair{UID: uid, GID: gid} return Identity{UID: uid, GID: gid}
} }
// ToHost returns the host UID and GID for the container uid, gid. // ToHost returns the host UID and GID for the container uid, gid.
// Remapping is only performed if the ids aren't already the remapped root ids // Remapping is only performed if the ids aren't already the remapped root ids
func (i *IDMappings) ToHost(pair IDPair) (IDPair, error) { func (i *IdentityMapping) ToHost(pair Identity) (Identity, error) {
var err error var err error
target := i.RootPair() target := i.RootPair()
@ -173,7 +174,7 @@ func (i *IDMappings) ToHost(pair IDPair) (IDPair, error) {
} }
// ToContainer returns the container UID and GID for the host uid and gid // ToContainer returns the container UID and GID for the host uid and gid
func (i *IDMappings) ToContainer(pair IDPair) (int, int, error) { func (i *IdentityMapping) ToContainer(pair Identity) (int, int, error) {
uid, err := toContainer(pair.UID, i.uids) uid, err := toContainer(pair.UID, i.uids)
if err != nil { if err != nil {
return -1, -1, err return -1, -1, err
@ -183,19 +184,19 @@ func (i *IDMappings) ToContainer(pair IDPair) (int, int, error) {
} }
// Empty returns true if there are no id mappings // Empty returns true if there are no id mappings
func (i *IDMappings) Empty() bool { func (i *IdentityMapping) Empty() bool {
return len(i.uids) == 0 && len(i.gids) == 0 return len(i.uids) == 0 && len(i.gids) == 0
} }
// UIDs return the UID mapping // UIDs return the UID mapping
// TODO: remove this once everything has been refactored to use pairs // TODO: remove this once everything has been refactored to use pairs
func (i *IDMappings) UIDs() []IDMap { func (i *IdentityMapping) UIDs() []IDMap {
return i.uids return i.uids
} }
// GIDs return the UID mapping // GIDs return the UID mapping
// TODO: remove this once everything has been refactored to use pairs // TODO: remove this once everything has been refactored to use pairs
func (i *IDMappings) GIDs() []IDMap { func (i *IdentityMapping) GIDs() []IDMap {
return i.gids return i.gids
} }

View file

@ -21,11 +21,12 @@ var (
getentCmd string getentCmd string
) )
func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chownExisting bool) error { func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error {
// make an array containing the original path asked for, plus (for mkAll == true) // make an array containing the original path asked for, plus (for mkAll == true)
// all path components leading up to the complete path that don't exist before we MkdirAll // all path components leading up to the complete path that don't exist before we MkdirAll
// so that we can chown all of them properly at the end. If chownExisting is false, we won't // so that we can chown all of them properly at the end. If chownExisting is false, we won't
// chown the full directory path if it exists // chown the full directory path if it exists
var paths []string var paths []string
stat, err := system.Stat(path) stat, err := system.Stat(path)
@ -38,7 +39,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
} }
// short-circuit--we were called with an existing directory and chown was requested // short-circuit--we were called with an existing directory and chown was requested
return lazyChown(path, ownerUID, ownerGID, stat) return lazyChown(path, owner.UID, owner.GID, stat)
} }
if os.IsNotExist(err) { if os.IsNotExist(err) {
@ -69,7 +70,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
// even if it existed, we will chown the requested path + any subpaths that // even if it existed, we will chown the requested path + any subpaths that
// didn't exist when we called MkdirAll // didn't exist when we called MkdirAll
for _, pathComponent := range paths { for _, pathComponent := range paths {
if err := lazyChown(pathComponent, ownerUID, ownerGID, nil); err != nil { if err := lazyChown(pathComponent, owner.UID, owner.GID, nil); err != nil {
return err return err
} }
} }
@ -78,7 +79,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
// CanAccess takes a valid (existing) directory and a uid, gid pair and determines // CanAccess takes a valid (existing) directory and a uid, gid pair and determines
// if that uid, gid pair has access (execute bit) to the directory // if that uid, gid pair has access (execute bit) to the directory
func CanAccess(path string, pair IDPair) bool { func CanAccess(path string, pair Identity) bool {
statInfo, err := system.Stat(path) statInfo, err := system.Stat(path)
if err != nil { if err != nil {
return false return false

View file

@ -46,7 +46,7 @@ func TestMkdirAllAndChown(t *testing.T) {
} }
// test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid // test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid
if err := MkdirAllAndChown(filepath.Join(dirName, "usr", "share"), 0755, IDPair{UID: 99, GID: 99}); err != nil { if err := MkdirAllAndChown(filepath.Join(dirName, "usr", "share"), 0755, Identity{UID: 99, GID: 99}); err != nil {
t.Fatal(err) t.Fatal(err)
} }
testTree["usr/share"] = node{99, 99} testTree["usr/share"] = node{99, 99}
@ -59,7 +59,7 @@ func TestMkdirAllAndChown(t *testing.T) {
} }
// test 2-deep new directories--both should be owned by the uid/gid pair // test 2-deep new directories--both should be owned by the uid/gid pair
if err := MkdirAllAndChown(filepath.Join(dirName, "lib", "some", "other"), 0755, IDPair{UID: 101, GID: 101}); err != nil { if err := MkdirAllAndChown(filepath.Join(dirName, "lib", "some", "other"), 0755, Identity{UID: 101, GID: 101}); err != nil {
t.Fatal(err) t.Fatal(err)
} }
testTree["lib/some"] = node{101, 101} testTree["lib/some"] = node{101, 101}
@ -73,7 +73,7 @@ func TestMkdirAllAndChown(t *testing.T) {
} }
// test a directory that already exists; should be chowned, but nothing else // test a directory that already exists; should be chowned, but nothing else
if err := MkdirAllAndChown(filepath.Join(dirName, "usr"), 0755, IDPair{UID: 102, GID: 102}); err != nil { if err := MkdirAllAndChown(filepath.Join(dirName, "usr"), 0755, Identity{UID: 102, GID: 102}); err != nil {
t.Fatal(err) t.Fatal(err)
} }
testTree["usr"] = node{102, 102} testTree["usr"] = node{102, 102}
@ -102,7 +102,7 @@ func TestMkdirAllAndChownNew(t *testing.T) {
assert.NilError(t, buildTree(dirName, testTree)) assert.NilError(t, buildTree(dirName, testTree))
// test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid // test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid
err = MkdirAllAndChownNew(filepath.Join(dirName, "usr", "share"), 0755, IDPair{UID: 99, GID: 99}) err = MkdirAllAndChownNew(filepath.Join(dirName, "usr", "share"), 0755, Identity{UID: 99, GID: 99})
assert.NilError(t, err) assert.NilError(t, err)
testTree["usr/share"] = node{99, 99} testTree["usr/share"] = node{99, 99}
@ -111,7 +111,7 @@ func TestMkdirAllAndChownNew(t *testing.T) {
assert.NilError(t, compareTrees(testTree, verifyTree)) assert.NilError(t, compareTrees(testTree, verifyTree))
// test 2-deep new directories--both should be owned by the uid/gid pair // test 2-deep new directories--both should be owned by the uid/gid pair
err = MkdirAllAndChownNew(filepath.Join(dirName, "lib", "some", "other"), 0755, IDPair{UID: 101, GID: 101}) err = MkdirAllAndChownNew(filepath.Join(dirName, "lib", "some", "other"), 0755, Identity{UID: 101, GID: 101})
assert.NilError(t, err) assert.NilError(t, err)
testTree["lib/some"] = node{101, 101} testTree["lib/some"] = node{101, 101}
testTree["lib/some/other"] = node{101, 101} testTree["lib/some/other"] = node{101, 101}
@ -120,7 +120,7 @@ func TestMkdirAllAndChownNew(t *testing.T) {
assert.NilError(t, compareTrees(testTree, verifyTree)) assert.NilError(t, compareTrees(testTree, verifyTree))
// test a directory that already exists; should NOT be chowned // test a directory that already exists; should NOT be chowned
err = MkdirAllAndChownNew(filepath.Join(dirName, "usr"), 0755, IDPair{UID: 102, GID: 102}) err = MkdirAllAndChownNew(filepath.Join(dirName, "usr"), 0755, Identity{UID: 102, GID: 102})
assert.NilError(t, err) assert.NilError(t, err)
verifyTree, err = readTree(dirName, "") verifyTree, err = readTree(dirName, "")
assert.NilError(t, err) assert.NilError(t, err)
@ -143,7 +143,7 @@ func TestMkdirAndChown(t *testing.T) {
} }
// test a directory that already exists; should just chown to the requested uid/gid // test a directory that already exists; should just chown to the requested uid/gid
if err := MkdirAndChown(filepath.Join(dirName, "usr"), 0755, IDPair{UID: 99, GID: 99}); err != nil { if err := MkdirAndChown(filepath.Join(dirName, "usr"), 0755, Identity{UID: 99, GID: 99}); err != nil {
t.Fatal(err) t.Fatal(err)
} }
testTree["usr"] = node{99, 99} testTree["usr"] = node{99, 99}
@ -156,12 +156,12 @@ func TestMkdirAndChown(t *testing.T) {
} }
// create a subdir under a dir which doesn't exist--should fail // create a subdir under a dir which doesn't exist--should fail
if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin", "subdir"), 0755, IDPair{UID: 102, GID: 102}); err == nil { if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin", "subdir"), 0755, Identity{UID: 102, GID: 102}); err == nil {
t.Fatalf("Trying to create a directory with Mkdir where the parent doesn't exist should have failed") t.Fatalf("Trying to create a directory with Mkdir where the parent doesn't exist should have failed")
} }
// create a subdir under an existing dir; should only change the ownership of the new subdir // create a subdir under an existing dir; should only change the ownership of the new subdir
if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin"), 0755, IDPair{UID: 102, GID: 102}); err != nil { if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin"), 0755, Identity{UID: 102, GID: 102}); err != nil {
t.Fatal(err) t.Fatal(err)
} }
testTree["usr/bin"] = node{102, 102} testTree["usr/bin"] = node{102, 102}
@ -326,19 +326,19 @@ func TestNewIDMappings(t *testing.T) {
group, err := user.LookupGroupId(string(gids[0])) group, err := user.LookupGroupId(string(gids[0]))
assert.Check(t, err) assert.Check(t, err)
idMappings, err := NewIDMappings(tempUser.Username, group.Name) idMapping, err := NewIdentityMapping(tempUser.Username, group.Name)
assert.Check(t, err) assert.Check(t, err)
rootUID, rootGID, err := GetRootUIDGID(idMappings.UIDs(), idMappings.GIDs()) rootUID, rootGID, err := GetRootUIDGID(idMapping.UIDs(), idMapping.GIDs())
assert.Check(t, err) assert.Check(t, err)
dirName, err := ioutil.TempDir("", "mkdirall") dirName, err := ioutil.TempDir("", "mkdirall")
assert.Check(t, err, "Couldn't create temp directory") assert.Check(t, err, "Couldn't create temp directory")
defer os.RemoveAll(dirName) defer os.RemoveAll(dirName)
err = MkdirAllAndChown(dirName, 0700, IDPair{UID: rootUID, GID: rootGID}) err = MkdirAllAndChown(dirName, 0700, Identity{UID: rootUID, GID: rootGID})
assert.Check(t, err, "Couldn't change ownership of file path. Got error") assert.Check(t, err, "Couldn't change ownership of file path. Got error")
assert.Check(t, CanAccess(dirName, idMappings.RootPair()), fmt.Sprintf("Unable to access %s directory with user UID:%d and GID:%d", dirName, rootUID, rootGID)) assert.Check(t, CanAccess(dirName, idMapping.RootPair()), fmt.Sprintf("Unable to access %s directory with user UID:%d and GID:%d", dirName, rootUID, rootGID))
} }
func TestLookupUserAndGroup(t *testing.T) { func TestLookupUserAndGroup(t *testing.T) {
@ -388,7 +388,7 @@ func TestMkdirIsNotDir(t *testing.T) {
} }
defer os.Remove(file.Name()) defer os.Remove(file.Name())
err = mkdirAs(file.Name(), 0755, 0, 0, false, false) err = mkdirAs(file.Name(), 0755, Identity{UID: 0, GID: 0}, false, false)
assert.Check(t, is.Error(err, "mkdir "+file.Name()+": not a directory")) assert.Check(t, is.Error(err, "mkdir "+file.Name()+": not a directory"))
} }

View file

@ -6,9 +6,11 @@ import (
"github.com/docker/docker/pkg/system" "github.com/docker/docker/pkg/system"
) )
// Platforms such as Windows do not support the UID/GID concept. So make this // This is currently a wrapper around MkdirAll, however, since currently
// just a wrapper around system.MkdirAll. // permissions aren't set through this path, the identity isn't utilized.
func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chownExisting bool) error { // Ownership is handled elsewhere, but in the future could be support here
// too.
func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error {
if err := system.MkdirAll(path, mode, ""); err != nil { if err := system.MkdirAll(path, mode, ""); err != nil {
return err return err
} }
@ -18,6 +20,6 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
// CanAccess takes a valid (existing) directory and a uid, gid pair and determines // CanAccess takes a valid (existing) directory and a uid, gid pair and determines
// if that uid, gid pair has access (execute bit) to the directory // if that uid, gid pair has access (execute bit) to the directory
// Windows does not require/support this function, so always return true // Windows does not require/support this function, so always return true
func CanAccess(path string, pair IDPair) bool { func CanAccess(path string, identity Identity) bool {
return true return true
} }

View file

@ -2,16 +2,62 @@ package system // import "github.com/docker/docker/pkg/system"
import ( import (
"fmt" "fmt"
"syscall"
"unsafe" "unsafe"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
const (
OWNER_SECURITY_INFORMATION = 0x00000001
GROUP_SECURITY_INFORMATION = 0x00000002
DACL_SECURITY_INFORMATION = 0x00000004
SACL_SECURITY_INFORMATION = 0x00000008
LABEL_SECURITY_INFORMATION = 0x00000010
ATTRIBUTE_SECURITY_INFORMATION = 0x00000020
SCOPE_SECURITY_INFORMATION = 0x00000040
PROCESS_TRUST_LABEL_SECURITY_INFORMATION = 0x00000080
ACCESS_FILTER_SECURITY_INFORMATION = 0x00000100
BACKUP_SECURITY_INFORMATION = 0x00010000
PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000
PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000
UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000
UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000
)
const (
SE_UNKNOWN_OBJECT_TYPE = iota
SE_FILE_OBJECT
SE_SERVICE
SE_PRINTER
SE_REGISTRY_KEY
SE_LMSHARE
SE_KERNEL_OBJECT
SE_WINDOW_OBJECT
SE_DS_OBJECT
SE_DS_OBJECT_ALL
SE_PROVIDER_DEFINED_OBJECT
SE_WMIGUID_OBJECT
SE_REGISTRY_WOW64_32KEY
)
const (
SeTakeOwnershipPrivilege = "SeTakeOwnershipPrivilege"
)
const (
ContainerAdministratorSidString = "S-1-5-93-2-1"
ContainerUserSidString = "S-1-5-93-2-2"
)
var ( var (
ntuserApiset = windows.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0") ntuserApiset = windows.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0")
procGetVersionExW = modkernel32.NewProc("GetVersionExW") modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
procGetProductInfo = modkernel32.NewProc("GetProductInfo") procGetVersionExW = modkernel32.NewProc("GetVersionExW")
procGetProductInfo = modkernel32.NewProc("GetProductInfo")
procSetNamedSecurityInfo = modadvapi32.NewProc("SetNamedSecurityInfoW")
procGetSecurityDescriptorDacl = modadvapi32.NewProc("GetSecurityDescriptorDacl")
) )
// OSVersion is a wrapper for Windows version information // OSVersion is a wrapper for Windows version information
@ -125,3 +171,23 @@ func HasWin32KSupport() bool {
// APIs. // APIs.
return ntuserApiset.Load() == nil return ntuserApiset.Load() == nil
} }
func SetNamedSecurityInfo(objectName *uint16, objectType uint32, securityInformation uint32, sidOwner *windows.SID, sidGroup *windows.SID, dacl *byte, sacl *byte) (result error) {
r0, _, _ := syscall.Syscall9(procSetNamedSecurityInfo.Addr(), 7, uintptr(unsafe.Pointer(objectName)), uintptr(objectType), uintptr(securityInformation), uintptr(unsafe.Pointer(sidOwner)), uintptr(unsafe.Pointer(sidGroup)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl)), 0, 0)
if r0 != 0 {
result = syscall.Errno(r0)
}
return
}
func GetSecurityDescriptorDacl(securityDescriptor *byte, daclPresent *uint32, dacl **byte, daclDefaulted *uint32) (result error) {
r1, _, e1 := syscall.Syscall6(procGetSecurityDescriptorDacl.Addr(), 4, uintptr(unsafe.Pointer(securityDescriptor)), uintptr(unsafe.Pointer(daclPresent)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(daclDefaulted)), 0, 0)
if r1 == 0 {
if e1 != 0 {
result = syscall.Errno(e1)
} else {
result = syscall.EINVAL
}
}
return
}

View file

@ -53,7 +53,7 @@ func (pm *Manager) enable(p *v2.Plugin, c *controller, force bool) error {
} }
rootFS := containerfs.NewLocalContainerFS(filepath.Join(pm.config.Root, p.PluginObj.ID, rootFSFileName)) rootFS := containerfs.NewLocalContainerFS(filepath.Join(pm.config.Root, p.PluginObj.ID, rootFSFileName))
if err := initlayer.Setup(rootFS, idtools.IDPair{UID: 0, GID: 0}); err != nil { if err := initlayer.Setup(rootFS, idtools.Identity{UID: 0, GID: 0}); err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }

View file

@ -46,18 +46,18 @@ type activeMount struct {
// New instantiates a new Root instance with the provided scope. Scope // New instantiates a new Root instance with the provided scope. Scope
// is the base path that the Root instance uses to store its // is the base path that the Root instance uses to store its
// volumes. The base path is created here if it does not exist. // volumes. The base path is created here if it does not exist.
func New(scope string, rootIDs idtools.IDPair) (*Root, error) { func New(scope string, rootIdentity idtools.Identity) (*Root, error) {
rootDirectory := filepath.Join(scope, volumesPathName) rootDirectory := filepath.Join(scope, volumesPathName)
if err := idtools.MkdirAllAndChown(rootDirectory, 0700, rootIDs); err != nil { if err := idtools.MkdirAllAndChown(rootDirectory, 0700, rootIdentity); err != nil {
return nil, err return nil, err
} }
r := &Root{ r := &Root{
scope: scope, scope: scope,
path: rootDirectory, path: rootDirectory,
volumes: make(map[string]*localVolume), volumes: make(map[string]*localVolume),
rootIDs: rootIDs, rootIdentity: rootIdentity,
} }
dirs, err := ioutil.ReadDir(rootDirectory) dirs, err := ioutil.ReadDir(rootDirectory)
@ -101,11 +101,11 @@ func New(scope string, rootIDs idtools.IDPair) (*Root, error) {
// manages the creation/removal of volumes. It uses only standard vfs // manages the creation/removal of volumes. It uses only standard vfs
// commands to create/remove dirs within its provided scope. // commands to create/remove dirs within its provided scope.
type Root struct { type Root struct {
m sync.Mutex m sync.Mutex
scope string scope string
path string path string
volumes map[string]*localVolume volumes map[string]*localVolume
rootIDs idtools.IDPair rootIdentity idtools.Identity
} }
// List lists all the volumes // List lists all the volumes
@ -146,7 +146,7 @@ func (r *Root) Create(name string, opts map[string]string) (volume.Volume, error
} }
path := r.DataPath(name) path := r.DataPath(name)
if err := idtools.MkdirAllAndChown(path, 0755, r.rootIDs); err != nil { if err := idtools.MkdirAllAndChown(path, 0755, r.rootIdentity); err != nil {
return nil, errors.Wrapf(errdefs.System(err), "error while creating volume path '%s'", path) return nil, errors.Wrapf(errdefs.System(err), "error while creating volume path '%s'", path)
} }

View file

@ -38,7 +38,7 @@ func TestRemove(t *testing.T) {
} }
defer os.RemoveAll(rootDir) defer os.RemoveAll(rootDir)
r, err := New(rootDir, idtools.IDPair{UID: os.Geteuid(), GID: os.Getegid()}) r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -80,7 +80,7 @@ func TestInitializeWithVolumes(t *testing.T) {
} }
defer os.RemoveAll(rootDir) defer os.RemoveAll(rootDir)
r, err := New(rootDir, idtools.IDPair{UID: os.Geteuid(), GID: os.Getegid()}) r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -90,7 +90,7 @@ func TestInitializeWithVolumes(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
r, err = New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()}) r, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -112,7 +112,7 @@ func TestCreate(t *testing.T) {
} }
defer os.RemoveAll(rootDir) defer os.RemoveAll(rootDir)
r, err := New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()}) r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -149,7 +149,7 @@ func TestCreate(t *testing.T) {
} }
} }
r, err = New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()}) r, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -186,7 +186,7 @@ func TestCreateWithOpts(t *testing.T) {
} }
defer os.RemoveAll(rootDir) defer os.RemoveAll(rootDir)
r, err := New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()}) r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -261,7 +261,7 @@ func TestCreateWithOpts(t *testing.T) {
t.Fatal("expected mount to still be active") t.Fatal("expected mount to still be active")
} }
r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0}) r, err = New(rootDir, idtools.Identity{UID: 0, GID: 0})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -283,7 +283,7 @@ func TestRelaodNoOpts(t *testing.T) {
} }
defer os.RemoveAll(rootDir) defer os.RemoveAll(rootDir)
r, err := New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()}) r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -311,7 +311,7 @@ func TestRelaodNoOpts(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
r, err = New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()}) r, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View file

@ -95,7 +95,7 @@ func (m *MountPoint) Cleanup() error {
// configured, or creating the source directory if supplied. // configured, or creating the source directory if supplied.
// The, optional, checkFun parameter allows doing additional checking // The, optional, checkFun parameter allows doing additional checking
// before creating the source directory on the host. // before creating the source directory on the host.
func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.IDPair, checkFun func(m *MountPoint) error) (path string, err error) { func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.Identity, checkFun func(m *MountPoint) error) (path string, err error) {
if m.SkipMountpointCreation { if m.SkipMountpointCreation {
return m.Source, nil return m.Source, nil
} }

View file

@ -9,7 +9,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
func setupDefaultDriver(store *drivers.Store, root string, rootIDs idtools.IDPair) error { func setupDefaultDriver(store *drivers.Store, root string, rootIDs idtools.Identity) error {
d, err := local.New(root, rootIDs) d, err := local.New(root, rootIDs)
if err != nil { if err != nil {
return errors.Wrap(err, "error setting up default driver") return errors.Wrap(err, "error setting up default driver")

View file

@ -7,4 +7,4 @@ import (
"github.com/docker/docker/volume/drivers" "github.com/docker/docker/volume/drivers"
) )
func setupDefaultDriver(_ *drivers.Store, _ string, _ idtools.IDPair) error { return nil } func setupDefaultDriver(_ *drivers.Store, _ string, _ idtools.Identity) error { return nil }

View file

@ -35,7 +35,7 @@ type VolumesService struct {
} }
// NewVolumeService creates a new volume service // NewVolumeService creates a new volume service
func NewVolumeService(root string, pg plugingetter.PluginGetter, rootIDs idtools.IDPair, logger volumeEventLogger) (*VolumesService, error) { func NewVolumeService(root string, pg plugingetter.PluginGetter, rootIDs idtools.Identity, logger volumeEventLogger) (*VolumesService, error) {
ds := drivers.NewStore(pg) ds := drivers.NewStore(pg)
if err := setupDefaultDriver(ds, root, rootIDs); err != nil { if err := setupDefaultDriver(ds, root, rootIDs); err != nil {
return nil, err return nil, err

View file

@ -25,7 +25,7 @@ func TestLocalVolumeSize(t *testing.T) {
assert.Assert(t, err) assert.Assert(t, err)
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
l, err := local.New(dir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()}) l, err := local.New(dir, idtools.Identity{UID: os.Getuid(), GID: os.Getegid()})
assert.Assert(t, err) assert.Assert(t, err)
assert.Assert(t, ds.Register(l, volume.DefaultDriverName)) assert.Assert(t, ds.Register(l, volume.DefaultDriverName))
assert.Assert(t, ds.Register(testutils.NewFakeDriver("fake"), "fake")) assert.Assert(t, ds.Register(testutils.NewFakeDriver("fake"), "fake"))