github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/builder/dockerfile/internals_windows.go (about)

     1  package dockerfile // import "github.com/docker/docker/builder/dockerfile"
     2  
     3  import (
     4  	"bytes"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  
     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
   120  }