moby/builder/dockerfile/copy_windows.go
Salahuddin Khan 763d839261 Add ADD/COPY --chown flag support to Windows
This implements chown support on Windows. Built-in accounts as well
as accounts included in the SAM database of the container are supported.

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

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

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

Signed-off-by: Salahuddin Khan <salah@docker.com>
2018-08-13 21:59:11 -07:00

109 lines
2.9 KiB
Go

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