github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/builder/dockerfile/internals_linux.go (about)

     1  package dockerfile // import "github.com/docker/docker/builder/dockerfile"
     2  
     3  import (
     4  	"context"
     5  	"path/filepath"
     6  	"strconv"
     7  	"strings"
     8  
     9  	"github.com/docker/docker/pkg/idtools"
    10  	"github.com/moby/sys/symlink"
    11  	lcUser "github.com/opencontainers/runc/libcontainer/user"
    12  	"github.com/pkg/errors"
    13  )
    14  
    15  func parseChownFlag(ctx context.Context, builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping idtools.IdentityMapping) (idtools.Identity, error) {
    16  	var userStr, grpStr string
    17  	parts := strings.Split(chown, ":")
    18  	if len(parts) > 2 {
    19  		return idtools.Identity{}, errors.New("invalid chown string format: " + chown)
    20  	}
    21  	if len(parts) == 1 {
    22  		// if no group specified, use the user spec as group as well
    23  		userStr, grpStr = parts[0], parts[0]
    24  	} else {
    25  		userStr, grpStr = parts[0], parts[1]
    26  	}
    27  
    28  	passwdPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "passwd"), ctrRootPath)
    29  	if err != nil {
    30  		return idtools.Identity{}, errors.Wrapf(err, "can't resolve /etc/passwd path in container rootfs")
    31  	}
    32  	groupPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "group"), ctrRootPath)
    33  	if err != nil {
    34  		return idtools.Identity{}, errors.Wrapf(err, "can't resolve /etc/group path in container rootfs")
    35  	}
    36  	uid, err := lookupUser(userStr, passwdPath)
    37  	if err != nil {
    38  		return idtools.Identity{}, errors.Wrapf(err, "can't find uid for user "+userStr)
    39  	}
    40  	gid, err := lookupGroup(grpStr, groupPath)
    41  	if err != nil {
    42  		return idtools.Identity{}, errors.Wrapf(err, "can't find gid for group "+grpStr)
    43  	}
    44  
    45  	// convert as necessary because of user namespaces
    46  	chownPair, err := identityMapping.ToHost(idtools.Identity{UID: uid, GID: gid})
    47  	if err != nil {
    48  		return idtools.Identity{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
    49  	}
    50  	return chownPair, nil
    51  }
    52  
    53  func lookupUser(userStr, filepath string) (int, error) {
    54  	// if the string is actually a uid integer, parse to int and return
    55  	// as we don't need to translate with the help of files
    56  	uid, err := strconv.Atoi(userStr)
    57  	if err == nil {
    58  		return uid, nil
    59  	}
    60  	users, err := lcUser.ParsePasswdFileFilter(filepath, func(u lcUser.User) bool {
    61  		return u.Name == userStr
    62  	})
    63  	if err != nil {
    64  		return 0, err
    65  	}
    66  	if len(users) == 0 {
    67  		return 0, errors.New("no such user: " + userStr)
    68  	}
    69  	return users[0].Uid, nil
    70  }
    71  
    72  func lookupGroup(groupStr, filepath string) (int, error) {
    73  	// if the string is actually a gid integer, parse to int and return
    74  	// as we don't need to translate with the help of files
    75  	gid, err := strconv.Atoi(groupStr)
    76  	if err == nil {
    77  		return gid, nil
    78  	}
    79  	groups, err := lcUser.ParseGroupFileFilter(filepath, func(g lcUser.Group) bool {
    80  		return g.Name == groupStr
    81  	})
    82  	if err != nil {
    83  		return 0, err
    84  	}
    85  	if len(groups) == 0 {
    86  		return 0, errors.New("no such group: " + groupStr)
    87  	}
    88  	return groups[0].Gid, nil
    89  }