internals_windows.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. package dockerfile // import "github.com/docker/docker/builder/dockerfile"
  2. import (
  3. "bytes"
  4. "os"
  5. "path/filepath"
  6. "strings"
  7. "github.com/containerd/containerd/platforms"
  8. "github.com/docker/docker/api/types/container"
  9. "github.com/docker/docker/api/types/mount"
  10. "github.com/docker/docker/pkg/idtools"
  11. "github.com/docker/docker/pkg/jsonmessage"
  12. "github.com/docker/docker/pkg/system"
  13. "github.com/pkg/errors"
  14. "golang.org/x/sys/windows"
  15. )
  16. func parseChownFlag(builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping *idtools.IdentityMapping) (idtools.Identity, error) {
  17. if builder.options.Platform == "windows" {
  18. return getAccountIdentity(builder, chown, ctrRootPath, state)
  19. }
  20. return identityMapping.RootPair(), nil
  21. }
  22. func getAccountIdentity(builder *Builder, accountName string, ctrRootPath string, state *dispatchState) (idtools.Identity, error) {
  23. // If this is potentially a string SID then attempt to convert it to verify
  24. // this, otherwise continue looking for the account.
  25. if strings.HasPrefix(accountName, "S-") || strings.HasPrefix(accountName, "s-") {
  26. sid, err := windows.StringToSid(accountName)
  27. if err == nil {
  28. accountSid, err := sid.String()
  29. if err != nil {
  30. return idtools.Identity{SID: ""}, errors.Wrapf(err, "error converting SID to string")
  31. }
  32. return idtools.Identity{SID: accountSid}, nil
  33. }
  34. }
  35. // Attempt to obtain the SID using the name.
  36. sid, _, accType, err := windows.LookupSID("", accountName)
  37. // If this is a SID that is built-in and hence the same across all systems then use that.
  38. if err == nil && (accType == windows.SidTypeAlias || accType == windows.SidTypeWellKnownGroup) {
  39. accountSid, err := sid.String()
  40. if err != nil {
  41. return idtools.Identity{SID: ""}, errors.Wrapf(err, "error converting SID to string")
  42. }
  43. return idtools.Identity{SID: accountSid}, nil
  44. }
  45. // Check if the account name is one unique to containers.
  46. if strings.EqualFold(accountName, "ContainerAdministrator") {
  47. return idtools.Identity{SID: system.ContainerAdministratorSidString}, nil
  48. } else if strings.EqualFold(accountName, "ContainerUser") {
  49. return idtools.Identity{SID: system.ContainerUserSidString}, nil
  50. }
  51. // All other lookups failed, so therefore determine if the account in
  52. // question exists in the container and if so, obtain its SID.
  53. return lookupNTAccount(builder, accountName, state)
  54. }
  55. func lookupNTAccount(builder *Builder, accountName string, state *dispatchState) (idtools.Identity, error) {
  56. source, _ := filepath.Split(os.Args[0])
  57. target := "C:\\Docker"
  58. targetExecutable := target + "\\containerutility.exe"
  59. optionsPlatform, err := platforms.Parse(builder.options.Platform)
  60. if err != nil {
  61. return idtools.Identity{}, err
  62. }
  63. runConfig := copyRunConfig(state.runConfig,
  64. withCmdCommentString("internal run to obtain NT account information.", optionsPlatform.OS))
  65. runConfig.ArgsEscaped = true
  66. runConfig.Cmd = []string{targetExecutable, "getaccountsid", accountName}
  67. hostConfig := &container.HostConfig{Mounts: []mount.Mount{
  68. {
  69. Type: mount.TypeBind,
  70. Source: source,
  71. Target: target,
  72. ReadOnly: true,
  73. },
  74. },
  75. }
  76. container, err := builder.containerManager.Create(runConfig, hostConfig)
  77. if err != nil {
  78. return idtools.Identity{}, err
  79. }
  80. stdout := new(bytes.Buffer)
  81. stderr := new(bytes.Buffer)
  82. if err := builder.containerManager.Run(builder.clientCtx, container.ID, stdout, stderr); err != nil {
  83. if err, ok := err.(*statusCodeError); ok {
  84. return idtools.Identity{}, &jsonmessage.JSONError{
  85. Message: stderr.String(),
  86. Code: err.StatusCode(),
  87. }
  88. }
  89. return idtools.Identity{}, err
  90. }
  91. accountSid := stdout.String()
  92. return idtools.Identity{SID: accountSid}, nil
  93. }