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>
| ... | ... |
@@ -56,21 +56,21 @@ type SessionGetter interface {
|
| 56 | 56 |
|
| 57 | 57 |
// BuildManager is shared across all Builder objects |
| 58 | 58 |
type BuildManager struct {
|
| 59 |
- idMappings *idtools.IDMappings |
|
| 60 |
- backend builder.Backend |
|
| 61 |
- pathCache pathCache // TODO: make this persistent |
|
| 62 |
- sg SessionGetter |
|
| 63 |
- fsCache *fscache.FSCache |
|
| 59 |
+ idMapping *idtools.IdentityMapping |
|
| 60 |
+ backend builder.Backend |
|
| 61 |
+ pathCache pathCache // TODO: make this persistent |
|
| 62 |
+ sg SessionGetter |
|
| 63 |
+ fsCache *fscache.FSCache |
|
| 64 | 64 |
} |
| 65 | 65 |
|
| 66 | 66 |
// NewBuildManager creates a BuildManager |
| 67 |
-func NewBuildManager(b builder.Backend, sg SessionGetter, fsCache *fscache.FSCache, idMappings *idtools.IDMappings) (*BuildManager, error) {
|
|
| 67 |
+func NewBuildManager(b builder.Backend, sg SessionGetter, fsCache *fscache.FSCache, identityMapping *idtools.IdentityMapping) (*BuildManager, error) {
|
|
| 68 | 68 |
bm := &BuildManager{
|
| 69 |
- backend: b, |
|
| 70 |
- pathCache: &syncmap.Map{},
|
|
| 71 |
- sg: sg, |
|
| 72 |
- idMappings: idMappings, |
|
| 73 |
- fsCache: fsCache, |
|
| 69 |
+ backend: b, |
|
| 70 |
+ pathCache: &syncmap.Map{},
|
|
| 71 |
+ sg: sg, |
|
| 72 |
+ idMapping: identityMapping, |
|
| 73 |
+ fsCache: fsCache, |
|
| 74 | 74 |
} |
| 75 | 75 |
if err := fsCache.RegisterTransport(remotecontext.ClientSessionRemote, NewClientSessionTransport()); err != nil {
|
| 76 | 76 |
return nil, err |
| ... | ... |
@@ -111,7 +111,7 @@ func (bm *BuildManager) Build(ctx context.Context, config backend.BuildConfig) ( |
| 111 | 111 |
ProgressWriter: config.ProgressWriter, |
| 112 | 112 |
Backend: bm.backend, |
| 113 | 113 |
PathCache: bm.pathCache, |
| 114 |
- IDMappings: bm.idMappings, |
|
| 114 |
+ IDMapping: bm.idMapping, |
|
| 115 | 115 |
} |
| 116 | 116 |
b, err := newBuilder(ctx, builderOptions) |
| 117 | 117 |
if err != nil {
|
| ... | ... |
@@ -159,7 +159,7 @@ type builderOptions struct {
|
| 159 | 159 |
Backend builder.Backend |
| 160 | 160 |
ProgressWriter backend.ProgressWriter |
| 161 | 161 |
PathCache pathCache |
| 162 |
- IDMappings *idtools.IDMappings |
|
| 162 |
+ IDMapping *idtools.IdentityMapping |
|
| 163 | 163 |
} |
| 164 | 164 |
|
| 165 | 165 |
// Builder is a Dockerfile builder |
| ... | ... |
@@ -175,7 +175,7 @@ type Builder struct {
|
| 175 | 175 |
docker builder.Backend |
| 176 | 176 |
clientCtx context.Context |
| 177 | 177 |
|
| 178 |
- idMappings *idtools.IDMappings |
|
| 178 |
+ idMapping *idtools.IdentityMapping |
|
| 179 | 179 |
disableCommit bool |
| 180 | 180 |
imageSources *imageSources |
| 181 | 181 |
pathCache pathCache |
| ... | ... |
@@ -199,7 +199,7 @@ func newBuilder(clientCtx context.Context, options builderOptions) (*Builder, er |
| 199 | 199 |
Aux: options.ProgressWriter.AuxFormatter, |
| 200 | 200 |
Output: options.ProgressWriter.Output, |
| 201 | 201 |
docker: options.Backend, |
| 202 |
- idMappings: options.IDMappings, |
|
| 202 |
+ idMapping: options.IDMapping, |
|
| 203 | 203 |
imageSources: newImageSources(clientCtx, options), |
| 204 | 204 |
pathCache: options.PathCache, |
| 205 | 205 |
imageProber: newImageProber(options.Backend, config.CacheFrom, config.NoCache), |
| ... | ... |
@@ -451,7 +451,7 @@ func downloadSource(output io.Writer, stdout io.Writer, srcURL string) (remote b |
| 451 | 451 |
|
| 452 | 452 |
type copyFileOptions struct {
|
| 453 | 453 |
decompress bool |
| 454 |
- chownPair idtools.IDPair |
|
| 454 |
+ identity idtools.Identity |
|
| 455 | 455 |
archiver Archiver |
| 456 | 456 |
} |
| 457 | 457 |
|
| ... | ... |
@@ -481,7 +481,7 @@ func performCopyForInfo(dest copyInfo, source copyInfo, options copyFileOptions) |
| 481 | 481 |
return errors.Wrapf(err, "source path not found") |
| 482 | 482 |
} |
| 483 | 483 |
if src.IsDir() {
|
| 484 |
- return copyDirectory(archiver, srcEndpoint, destEndpoint, options.chownPair) |
|
| 484 |
+ return copyDirectory(archiver, srcEndpoint, destEndpoint, options.identity) |
|
| 485 | 485 |
} |
| 486 | 486 |
if options.decompress && isArchivePath(source.root, srcPath) && !source.noDecompress {
|
| 487 | 487 |
return archiver.UntarPath(srcPath, destPath) |
| ... | ... |
@@ -499,7 +499,7 @@ func performCopyForInfo(dest copyInfo, source copyInfo, options copyFileOptions) |
| 499 | 499 |
destPath = dest.root.Join(destPath, source.root.Base(source.path)) |
| 500 | 500 |
destEndpoint = ©Endpoint{driver: dest.root, path: destPath}
|
| 501 | 501 |
} |
| 502 |
- return copyFile(archiver, srcEndpoint, destEndpoint, options.chownPair) |
|
| 502 |
+ return copyFile(archiver, srcEndpoint, destEndpoint, options.identity) |
|
| 503 | 503 |
} |
| 504 | 504 |
|
| 505 | 505 |
func isArchivePath(driver containerfs.ContainerFS, path string) bool {
|
| ... | ... |
@@ -517,7 +517,7 @@ func isArchivePath(driver containerfs.ContainerFS, path string) bool {
|
| 517 | 517 |
return err == nil |
| 518 | 518 |
} |
| 519 | 519 |
|
| 520 |
-func copyDirectory(archiver Archiver, source, dest *copyEndpoint, chownPair idtools.IDPair) error {
|
|
| 520 |
+func copyDirectory(archiver Archiver, source, dest *copyEndpoint, identity idtools.Identity) error {
|
|
| 521 | 521 |
destExists, err := isExistingDirectory(dest) |
| 522 | 522 |
if err != nil {
|
| 523 | 523 |
return errors.Wrapf(err, "failed to query destination path") |
| ... | ... |
@@ -527,17 +527,17 @@ func copyDirectory(archiver Archiver, source, dest *copyEndpoint, chownPair idto |
| 527 | 527 |
return errors.Wrapf(err, "failed to copy directory") |
| 528 | 528 |
} |
| 529 | 529 |
// TODO: @gupta-ak. Investigate how LCOW permission mappings will work. |
| 530 |
- return fixPermissions(source.path, dest.path, chownPair, !destExists) |
|
| 530 |
+ return fixPermissions(source.path, dest.path, identity, !destExists) |
|
| 531 | 531 |
} |
| 532 | 532 |
|
| 533 |
-func copyFile(archiver Archiver, source, dest *copyEndpoint, chownPair idtools.IDPair) error {
|
|
| 533 |
+func copyFile(archiver Archiver, source, dest *copyEndpoint, identity idtools.Identity) error {
|
|
| 534 | 534 |
if runtime.GOOS == "windows" && dest.driver.OS() == "linux" {
|
| 535 | 535 |
// LCOW |
| 536 | 536 |
if err := dest.driver.MkdirAll(dest.driver.Dir(dest.path), 0755); err != nil {
|
| 537 | 537 |
return errors.Wrapf(err, "failed to create new directory") |
| 538 | 538 |
} |
| 539 | 539 |
} else {
|
| 540 |
- if err := idtools.MkdirAllAndChownNew(filepath.Dir(dest.path), 0755, chownPair); err != nil {
|
|
| 540 |
+ if err := idtools.MkdirAllAndChownNew(filepath.Dir(dest.path), 0755, identity); err != nil {
|
|
| 541 | 541 |
// Normal containers |
| 542 | 542 |
return errors.Wrapf(err, "failed to create new directory") |
| 543 | 543 |
} |
| ... | ... |
@@ -547,7 +547,7 @@ func copyFile(archiver Archiver, source, dest *copyEndpoint, chownPair idtools.I |
| 547 | 547 |
return errors.Wrapf(err, "failed to copy file") |
| 548 | 548 |
} |
| 549 | 549 |
// TODO: @gupta-ak. Investigate how LCOW permission mappings will work. |
| 550 |
- return fixPermissions(source.path, dest.path, chownPair, false) |
|
| 550 |
+ return fixPermissions(source.path, dest.path, identity, false) |
|
| 551 | 551 |
} |
| 552 | 552 |
|
| 553 | 553 |
func endsInSlash(driver containerfs.Driver, path string) bool {
|
| ... | ... |
@@ -10,7 +10,7 @@ import ( |
| 10 | 10 |
"github.com/docker/docker/pkg/idtools" |
| 11 | 11 |
) |
| 12 | 12 |
|
| 13 |
-func fixPermissions(source, destination string, rootIDs idtools.IDPair, overrideSkip bool) error {
|
|
| 13 |
+func fixPermissions(source, destination string, identity idtools.Identity, overrideSkip bool) error {
|
|
| 14 | 14 |
var ( |
| 15 | 15 |
skipChownRoot bool |
| 16 | 16 |
err error |
| ... | ... |
@@ -39,7 +39,7 @@ func fixPermissions(source, destination string, rootIDs idtools.IDPair, override |
| 39 | 39 |
} |
| 40 | 40 |
|
| 41 | 41 |
fullpath = filepath.Join(destination, cleaned) |
| 42 |
- return os.Lchown(fullpath, rootIDs.UID, rootIDs.GID) |
|
| 42 |
+ return os.Lchown(fullpath, identity.UID, identity.GID) |
|
| 43 | 43 |
}) |
| 44 | 44 |
} |
| 45 | 45 |
|
| ... | ... |
@@ -1,11 +1,17 @@ |
| 1 | 1 |
package dockerfile // import "github.com/docker/docker/builder/dockerfile" |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "errors" |
|
| 4 |
+ "fmt" |
|
| 5 |
+ "os" |
|
| 5 | 6 |
"path/filepath" |
| 6 | 7 |
"strings" |
| 7 | 8 |
|
| 9 |
+ "github.com/Microsoft/go-winio" |
|
| 8 | 10 |
"github.com/docker/docker/pkg/idtools" |
| 11 |
+ "github.com/docker/docker/pkg/reexec" |
|
| 12 |
+ "github.com/docker/docker/pkg/system" |
|
| 13 |
+ "github.com/pkg/errors" |
|
| 14 |
+ "golang.org/x/sys/windows" |
|
| 9 | 15 |
) |
| 10 | 16 |
|
| 11 | 17 |
var pathBlacklist = map[string]bool{
|
| ... | ... |
@@ -13,9 +19,69 @@ var pathBlacklist = map[string]bool{
|
| 13 | 13 |
"c:\\windows": true, |
| 14 | 14 |
} |
| 15 | 15 |
|
| 16 |
-func fixPermissions(source, destination string, rootIDs idtools.IDPair, overrideSkip bool) error {
|
|
| 17 |
- // chown is not supported on Windows |
|
| 18 |
- return nil |
|
| 16 |
+func init() {
|
|
| 17 |
+ reexec.Register("windows-fix-permissions", fixPermissionsReexec)
|
|
| 18 |
+} |
|
| 19 |
+ |
|
| 20 |
+func fixPermissions(source, destination string, identity idtools.Identity, _ bool) error {
|
|
| 21 |
+ if identity.SID == "" {
|
|
| 22 |
+ return nil |
|
| 23 |
+ } |
|
| 24 |
+ |
|
| 25 |
+ cmd := reexec.Command("windows-fix-permissions", source, destination, identity.SID)
|
|
| 26 |
+ output, err := cmd.CombinedOutput() |
|
| 27 |
+ |
|
| 28 |
+ return errors.Wrapf(err, "failed to exec windows-fix-permissions: %s", output) |
|
| 29 |
+} |
|
| 30 |
+ |
|
| 31 |
+func fixPermissionsReexec() {
|
|
| 32 |
+ err := fixPermissionsWindows(os.Args[1], os.Args[2], os.Args[3]) |
|
| 33 |
+ if err != nil {
|
|
| 34 |
+ fmt.Fprint(os.Stderr, err) |
|
| 35 |
+ os.Exit(1) |
|
| 36 |
+ } |
|
| 37 |
+} |
|
| 38 |
+ |
|
| 39 |
+func fixPermissionsWindows(source, destination, SID string) error {
|
|
| 40 |
+ |
|
| 41 |
+ privileges := []string{winio.SeRestorePrivilege, system.SeTakeOwnershipPrivilege}
|
|
| 42 |
+ |
|
| 43 |
+ err := winio.EnableProcessPrivileges(privileges) |
|
| 44 |
+ if err != nil {
|
|
| 45 |
+ return err |
|
| 46 |
+ } |
|
| 47 |
+ |
|
| 48 |
+ defer winio.DisableProcessPrivileges(privileges) |
|
| 49 |
+ |
|
| 50 |
+ sid, err := windows.StringToSid(SID) |
|
| 51 |
+ if err != nil {
|
|
| 52 |
+ return err |
|
| 53 |
+ } |
|
| 54 |
+ |
|
| 55 |
+ // Owners on *nix have read/write/delete/read control and write DAC. |
|
| 56 |
+ // Add an ACE that grants this to the user/group specified with the |
|
| 57 |
+ // chown option. Currently Windows is not honoring the owner change, |
|
| 58 |
+ // however, they are aware of this and it should be fixed at some |
|
| 59 |
+ // point. |
|
| 60 |
+ |
|
| 61 |
+ sddlString := system.SddlAdministratorsLocalSystem |
|
| 62 |
+ sddlString += "(A;OICI;GRGWGXRCWDSD;;;" + SID + ")" |
|
| 63 |
+ |
|
| 64 |
+ securityDescriptor, err := winio.SddlToSecurityDescriptor(sddlString) |
|
| 65 |
+ if err != nil {
|
|
| 66 |
+ return err |
|
| 67 |
+ } |
|
| 68 |
+ |
|
| 69 |
+ var daclPresent uint32 |
|
| 70 |
+ var daclDefaulted uint32 |
|
| 71 |
+ var dacl *byte |
|
| 72 |
+ |
|
| 73 |
+ err = system.GetSecurityDescriptorDacl(&securityDescriptor[0], &daclPresent, &dacl, &daclDefaulted) |
|
| 74 |
+ if err != nil {
|
|
| 75 |
+ return err |
|
| 76 |
+ } |
|
| 77 |
+ |
|
| 78 |
+ return system.SetNamedSecurityInfo(windows.StringToUTF16Ptr(destination), system.SE_FILE_OBJECT, system.OWNER_SECURITY_INFORMATION|system.DACL_SECURITY_INFORMATION, sid, nil, dacl, nil) |
|
| 19 | 79 |
} |
| 20 | 80 |
|
| 21 | 81 |
func validateCopySourcePath(imageSource *imageMount, origPath, platform string) error {
|
| ... | ... |
@@ -37,7 +37,7 @@ type Archiver interface {
|
| 37 | 37 |
UntarPath(src, dst string) error |
| 38 | 38 |
CopyWithTar(src, dst string) error |
| 39 | 39 |
CopyFileWithTar(src, dst string) error |
| 40 |
- IDMappings() *idtools.IDMappings |
|
| 40 |
+ IdentityMapping() *idtools.IdentityMapping |
|
| 41 | 41 |
} |
| 42 | 42 |
|
| 43 | 43 |
// The builder will use the following interfaces if the container fs implements |
| ... | ... |
@@ -68,11 +68,11 @@ func tarFunc(i interface{}) containerfs.TarFunc {
|
| 68 | 68 |
func (b *Builder) getArchiver(src, dst containerfs.Driver) Archiver {
|
| 69 | 69 |
t, u := tarFunc(src), untarFunc(dst) |
| 70 | 70 |
return &containerfs.Archiver{
|
| 71 |
- SrcDriver: src, |
|
| 72 |
- DstDriver: dst, |
|
| 73 |
- Tar: t, |
|
| 74 |
- Untar: u, |
|
| 75 |
- IDMappingsVar: b.idMappings, |
|
| 71 |
+ SrcDriver: src, |
|
| 72 |
+ DstDriver: dst, |
|
| 73 |
+ Tar: t, |
|
| 74 |
+ Untar: u, |
|
| 75 |
+ IDMapping: b.idMapping, |
|
| 76 | 76 |
} |
| 77 | 77 |
} |
| 78 | 78 |
|
| ... | ... |
@@ -185,14 +185,18 @@ func (b *Builder) performCopy(req dispatchRequest, inst copyInstruction) error {
|
| 185 | 185 |
return err |
| 186 | 186 |
} |
| 187 | 187 |
|
| 188 |
- chownPair := b.idMappings.RootPair() |
|
| 188 |
+ identity := b.idMapping.RootPair() |
|
| 189 | 189 |
// if a chown was requested, perform the steps to get the uid, gid |
| 190 | 190 |
// translated (if necessary because of user namespaces), and replace |
| 191 | 191 |
// the root pair with the chown pair for copy operations |
| 192 | 192 |
if inst.chownStr != "" {
|
| 193 |
- chownPair, err = parseChownFlag(inst.chownStr, destInfo.root.Path(), b.idMappings) |
|
| 193 |
+ identity, err = parseChownFlag(b, state, inst.chownStr, destInfo.root.Path(), b.idMapping) |
|
| 194 | 194 |
if err != nil {
|
| 195 |
- return errors.Wrapf(err, "unable to convert uid/gid chown string to host mapping") |
|
| 195 |
+ if b.options.Platform != "windows" {
|
|
| 196 |
+ return errors.Wrapf(err, "unable to convert uid/gid chown string to host mapping") |
|
| 197 |
+ } |
|
| 198 |
+ |
|
| 199 |
+ return errors.Wrapf(err, "unable to map container user account name to SID") |
|
| 196 | 200 |
} |
| 197 | 201 |
} |
| 198 | 202 |
|
| ... | ... |
@@ -200,7 +204,7 @@ func (b *Builder) performCopy(req dispatchRequest, inst copyInstruction) error {
|
| 200 | 200 |
opts := copyFileOptions{
|
| 201 | 201 |
decompress: inst.allowLocalDecompression, |
| 202 | 202 |
archiver: b.getArchiver(info.root, destInfo.root), |
| 203 |
- chownPair: chownPair, |
|
| 203 |
+ identity: identity, |
|
| 204 | 204 |
} |
| 205 | 205 |
if err := performCopyForInfo(destInfo, info, opts); err != nil {
|
| 206 | 206 |
return errors.Wrapf(err, "failed to copy files") |
| ... | ... |
@@ -11,11 +11,11 @@ import ( |
| 11 | 11 |
"github.com/pkg/errors" |
| 12 | 12 |
) |
| 13 | 13 |
|
| 14 |
-func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) {
|
|
| 14 |
+func parseChownFlag(builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping *idtools.IdentityMapping) (idtools.Identity, error) {
|
|
| 15 | 15 |
var userStr, grpStr string |
| 16 | 16 |
parts := strings.Split(chown, ":") |
| 17 | 17 |
if len(parts) > 2 {
|
| 18 |
- return idtools.IDPair{}, errors.New("invalid chown string format: " + chown)
|
|
| 18 |
+ return idtools.Identity{}, errors.New("invalid chown string format: " + chown)
|
|
| 19 | 19 |
} |
| 20 | 20 |
if len(parts) == 1 {
|
| 21 | 21 |
// if no group specified, use the user spec as group as well |
| ... | ... |
@@ -26,25 +26,25 @@ func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) ( |
| 26 | 26 |
|
| 27 | 27 |
passwdPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "passwd"), ctrRootPath) |
| 28 | 28 |
if err != nil {
|
| 29 |
- return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/passwd path in container rootfs")
|
|
| 29 |
+ return idtools.Identity{}, errors.Wrapf(err, "can't resolve /etc/passwd path in container rootfs")
|
|
| 30 | 30 |
} |
| 31 | 31 |
groupPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "group"), ctrRootPath) |
| 32 | 32 |
if err != nil {
|
| 33 |
- return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/group path in container rootfs")
|
|
| 33 |
+ return idtools.Identity{}, errors.Wrapf(err, "can't resolve /etc/group path in container rootfs")
|
|
| 34 | 34 |
} |
| 35 | 35 |
uid, err := lookupUser(userStr, passwdPath) |
| 36 | 36 |
if err != nil {
|
| 37 |
- return idtools.IDPair{}, errors.Wrapf(err, "can't find uid for user "+userStr)
|
|
| 37 |
+ return idtools.Identity{}, errors.Wrapf(err, "can't find uid for user "+userStr)
|
|
| 38 | 38 |
} |
| 39 | 39 |
gid, err := lookupGroup(grpStr, groupPath) |
| 40 | 40 |
if err != nil {
|
| 41 |
- return idtools.IDPair{}, errors.Wrapf(err, "can't find gid for group "+grpStr)
|
|
| 41 |
+ return idtools.Identity{}, errors.Wrapf(err, "can't find gid for group "+grpStr)
|
|
| 42 | 42 |
} |
| 43 | 43 |
|
| 44 | 44 |
// convert as necessary because of user namespaces |
| 45 |
- chownPair, err := idMappings.ToHost(idtools.IDPair{UID: uid, GID: gid})
|
|
| 45 |
+ chownPair, err := identityMapping.ToHost(idtools.Identity{UID: uid, GID: gid})
|
|
| 46 | 46 |
if err != nil {
|
| 47 |
- return idtools.IDPair{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
|
|
| 47 |
+ return idtools.Identity{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
|
|
| 48 | 48 |
} |
| 49 | 49 |
return chownPair, nil |
| 50 | 50 |
} |
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
"path/filepath" |
| 6 | 6 |
"testing" |
| 7 | 7 |
|
| 8 |
+ "github.com/docker/docker/api/types" |
|
| 8 | 9 |
"github.com/docker/docker/pkg/idtools" |
| 9 | 10 |
"gotest.tools/assert" |
| 10 | 11 |
is "gotest.tools/assert/cmp" |
| ... | ... |
@@ -34,7 +35,7 @@ othergrp:x:6666: |
| 34 | 34 |
}, |
| 35 | 35 |
} |
| 36 | 36 |
remapped := idtools.NewIDMappingsFromMaps(idMaps, idMaps) |
| 37 |
- unmapped := &idtools.IDMappings{}
|
|
| 37 |
+ unmapped := &idtools.IdentityMapping{}
|
|
| 38 | 38 |
|
| 39 | 39 |
contextDir, cleanup := createTestTempDir(t, "", "builder-chown-parse-test") |
| 40 | 40 |
defer cleanup() |
| ... | ... |
@@ -49,56 +50,72 @@ othergrp:x:6666: |
| 49 | 49 |
|
| 50 | 50 |
// positive tests |
| 51 | 51 |
for _, testcase := range []struct {
|
| 52 |
+ builder *Builder |
|
| 52 | 53 |
name string |
| 53 | 54 |
chownStr string |
| 54 |
- idMapping *idtools.IDMappings |
|
| 55 |
- expected idtools.IDPair |
|
| 55 |
+ idMapping *idtools.IdentityMapping |
|
| 56 |
+ state *dispatchState |
|
| 57 |
+ expected idtools.Identity |
|
| 56 | 58 |
}{
|
| 57 | 59 |
{
|
| 60 |
+ builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
|
| 58 | 61 |
name: "UIDNoMap", |
| 59 | 62 |
chownStr: "1", |
| 60 | 63 |
idMapping: unmapped, |
| 61 |
- expected: idtools.IDPair{UID: 1, GID: 1},
|
|
| 64 |
+ state: &dispatchState{},
|
|
| 65 |
+ expected: idtools.Identity{UID: 1, GID: 1},
|
|
| 62 | 66 |
}, |
| 63 | 67 |
{
|
| 68 |
+ builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
|
| 64 | 69 |
name: "UIDGIDNoMap", |
| 65 | 70 |
chownStr: "0:1", |
| 66 | 71 |
idMapping: unmapped, |
| 67 |
- expected: idtools.IDPair{UID: 0, GID: 1},
|
|
| 72 |
+ state: &dispatchState{},
|
|
| 73 |
+ expected: idtools.Identity{UID: 0, GID: 1},
|
|
| 68 | 74 |
}, |
| 69 | 75 |
{
|
| 76 |
+ builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
|
| 70 | 77 |
name: "UIDWithMap", |
| 71 | 78 |
chownStr: "0", |
| 72 | 79 |
idMapping: remapped, |
| 73 |
- expected: idtools.IDPair{UID: 100000, GID: 100000},
|
|
| 80 |
+ state: &dispatchState{},
|
|
| 81 |
+ expected: idtools.Identity{UID: 100000, GID: 100000},
|
|
| 74 | 82 |
}, |
| 75 | 83 |
{
|
| 84 |
+ builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
|
| 76 | 85 |
name: "UIDGIDWithMap", |
| 77 | 86 |
chownStr: "1:33", |
| 78 | 87 |
idMapping: remapped, |
| 79 |
- expected: idtools.IDPair{UID: 100001, GID: 100033},
|
|
| 88 |
+ state: &dispatchState{},
|
|
| 89 |
+ expected: idtools.Identity{UID: 100001, GID: 100033},
|
|
| 80 | 90 |
}, |
| 81 | 91 |
{
|
| 92 |
+ builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
|
| 82 | 93 |
name: "UserNoMap", |
| 83 | 94 |
chownStr: "bin:5555", |
| 84 | 95 |
idMapping: unmapped, |
| 85 |
- expected: idtools.IDPair{UID: 1, GID: 5555},
|
|
| 96 |
+ state: &dispatchState{},
|
|
| 97 |
+ expected: idtools.Identity{UID: 1, GID: 5555},
|
|
| 86 | 98 |
}, |
| 87 | 99 |
{
|
| 100 |
+ builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
|
| 88 | 101 |
name: "GroupWithMap", |
| 89 | 102 |
chownStr: "0:unicorn", |
| 90 | 103 |
idMapping: remapped, |
| 91 |
- expected: idtools.IDPair{UID: 100000, GID: 101002},
|
|
| 104 |
+ state: &dispatchState{},
|
|
| 105 |
+ expected: idtools.Identity{UID: 100000, GID: 101002},
|
|
| 92 | 106 |
}, |
| 93 | 107 |
{
|
| 108 |
+ builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
|
| 94 | 109 |
name: "UserOnlyWithMap", |
| 95 | 110 |
chownStr: "unicorn", |
| 96 | 111 |
idMapping: remapped, |
| 97 |
- expected: idtools.IDPair{UID: 101001, GID: 101002},
|
|
| 112 |
+ state: &dispatchState{},
|
|
| 113 |
+ expected: idtools.Identity{UID: 101001, GID: 101002},
|
|
| 98 | 114 |
}, |
| 99 | 115 |
} {
|
| 100 | 116 |
t.Run(testcase.name, func(t *testing.T) {
|
| 101 |
- idPair, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping) |
|
| 117 |
+ idPair, err := parseChownFlag(testcase.builder, testcase.state, testcase.chownStr, contextDir, testcase.idMapping) |
|
| 102 | 118 |
assert.NilError(t, err, "Failed to parse chown flag: %q", testcase.chownStr) |
| 103 | 119 |
assert.Check(t, is.DeepEqual(testcase.expected, idPair), "chown flag mapping failure") |
| 104 | 120 |
}) |
| ... | ... |
@@ -106,32 +123,40 @@ othergrp:x:6666: |
| 106 | 106 |
|
| 107 | 107 |
// error tests |
| 108 | 108 |
for _, testcase := range []struct {
|
| 109 |
+ builder *Builder |
|
| 109 | 110 |
name string |
| 110 | 111 |
chownStr string |
| 111 |
- idMapping *idtools.IDMappings |
|
| 112 |
+ idMapping *idtools.IdentityMapping |
|
| 113 |
+ state *dispatchState |
|
| 112 | 114 |
descr string |
| 113 | 115 |
}{
|
| 114 | 116 |
{
|
| 117 |
+ builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
|
| 115 | 118 |
name: "BadChownFlagFormat", |
| 116 | 119 |
chownStr: "bob:1:555", |
| 117 | 120 |
idMapping: unmapped, |
| 121 |
+ state: &dispatchState{},
|
|
| 118 | 122 |
descr: "invalid chown string format: bob:1:555", |
| 119 | 123 |
}, |
| 120 | 124 |
{
|
| 125 |
+ builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
|
| 121 | 126 |
name: "UserNoExist", |
| 122 | 127 |
chownStr: "bob", |
| 123 | 128 |
idMapping: unmapped, |
| 129 |
+ state: &dispatchState{},
|
|
| 124 | 130 |
descr: "can't find uid for user bob: no such user: bob", |
| 125 | 131 |
}, |
| 126 | 132 |
{
|
| 133 |
+ builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
|
|
| 127 | 134 |
name: "GroupNoExist", |
| 128 | 135 |
chownStr: "root:bob", |
| 129 | 136 |
idMapping: unmapped, |
| 137 |
+ state: &dispatchState{},
|
|
| 130 | 138 |
descr: "can't find gid for group bob: no such group: bob", |
| 131 | 139 |
}, |
| 132 | 140 |
} {
|
| 133 | 141 |
t.Run(testcase.name, func(t *testing.T) {
|
| 134 |
- _, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping) |
|
| 142 |
+ _, err := parseChownFlag(testcase.builder, testcase.state, testcase.chownStr, contextDir, testcase.idMapping) |
|
| 135 | 143 |
assert.Check(t, is.Error(err, testcase.descr), "Expected error string doesn't match") |
| 136 | 144 |
}) |
| 137 | 145 |
} |
| ... | ... |
@@ -1,7 +1,120 @@ |
| 1 | 1 |
package dockerfile // import "github.com/docker/docker/builder/dockerfile" |
| 2 | 2 |
|
| 3 |
-import "github.com/docker/docker/pkg/idtools" |
|
| 3 |
+import ( |
|
| 4 |
+ "bytes" |
|
| 5 |
+ "os" |
|
| 6 |
+ "path/filepath" |
|
| 7 |
+ "strings" |
|
| 4 | 8 |
|
| 5 |
-func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) {
|
|
| 6 |
- return idMappings.RootPair(), nil |
|
| 9 |
+ "github.com/containerd/containerd/platforms" |
|
| 10 |
+ "github.com/docker/docker/api/types/container" |
|
| 11 |
+ "github.com/docker/docker/api/types/mount" |
|
| 12 |
+ "github.com/docker/docker/pkg/idtools" |
|
| 13 |
+ "github.com/docker/docker/pkg/jsonmessage" |
|
| 14 |
+ "github.com/docker/docker/pkg/system" |
|
| 15 |
+ "github.com/pkg/errors" |
|
| 16 |
+ "golang.org/x/sys/windows" |
|
| 17 |
+) |
|
| 18 |
+ |
|
| 19 |
+func parseChownFlag(builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping *idtools.IdentityMapping) (idtools.Identity, error) {
|
|
| 20 |
+ if builder.options.Platform == "windows" {
|
|
| 21 |
+ return getAccountIdentity(builder, chown, ctrRootPath, state) |
|
| 22 |
+ } |
|
| 23 |
+ |
|
| 24 |
+ return identityMapping.RootPair(), nil |
|
| 25 |
+} |
|
| 26 |
+ |
|
| 27 |
+func getAccountIdentity(builder *Builder, accountName string, ctrRootPath string, state *dispatchState) (idtools.Identity, error) {
|
|
| 28 |
+ // If this is potentially a string SID then attempt to convert it to verify |
|
| 29 |
+ // this, otherwise continue looking for the account. |
|
| 30 |
+ if strings.HasPrefix(accountName, "S-") || strings.HasPrefix(accountName, "s-") {
|
|
| 31 |
+ sid, err := windows.StringToSid(accountName) |
|
| 32 |
+ |
|
| 33 |
+ if err == nil {
|
|
| 34 |
+ accountSid, err := sid.String() |
|
| 35 |
+ |
|
| 36 |
+ if err != nil {
|
|
| 37 |
+ return idtools.Identity{SID: ""}, errors.Wrapf(err, "error converting SID to string")
|
|
| 38 |
+ } |
|
| 39 |
+ |
|
| 40 |
+ return idtools.Identity{SID: accountSid}, nil
|
|
| 41 |
+ } |
|
| 42 |
+ } |
|
| 43 |
+ |
|
| 44 |
+ // Attempt to obtain the SID using the name. |
|
| 45 |
+ sid, _, accType, err := windows.LookupSID("", accountName)
|
|
| 46 |
+ |
|
| 47 |
+ // If this is a SID that is built-in and hence the same across all systems then use that. |
|
| 48 |
+ if err == nil && (accType == windows.SidTypeAlias || accType == windows.SidTypeWellKnownGroup) {
|
|
| 49 |
+ accountSid, err := sid.String() |
|
| 50 |
+ |
|
| 51 |
+ if err != nil {
|
|
| 52 |
+ return idtools.Identity{SID: ""}, errors.Wrapf(err, "error converting SID to string")
|
|
| 53 |
+ } |
|
| 54 |
+ |
|
| 55 |
+ return idtools.Identity{SID: accountSid}, nil
|
|
| 56 |
+ } |
|
| 57 |
+ |
|
| 58 |
+ // Check if the account name is one unique to containers. |
|
| 59 |
+ if strings.EqualFold(accountName, "ContainerAdministrator") {
|
|
| 60 |
+ return idtools.Identity{SID: system.ContainerAdministratorSidString}, nil
|
|
| 61 |
+ |
|
| 62 |
+ } else if strings.EqualFold(accountName, "ContainerUser") {
|
|
| 63 |
+ return idtools.Identity{SID: system.ContainerUserSidString}, nil
|
|
| 64 |
+ } |
|
| 65 |
+ |
|
| 66 |
+ // All other lookups failed, so therefore determine if the account in |
|
| 67 |
+ // question exists in the container and if so, obtain its SID. |
|
| 68 |
+ return lookupNTAccount(builder, accountName, state) |
|
| 69 |
+} |
|
| 70 |
+ |
|
| 71 |
+func lookupNTAccount(builder *Builder, accountName string, state *dispatchState) (idtools.Identity, error) {
|
|
| 72 |
+ |
|
| 73 |
+ source, _ := filepath.Split(os.Args[0]) |
|
| 74 |
+ |
|
| 75 |
+ target := "C:\\Docker" |
|
| 76 |
+ targetExecutable := target + "\\containerutility.exe" |
|
| 77 |
+ |
|
| 78 |
+ optionsPlatform, err := platforms.Parse(builder.options.Platform) |
|
| 79 |
+ if err != nil {
|
|
| 80 |
+ return idtools.Identity{}, err
|
|
| 81 |
+ } |
|
| 82 |
+ |
|
| 83 |
+ runConfig := copyRunConfig(state.runConfig, |
|
| 84 |
+ withCmdCommentString("internal run to obtain NT account information.", optionsPlatform.OS))
|
|
| 85 |
+ |
|
| 86 |
+ runConfig.ArgsEscaped = true |
|
| 87 |
+ runConfig.Cmd = []string{targetExecutable, "getaccountsid", accountName}
|
|
| 88 |
+ |
|
| 89 |
+ hostConfig := &container.HostConfig{Mounts: []mount.Mount{
|
|
| 90 |
+ {
|
|
| 91 |
+ Type: mount.TypeBind, |
|
| 92 |
+ Source: source, |
|
| 93 |
+ Target: target, |
|
| 94 |
+ ReadOnly: true, |
|
| 95 |
+ }, |
|
| 96 |
+ }, |
|
| 97 |
+ } |
|
| 98 |
+ |
|
| 99 |
+ container, err := builder.containerManager.Create(runConfig, hostConfig) |
|
| 100 |
+ if err != nil {
|
|
| 101 |
+ return idtools.Identity{}, err
|
|
| 102 |
+ } |
|
| 103 |
+ |
|
| 104 |
+ stdout := new(bytes.Buffer) |
|
| 105 |
+ stderr := new(bytes.Buffer) |
|
| 106 |
+ |
|
| 107 |
+ if err := builder.containerManager.Run(builder.clientCtx, container.ID, stdout, stderr); err != nil {
|
|
| 108 |
+ if err, ok := err.(*statusCodeError); ok {
|
|
| 109 |
+ return idtools.Identity{}, &jsonmessage.JSONError{
|
|
| 110 |
+ Message: stderr.String(), |
|
| 111 |
+ Code: err.StatusCode(), |
|
| 112 |
+ } |
|
| 113 |
+ } |
|
| 114 |
+ return idtools.Identity{}, err
|
|
| 115 |
+ } |
|
| 116 |
+ |
|
| 117 |
+ accountSid := stdout.String() |
|
| 118 |
+ |
|
| 119 |
+ return idtools.Identity{SID: accountSid}, nil
|
|
| 7 | 120 |
} |
| ... | ... |
@@ -267,7 +267,7 @@ func newRouterOptions(config *config.Config, daemon *daemon.Daemon) (routerOptio |
| 267 | 267 |
return opts, errors.Wrap(err, "failed to create fscache") |
| 268 | 268 |
} |
| 269 | 269 |
|
| 270 |
- manager, err := dockerfile.NewBuildManager(daemon.BuilderBackend(), sm, buildCache, daemon.IDMappings()) |
|
| 270 |
+ manager, err := dockerfile.NewBuildManager(daemon.BuilderBackend(), sm, buildCache, daemon.IdentityMapping()) |
|
| 271 | 271 |
if err != nil {
|
| 272 | 272 |
return opts, err |
| 273 | 273 |
} |
| ... | ... |
@@ -254,7 +254,7 @@ func (container *Container) WriteHostConfig() (*containertypes.HostConfig, error |
| 254 | 254 |
} |
| 255 | 255 |
|
| 256 | 256 |
// SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir |
| 257 |
-func (container *Container) SetupWorkingDirectory(rootIDs idtools.IDPair) error {
|
|
| 257 |
+func (container *Container) SetupWorkingDirectory(rootIdentity idtools.Identity) error {
|
|
| 258 | 258 |
// TODO @jhowardmsft, @gupta-ak LCOW Support. This will need revisiting. |
| 259 | 259 |
// We will need to do remote filesystem operations here. |
| 260 | 260 |
if container.OS != runtime.GOOS {
|
| ... | ... |
@@ -271,7 +271,7 @@ func (container *Container) SetupWorkingDirectory(rootIDs idtools.IDPair) error |
| 271 | 271 |
return err |
| 272 | 272 |
} |
| 273 | 273 |
|
| 274 |
- if err := idtools.MkdirAllAndChownNew(pth, 0755, rootIDs); err != nil {
|
|
| 274 |
+ if err := idtools.MkdirAllAndChownNew(pth, 0755, rootIdentity); err != nil {
|
|
| 275 | 275 |
pthInfo, err2 := os.Stat(pth) |
| 276 | 276 |
if err2 == nil && pthInfo != nil && !pthInfo.IsDir() {
|
| 277 | 277 |
return errors.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir)
|
| ... | ... |
@@ -9,7 +9,7 @@ import ( |
| 9 | 9 |
func (daemon *Daemon) defaultTarCopyOptions(noOverwriteDirNonDir bool) *archive.TarOptions {
|
| 10 | 10 |
return &archive.TarOptions{
|
| 11 | 11 |
NoOverwriteDirNonDir: noOverwriteDirNonDir, |
| 12 |
- UIDMaps: daemon.idMappings.UIDs(), |
|
| 13 |
- GIDMaps: daemon.idMappings.GIDs(), |
|
| 12 |
+ UIDMaps: daemon.idMapping.UIDs(), |
|
| 13 |
+ GIDMaps: daemon.idMapping.GIDs(), |
|
| 14 | 14 |
} |
| 15 | 15 |
} |
| ... | ... |
@@ -18,8 +18,10 @@ func (daemon *Daemon) tarCopyOptions(container *container.Container, noOverwrite |
| 18 | 18 |
return nil, err |
| 19 | 19 |
} |
| 20 | 20 |
|
| 21 |
+ identity := idtools.Identity{UID: user.Uid, GID: user.Gid}
|
|
| 22 |
+ |
|
| 21 | 23 |
return &archive.TarOptions{
|
| 22 | 24 |
NoOverwriteDirNonDir: noOverwriteDirNonDir, |
| 23 |
- ChownOpts: &idtools.IDPair{UID: user.Uid, GID: user.Gid},
|
|
| 25 |
+ ChownOpts: &identity, |
|
| 24 | 26 |
}, nil |
| 25 | 27 |
} |
| ... | ... |
@@ -132,7 +132,7 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
|
| 132 | 132 |
fallthrough |
| 133 | 133 |
|
| 134 | 134 |
case ipcMode.IsShareable(): |
| 135 |
- rootIDs := daemon.idMappings.RootPair() |
|
| 135 |
+ rootIDs := daemon.idMapping.RootPair() |
|
| 136 | 136 |
if !c.HasMountFor("/dev/shm") {
|
| 137 | 137 |
shmPath, err := c.ShmResourcePath() |
| 138 | 138 |
if err != nil {
|
| ... | ... |
@@ -179,7 +179,7 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
|
| 179 | 179 |
} |
| 180 | 180 |
|
| 181 | 181 |
// retrieve possible remapped range start for root UID, GID |
| 182 |
- rootIDs := daemon.idMappings.RootPair() |
|
| 182 |
+ rootIDs := daemon.idMapping.RootPair() |
|
| 183 | 183 |
|
| 184 | 184 |
for _, s := range c.SecretReferences {
|
| 185 | 185 |
// TODO (ehazlett): use type switch when more are supported |
| ... | ... |
@@ -278,7 +278,7 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
|
| 278 | 278 |
// In practice this is using a tmpfs mount and is used for both "configs" and "secrets" |
| 279 | 279 |
func (daemon *Daemon) createSecretsDir(c *container.Container) error {
|
| 280 | 280 |
// retrieve possible remapped range start for root UID, GID |
| 281 |
- rootIDs := daemon.idMappings.RootPair() |
|
| 281 |
+ rootIDs := daemon.idMapping.RootPair() |
|
| 282 | 282 |
dir, err := c.SecretMountPath() |
| 283 | 283 |
if err != nil {
|
| 284 | 284 |
return errors.Wrap(err, "error getting container secrets dir") |
| ... | ... |
@@ -304,7 +304,7 @@ func (daemon *Daemon) remountSecretDir(c *container.Container) error {
|
| 304 | 304 |
if err := label.Relabel(dir, c.MountLabel, false); err != nil {
|
| 305 | 305 |
logrus.WithError(err).WithField("dir", dir).Warn("Error while attempting to set selinux label")
|
| 306 | 306 |
} |
| 307 |
- rootIDs := daemon.idMappings.RootPair() |
|
| 307 |
+ rootIDs := daemon.idMapping.RootPair() |
|
| 308 | 308 |
tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
|
| 309 | 309 |
|
| 310 | 310 |
// remount secrets ro |
| ... | ... |
@@ -407,5 +407,5 @@ func (daemon *Daemon) setupContainerMountsRoot(c *container.Container) error {
|
| 407 | 407 |
if err != nil {
|
| 408 | 408 |
return err |
| 409 | 409 |
} |
| 410 |
- return idtools.MkdirAllAndChown(p, 0700, daemon.idMappings.RootPair()) |
|
| 410 |
+ return idtools.MkdirAllAndChown(p, 0700, daemon.idMapping.RootPair()) |
|
| 411 | 411 |
} |
| ... | ... |
@@ -155,13 +155,14 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) ( |
| 155 | 155 |
} |
| 156 | 156 |
|
| 157 | 157 |
// Set RWLayer for container after mount labels have been set |
| 158 |
- rwLayer, err := daemon.imageService.CreateLayer(container, setupInitLayer(daemon.idMappings)) |
|
| 158 |
+ rwLayer, err := daemon.imageService.CreateLayer(container, setupInitLayer(daemon.idMapping)) |
|
| 159 | 159 |
if err != nil {
|
| 160 | 160 |
return nil, errdefs.System(err) |
| 161 | 161 |
} |
| 162 | 162 |
container.RWLayer = rwLayer |
| 163 | 163 |
|
| 164 |
- rootIDs := daemon.idMappings.RootPair() |
|
| 164 |
+ rootIDs := daemon.idMapping.RootPair() |
|
| 165 |
+ |
|
| 165 | 166 |
if err := idtools.MkdirAndChown(container.Root, 0700, rootIDs); err != nil {
|
| 166 | 167 |
return nil, err |
| 167 | 168 |
} |
| ... | ... |
@@ -25,7 +25,7 @@ func (daemon *Daemon) createContainerOSSpecificSettings(container *container.Con |
| 25 | 25 |
} |
| 26 | 26 |
defer daemon.Unmount(container) |
| 27 | 27 |
|
| 28 |
- rootIDs := daemon.idMappings.RootPair() |
|
| 28 |
+ rootIDs := daemon.idMapping.RootPair() |
|
| 29 | 29 |
if err := container.SetupWorkingDirectory(rootIDs); err != nil {
|
| 30 | 30 |
return err |
| 31 | 31 |
} |
| ... | ... |
@@ -87,7 +87,7 @@ type Daemon struct {
|
| 87 | 87 |
seccompEnabled bool |
| 88 | 88 |
apparmorEnabled bool |
| 89 | 89 |
shutdown bool |
| 90 |
- idMappings *idtools.IDMappings |
|
| 90 |
+ idMapping *idtools.IdentityMapping |
|
| 91 | 91 |
// TODO: move graphDrivers field to an InfoService |
| 92 | 92 |
graphDrivers map[string]string // By operating system |
| 93 | 93 |
|
| ... | ... |
@@ -594,11 +594,11 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe |
| 594 | 594 |
return nil, err |
| 595 | 595 |
} |
| 596 | 596 |
|
| 597 |
- idMappings, err := setupRemappedRoot(config) |
|
| 597 |
+ idMapping, err := setupRemappedRoot(config) |
|
| 598 | 598 |
if err != nil {
|
| 599 | 599 |
return nil, err |
| 600 | 600 |
} |
| 601 |
- rootIDs := idMappings.RootPair() |
|
| 601 |
+ rootIDs := idMapping.RootPair() |
|
| 602 | 602 |
if err := setupDaemonProcess(config); err != nil {
|
| 603 | 603 |
return nil, err |
| 604 | 604 |
} |
| ... | ... |
@@ -749,7 +749,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe |
| 749 | 749 |
MetadataStorePathTemplate: filepath.Join(config.Root, "image", "%s", "layerdb"), |
| 750 | 750 |
GraphDriver: gd, |
| 751 | 751 |
GraphDriverOptions: config.GraphOptions, |
| 752 |
- IDMappings: idMappings, |
|
| 752 |
+ IDMapping: idMapping, |
|
| 753 | 753 |
PluginGetter: d.PluginStore, |
| 754 | 754 |
ExperimentalEnabled: config.Experimental, |
| 755 | 755 |
OS: operatingSystem, |
| ... | ... |
@@ -856,7 +856,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe |
| 856 | 856 |
|
| 857 | 857 |
d.EventsService = events.New() |
| 858 | 858 |
d.root = config.Root |
| 859 |
- d.idMappings = idMappings |
|
| 859 |
+ d.idMapping = idMapping |
|
| 860 | 860 |
d.seccompEnabled = sysInfo.Seccomp |
| 861 | 861 |
d.apparmorEnabled = sysInfo.AppArmor |
| 862 | 862 |
|
| ... | ... |
@@ -1106,7 +1106,7 @@ func (daemon *Daemon) Subnets() ([]net.IPNet, []net.IPNet) {
|
| 1106 | 1106 |
// prepareTempDir prepares and returns the default directory to use |
| 1107 | 1107 |
// for temporary files. |
| 1108 | 1108 |
// If it doesn't exist, it is created. If it exists, its content is removed. |
| 1109 |
-func prepareTempDir(rootDir string, rootIDs idtools.IDPair) (string, error) {
|
|
| 1109 |
+func prepareTempDir(rootDir string, rootIdentity idtools.Identity) (string, error) {
|
|
| 1110 | 1110 |
var tmpDir string |
| 1111 | 1111 |
if tmpDir = os.Getenv("DOCKER_TMPDIR"); tmpDir == "" {
|
| 1112 | 1112 |
tmpDir = filepath.Join(rootDir, "tmp") |
| ... | ... |
@@ -1126,7 +1126,7 @@ func prepareTempDir(rootDir string, rootIDs idtools.IDPair) (string, error) {
|
| 1126 | 1126 |
} |
| 1127 | 1127 |
// We don't remove the content of tmpdir if it's not the default, |
| 1128 | 1128 |
// it may hold things that do not belong to us. |
| 1129 |
- return tmpDir, idtools.MkdirAllAndChown(tmpDir, 0700, rootIDs) |
|
| 1129 |
+ return tmpDir, idtools.MkdirAllAndChown(tmpDir, 0700, rootIdentity) |
|
| 1130 | 1130 |
} |
| 1131 | 1131 |
|
| 1132 | 1132 |
func (daemon *Daemon) setGenericResources(conf *config.Config) error {
|
| ... | ... |
@@ -1274,11 +1274,11 @@ func CreateDaemonRoot(config *config.Config) error {
|
| 1274 | 1274 |
} |
| 1275 | 1275 |
} |
| 1276 | 1276 |
|
| 1277 |
- idMappings, err := setupRemappedRoot(config) |
|
| 1277 |
+ idMapping, err := setupRemappedRoot(config) |
|
| 1278 | 1278 |
if err != nil {
|
| 1279 | 1279 |
return err |
| 1280 | 1280 |
} |
| 1281 |
- return setupDaemonRoot(config, realRoot, idMappings.RootPair()) |
|
| 1281 |
+ return setupDaemonRoot(config, realRoot, idMapping.RootPair()) |
|
| 1282 | 1282 |
} |
| 1283 | 1283 |
|
| 1284 | 1284 |
// checkpointAndSave grabs a container lock to safely call container.CheckpointTo |
| ... | ... |
@@ -1304,9 +1304,9 @@ func (daemon *Daemon) GetAttachmentStore() *network.AttachmentStore {
|
| 1304 | 1304 |
return &daemon.attachmentStore |
| 1305 | 1305 |
} |
| 1306 | 1306 |
|
| 1307 |
-// IDMappings returns uid/gid mappings for the builder |
|
| 1308 |
-func (daemon *Daemon) IDMappings() *idtools.IDMappings {
|
|
| 1309 |
- return daemon.idMappings |
|
| 1307 |
+// IdentityMapping returns uid/gid mapping or a SID (in the case of Windows) for the builder |
|
| 1308 |
+func (daemon *Daemon) IdentityMapping() *idtools.IdentityMapping {
|
|
| 1309 |
+ return daemon.idMapping |
|
| 1310 | 1310 |
} |
| 1311 | 1311 |
|
| 1312 | 1312 |
// ImageService returns the Daemon's ImageService |
| ... | ... |
@@ -124,7 +124,7 @@ func TestTmpfsDevShmSizeOverride(t *testing.T) {
|
| 124 | 124 |
mnt := "/dev/shm" |
| 125 | 125 |
|
| 126 | 126 |
d := Daemon{
|
| 127 |
- idMappings: &idtools.IDMappings{},
|
|
| 127 |
+ idMapping: &idtools.IdentityMapping{},
|
|
| 128 | 128 |
} |
| 129 | 129 |
c := &container.Container{
|
| 130 | 130 |
HostConfig: &containertypes.HostConfig{
|
| ... | ... |
@@ -118,7 +118,7 @@ func initDaemonWithVolumeStore(tmp string) (*Daemon, error) {
|
| 118 | 118 |
repository: tmp, |
| 119 | 119 |
root: tmp, |
| 120 | 120 |
} |
| 121 |
- daemon.volumes, err = volumesservice.NewVolumeService(tmp, nil, idtools.IDPair{UID: 0, GID: 0}, daemon)
|
|
| 121 |
+ daemon.volumes, err = volumesservice.NewVolumeService(tmp, nil, idtools.Identity{UID: 0, GID: 0}, daemon)
|
|
| 122 | 122 |
if err != nil {
|
| 123 | 123 |
return nil, err |
| 124 | 124 |
} |
| ... | ... |
@@ -1003,9 +1003,9 @@ func removeDefaultBridgeInterface() {
|
| 1003 | 1003 |
} |
| 1004 | 1004 |
} |
| 1005 | 1005 |
|
| 1006 |
-func setupInitLayer(idMappings *idtools.IDMappings) func(containerfs.ContainerFS) error {
|
|
| 1006 |
+func setupInitLayer(idMapping *idtools.IdentityMapping) func(containerfs.ContainerFS) error {
|
|
| 1007 | 1007 |
return func(initPath containerfs.ContainerFS) error {
|
| 1008 |
- return initlayer.Setup(initPath, idMappings.RootPair()) |
|
| 1008 |
+ return initlayer.Setup(initPath, idMapping.RootPair()) |
|
| 1009 | 1009 |
} |
| 1010 | 1010 |
} |
| 1011 | 1011 |
|
| ... | ... |
@@ -1102,7 +1102,7 @@ func parseRemappedRoot(usergrp string) (string, string, error) {
|
| 1102 | 1102 |
return username, groupname, nil |
| 1103 | 1103 |
} |
| 1104 | 1104 |
|
| 1105 |
-func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) {
|
|
| 1105 |
+func setupRemappedRoot(config *config.Config) (*idtools.IdentityMapping, error) {
|
|
| 1106 | 1106 |
if runtime.GOOS != "linux" && config.RemappedRoot != "" {
|
| 1107 | 1107 |
return nil, fmt.Errorf("User namespaces are only supported on Linux")
|
| 1108 | 1108 |
} |
| ... | ... |
@@ -1118,22 +1118,22 @@ func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) {
|
| 1118 | 1118 |
// Cannot setup user namespaces with a 1-to-1 mapping; "--root=0:0" is a no-op |
| 1119 | 1119 |
// effectively |
| 1120 | 1120 |
logrus.Warn("User namespaces: root cannot be remapped with itself; user namespaces are OFF")
|
| 1121 |
- return &idtools.IDMappings{}, nil
|
|
| 1121 |
+ return &idtools.IdentityMapping{}, nil
|
|
| 1122 | 1122 |
} |
| 1123 | 1123 |
logrus.Infof("User namespaces: ID ranges will be mapped to subuid/subgid ranges of: %s:%s", username, groupname)
|
| 1124 | 1124 |
// update remapped root setting now that we have resolved them to actual names |
| 1125 | 1125 |
config.RemappedRoot = fmt.Sprintf("%s:%s", username, groupname)
|
| 1126 | 1126 |
|
| 1127 |
- mappings, err := idtools.NewIDMappings(username, groupname) |
|
| 1127 |
+ mappings, err := idtools.NewIdentityMapping(username, groupname) |
|
| 1128 | 1128 |
if err != nil {
|
| 1129 | 1129 |
return nil, errors.Wrap(err, "Can't create ID mappings") |
| 1130 | 1130 |
} |
| 1131 | 1131 |
return mappings, nil |
| 1132 | 1132 |
} |
| 1133 |
- return &idtools.IDMappings{}, nil
|
|
| 1133 |
+ return &idtools.IdentityMapping{}, nil
|
|
| 1134 | 1134 |
} |
| 1135 | 1135 |
|
| 1136 |
-func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPair) error {
|
|
| 1136 |
+func setupDaemonRoot(config *config.Config, rootDir string, rootIdentity idtools.Identity) error {
|
|
| 1137 | 1137 |
config.Root = rootDir |
| 1138 | 1138 |
// the docker root metadata directory needs to have execute permissions for all users (g+x,o+x) |
| 1139 | 1139 |
// 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 |
| 1158 | 1158 |
// a new subdirectory with ownership set to the remapped uid/gid (so as to allow |
| 1159 | 1159 |
// `chdir()` to work for containers namespaced to that uid/gid) |
| 1160 | 1160 |
if config.RemappedRoot != "" {
|
| 1161 |
- config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootIDs.UID, rootIDs.GID))
|
|
| 1161 |
+ config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootIdentity.UID, rootIdentity.GID))
|
|
| 1162 | 1162 |
logrus.Debugf("Creating user namespaced daemon root: %s", config.Root)
|
| 1163 | 1163 |
// Create the root directory if it doesn't exist |
| 1164 |
- if err := idtools.MkdirAllAndChown(config.Root, 0700, rootIDs); err != nil {
|
|
| 1164 |
+ if err := idtools.MkdirAllAndChown(config.Root, 0700, rootIdentity); err != nil {
|
|
| 1165 | 1165 |
return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err)
|
| 1166 | 1166 |
} |
| 1167 | 1167 |
// 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 |
| 1174 | 1174 |
if dirPath == "/" {
|
| 1175 | 1175 |
break |
| 1176 | 1176 |
} |
| 1177 |
- if !idtools.CanAccess(dirPath, rootIDs) {
|
|
| 1177 |
+ if !idtools.CanAccess(dirPath, rootIdentity) {
|
|
| 1178 | 1178 |
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)
|
| 1179 | 1179 |
} |
| 1180 | 1180 |
} |
| ... | ... |
@@ -53,7 +53,7 @@ func parseSecurityOpt(container *container.Container, config *containertypes.Hos |
| 53 | 53 |
return nil |
| 54 | 54 |
} |
| 55 | 55 |
|
| 56 |
-func setupInitLayer(idMappings *idtools.IDMappings) func(containerfs.ContainerFS) error {
|
|
| 56 |
+func setupInitLayer(idMapping *idtools.IdentityMapping) func(containerfs.ContainerFS) error {
|
|
| 57 | 57 |
return nil |
| 58 | 58 |
} |
| 59 | 59 |
|
| ... | ... |
@@ -465,11 +465,11 @@ func (daemon *Daemon) cleanupMounts() error {
|
| 465 | 465 |
return nil |
| 466 | 466 |
} |
| 467 | 467 |
|
| 468 |
-func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) {
|
|
| 469 |
- return &idtools.IDMappings{}, nil
|
|
| 468 |
+func setupRemappedRoot(config *config.Config) (*idtools.IdentityMapping, error) {
|
|
| 469 |
+ return &idtools.IdentityMapping{}, nil
|
|
| 470 | 470 |
} |
| 471 | 471 |
|
| 472 |
-func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPair) error {
|
|
| 472 |
+func setupDaemonRoot(config *config.Config, rootDir string, rootIdentity idtools.Identity) error {
|
|
| 473 | 473 |
config.Root = rootDir |
| 474 | 474 |
// Create the root directory if it doesn't exists |
| 475 | 475 |
if err := system.MkdirAllWithACL(config.Root, 0, system.SddlAdministratorsLocalSystem); err != nil {
|
| ... | ... |
@@ -68,8 +68,8 @@ func (daemon *Daemon) containerExport(container *container.Container) (arch io.R |
| 68 | 68 |
|
| 69 | 69 |
archive, err := archivePath(basefs, basefs.Path(), &archive.TarOptions{
|
| 70 | 70 |
Compression: archive.Uncompressed, |
| 71 |
- UIDMaps: daemon.idMappings.UIDs(), |
|
| 72 |
- GIDMaps: daemon.idMappings.GIDs(), |
|
| 71 |
+ UIDMaps: daemon.idMapping.UIDs(), |
|
| 72 |
+ GIDMaps: daemon.idMapping.GIDs(), |
|
| 73 | 73 |
}) |
| 74 | 74 |
if err != nil {
|
| 75 | 75 |
rwlayer.Unmount() |
| ... | ... |
@@ -135,13 +135,13 @@ func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap |
| 135 | 135 |
return nil, err |
| 136 | 136 |
} |
| 137 | 137 |
// Create the root aufs driver dir |
| 138 |
- if err := idtools.MkdirAllAndChown(root, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 138 |
+ if err := idtools.MkdirAllAndChown(root, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 139 | 139 |
return nil, err |
| 140 | 140 |
} |
| 141 | 141 |
|
| 142 | 142 |
// Populate the dir structure |
| 143 | 143 |
for _, p := range paths {
|
| 144 |
- if err := idtools.MkdirAllAndChown(path.Join(root, p), 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 144 |
+ if err := idtools.MkdirAllAndChown(path.Join(root, p), 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 145 | 145 |
return nil, err |
| 146 | 146 |
} |
| 147 | 147 |
} |
| ... | ... |
@@ -289,7 +289,7 @@ func (a *Driver) createDirsFor(id string) error {
|
| 289 | 289 |
// The path of directories are <aufs_root_path>/mnt/<image_id> |
| 290 | 290 |
// and <aufs_root_path>/diff/<image_id> |
| 291 | 291 |
for _, p := range paths {
|
| 292 |
- if err := idtools.MkdirAllAndChown(path.Join(a.rootPath(), p, id), 0755, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 292 |
+ if err := idtools.MkdirAllAndChown(path.Join(a.rootPath(), p, id), 0755, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 293 | 293 |
return err |
| 294 | 294 |
} |
| 295 | 295 |
} |
| ... | ... |
@@ -72,7 +72,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap |
| 72 | 72 |
if err != nil {
|
| 73 | 73 |
return nil, err |
| 74 | 74 |
} |
| 75 |
- if err := idtools.MkdirAllAndChown(home, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 75 |
+ if err := idtools.MkdirAllAndChown(home, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 76 | 76 |
return nil, err |
| 77 | 77 |
} |
| 78 | 78 |
|
| ... | ... |
@@ -502,7 +502,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
|
| 502 | 502 |
if err != nil {
|
| 503 | 503 |
return err |
| 504 | 504 |
} |
| 505 |
- if err := idtools.MkdirAllAndChown(subvolumes, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 505 |
+ if err := idtools.MkdirAllAndChown(subvolumes, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 506 | 506 |
return err |
| 507 | 507 |
} |
| 508 | 508 |
if parent == "" {
|
| ... | ... |
@@ -537,7 +537,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
|
| 537 | 537 |
if err := d.setStorageSize(path.Join(subvolumes, id), driver); err != nil {
|
| 538 | 538 |
return err |
| 539 | 539 |
} |
| 540 |
- if err := idtools.MkdirAllAndChown(quotas, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 540 |
+ if err := idtools.MkdirAllAndChown(quotas, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 541 | 541 |
return err |
| 542 | 542 |
} |
| 543 | 543 |
if err := ioutil.WriteFile(path.Join(quotas, id), []byte(fmt.Sprint(driver.options.size)), 0644); err != nil {
|
| ... | ... |
@@ -268,7 +268,7 @@ func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) {
|
| 268 | 268 |
if err != nil {
|
| 269 | 269 |
return "", err |
| 270 | 270 |
} |
| 271 |
- if err := idtools.MkdirAllAndChown(dirname, 0700, idtools.IDPair{UID: uid, GID: gid}); err != nil {
|
|
| 271 |
+ if err := idtools.MkdirAllAndChown(dirname, 0700, idtools.Identity{UID: uid, GID: gid}); err != nil {
|
|
| 272 | 272 |
return "", err |
| 273 | 273 |
} |
| 274 | 274 |
|
| ... | ... |
@@ -1691,7 +1691,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) (retErr error) {
|
| 1691 | 1691 |
if err != nil {
|
| 1692 | 1692 |
return err |
| 1693 | 1693 |
} |
| 1694 |
- if err := idtools.MkdirAndChown(devices.root, 0700, idtools.IDPair{UID: uid, GID: gid}); err != nil {
|
|
| 1694 |
+ if err := idtools.MkdirAndChown(devices.root, 0700, idtools.Identity{UID: uid, GID: gid}); err != nil {
|
|
| 1695 | 1695 |
return err |
| 1696 | 1696 |
} |
| 1697 | 1697 |
if err := os.MkdirAll(devices.metadataDir(), 0700); err != nil {
|
| ... | ... |
@@ -200,11 +200,11 @@ func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
|
| 200 | 200 |
} |
| 201 | 201 |
|
| 202 | 202 |
// Create the target directories if they don't exist |
| 203 |
- if err := idtools.MkdirAllAndChown(path.Join(d.home, "mnt"), 0755, idtools.IDPair{UID: uid, GID: gid}); err != nil {
|
|
| 203 |
+ if err := idtools.MkdirAllAndChown(path.Join(d.home, "mnt"), 0755, idtools.Identity{UID: uid, GID: gid}); err != nil {
|
|
| 204 | 204 |
d.ctr.Decrement(mp) |
| 205 | 205 |
return nil, err |
| 206 | 206 |
} |
| 207 |
- if err := idtools.MkdirAndChown(mp, 0755, idtools.IDPair{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
|
|
| 207 |
+ if err := idtools.MkdirAndChown(mp, 0755, idtools.Identity{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
|
|
| 208 | 208 |
d.ctr.Decrement(mp) |
| 209 | 209 |
return nil, err |
| 210 | 210 |
} |
| ... | ... |
@@ -215,7 +215,7 @@ func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
|
| 215 | 215 |
return nil, err |
| 216 | 216 |
} |
| 217 | 217 |
|
| 218 |
- if err := idtools.MkdirAllAndChown(rootFs, 0755, idtools.IDPair{UID: uid, GID: gid}); err != nil {
|
|
| 218 |
+ if err := idtools.MkdirAllAndChown(rootFs, 0755, idtools.Identity{UID: uid, GID: gid}); err != nil {
|
|
| 219 | 219 |
d.ctr.Decrement(mp) |
| 220 | 220 |
d.DeviceSet.UnmountDevice(id, mp) |
| 221 | 221 |
return nil, err |
| ... | ... |
@@ -183,17 +183,17 @@ func InitDriver(dataRoot string, options []string, _, _ []idtools.IDMap) (graphd |
| 183 | 183 |
} |
| 184 | 184 |
|
| 185 | 185 |
// Make sure the dataRoot directory is created |
| 186 |
- if err := idtools.MkdirAllAndChown(dataRoot, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil {
|
|
| 186 |
+ if err := idtools.MkdirAllAndChown(dataRoot, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
|
|
| 187 | 187 |
return nil, fmt.Errorf("%s failed to create '%s': %v", title, dataRoot, err)
|
| 188 | 188 |
} |
| 189 | 189 |
|
| 190 | 190 |
// Make sure the cache directory is created under dataRoot |
| 191 |
- if err := idtools.MkdirAllAndChown(cd, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil {
|
|
| 191 |
+ if err := idtools.MkdirAllAndChown(cd, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
|
|
| 192 | 192 |
return nil, fmt.Errorf("%s failed to create '%s': %v", title, cd, err)
|
| 193 | 193 |
} |
| 194 | 194 |
|
| 195 | 195 |
// Make sure the scratch directory is created under dataRoot |
| 196 |
- if err := idtools.MkdirAllAndChown(sd, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil {
|
|
| 196 |
+ if err := idtools.MkdirAllAndChown(sd, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
|
|
| 197 | 197 |
return nil, fmt.Errorf("%s failed to create '%s': %v", title, sd, err)
|
| 198 | 198 |
} |
| 199 | 199 |
|
| ... | ... |
@@ -168,7 +168,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap |
| 168 | 168 |
return nil, err |
| 169 | 169 |
} |
| 170 | 170 |
// Create the driver home dir |
| 171 |
- if err := idtools.MkdirAllAndChown(home, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 171 |
+ if err := idtools.MkdirAllAndChown(home, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 172 | 172 |
return nil, err |
| 173 | 173 |
} |
| 174 | 174 |
|
| ... | ... |
@@ -291,7 +291,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr |
| 291 | 291 |
if err != nil {
|
| 292 | 292 |
return err |
| 293 | 293 |
} |
| 294 |
- root := idtools.IDPair{UID: rootUID, GID: rootGID}
|
|
| 294 |
+ root := idtools.Identity{UID: rootUID, GID: rootGID}
|
|
| 295 | 295 |
|
| 296 | 296 |
if err := idtools.MkdirAllAndChown(path.Dir(dir), 0700, root); err != nil {
|
| 297 | 297 |
return err |
| ... | ... |
@@ -413,7 +413,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, err erro |
| 413 | 413 |
if err != nil {
|
| 414 | 414 |
return nil, err |
| 415 | 415 |
} |
| 416 |
- if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 416 |
+ if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 417 | 417 |
return nil, err |
| 418 | 418 |
} |
| 419 | 419 |
var ( |
| ... | ... |
@@ -200,7 +200,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap |
| 200 | 200 |
return nil, err |
| 201 | 201 |
} |
| 202 | 202 |
// Create the driver home dir |
| 203 |
- if err := idtools.MkdirAllAndChown(path.Join(home, linkDir), 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 203 |
+ if err := idtools.MkdirAllAndChown(path.Join(home, linkDir), 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 204 | 204 |
return nil, err |
| 205 | 205 |
} |
| 206 | 206 |
|
| ... | ... |
@@ -378,7 +378,7 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr |
| 378 | 378 |
if err != nil {
|
| 379 | 379 |
return err |
| 380 | 380 |
} |
| 381 |
- root := idtools.IDPair{UID: rootUID, GID: rootGID}
|
|
| 381 |
+ root := idtools.Identity{UID: rootUID, GID: rootGID}
|
|
| 382 | 382 |
|
| 383 | 383 |
if err := idtools.MkdirAllAndChown(path.Dir(dir), 0700, root); err != nil {
|
| 384 | 384 |
return err |
| ... | ... |
@@ -586,7 +586,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e |
| 586 | 586 |
if err != nil {
|
| 587 | 587 |
return nil, err |
| 588 | 588 |
} |
| 589 |
- if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 589 |
+ if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 590 | 590 |
return nil, err |
| 591 | 591 |
} |
| 592 | 592 |
|
| ... | ... |
@@ -27,10 +27,10 @@ func init() {
|
| 27 | 27 |
// This sets the home directory for the driver and returns NaiveDiffDriver. |
| 28 | 28 |
func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
|
| 29 | 29 |
d := &Driver{
|
| 30 |
- home: home, |
|
| 31 |
- idMappings: idtools.NewIDMappingsFromMaps(uidMaps, gidMaps), |
|
| 30 |
+ home: home, |
|
| 31 |
+ idMapping: idtools.NewIDMappingsFromMaps(uidMaps, gidMaps), |
|
| 32 | 32 |
} |
| 33 |
- rootIDs := d.idMappings.RootPair() |
|
| 33 |
+ rootIDs := d.idMapping.RootPair() |
|
| 34 | 34 |
if err := idtools.MkdirAllAndChown(home, 0700, rootIDs); err != nil {
|
| 35 | 35 |
return nil, err |
| 36 | 36 |
} |
| ... | ... |
@@ -46,8 +46,8 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap |
| 46 | 46 |
// Driver must be wrapped in NaiveDiffDriver to be used as a graphdriver.Driver |
| 47 | 47 |
type Driver struct {
|
| 48 | 48 |
driverQuota |
| 49 |
- home string |
|
| 50 |
- idMappings *idtools.IDMappings |
|
| 49 |
+ home string |
|
| 50 |
+ idMapping *idtools.IdentityMapping |
|
| 51 | 51 |
} |
| 52 | 52 |
|
| 53 | 53 |
func (d *Driver) String() string {
|
| ... | ... |
@@ -105,7 +105,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
|
| 105 | 105 |
|
| 106 | 106 |
func (d *Driver) create(id, parent string, size uint64) error {
|
| 107 | 107 |
dir := d.dir(id) |
| 108 |
- rootIDs := d.idMappings.RootPair() |
|
| 108 |
+ rootIDs := d.idMapping.RootPair() |
|
| 109 | 109 |
if err := idtools.MkdirAllAndChown(filepath.Dir(dir), 0700, rootIDs); err != nil {
|
| 110 | 110 |
return err |
| 111 | 111 |
} |
| ... | ... |
@@ -95,7 +95,7 @@ func InitFilter(home string, options []string, uidMaps, gidMaps []idtools.IDMap) |
| 95 | 95 |
return nil, fmt.Errorf("%s is on an ReFS volume - ReFS volumes are not supported", home)
|
| 96 | 96 |
} |
| 97 | 97 |
|
| 98 |
- if err := idtools.MkdirAllAndChown(home, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil {
|
|
| 98 |
+ if err := idtools.MkdirAllAndChown(home, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
|
|
| 99 | 99 |
return nil, fmt.Errorf("windowsfilter failed to create '%s': %v", home, err)
|
| 100 | 100 |
} |
| 101 | 101 |
|
| ... | ... |
@@ -106,7 +106,7 @@ func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdri |
| 106 | 106 |
if err != nil {
|
| 107 | 107 |
return nil, fmt.Errorf("Failed to get root uid/guid: %v", err)
|
| 108 | 108 |
} |
| 109 |
- if err := idtools.MkdirAllAndChown(base, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 109 |
+ if err := idtools.MkdirAllAndChown(base, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 110 | 110 |
return nil, fmt.Errorf("Failed to create '%s': %v", base, err)
|
| 111 | 111 |
} |
| 112 | 112 |
|
| ... | ... |
@@ -385,7 +385,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e |
| 385 | 385 |
return nil, err |
| 386 | 386 |
} |
| 387 | 387 |
// Create the target directories if they don't exist |
| 388 |
- if err := idtools.MkdirAllAndChown(mountpoint, 0755, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 388 |
+ if err := idtools.MkdirAllAndChown(mountpoint, 0755, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
|
|
| 389 | 389 |
return nil, err |
| 390 | 390 |
} |
| 391 | 391 |
|
| ... | ... |
@@ -162,7 +162,7 @@ func (daemon *Daemon) fillSecurityOptions(v *types.Info, sysInfo *sysinfo.SysInf |
| 162 | 162 |
if selinuxEnabled() {
|
| 163 | 163 |
securityOptions = append(securityOptions, "name=selinux") |
| 164 | 164 |
} |
| 165 |
- if rootIDs := daemon.idMappings.RootPair(); rootIDs.UID != 0 || rootIDs.GID != 0 {
|
|
| 165 |
+ if rootIDs := daemon.idMapping.RootPair(); rootIDs.UID != 0 || rootIDs.GID != 0 {
|
|
| 166 | 166 |
securityOptions = append(securityOptions, "name=userns") |
| 167 | 167 |
} |
| 168 | 168 |
v.SecurityOptions = securityOptions |
| ... | ... |
@@ -17,7 +17,7 @@ import ( |
| 17 | 17 |
// |
| 18 | 18 |
// This extra layer is used by all containers as the top-most ro layer. It protects |
| 19 | 19 |
// the container from unwanted side-effects on the rw layer. |
| 20 |
-func Setup(initLayerFs containerfs.ContainerFS, rootIDs idtools.IDPair) error {
|
|
| 20 |
+func Setup(initLayerFs containerfs.ContainerFS, rootIdentity idtools.Identity) error {
|
|
| 21 | 21 |
// Since all paths are local to the container, we can just extract initLayerFs.Path() |
| 22 | 22 |
initLayer := initLayerFs.Path() |
| 23 | 23 |
|
| ... | ... |
@@ -42,12 +42,12 @@ func Setup(initLayerFs containerfs.ContainerFS, rootIDs idtools.IDPair) error {
|
| 42 | 42 |
|
| 43 | 43 |
if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil {
|
| 44 | 44 |
if os.IsNotExist(err) {
|
| 45 |
- if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootIDs); err != nil {
|
|
| 45 |
+ if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootIdentity); err != nil {
|
|
| 46 | 46 |
return err |
| 47 | 47 |
} |
| 48 | 48 |
switch typ {
|
| 49 | 49 |
case "dir": |
| 50 |
- if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, pth), 0755, rootIDs); err != nil {
|
|
| 50 |
+ if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, pth), 0755, rootIdentity); err != nil {
|
|
| 51 | 51 |
return err |
| 52 | 52 |
} |
| 53 | 53 |
case "file": |
| ... | ... |
@@ -55,7 +55,7 @@ func Setup(initLayerFs containerfs.ContainerFS, rootIDs idtools.IDPair) error {
|
| 55 | 55 |
if err != nil {
|
| 56 | 56 |
return err |
| 57 | 57 |
} |
| 58 |
- f.Chown(rootIDs.UID, rootIDs.GID) |
|
| 58 |
+ f.Chown(rootIdentity.UID, rootIdentity.GID) |
|
| 59 | 59 |
f.Close() |
| 60 | 60 |
default: |
| 61 | 61 |
if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil {
|
| ... | ... |
@@ -11,6 +11,6 @@ import ( |
| 11 | 11 |
// |
| 12 | 12 |
// This extra layer is used by all containers as the top-most ro layer. It protects |
| 13 | 13 |
// the container from unwanted side-effects on the rw layer. |
| 14 |
-func Setup(initLayer containerfs.ContainerFS, rootIDs idtools.IDPair) error {
|
|
| 14 |
+func Setup(initLayer containerfs.ContainerFS, rootIDs idtools.Identity) error {
|
|
| 15 | 15 |
return nil |
| 16 | 16 |
} |
| ... | ... |
@@ -217,13 +217,13 @@ func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error |
| 217 | 217 |
userNS := false |
| 218 | 218 |
// user |
| 219 | 219 |
if c.HostConfig.UsernsMode.IsPrivate() {
|
| 220 |
- uidMap := daemon.idMappings.UIDs() |
|
| 220 |
+ uidMap := daemon.idMapping.UIDs() |
|
| 221 | 221 |
if uidMap != nil {
|
| 222 | 222 |
userNS = true |
| 223 | 223 |
ns := specs.LinuxNamespace{Type: "user"}
|
| 224 | 224 |
setNamespace(s, ns) |
| 225 | 225 |
s.Linux.UIDMappings = specMapping(uidMap) |
| 226 |
- s.Linux.GIDMappings = specMapping(daemon.idMappings.GIDs()) |
|
| 226 |
+ s.Linux.GIDMappings = specMapping(daemon.idMapping.GIDs()) |
|
| 227 | 227 |
} |
| 228 | 228 |
} |
| 229 | 229 |
// network |
| ... | ... |
@@ -619,7 +619,7 @@ func setMounts(daemon *Daemon, s *specs.Spec, c *container.Container, mounts []c |
| 619 | 619 |
|
| 620 | 620 |
// TODO: until a kernel/mount solution exists for handling remount in a user namespace, |
| 621 | 621 |
// we must clear the readonly flag for the cgroups mount (@mrunalp concurs) |
| 622 |
- if uidMap := daemon.idMappings.UIDs(); uidMap != nil || c.HostConfig.Privileged {
|
|
| 622 |
+ if uidMap := daemon.idMapping.UIDs(); uidMap != nil || c.HostConfig.Privileged {
|
|
| 623 | 623 |
for i, m := range s.Mounts {
|
| 624 | 624 |
if m.Type == "cgroup" {
|
| 625 | 625 |
clearReadOnly(&s.Mounts[i]) |
| ... | ... |
@@ -642,7 +642,7 @@ func (daemon *Daemon) populateCommonSpec(s *specs.Spec, c *container.Container) |
| 642 | 642 |
Path: c.BaseFS.Path(), |
| 643 | 643 |
Readonly: c.HostConfig.ReadonlyRootfs, |
| 644 | 644 |
} |
| 645 |
- if err := c.SetupWorkingDirectory(daemon.idMappings.RootPair()); err != nil {
|
|
| 645 |
+ if err := c.SetupWorkingDirectory(daemon.idMapping.RootPair()); err != nil {
|
|
| 646 | 646 |
return err |
| 647 | 647 |
} |
| 648 | 648 |
cwd := c.Config.WorkingDir |
| ... | ... |
@@ -21,7 +21,7 @@ func TestTmpfsDevShmNoDupMount(t *testing.T) {
|
| 21 | 21 |
d := Daemon{
|
| 22 | 22 |
// some empty structs to avoid getting a panic |
| 23 | 23 |
// caused by a null pointer dereference |
| 24 |
- idMappings: &idtools.IDMappings{},
|
|
| 24 |
+ idMapping: &idtools.IdentityMapping{},
|
|
| 25 | 25 |
configStore: &config.Config{},
|
| 26 | 26 |
} |
| 27 | 27 |
c := &container.Container{
|
| ... | ... |
@@ -58,7 +58,7 @@ func TestIpcPrivateVsReadonly(t *testing.T) {
|
| 58 | 58 |
d := Daemon{
|
| 59 | 59 |
// some empty structs to avoid getting a panic |
| 60 | 60 |
// caused by a null pointer dereference |
| 61 |
- idMappings: &idtools.IDMappings{},
|
|
| 61 |
+ idMapping: &idtools.IdentityMapping{},
|
|
| 62 | 62 |
configStore: &config.Config{},
|
| 63 | 63 |
} |
| 64 | 64 |
c := &container.Container{
|
| ... | ... |
@@ -47,7 +47,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er |
| 47 | 47 |
return nil |
| 48 | 48 |
} |
| 49 | 49 |
|
| 50 |
- path, err := m.Setup(c.MountLabel, daemon.idMappings.RootPair(), checkfunc) |
|
| 50 |
+ path, err := m.Setup(c.MountLabel, daemon.idMapping.RootPair(), checkfunc) |
|
| 51 | 51 |
if err != nil {
|
| 52 | 52 |
return nil, err |
| 53 | 53 |
} |
| ... | ... |
@@ -77,7 +77,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er |
| 77 | 77 |
// if we are going to mount any of the network files from container |
| 78 | 78 |
// metadata, the ownership must be set properly for potential container |
| 79 | 79 |
// remapped root (user namespaces) |
| 80 |
- rootIDs := daemon.idMappings.RootPair() |
|
| 80 |
+ rootIDs := daemon.idMapping.RootPair() |
|
| 81 | 81 |
for _, mount := range netMounts {
|
| 82 | 82 |
// we should only modify ownership of network files within our own container |
| 83 | 83 |
// metadata repository. If the user specifies a mount path external, it is |
| ... | ... |
@@ -24,7 +24,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er |
| 24 | 24 |
if err := daemon.lazyInitializeVolume(c.ID, mount); err != nil {
|
| 25 | 25 |
return nil, err |
| 26 | 26 |
} |
| 27 |
- s, err := mount.Setup(c.MountLabel, idtools.IDPair{UID: 0, GID: 0}, nil)
|
|
| 27 |
+ s, err := mount.Setup(c.MountLabel, idtools.Identity{}, nil)
|
|
| 28 | 28 |
if err != nil {
|
| 29 | 29 |
return nil, err |
| 30 | 30 |
} |
| ... | ... |
@@ -16,5 +16,5 @@ func (daemon *Daemon) ContainerCreateWorkdir(cID string) error {
|
| 16 | 16 |
return err |
| 17 | 17 |
} |
| 18 | 18 |
defer daemon.Unmount(container) |
| 19 |
- return container.SetupWorkingDirectory(daemon.idMappings.RootPair()) |
|
| 19 |
+ return container.SetupWorkingDirectory(daemon.idMapping.RootPair()) |
|
| 20 | 20 |
} |
| 21 | 21 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,20 @@ |
| 0 |
+#!/usr/bin/env bash |
|
| 1 |
+set -e |
|
| 2 |
+ |
|
| 3 |
+CONTAINER_UTILITY_COMMIT=e004a1415a433447369e315b9d7df357102be0d2 # v0.9.0 |
|
| 4 |
+ |
|
| 5 |
+( |
|
| 6 |
+ git clone https://github.com/docker/windows-container-utility.git "$GOPATH/src/github.com/docker/windows-container-utility" |
|
| 7 |
+ cd "$GOPATH/src/github.com/docker/windows-container-utility" |
|
| 8 |
+ git checkout -q "$CONTAINER_UTILITY_COMMIT" |
|
| 9 |
+ |
|
| 10 |
+ echo Building: ${DEST}/containerutility.exe
|
|
| 11 |
+ |
|
| 12 |
+ ( |
|
| 13 |
+ make |
|
| 14 |
+ ) |
|
| 15 |
+ |
|
| 16 |
+ mkdir -p ${ABS_DEST}
|
|
| 17 |
+ |
|
| 18 |
+ cp containerutility.exe ${ABS_DEST}/containerutility.exe
|
|
| 19 |
+) |
| ... | ... |
@@ -45,7 +45,7 @@ type StoreOptions struct {
|
| 45 | 45 |
MetadataStorePathTemplate string |
| 46 | 46 |
GraphDriver string |
| 47 | 47 |
GraphDriverOptions []string |
| 48 |
- IDMappings *idtools.IDMappings |
|
| 48 |
+ IDMapping *idtools.IdentityMapping |
|
| 49 | 49 |
PluginGetter plugingetter.PluginGetter |
| 50 | 50 |
ExperimentalEnabled bool |
| 51 | 51 |
OS string |
| ... | ... |
@@ -56,8 +56,8 @@ func NewStoreFromOptions(options StoreOptions) (Store, error) {
|
| 56 | 56 |
driver, err := graphdriver.New(options.GraphDriver, options.PluginGetter, graphdriver.Options{
|
| 57 | 57 |
Root: options.Root, |
| 58 | 58 |
DriverOptions: options.GraphDriverOptions, |
| 59 |
- UIDMaps: options.IDMappings.UIDs(), |
|
| 60 |
- GIDMaps: options.IDMappings.GIDs(), |
|
| 59 |
+ UIDMaps: options.IDMapping.UIDs(), |
|
| 60 |
+ GIDMaps: options.IDMapping.GIDs(), |
|
| 61 | 61 |
ExperimentalEnabled: options.ExperimentalEnabled, |
| 62 | 62 |
}) |
| 63 | 63 |
if err != nil {
|
| ... | ... |
@@ -58,7 +58,7 @@ func getSpecUser(ociSpec *specs.Spec) (int, int) {
|
| 58 | 58 |
func prepareBundleDir(bundleDir string, ociSpec *specs.Spec) (string, error) {
|
| 59 | 59 |
uid, gid := getSpecUser(ociSpec) |
| 60 | 60 |
if uid == 0 && gid == 0 {
|
| 61 |
- return bundleDir, idtools.MkdirAllAndChownNew(bundleDir, 0755, idtools.IDPair{UID: 0, GID: 0})
|
|
| 61 |
+ return bundleDir, idtools.MkdirAllAndChownNew(bundleDir, 0755, idtools.Identity{UID: 0, GID: 0})
|
|
| 62 | 62 |
} |
| 63 | 63 |
|
| 64 | 64 |
p := string(filepath.Separator) |
| ... | ... |
@@ -71,7 +71,7 @@ func prepareBundleDir(bundleDir string, ociSpec *specs.Spec) (string, error) {
|
| 71 | 71 |
} |
| 72 | 72 |
if os.IsNotExist(err) || fi.Mode()&1 == 0 {
|
| 73 | 73 |
p = fmt.Sprintf("%s.%d.%d", p, uid, gid)
|
| 74 |
- if err := idtools.MkdirAndChown(p, 0700, idtools.IDPair{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
|
|
| 74 |
+ if err := idtools.MkdirAndChown(p, 0700, idtools.Identity{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
|
|
| 75 | 75 |
return "", err |
| 76 | 76 |
} |
| 77 | 77 |
} |
| ... | ... |
@@ -52,7 +52,7 @@ type ( |
| 52 | 52 |
NoLchown bool |
| 53 | 53 |
UIDMaps []idtools.IDMap |
| 54 | 54 |
GIDMaps []idtools.IDMap |
| 55 |
- ChownOpts *idtools.IDPair |
|
| 55 |
+ ChownOpts *idtools.Identity |
|
| 56 | 56 |
IncludeSourceDir bool |
| 57 | 57 |
// WhiteoutFormat is the expected on disk format for whiteout files. |
| 58 | 58 |
// This format will be converted to the standard format on pack |
| ... | ... |
@@ -72,13 +72,13 @@ type ( |
| 72 | 72 |
// this package with a pluggable Untar function. Also, to facilitate the passing of specific id |
| 73 | 73 |
// mappings for untar, an Archiver can be created with maps which will then be passed to Untar operations. |
| 74 | 74 |
type Archiver struct {
|
| 75 |
- Untar func(io.Reader, string, *TarOptions) error |
|
| 76 |
- IDMappingsVar *idtools.IDMappings |
|
| 75 |
+ Untar func(io.Reader, string, *TarOptions) error |
|
| 76 |
+ IDMapping *idtools.IdentityMapping |
|
| 77 | 77 |
} |
| 78 | 78 |
|
| 79 |
-// NewDefaultArchiver returns a new Archiver without any IDMappings |
|
| 79 |
+// NewDefaultArchiver returns a new Archiver without any IdentityMapping |
|
| 80 | 80 |
func NewDefaultArchiver() *Archiver {
|
| 81 |
- return &Archiver{Untar: Untar, IDMappingsVar: &idtools.IDMappings{}}
|
|
| 81 |
+ return &Archiver{Untar: Untar, IDMapping: &idtools.IdentityMapping{}}
|
|
| 82 | 82 |
} |
| 83 | 83 |
|
| 84 | 84 |
// breakoutError is used to differentiate errors related to breaking out |
| ... | ... |
@@ -420,9 +420,9 @@ type tarAppender struct {
|
| 420 | 420 |
Buffer *bufio.Writer |
| 421 | 421 |
|
| 422 | 422 |
// for hardlink mapping |
| 423 |
- SeenFiles map[uint64]string |
|
| 424 |
- IDMappings *idtools.IDMappings |
|
| 425 |
- ChownOpts *idtools.IDPair |
|
| 423 |
+ SeenFiles map[uint64]string |
|
| 424 |
+ IdentityMapping *idtools.IdentityMapping |
|
| 425 |
+ ChownOpts *idtools.Identity |
|
| 426 | 426 |
|
| 427 | 427 |
// For packing and unpacking whiteout files in the |
| 428 | 428 |
// non standard format. The whiteout files defined |
| ... | ... |
@@ -431,13 +431,13 @@ type tarAppender struct {
|
| 431 | 431 |
WhiteoutConverter tarWhiteoutConverter |
| 432 | 432 |
} |
| 433 | 433 |
|
| 434 |
-func newTarAppender(idMapping *idtools.IDMappings, writer io.Writer, chownOpts *idtools.IDPair) *tarAppender {
|
|
| 434 |
+func newTarAppender(idMapping *idtools.IdentityMapping, writer io.Writer, chownOpts *idtools.Identity) *tarAppender {
|
|
| 435 | 435 |
return &tarAppender{
|
| 436 |
- SeenFiles: make(map[uint64]string), |
|
| 437 |
- TarWriter: tar.NewWriter(writer), |
|
| 438 |
- Buffer: pools.BufioWriter32KPool.Get(nil), |
|
| 439 |
- IDMappings: idMapping, |
|
| 440 |
- ChownOpts: chownOpts, |
|
| 436 |
+ SeenFiles: make(map[uint64]string), |
|
| 437 |
+ TarWriter: tar.NewWriter(writer), |
|
| 438 |
+ Buffer: pools.BufioWriter32KPool.Get(nil), |
|
| 439 |
+ IdentityMapping: idMapping, |
|
| 440 |
+ ChownOpts: chownOpts, |
|
| 441 | 441 |
} |
| 442 | 442 |
} |
| 443 | 443 |
|
| ... | ... |
@@ -502,14 +502,12 @@ func (ta *tarAppender) addTarFile(path, name string) error {
|
| 502 | 502 |
//handle re-mapping container ID mappings back to host ID mappings before |
| 503 | 503 |
//writing tar headers/files. We skip whiteout files because they were written |
| 504 | 504 |
//by the kernel and already have proper ownership relative to the host |
| 505 |
- if !isOverlayWhiteout && |
|
| 506 |
- !strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) && |
|
| 507 |
- !ta.IDMappings.Empty() {
|
|
| 505 |
+ if !isOverlayWhiteout && !strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) && !ta.IdentityMapping.Empty() {
|
|
| 508 | 506 |
fileIDPair, err := getFileUIDGID(fi.Sys()) |
| 509 | 507 |
if err != nil {
|
| 510 | 508 |
return err |
| 511 | 509 |
} |
| 512 |
- hdr.Uid, hdr.Gid, err = ta.IDMappings.ToContainer(fileIDPair) |
|
| 510 |
+ hdr.Uid, hdr.Gid, err = ta.IdentityMapping.ToContainer(fileIDPair) |
|
| 513 | 511 |
if err != nil {
|
| 514 | 512 |
return err |
| 515 | 513 |
} |
| ... | ... |
@@ -572,7 +570,7 @@ func (ta *tarAppender) addTarFile(path, name string) error {
|
| 572 | 572 |
return nil |
| 573 | 573 |
} |
| 574 | 574 |
|
| 575 |
-func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *idtools.IDPair, inUserns bool) error {
|
|
| 575 |
+func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *idtools.Identity, inUserns bool) error {
|
|
| 576 | 576 |
// hdr.Mode is in linux format, which we can use for sycalls, |
| 577 | 577 |
// but for os.Foo() calls we need the mode converted to os.FileMode, |
| 578 | 578 |
// 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 |
| 652 | 652 |
// Lchown is not supported on Windows. |
| 653 | 653 |
if Lchown && runtime.GOOS != "windows" {
|
| 654 | 654 |
if chownOpts == nil {
|
| 655 |
- chownOpts = &idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid}
|
|
| 655 |
+ chownOpts = &idtools.Identity{UID: hdr.Uid, GID: hdr.Gid}
|
|
| 656 | 656 |
} |
| 657 | 657 |
if err := os.Lchown(path, chownOpts.UID, chownOpts.GID); err != nil {
|
| 658 | 658 |
return err |
| ... | ... |
@@ -901,8 +899,8 @@ func Unpack(decompressedArchive io.Reader, dest string, options *TarOptions) err |
| 901 | 901 |
defer pools.BufioReader32KPool.Put(trBuf) |
| 902 | 902 |
|
| 903 | 903 |
var dirs []*tar.Header |
| 904 |
- idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps) |
|
| 905 |
- rootIDs := idMappings.RootPair() |
|
| 904 |
+ idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps) |
|
| 905 |
+ rootIDs := idMapping.RootPair() |
|
| 906 | 906 |
whiteoutConverter := getWhiteoutConverter(options.WhiteoutFormat) |
| 907 | 907 |
|
| 908 | 908 |
// Iterate through the files in the archive. |
| ... | ... |
@@ -981,7 +979,7 @@ loop: |
| 981 | 981 |
} |
| 982 | 982 |
trBuf.Reset(tr) |
| 983 | 983 |
|
| 984 |
- if err := remapIDs(idMappings, hdr); err != nil {
|
|
| 984 |
+ if err := remapIDs(idMapping, hdr); err != nil {
|
|
| 985 | 985 |
return err |
| 986 | 986 |
} |
| 987 | 987 |
|
| ... | ... |
@@ -1068,8 +1066,8 @@ func (archiver *Archiver) TarUntar(src, dst string) error {
|
| 1068 | 1068 |
} |
| 1069 | 1069 |
defer archive.Close() |
| 1070 | 1070 |
options := &TarOptions{
|
| 1071 |
- UIDMaps: archiver.IDMappingsVar.UIDs(), |
|
| 1072 |
- GIDMaps: archiver.IDMappingsVar.GIDs(), |
|
| 1071 |
+ UIDMaps: archiver.IDMapping.UIDs(), |
|
| 1072 |
+ GIDMaps: archiver.IDMapping.GIDs(), |
|
| 1073 | 1073 |
} |
| 1074 | 1074 |
return archiver.Untar(archive, dst, options) |
| 1075 | 1075 |
} |
| ... | ... |
@@ -1082,8 +1080,8 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
|
| 1082 | 1082 |
} |
| 1083 | 1083 |
defer archive.Close() |
| 1084 | 1084 |
options := &TarOptions{
|
| 1085 |
- UIDMaps: archiver.IDMappingsVar.UIDs(), |
|
| 1086 |
- GIDMaps: archiver.IDMappingsVar.GIDs(), |
|
| 1085 |
+ UIDMaps: archiver.IDMapping.UIDs(), |
|
| 1086 |
+ GIDMaps: archiver.IDMapping.GIDs(), |
|
| 1087 | 1087 |
} |
| 1088 | 1088 |
return archiver.Untar(archive, dst, options) |
| 1089 | 1089 |
} |
| ... | ... |
@@ -1104,7 +1102,7 @@ func (archiver *Archiver) CopyWithTar(src, dst string) error {
|
| 1104 | 1104 |
// if this Archiver is set up with ID mapping we need to create |
| 1105 | 1105 |
// the new destination directory with the remapped root UID/GID pair |
| 1106 | 1106 |
// as owner |
| 1107 |
- rootIDs := archiver.IDMappingsVar.RootPair() |
|
| 1107 |
+ rootIDs := archiver.IDMapping.RootPair() |
|
| 1108 | 1108 |
// Create dst, copy src's content into it |
| 1109 | 1109 |
logrus.Debugf("Creating dest directory: %s", dst)
|
| 1110 | 1110 |
if err := idtools.MkdirAllAndChownNew(dst, 0755, rootIDs); err != nil {
|
| ... | ... |
@@ -1164,7 +1162,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
|
| 1164 | 1164 |
hdr.Name = filepath.Base(dst) |
| 1165 | 1165 |
hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode))) |
| 1166 | 1166 |
|
| 1167 |
- if err := remapIDs(archiver.IDMappingsVar, hdr); err != nil {
|
|
| 1167 |
+ if err := remapIDs(archiver.IDMapping, hdr); err != nil {
|
|
| 1168 | 1168 |
return err |
| 1169 | 1169 |
} |
| 1170 | 1170 |
|
| ... | ... |
@@ -1192,13 +1190,13 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
|
| 1192 | 1192 |
return err |
| 1193 | 1193 |
} |
| 1194 | 1194 |
|
| 1195 |
-// IDMappings returns the IDMappings of the archiver. |
|
| 1196 |
-func (archiver *Archiver) IDMappings() *idtools.IDMappings {
|
|
| 1197 |
- return archiver.IDMappingsVar |
|
| 1195 |
+// IdentityMapping returns the IdentityMapping of the archiver. |
|
| 1196 |
+func (archiver *Archiver) IdentityMapping() *idtools.IdentityMapping {
|
|
| 1197 |
+ return archiver.IDMapping |
|
| 1198 | 1198 |
} |
| 1199 | 1199 |
|
| 1200 |
-func remapIDs(idMappings *idtools.IDMappings, hdr *tar.Header) error {
|
|
| 1201 |
- ids, err := idMappings.ToHost(idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid})
|
|
| 1200 |
+func remapIDs(idMapping *idtools.IdentityMapping, hdr *tar.Header) error {
|
|
| 1201 |
+ ids, err := idMapping.ToHost(idtools.Identity{UID: hdr.Uid, GID: hdr.Gid})
|
|
| 1202 | 1202 |
hdr.Uid, hdr.Gid = ids.UID, ids.GID |
| 1203 | 1203 |
return err |
| 1204 | 1204 |
} |
| ... | ... |
@@ -755,11 +755,11 @@ func TestTarWithOptionsChownOptsAlwaysOverridesIdPair(t *testing.T) {
|
| 755 | 755 |
expectedUID int |
| 756 | 756 |
expectedGID int |
| 757 | 757 |
}{
|
| 758 |
- {&TarOptions{ChownOpts: &idtools.IDPair{UID: 1337, GID: 42}}, 1337, 42},
|
|
| 759 |
- {&TarOptions{ChownOpts: &idtools.IDPair{UID: 100001, GID: 100001}, UIDMaps: idMaps, GIDMaps: idMaps}, 100001, 100001},
|
|
| 760 |
- {&TarOptions{ChownOpts: &idtools.IDPair{UID: 0, GID: 0}, NoLchown: false}, 0, 0},
|
|
| 761 |
- {&TarOptions{ChownOpts: &idtools.IDPair{UID: 1, GID: 1}, NoLchown: true}, 1, 1},
|
|
| 762 |
- {&TarOptions{ChownOpts: &idtools.IDPair{UID: 1000, GID: 1000}, NoLchown: true}, 1000, 1000},
|
|
| 758 |
+ {&TarOptions{ChownOpts: &idtools.Identity{UID: 1337, GID: 42}}, 1337, 42},
|
|
| 759 |
+ {&TarOptions{ChownOpts: &idtools.Identity{UID: 100001, GID: 100001}, UIDMaps: idMaps, GIDMaps: idMaps}, 100001, 100001},
|
|
| 760 |
+ {&TarOptions{ChownOpts: &idtools.Identity{UID: 0, GID: 0}, NoLchown: false}, 0, 0},
|
|
| 761 |
+ {&TarOptions{ChownOpts: &idtools.Identity{UID: 1, GID: 1}, NoLchown: true}, 1, 1},
|
|
| 762 |
+ {&TarOptions{ChownOpts: &idtools.Identity{UID: 1000, GID: 1000}, NoLchown: true}, 1000, 1000},
|
|
| 763 | 763 |
} |
| 764 | 764 |
for _, testCase := range cases {
|
| 765 | 765 |
reader, err := TarWithOptions(filePath, testCase.opts) |
| ... | ... |
@@ -68,13 +68,13 @@ func getInodeFromStat(stat interface{}) (inode uint64, err error) {
|
| 68 | 68 |
return |
| 69 | 69 |
} |
| 70 | 70 |
|
| 71 |
-func getFileUIDGID(stat interface{}) (idtools.IDPair, error) {
|
|
| 71 |
+func getFileUIDGID(stat interface{}) (idtools.Identity, error) {
|
|
| 72 | 72 |
s, ok := stat.(*syscall.Stat_t) |
| 73 | 73 |
|
| 74 | 74 |
if !ok {
|
| 75 |
- return idtools.IDPair{}, errors.New("cannot convert stat value to syscall.Stat_t")
|
|
| 75 |
+ return idtools.Identity{}, errors.New("cannot convert stat value to syscall.Stat_t")
|
|
| 76 | 76 |
} |
| 77 |
- return idtools.IDPair{UID: int(s.Uid), GID: int(s.Gid)}, nil
|
|
| 77 |
+ return idtools.Identity{UID: int(s.Uid), GID: int(s.Gid)}, nil
|
|
| 78 | 78 |
} |
| 79 | 79 |
|
| 80 | 80 |
// handleTarTypeBlockCharFifo is an OS-specific helper function used by |
| ... | ... |
@@ -61,7 +61,7 @@ func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
|
| 61 | 61 |
return nil |
| 62 | 62 |
} |
| 63 | 63 |
|
| 64 |
-func getFileUIDGID(stat interface{}) (idtools.IDPair, error) {
|
|
| 64 |
+func getFileUIDGID(stat interface{}) (idtools.Identity, error) {
|
|
| 65 | 65 |
// no notion of file ownership mapping yet on Windows |
| 66 |
- return idtools.IDPair{UID: 0, GID: 0}, nil
|
|
| 66 |
+ return idtools.Identity{UID: 0, GID: 0}, nil
|
|
| 67 | 67 |
} |
| ... | ... |
@@ -33,7 +33,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64, |
| 33 | 33 |
if options.ExcludePatterns == nil {
|
| 34 | 34 |
options.ExcludePatterns = []string{}
|
| 35 | 35 |
} |
| 36 |
- idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps) |
|
| 36 |
+ idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps) |
|
| 37 | 37 |
|
| 38 | 38 |
aufsTempdir := "" |
| 39 | 39 |
aufsHardlinks := make(map[string]*tar.Header) |
| ... | ... |
@@ -192,7 +192,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64, |
| 192 | 192 |
srcData = tmpFile |
| 193 | 193 |
} |
| 194 | 194 |
|
| 195 |
- if err := remapIDs(idMappings, srcHdr); err != nil {
|
|
| 195 |
+ if err := remapIDs(idMapping, srcHdr); err != nil {
|
|
| 196 | 196 |
return 0, err |
| 197 | 197 |
} |
| 198 | 198 |
|
| ... | ... |
@@ -12,13 +12,13 @@ import ( |
| 12 | 12 |
) |
| 13 | 13 |
|
| 14 | 14 |
// NewArchiver returns a new Archiver which uses chrootarchive.Untar |
| 15 |
-func NewArchiver(idMappings *idtools.IDMappings) *archive.Archiver {
|
|
| 16 |
- if idMappings == nil {
|
|
| 17 |
- idMappings = &idtools.IDMappings{}
|
|
| 15 |
+func NewArchiver(idMapping *idtools.IdentityMapping) *archive.Archiver {
|
|
| 16 |
+ if idMapping == nil {
|
|
| 17 |
+ idMapping = &idtools.IdentityMapping{}
|
|
| 18 | 18 |
} |
| 19 | 19 |
return &archive.Archiver{
|
| 20 |
- Untar: Untar, |
|
| 21 |
- IDMappingsVar: idMappings, |
|
| 20 |
+ Untar: Untar, |
|
| 21 |
+ IDMapping: idMapping, |
|
| 22 | 22 |
} |
| 23 | 23 |
} |
| 24 | 24 |
|
| ... | ... |
@@ -49,8 +49,8 @@ func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions |
| 49 | 49 |
options.ExcludePatterns = []string{}
|
| 50 | 50 |
} |
| 51 | 51 |
|
| 52 |
- idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps) |
|
| 53 |
- rootIDs := idMappings.RootPair() |
|
| 52 |
+ idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps) |
|
| 53 |
+ rootIDs := idMapping.RootPair() |
|
| 54 | 54 |
|
| 55 | 55 |
dest = filepath.Clean(dest) |
| 56 | 56 |
if _, err := os.Stat(dest); os.IsNotExist(err) {
|
| ... | ... |
@@ -22,11 +22,11 @@ type UntarFunc func(io.Reader, string, *archive.TarOptions) error |
| 22 | 22 |
|
| 23 | 23 |
// Archiver provides a similar implementation of the archive.Archiver package with the rootfs abstraction |
| 24 | 24 |
type Archiver struct {
|
| 25 |
- SrcDriver Driver |
|
| 26 |
- DstDriver Driver |
|
| 27 |
- Tar TarFunc |
|
| 28 |
- Untar UntarFunc |
|
| 29 |
- IDMappingsVar *idtools.IDMappings |
|
| 25 |
+ SrcDriver Driver |
|
| 26 |
+ DstDriver Driver |
|
| 27 |
+ Tar TarFunc |
|
| 28 |
+ Untar UntarFunc |
|
| 29 |
+ IDMapping *idtools.IdentityMapping |
|
| 30 | 30 |
} |
| 31 | 31 |
|
| 32 | 32 |
// 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 {
|
| 39 | 39 |
} |
| 40 | 40 |
defer tarArchive.Close() |
| 41 | 41 |
options := &archive.TarOptions{
|
| 42 |
- UIDMaps: archiver.IDMappingsVar.UIDs(), |
|
| 43 |
- GIDMaps: archiver.IDMappingsVar.GIDs(), |
|
| 42 |
+ UIDMaps: archiver.IDMapping.UIDs(), |
|
| 43 |
+ GIDMaps: archiver.IDMapping.GIDs(), |
|
| 44 | 44 |
} |
| 45 | 45 |
return archiver.Untar(tarArchive, dst, options) |
| 46 | 46 |
} |
| ... | ... |
@@ -53,8 +53,8 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
|
| 53 | 53 |
} |
| 54 | 54 |
defer tarArchive.Close() |
| 55 | 55 |
options := &archive.TarOptions{
|
| 56 |
- UIDMaps: archiver.IDMappingsVar.UIDs(), |
|
| 57 |
- GIDMaps: archiver.IDMappingsVar.GIDs(), |
|
| 56 |
+ UIDMaps: archiver.IDMapping.UIDs(), |
|
| 57 |
+ GIDMaps: archiver.IDMapping.GIDs(), |
|
| 58 | 58 |
} |
| 59 | 59 |
return archiver.Untar(tarArchive, dst, options) |
| 60 | 60 |
} |
| ... | ... |
@@ -75,9 +75,11 @@ func (archiver *Archiver) CopyWithTar(src, dst string) error {
|
| 75 | 75 |
// if this archiver is set up with ID mapping we need to create |
| 76 | 76 |
// the new destination directory with the remapped root UID/GID pair |
| 77 | 77 |
// as owner |
| 78 |
- rootIDs := archiver.IDMappingsVar.RootPair() |
|
| 78 |
+ |
|
| 79 |
+ identity := idtools.Identity{UID: archiver.IDMapping.RootPair().UID, GID: archiver.IDMapping.RootPair().GID}
|
|
| 80 |
+ |
|
| 79 | 81 |
// Create dst, copy src's content into it |
| 80 |
- if err := idtools.MkdirAllAndChownNew(dst, 0755, rootIDs); err != nil {
|
|
| 82 |
+ if err := idtools.MkdirAllAndChownNew(dst, 0755, identity); err != nil {
|
|
| 81 | 83 |
return err |
| 82 | 84 |
} |
| 83 | 85 |
logrus.Debugf("Calling TarUntar(%s, %s)", src, dst)
|
| ... | ... |
@@ -150,7 +152,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
|
| 150 | 150 |
hdr.Mode = int64(os.FileMode(hdr.Mode)) |
| 151 | 151 |
} |
| 152 | 152 |
|
| 153 |
- if err := remapIDs(archiver.IDMappingsVar, hdr); err != nil {
|
|
| 153 |
+ if err := remapIDs(archiver.IDMapping, hdr); err != nil {
|
|
| 154 | 154 |
return err |
| 155 | 155 |
} |
| 156 | 156 |
|
| ... | ... |
@@ -178,13 +180,13 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
|
| 178 | 178 |
return err |
| 179 | 179 |
} |
| 180 | 180 |
|
| 181 |
-// IDMappings returns the IDMappings of the archiver. |
|
| 182 |
-func (archiver *Archiver) IDMappings() *idtools.IDMappings {
|
|
| 183 |
- return archiver.IDMappingsVar |
|
| 181 |
+// IdentityMapping returns the IdentityMapping of the archiver. |
|
| 182 |
+func (archiver *Archiver) IdentityMapping() *idtools.IdentityMapping {
|
|
| 183 |
+ return archiver.IDMapping |
|
| 184 | 184 |
} |
| 185 | 185 |
|
| 186 |
-func remapIDs(idMappings *idtools.IDMappings, hdr *tar.Header) error {
|
|
| 187 |
- ids, err := idMappings.ToHost(idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid})
|
|
| 186 |
+func remapIDs(idMapping *idtools.IdentityMapping, hdr *tar.Header) error {
|
|
| 187 |
+ ids, err := idMapping.ToHost(idtools.Identity{UID: hdr.Uid, GID: hdr.Gid})
|
|
| 188 | 188 |
hdr.Uid, hdr.Gid = ids.UID, ids.GID |
| 189 | 189 |
return err |
| 190 | 190 |
} |
| ... | ... |
@@ -37,23 +37,23 @@ const ( |
| 37 | 37 |
// MkdirAllAndChown creates a directory (include any along the path) and then modifies |
| 38 | 38 |
// ownership to the requested uid/gid. If the directory already exists, this |
| 39 | 39 |
// function will still change ownership to the requested uid/gid pair. |
| 40 |
-func MkdirAllAndChown(path string, mode os.FileMode, owner IDPair) error {
|
|
| 41 |
- return mkdirAs(path, mode, owner.UID, owner.GID, true, true) |
|
| 40 |
+func MkdirAllAndChown(path string, mode os.FileMode, owner Identity) error {
|
|
| 41 |
+ return mkdirAs(path, mode, owner, true, true) |
|
| 42 | 42 |
} |
| 43 | 43 |
|
| 44 | 44 |
// MkdirAndChown creates a directory and then modifies ownership to the requested uid/gid. |
| 45 | 45 |
// If the directory already exists, this function still changes ownership. |
| 46 | 46 |
// Note that unlike os.Mkdir(), this function does not return IsExist error |
| 47 | 47 |
// in case path already exists. |
| 48 |
-func MkdirAndChown(path string, mode os.FileMode, owner IDPair) error {
|
|
| 49 |
- return mkdirAs(path, mode, owner.UID, owner.GID, false, true) |
|
| 48 |
+func MkdirAndChown(path string, mode os.FileMode, owner Identity) error {
|
|
| 49 |
+ return mkdirAs(path, mode, owner, false, true) |
|
| 50 | 50 |
} |
| 51 | 51 |
|
| 52 | 52 |
// MkdirAllAndChownNew creates a directory (include any along the path) and then modifies |
| 53 | 53 |
// ownership ONLY of newly created directories to the requested uid/gid. If the |
| 54 | 54 |
// directories along the path exist, no change of ownership will be performed |
| 55 |
-func MkdirAllAndChownNew(path string, mode os.FileMode, owner IDPair) error {
|
|
| 56 |
- return mkdirAs(path, mode, owner.UID, owner.GID, true, false) |
|
| 55 |
+func MkdirAllAndChownNew(path string, mode os.FileMode, owner Identity) error {
|
|
| 56 |
+ return mkdirAs(path, mode, owner, true, false) |
|
| 57 | 57 |
} |
| 58 | 58 |
|
| 59 | 59 |
// 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) {
|
| 102 | 102 |
return -1, fmt.Errorf("Container ID %d cannot be mapped to a host ID", contID)
|
| 103 | 103 |
} |
| 104 | 104 |
|
| 105 |
-// IDPair is a UID and GID pair |
|
| 106 |
-type IDPair struct {
|
|
| 105 |
+// Identity is either a UID and GID pair or a SID (but not both) |
|
| 106 |
+type Identity struct {
|
|
| 107 | 107 |
UID int |
| 108 | 108 |
GID int |
| 109 |
+ SID string |
|
| 109 | 110 |
} |
| 110 | 111 |
|
| 111 |
-// IDMappings contains a mappings of UIDs and GIDs |
|
| 112 |
-type IDMappings struct {
|
|
| 112 |
+// IdentityMapping contains a mappings of UIDs and GIDs |
|
| 113 |
+type IdentityMapping struct {
|
|
| 113 | 114 |
uids []IDMap |
| 114 | 115 |
gids []IDMap |
| 115 | 116 |
} |
| 116 | 117 |
|
| 117 |
-// NewIDMappings takes a requested user and group name and |
|
| 118 |
+// NewIdentityMapping takes a requested user and group name and |
|
| 118 | 119 |
// using the data from /etc/sub{uid,gid} ranges, creates the
|
| 119 | 120 |
// proper uid and gid remapping ranges for that user/group pair |
| 120 |
-func NewIDMappings(username, groupname string) (*IDMappings, error) {
|
|
| 121 |
+func NewIdentityMapping(username, groupname string) (*IdentityMapping, error) {
|
|
| 121 | 122 |
subuidRanges, err := parseSubuid(username) |
| 122 | 123 |
if err != nil {
|
| 123 | 124 |
return nil, err |
| ... | ... |
@@ -133,7 +134,7 @@ func NewIDMappings(username, groupname string) (*IDMappings, error) {
|
| 133 | 133 |
return nil, fmt.Errorf("No subgid ranges found for group %q", groupname)
|
| 134 | 134 |
} |
| 135 | 135 |
|
| 136 |
- return &IDMappings{
|
|
| 136 |
+ return &IdentityMapping{
|
|
| 137 | 137 |
uids: createIDMap(subuidRanges), |
| 138 | 138 |
gids: createIDMap(subgidRanges), |
| 139 | 139 |
}, nil |
| ... | ... |
@@ -141,21 +142,21 @@ func NewIDMappings(username, groupname string) (*IDMappings, error) {
|
| 141 | 141 |
|
| 142 | 142 |
// NewIDMappingsFromMaps creates a new mapping from two slices |
| 143 | 143 |
// Deprecated: this is a temporary shim while transitioning to IDMapping |
| 144 |
-func NewIDMappingsFromMaps(uids []IDMap, gids []IDMap) *IDMappings {
|
|
| 145 |
- return &IDMappings{uids: uids, gids: gids}
|
|
| 144 |
+func NewIDMappingsFromMaps(uids []IDMap, gids []IDMap) *IdentityMapping {
|
|
| 145 |
+ return &IdentityMapping{uids: uids, gids: gids}
|
|
| 146 | 146 |
} |
| 147 | 147 |
|
| 148 | 148 |
// RootPair returns a uid and gid pair for the root user. The error is ignored |
| 149 | 149 |
// because a root user always exists, and the defaults are correct when the uid |
| 150 | 150 |
// and gid maps are empty. |
| 151 |
-func (i *IDMappings) RootPair() IDPair {
|
|
| 151 |
+func (i *IdentityMapping) RootPair() Identity {
|
|
| 152 | 152 |
uid, gid, _ := GetRootUIDGID(i.uids, i.gids) |
| 153 |
- return IDPair{UID: uid, GID: gid}
|
|
| 153 |
+ return Identity{UID: uid, GID: gid}
|
|
| 154 | 154 |
} |
| 155 | 155 |
|
| 156 | 156 |
// ToHost returns the host UID and GID for the container uid, gid. |
| 157 | 157 |
// Remapping is only performed if the ids aren't already the remapped root ids |
| 158 |
-func (i *IDMappings) ToHost(pair IDPair) (IDPair, error) {
|
|
| 158 |
+func (i *IdentityMapping) ToHost(pair Identity) (Identity, error) {
|
|
| 159 | 159 |
var err error |
| 160 | 160 |
target := i.RootPair() |
| 161 | 161 |
|
| ... | ... |
@@ -173,7 +174,7 @@ func (i *IDMappings) ToHost(pair IDPair) (IDPair, error) {
|
| 173 | 173 |
} |
| 174 | 174 |
|
| 175 | 175 |
// ToContainer returns the container UID and GID for the host uid and gid |
| 176 |
-func (i *IDMappings) ToContainer(pair IDPair) (int, int, error) {
|
|
| 176 |
+func (i *IdentityMapping) ToContainer(pair Identity) (int, int, error) {
|
|
| 177 | 177 |
uid, err := toContainer(pair.UID, i.uids) |
| 178 | 178 |
if err != nil {
|
| 179 | 179 |
return -1, -1, err |
| ... | ... |
@@ -183,19 +184,19 @@ func (i *IDMappings) ToContainer(pair IDPair) (int, int, error) {
|
| 183 | 183 |
} |
| 184 | 184 |
|
| 185 | 185 |
// Empty returns true if there are no id mappings |
| 186 |
-func (i *IDMappings) Empty() bool {
|
|
| 186 |
+func (i *IdentityMapping) Empty() bool {
|
|
| 187 | 187 |
return len(i.uids) == 0 && len(i.gids) == 0 |
| 188 | 188 |
} |
| 189 | 189 |
|
| 190 | 190 |
// UIDs return the UID mapping |
| 191 | 191 |
// TODO: remove this once everything has been refactored to use pairs |
| 192 |
-func (i *IDMappings) UIDs() []IDMap {
|
|
| 192 |
+func (i *IdentityMapping) UIDs() []IDMap {
|
|
| 193 | 193 |
return i.uids |
| 194 | 194 |
} |
| 195 | 195 |
|
| 196 | 196 |
// GIDs return the UID mapping |
| 197 | 197 |
// TODO: remove this once everything has been refactored to use pairs |
| 198 |
-func (i *IDMappings) GIDs() []IDMap {
|
|
| 198 |
+func (i *IdentityMapping) GIDs() []IDMap {
|
|
| 199 | 199 |
return i.gids |
| 200 | 200 |
} |
| 201 | 201 |
|
| ... | ... |
@@ -21,11 +21,12 @@ var ( |
| 21 | 21 |
getentCmd string |
| 22 | 22 |
) |
| 23 | 23 |
|
| 24 |
-func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chownExisting bool) error {
|
|
| 24 |
+func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error {
|
|
| 25 | 25 |
// make an array containing the original path asked for, plus (for mkAll == true) |
| 26 | 26 |
// all path components leading up to the complete path that don't exist before we MkdirAll |
| 27 | 27 |
// so that we can chown all of them properly at the end. If chownExisting is false, we won't |
| 28 | 28 |
// chown the full directory path if it exists |
| 29 |
+ |
|
| 29 | 30 |
var paths []string |
| 30 | 31 |
|
| 31 | 32 |
stat, err := system.Stat(path) |
| ... | ... |
@@ -38,7 +39,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown |
| 38 | 38 |
} |
| 39 | 39 |
|
| 40 | 40 |
// short-circuit--we were called with an existing directory and chown was requested |
| 41 |
- return lazyChown(path, ownerUID, ownerGID, stat) |
|
| 41 |
+ return lazyChown(path, owner.UID, owner.GID, stat) |
|
| 42 | 42 |
} |
| 43 | 43 |
|
| 44 | 44 |
if os.IsNotExist(err) {
|
| ... | ... |
@@ -69,7 +70,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown |
| 69 | 69 |
// even if it existed, we will chown the requested path + any subpaths that |
| 70 | 70 |
// didn't exist when we called MkdirAll |
| 71 | 71 |
for _, pathComponent := range paths {
|
| 72 |
- if err := lazyChown(pathComponent, ownerUID, ownerGID, nil); err != nil {
|
|
| 72 |
+ if err := lazyChown(pathComponent, owner.UID, owner.GID, nil); err != nil {
|
|
| 73 | 73 |
return err |
| 74 | 74 |
} |
| 75 | 75 |
} |
| ... | ... |
@@ -78,7 +79,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown |
| 78 | 78 |
|
| 79 | 79 |
// CanAccess takes a valid (existing) directory and a uid, gid pair and determines |
| 80 | 80 |
// if that uid, gid pair has access (execute bit) to the directory |
| 81 |
-func CanAccess(path string, pair IDPair) bool {
|
|
| 81 |
+func CanAccess(path string, pair Identity) bool {
|
|
| 82 | 82 |
statInfo, err := system.Stat(path) |
| 83 | 83 |
if err != nil {
|
| 84 | 84 |
return false |
| ... | ... |
@@ -46,7 +46,7 @@ func TestMkdirAllAndChown(t *testing.T) {
|
| 46 | 46 |
} |
| 47 | 47 |
|
| 48 | 48 |
// test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid |
| 49 |
- if err := MkdirAllAndChown(filepath.Join(dirName, "usr", "share"), 0755, IDPair{UID: 99, GID: 99}); err != nil {
|
|
| 49 |
+ if err := MkdirAllAndChown(filepath.Join(dirName, "usr", "share"), 0755, Identity{UID: 99, GID: 99}); err != nil {
|
|
| 50 | 50 |
t.Fatal(err) |
| 51 | 51 |
} |
| 52 | 52 |
testTree["usr/share"] = node{99, 99}
|
| ... | ... |
@@ -59,7 +59,7 @@ func TestMkdirAllAndChown(t *testing.T) {
|
| 59 | 59 |
} |
| 60 | 60 |
|
| 61 | 61 |
// test 2-deep new directories--both should be owned by the uid/gid pair |
| 62 |
- if err := MkdirAllAndChown(filepath.Join(dirName, "lib", "some", "other"), 0755, IDPair{UID: 101, GID: 101}); err != nil {
|
|
| 62 |
+ if err := MkdirAllAndChown(filepath.Join(dirName, "lib", "some", "other"), 0755, Identity{UID: 101, GID: 101}); err != nil {
|
|
| 63 | 63 |
t.Fatal(err) |
| 64 | 64 |
} |
| 65 | 65 |
testTree["lib/some"] = node{101, 101}
|
| ... | ... |
@@ -73,7 +73,7 @@ func TestMkdirAllAndChown(t *testing.T) {
|
| 73 | 73 |
} |
| 74 | 74 |
|
| 75 | 75 |
// test a directory that already exists; should be chowned, but nothing else |
| 76 |
- if err := MkdirAllAndChown(filepath.Join(dirName, "usr"), 0755, IDPair{UID: 102, GID: 102}); err != nil {
|
|
| 76 |
+ if err := MkdirAllAndChown(filepath.Join(dirName, "usr"), 0755, Identity{UID: 102, GID: 102}); err != nil {
|
|
| 77 | 77 |
t.Fatal(err) |
| 78 | 78 |
} |
| 79 | 79 |
testTree["usr"] = node{102, 102}
|
| ... | ... |
@@ -102,7 +102,7 @@ func TestMkdirAllAndChownNew(t *testing.T) {
|
| 102 | 102 |
assert.NilError(t, buildTree(dirName, testTree)) |
| 103 | 103 |
|
| 104 | 104 |
// test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid |
| 105 |
- err = MkdirAllAndChownNew(filepath.Join(dirName, "usr", "share"), 0755, IDPair{UID: 99, GID: 99})
|
|
| 105 |
+ err = MkdirAllAndChownNew(filepath.Join(dirName, "usr", "share"), 0755, Identity{UID: 99, GID: 99})
|
|
| 106 | 106 |
assert.NilError(t, err) |
| 107 | 107 |
|
| 108 | 108 |
testTree["usr/share"] = node{99, 99}
|
| ... | ... |
@@ -111,7 +111,7 @@ func TestMkdirAllAndChownNew(t *testing.T) {
|
| 111 | 111 |
assert.NilError(t, compareTrees(testTree, verifyTree)) |
| 112 | 112 |
|
| 113 | 113 |
// test 2-deep new directories--both should be owned by the uid/gid pair |
| 114 |
- err = MkdirAllAndChownNew(filepath.Join(dirName, "lib", "some", "other"), 0755, IDPair{UID: 101, GID: 101})
|
|
| 114 |
+ err = MkdirAllAndChownNew(filepath.Join(dirName, "lib", "some", "other"), 0755, Identity{UID: 101, GID: 101})
|
|
| 115 | 115 |
assert.NilError(t, err) |
| 116 | 116 |
testTree["lib/some"] = node{101, 101}
|
| 117 | 117 |
testTree["lib/some/other"] = node{101, 101}
|
| ... | ... |
@@ -120,7 +120,7 @@ func TestMkdirAllAndChownNew(t *testing.T) {
|
| 120 | 120 |
assert.NilError(t, compareTrees(testTree, verifyTree)) |
| 121 | 121 |
|
| 122 | 122 |
// test a directory that already exists; should NOT be chowned |
| 123 |
- err = MkdirAllAndChownNew(filepath.Join(dirName, "usr"), 0755, IDPair{UID: 102, GID: 102})
|
|
| 123 |
+ err = MkdirAllAndChownNew(filepath.Join(dirName, "usr"), 0755, Identity{UID: 102, GID: 102})
|
|
| 124 | 124 |
assert.NilError(t, err) |
| 125 | 125 |
verifyTree, err = readTree(dirName, "") |
| 126 | 126 |
assert.NilError(t, err) |
| ... | ... |
@@ -143,7 +143,7 @@ func TestMkdirAndChown(t *testing.T) {
|
| 143 | 143 |
} |
| 144 | 144 |
|
| 145 | 145 |
// test a directory that already exists; should just chown to the requested uid/gid |
| 146 |
- if err := MkdirAndChown(filepath.Join(dirName, "usr"), 0755, IDPair{UID: 99, GID: 99}); err != nil {
|
|
| 146 |
+ if err := MkdirAndChown(filepath.Join(dirName, "usr"), 0755, Identity{UID: 99, GID: 99}); err != nil {
|
|
| 147 | 147 |
t.Fatal(err) |
| 148 | 148 |
} |
| 149 | 149 |
testTree["usr"] = node{99, 99}
|
| ... | ... |
@@ -156,12 +156,12 @@ func TestMkdirAndChown(t *testing.T) {
|
| 156 | 156 |
} |
| 157 | 157 |
|
| 158 | 158 |
// create a subdir under a dir which doesn't exist--should fail |
| 159 |
- if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin", "subdir"), 0755, IDPair{UID: 102, GID: 102}); err == nil {
|
|
| 159 |
+ if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin", "subdir"), 0755, Identity{UID: 102, GID: 102}); err == nil {
|
|
| 160 | 160 |
t.Fatalf("Trying to create a directory with Mkdir where the parent doesn't exist should have failed")
|
| 161 | 161 |
} |
| 162 | 162 |
|
| 163 | 163 |
// create a subdir under an existing dir; should only change the ownership of the new subdir |
| 164 |
- if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin"), 0755, IDPair{UID: 102, GID: 102}); err != nil {
|
|
| 164 |
+ if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin"), 0755, Identity{UID: 102, GID: 102}); err != nil {
|
|
| 165 | 165 |
t.Fatal(err) |
| 166 | 166 |
} |
| 167 | 167 |
testTree["usr/bin"] = node{102, 102}
|
| ... | ... |
@@ -326,19 +326,19 @@ func TestNewIDMappings(t *testing.T) {
|
| 326 | 326 |
group, err := user.LookupGroupId(string(gids[0])) |
| 327 | 327 |
assert.Check(t, err) |
| 328 | 328 |
|
| 329 |
- idMappings, err := NewIDMappings(tempUser.Username, group.Name) |
|
| 329 |
+ idMapping, err := NewIdentityMapping(tempUser.Username, group.Name) |
|
| 330 | 330 |
assert.Check(t, err) |
| 331 | 331 |
|
| 332 |
- rootUID, rootGID, err := GetRootUIDGID(idMappings.UIDs(), idMappings.GIDs()) |
|
| 332 |
+ rootUID, rootGID, err := GetRootUIDGID(idMapping.UIDs(), idMapping.GIDs()) |
|
| 333 | 333 |
assert.Check(t, err) |
| 334 | 334 |
|
| 335 | 335 |
dirName, err := ioutil.TempDir("", "mkdirall")
|
| 336 | 336 |
assert.Check(t, err, "Couldn't create temp directory") |
| 337 | 337 |
defer os.RemoveAll(dirName) |
| 338 | 338 |
|
| 339 |
- err = MkdirAllAndChown(dirName, 0700, IDPair{UID: rootUID, GID: rootGID})
|
|
| 339 |
+ err = MkdirAllAndChown(dirName, 0700, Identity{UID: rootUID, GID: rootGID})
|
|
| 340 | 340 |
assert.Check(t, err, "Couldn't change ownership of file path. Got error") |
| 341 |
- assert.Check(t, CanAccess(dirName, idMappings.RootPair()), fmt.Sprintf("Unable to access %s directory with user UID:%d and GID:%d", dirName, rootUID, rootGID))
|
|
| 341 |
+ assert.Check(t, CanAccess(dirName, idMapping.RootPair()), fmt.Sprintf("Unable to access %s directory with user UID:%d and GID:%d", dirName, rootUID, rootGID))
|
|
| 342 | 342 |
} |
| 343 | 343 |
|
| 344 | 344 |
func TestLookupUserAndGroup(t *testing.T) {
|
| ... | ... |
@@ -388,7 +388,7 @@ func TestMkdirIsNotDir(t *testing.T) {
|
| 388 | 388 |
} |
| 389 | 389 |
defer os.Remove(file.Name()) |
| 390 | 390 |
|
| 391 |
- err = mkdirAs(file.Name(), 0755, 0, 0, false, false) |
|
| 391 |
+ err = mkdirAs(file.Name(), 0755, Identity{UID: 0, GID: 0}, false, false)
|
|
| 392 | 392 |
assert.Check(t, is.Error(err, "mkdir "+file.Name()+": not a directory")) |
| 393 | 393 |
} |
| 394 | 394 |
|
| ... | ... |
@@ -6,9 +6,11 @@ import ( |
| 6 | 6 |
"github.com/docker/docker/pkg/system" |
| 7 | 7 |
) |
| 8 | 8 |
|
| 9 |
-// Platforms such as Windows do not support the UID/GID concept. So make this |
|
| 10 |
-// just a wrapper around system.MkdirAll. |
|
| 11 |
-func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chownExisting bool) error {
|
|
| 9 |
+// This is currently a wrapper around MkdirAll, however, since currently |
|
| 10 |
+// permissions aren't set through this path, the identity isn't utilized. |
|
| 11 |
+// Ownership is handled elsewhere, but in the future could be support here |
|
| 12 |
+// too. |
|
| 13 |
+func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error {
|
|
| 12 | 14 |
if err := system.MkdirAll(path, mode, ""); err != nil {
|
| 13 | 15 |
return err |
| 14 | 16 |
} |
| ... | ... |
@@ -18,6 +20,6 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown |
| 18 | 18 |
// CanAccess takes a valid (existing) directory and a uid, gid pair and determines |
| 19 | 19 |
// if that uid, gid pair has access (execute bit) to the directory |
| 20 | 20 |
// Windows does not require/support this function, so always return true |
| 21 |
-func CanAccess(path string, pair IDPair) bool {
|
|
| 21 |
+func CanAccess(path string, identity Identity) bool {
|
|
| 22 | 22 |
return true |
| 23 | 23 |
} |
| ... | ... |
@@ -2,16 +2,62 @@ package system // import "github.com/docker/docker/pkg/system" |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 |
+ "syscall" |
|
| 5 | 6 |
"unsafe" |
| 6 | 7 |
|
| 7 | 8 |
"github.com/sirupsen/logrus" |
| 8 | 9 |
"golang.org/x/sys/windows" |
| 9 | 10 |
) |
| 10 | 11 |
|
| 12 |
+const ( |
|
| 13 |
+ OWNER_SECURITY_INFORMATION = 0x00000001 |
|
| 14 |
+ GROUP_SECURITY_INFORMATION = 0x00000002 |
|
| 15 |
+ DACL_SECURITY_INFORMATION = 0x00000004 |
|
| 16 |
+ SACL_SECURITY_INFORMATION = 0x00000008 |
|
| 17 |
+ LABEL_SECURITY_INFORMATION = 0x00000010 |
|
| 18 |
+ ATTRIBUTE_SECURITY_INFORMATION = 0x00000020 |
|
| 19 |
+ SCOPE_SECURITY_INFORMATION = 0x00000040 |
|
| 20 |
+ PROCESS_TRUST_LABEL_SECURITY_INFORMATION = 0x00000080 |
|
| 21 |
+ ACCESS_FILTER_SECURITY_INFORMATION = 0x00000100 |
|
| 22 |
+ BACKUP_SECURITY_INFORMATION = 0x00010000 |
|
| 23 |
+ PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000 |
|
| 24 |
+ PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000 |
|
| 25 |
+ UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000 |
|
| 26 |
+ UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000 |
|
| 27 |
+) |
|
| 28 |
+ |
|
| 29 |
+const ( |
|
| 30 |
+ SE_UNKNOWN_OBJECT_TYPE = iota |
|
| 31 |
+ SE_FILE_OBJECT |
|
| 32 |
+ SE_SERVICE |
|
| 33 |
+ SE_PRINTER |
|
| 34 |
+ SE_REGISTRY_KEY |
|
| 35 |
+ SE_LMSHARE |
|
| 36 |
+ SE_KERNEL_OBJECT |
|
| 37 |
+ SE_WINDOW_OBJECT |
|
| 38 |
+ SE_DS_OBJECT |
|
| 39 |
+ SE_DS_OBJECT_ALL |
|
| 40 |
+ SE_PROVIDER_DEFINED_OBJECT |
|
| 41 |
+ SE_WMIGUID_OBJECT |
|
| 42 |
+ SE_REGISTRY_WOW64_32KEY |
|
| 43 |
+) |
|
| 44 |
+ |
|
| 45 |
+const ( |
|
| 46 |
+ SeTakeOwnershipPrivilege = "SeTakeOwnershipPrivilege" |
|
| 47 |
+) |
|
| 48 |
+ |
|
| 49 |
+const ( |
|
| 50 |
+ ContainerAdministratorSidString = "S-1-5-93-2-1" |
|
| 51 |
+ ContainerUserSidString = "S-1-5-93-2-2" |
|
| 52 |
+) |
|
| 53 |
+ |
|
| 11 | 54 |
var ( |
| 12 |
- ntuserApiset = windows.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0")
|
|
| 13 |
- procGetVersionExW = modkernel32.NewProc("GetVersionExW")
|
|
| 14 |
- procGetProductInfo = modkernel32.NewProc("GetProductInfo")
|
|
| 55 |
+ ntuserApiset = windows.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0")
|
|
| 56 |
+ modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
|
| 57 |
+ procGetVersionExW = modkernel32.NewProc("GetVersionExW")
|
|
| 58 |
+ procGetProductInfo = modkernel32.NewProc("GetProductInfo")
|
|
| 59 |
+ procSetNamedSecurityInfo = modadvapi32.NewProc("SetNamedSecurityInfoW")
|
|
| 60 |
+ procGetSecurityDescriptorDacl = modadvapi32.NewProc("GetSecurityDescriptorDacl")
|
|
| 15 | 61 |
) |
| 16 | 62 |
|
| 17 | 63 |
// OSVersion is a wrapper for Windows version information |
| ... | ... |
@@ -125,3 +171,23 @@ func HasWin32KSupport() bool {
|
| 125 | 125 |
// APIs. |
| 126 | 126 |
return ntuserApiset.Load() == nil |
| 127 | 127 |
} |
| 128 |
+ |
|
| 129 |
+func SetNamedSecurityInfo(objectName *uint16, objectType uint32, securityInformation uint32, sidOwner *windows.SID, sidGroup *windows.SID, dacl *byte, sacl *byte) (result error) {
|
|
| 130 |
+ 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) |
|
| 131 |
+ if r0 != 0 {
|
|
| 132 |
+ result = syscall.Errno(r0) |
|
| 133 |
+ } |
|
| 134 |
+ return |
|
| 135 |
+} |
|
| 136 |
+ |
|
| 137 |
+func GetSecurityDescriptorDacl(securityDescriptor *byte, daclPresent *uint32, dacl **byte, daclDefaulted *uint32) (result error) {
|
|
| 138 |
+ 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) |
|
| 139 |
+ if r1 == 0 {
|
|
| 140 |
+ if e1 != 0 {
|
|
| 141 |
+ result = syscall.Errno(e1) |
|
| 142 |
+ } else {
|
|
| 143 |
+ result = syscall.EINVAL |
|
| 144 |
+ } |
|
| 145 |
+ } |
|
| 146 |
+ return |
|
| 147 |
+} |
| ... | ... |
@@ -53,7 +53,7 @@ func (pm *Manager) enable(p *v2.Plugin, c *controller, force bool) error {
|
| 53 | 53 |
} |
| 54 | 54 |
|
| 55 | 55 |
rootFS := containerfs.NewLocalContainerFS(filepath.Join(pm.config.Root, p.PluginObj.ID, rootFSFileName)) |
| 56 |
- if err := initlayer.Setup(rootFS, idtools.IDPair{UID: 0, GID: 0}); err != nil {
|
|
| 56 |
+ if err := initlayer.Setup(rootFS, idtools.Identity{UID: 0, GID: 0}); err != nil {
|
|
| 57 | 57 |
return errors.WithStack(err) |
| 58 | 58 |
} |
| 59 | 59 |
|
| ... | ... |
@@ -46,18 +46,18 @@ type activeMount struct {
|
| 46 | 46 |
// New instantiates a new Root instance with the provided scope. Scope |
| 47 | 47 |
// is the base path that the Root instance uses to store its |
| 48 | 48 |
// volumes. The base path is created here if it does not exist. |
| 49 |
-func New(scope string, rootIDs idtools.IDPair) (*Root, error) {
|
|
| 49 |
+func New(scope string, rootIdentity idtools.Identity) (*Root, error) {
|
|
| 50 | 50 |
rootDirectory := filepath.Join(scope, volumesPathName) |
| 51 | 51 |
|
| 52 |
- if err := idtools.MkdirAllAndChown(rootDirectory, 0700, rootIDs); err != nil {
|
|
| 52 |
+ if err := idtools.MkdirAllAndChown(rootDirectory, 0700, rootIdentity); err != nil {
|
|
| 53 | 53 |
return nil, err |
| 54 | 54 |
} |
| 55 | 55 |
|
| 56 | 56 |
r := &Root{
|
| 57 |
- scope: scope, |
|
| 58 |
- path: rootDirectory, |
|
| 59 |
- volumes: make(map[string]*localVolume), |
|
| 60 |
- rootIDs: rootIDs, |
|
| 57 |
+ scope: scope, |
|
| 58 |
+ path: rootDirectory, |
|
| 59 |
+ volumes: make(map[string]*localVolume), |
|
| 60 |
+ rootIdentity: rootIdentity, |
|
| 61 | 61 |
} |
| 62 | 62 |
|
| 63 | 63 |
dirs, err := ioutil.ReadDir(rootDirectory) |
| ... | ... |
@@ -101,11 +101,11 @@ func New(scope string, rootIDs idtools.IDPair) (*Root, error) {
|
| 101 | 101 |
// manages the creation/removal of volumes. It uses only standard vfs |
| 102 | 102 |
// commands to create/remove dirs within its provided scope. |
| 103 | 103 |
type Root struct {
|
| 104 |
- m sync.Mutex |
|
| 105 |
- scope string |
|
| 106 |
- path string |
|
| 107 |
- volumes map[string]*localVolume |
|
| 108 |
- rootIDs idtools.IDPair |
|
| 104 |
+ m sync.Mutex |
|
| 105 |
+ scope string |
|
| 106 |
+ path string |
|
| 107 |
+ volumes map[string]*localVolume |
|
| 108 |
+ rootIdentity idtools.Identity |
|
| 109 | 109 |
} |
| 110 | 110 |
|
| 111 | 111 |
// List lists all the volumes |
| ... | ... |
@@ -146,7 +146,7 @@ func (r *Root) Create(name string, opts map[string]string) (volume.Volume, error |
| 146 | 146 |
} |
| 147 | 147 |
|
| 148 | 148 |
path := r.DataPath(name) |
| 149 |
- if err := idtools.MkdirAllAndChown(path, 0755, r.rootIDs); err != nil {
|
|
| 149 |
+ if err := idtools.MkdirAllAndChown(path, 0755, r.rootIdentity); err != nil {
|
|
| 150 | 150 |
return nil, errors.Wrapf(errdefs.System(err), "error while creating volume path '%s'", path) |
| 151 | 151 |
} |
| 152 | 152 |
|
| ... | ... |
@@ -38,7 +38,7 @@ func TestRemove(t *testing.T) {
|
| 38 | 38 |
} |
| 39 | 39 |
defer os.RemoveAll(rootDir) |
| 40 | 40 |
|
| 41 |
- r, err := New(rootDir, idtools.IDPair{UID: os.Geteuid(), GID: os.Getegid()})
|
|
| 41 |
+ r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
|
|
| 42 | 42 |
if err != nil {
|
| 43 | 43 |
t.Fatal(err) |
| 44 | 44 |
} |
| ... | ... |
@@ -80,7 +80,7 @@ func TestInitializeWithVolumes(t *testing.T) {
|
| 80 | 80 |
} |
| 81 | 81 |
defer os.RemoveAll(rootDir) |
| 82 | 82 |
|
| 83 |
- r, err := New(rootDir, idtools.IDPair{UID: os.Geteuid(), GID: os.Getegid()})
|
|
| 83 |
+ r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
|
|
| 84 | 84 |
if err != nil {
|
| 85 | 85 |
t.Fatal(err) |
| 86 | 86 |
} |
| ... | ... |
@@ -90,7 +90,7 @@ func TestInitializeWithVolumes(t *testing.T) {
|
| 90 | 90 |
t.Fatal(err) |
| 91 | 91 |
} |
| 92 | 92 |
|
| 93 |
- r, err = New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
|
|
| 93 |
+ r, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
|
|
| 94 | 94 |
if err != nil {
|
| 95 | 95 |
t.Fatal(err) |
| 96 | 96 |
} |
| ... | ... |
@@ -112,7 +112,7 @@ func TestCreate(t *testing.T) {
|
| 112 | 112 |
} |
| 113 | 113 |
defer os.RemoveAll(rootDir) |
| 114 | 114 |
|
| 115 |
- r, err := New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
|
|
| 115 |
+ r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
|
|
| 116 | 116 |
if err != nil {
|
| 117 | 117 |
t.Fatal(err) |
| 118 | 118 |
} |
| ... | ... |
@@ -149,7 +149,7 @@ func TestCreate(t *testing.T) {
|
| 149 | 149 |
} |
| 150 | 150 |
} |
| 151 | 151 |
|
| 152 |
- r, err = New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
|
|
| 152 |
+ r, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
|
|
| 153 | 153 |
if err != nil {
|
| 154 | 154 |
t.Fatal(err) |
| 155 | 155 |
} |
| ... | ... |
@@ -186,7 +186,7 @@ func TestCreateWithOpts(t *testing.T) {
|
| 186 | 186 |
} |
| 187 | 187 |
defer os.RemoveAll(rootDir) |
| 188 | 188 |
|
| 189 |
- r, err := New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
|
|
| 189 |
+ r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
|
|
| 190 | 190 |
if err != nil {
|
| 191 | 191 |
t.Fatal(err) |
| 192 | 192 |
} |
| ... | ... |
@@ -261,7 +261,7 @@ func TestCreateWithOpts(t *testing.T) {
|
| 261 | 261 |
t.Fatal("expected mount to still be active")
|
| 262 | 262 |
} |
| 263 | 263 |
|
| 264 |
- r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0})
|
|
| 264 |
+ r, err = New(rootDir, idtools.Identity{UID: 0, GID: 0})
|
|
| 265 | 265 |
if err != nil {
|
| 266 | 266 |
t.Fatal(err) |
| 267 | 267 |
} |
| ... | ... |
@@ -283,7 +283,7 @@ func TestRelaodNoOpts(t *testing.T) {
|
| 283 | 283 |
} |
| 284 | 284 |
defer os.RemoveAll(rootDir) |
| 285 | 285 |
|
| 286 |
- r, err := New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
|
|
| 286 |
+ r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
|
|
| 287 | 287 |
if err != nil {
|
| 288 | 288 |
t.Fatal(err) |
| 289 | 289 |
} |
| ... | ... |
@@ -311,7 +311,7 @@ func TestRelaodNoOpts(t *testing.T) {
|
| 311 | 311 |
t.Fatal(err) |
| 312 | 312 |
} |
| 313 | 313 |
|
| 314 |
- r, err = New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
|
|
| 314 |
+ r, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
|
|
| 315 | 315 |
if err != nil {
|
| 316 | 316 |
t.Fatal(err) |
| 317 | 317 |
} |
| ... | ... |
@@ -95,7 +95,7 @@ func (m *MountPoint) Cleanup() error {
|
| 95 | 95 |
// configured, or creating the source directory if supplied. |
| 96 | 96 |
// The, optional, checkFun parameter allows doing additional checking |
| 97 | 97 |
// before creating the source directory on the host. |
| 98 |
-func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.IDPair, checkFun func(m *MountPoint) error) (path string, err error) {
|
|
| 98 |
+func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.Identity, checkFun func(m *MountPoint) error) (path string, err error) {
|
|
| 99 | 99 |
if m.SkipMountpointCreation {
|
| 100 | 100 |
return m.Source, nil |
| 101 | 101 |
} |
| ... | ... |
@@ -9,7 +9,7 @@ import ( |
| 9 | 9 |
"github.com/pkg/errors" |
| 10 | 10 |
) |
| 11 | 11 |
|
| 12 |
-func setupDefaultDriver(store *drivers.Store, root string, rootIDs idtools.IDPair) error {
|
|
| 12 |
+func setupDefaultDriver(store *drivers.Store, root string, rootIDs idtools.Identity) error {
|
|
| 13 | 13 |
d, err := local.New(root, rootIDs) |
| 14 | 14 |
if err != nil {
|
| 15 | 15 |
return errors.Wrap(err, "error setting up default driver") |
| ... | ... |
@@ -35,7 +35,7 @@ type VolumesService struct {
|
| 35 | 35 |
} |
| 36 | 36 |
|
| 37 | 37 |
// NewVolumeService creates a new volume service |
| 38 |
-func NewVolumeService(root string, pg plugingetter.PluginGetter, rootIDs idtools.IDPair, logger volumeEventLogger) (*VolumesService, error) {
|
|
| 38 |
+func NewVolumeService(root string, pg plugingetter.PluginGetter, rootIDs idtools.Identity, logger volumeEventLogger) (*VolumesService, error) {
|
|
| 39 | 39 |
ds := drivers.NewStore(pg) |
| 40 | 40 |
if err := setupDefaultDriver(ds, root, rootIDs); err != nil {
|
| 41 | 41 |
return nil, err |
| ... | ... |
@@ -25,7 +25,7 @@ func TestLocalVolumeSize(t *testing.T) {
|
| 25 | 25 |
assert.Assert(t, err) |
| 26 | 26 |
defer os.RemoveAll(dir) |
| 27 | 27 |
|
| 28 |
- l, err := local.New(dir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
|
|
| 28 |
+ l, err := local.New(dir, idtools.Identity{UID: os.Getuid(), GID: os.Getegid()})
|
|
| 29 | 29 |
assert.Assert(t, err) |
| 30 | 30 |
assert.Assert(t, ds.Register(l, volume.DefaultDriverName)) |
| 31 | 31 |
assert.Assert(t, ds.Register(testutils.NewFakeDriver("fake"), "fake"))
|