2018-02-05 16:05:59 -05:00
|
|
|
package dockerfile // import "github.com/docker/docker/builder/dockerfile"
|
2018-01-12 20:57:50 -05:00
|
|
|
|
|
|
|
import (
|
|
|
|
"path/filepath"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/docker/docker/pkg/idtools"
|
|
|
|
"github.com/docker/docker/pkg/symlink"
|
|
|
|
lcUser "github.com/opencontainers/runc/libcontainer/user"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
)
|
|
|
|
|
|
|
|
func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) {
|
|
|
|
var userStr, grpStr string
|
|
|
|
parts := strings.Split(chown, ":")
|
|
|
|
if len(parts) > 2 {
|
|
|
|
return idtools.IDPair{}, errors.New("invalid chown string format: " + chown)
|
|
|
|
}
|
|
|
|
if len(parts) == 1 {
|
|
|
|
// if no group specified, use the user spec as group as well
|
|
|
|
userStr, grpStr = parts[0], parts[0]
|
|
|
|
} else {
|
|
|
|
userStr, grpStr = parts[0], parts[1]
|
|
|
|
}
|
|
|
|
|
|
|
|
passwdPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "passwd"), ctrRootPath)
|
|
|
|
if err != nil {
|
|
|
|
return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/passwd path in container rootfs")
|
|
|
|
}
|
|
|
|
groupPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "group"), ctrRootPath)
|
|
|
|
if err != nil {
|
|
|
|
return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/group path in container rootfs")
|
|
|
|
}
|
|
|
|
uid, err := lookupUser(userStr, passwdPath)
|
|
|
|
if err != nil {
|
|
|
|
return idtools.IDPair{}, errors.Wrapf(err, "can't find uid for user "+userStr)
|
|
|
|
}
|
|
|
|
gid, err := lookupGroup(grpStr, groupPath)
|
|
|
|
if err != nil {
|
|
|
|
return idtools.IDPair{}, errors.Wrapf(err, "can't find gid for group "+grpStr)
|
|
|
|
}
|
|
|
|
|
|
|
|
// convert as necessary because of user namespaces
|
|
|
|
chownPair, err := idMappings.ToHost(idtools.IDPair{UID: uid, GID: gid})
|
|
|
|
if err != nil {
|
|
|
|
return idtools.IDPair{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
|
|
|
|
}
|
|
|
|
return chownPair, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func lookupUser(userStr, filepath string) (int, error) {
|
|
|
|
// if the string is actually a uid integer, parse to int and return
|
|
|
|
// as we don't need to translate with the help of files
|
|
|
|
uid, err := strconv.Atoi(userStr)
|
|
|
|
if err == nil {
|
|
|
|
return uid, nil
|
|
|
|
}
|
|
|
|
users, err := lcUser.ParsePasswdFileFilter(filepath, func(u lcUser.User) bool {
|
|
|
|
return u.Name == userStr
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
if len(users) == 0 {
|
|
|
|
return 0, errors.New("no such user: " + userStr)
|
|
|
|
}
|
|
|
|
return users[0].Uid, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func lookupGroup(groupStr, filepath string) (int, error) {
|
|
|
|
// if the string is actually a gid integer, parse to int and return
|
|
|
|
// as we don't need to translate with the help of files
|
|
|
|
gid, err := strconv.Atoi(groupStr)
|
|
|
|
if err == nil {
|
|
|
|
return gid, nil
|
|
|
|
}
|
|
|
|
groups, err := lcUser.ParseGroupFileFilter(filepath, func(g lcUser.Group) bool {
|
|
|
|
return g.Name == groupStr
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
if len(groups) == 0 {
|
|
|
|
return 0, errors.New("no such group: " + groupStr)
|
|
|
|
}
|
|
|
|
return groups[0].Gid, nil
|
|
|
|
}
|