summaryrefslogtreecommitdiff
path: root/pkg/lookup
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/lookup')
-rw-r--r--pkg/lookup/lookup.go156
1 files changed, 156 insertions, 0 deletions
diff --git a/pkg/lookup/lookup.go b/pkg/lookup/lookup.go
new file mode 100644
index 000000000..b27e2a724
--- /dev/null
+++ b/pkg/lookup/lookup.go
@@ -0,0 +1,156 @@
+package lookup
+
+import (
+ "github.com/cyphar/filepath-securejoin"
+ "github.com/opencontainers/runc/libcontainer/user"
+ "github.com/sirupsen/logrus"
+ "strconv"
+)
+
+const (
+ etcpasswd = "/etc/passwd"
+ etcgroup = "/etc/group"
+)
+
+// Overrides allows you to override defaults in GetUserGroupInfo
+type Overrides struct {
+ DefaultUser *user.ExecUser
+ ContainerEtcPasswdPath string
+ ContainerEtcGroupPath string
+}
+
+// GetUserGroupInfo takes string forms of the the container's mount path and the container user and
+// returns a ExecUser with uid, gid, sgids, and home. And override can be provided for defaults.
+func GetUserGroupInfo(containerMount, containerUser string, override *Overrides) (*user.ExecUser, error) {
+ var (
+ passwdDest, groupDest string
+ defaultExecUser *user.ExecUser
+ err error
+ )
+ passwdPath := etcpasswd
+ groupPath := etcgroup
+
+ if override != nil {
+ // Check for an override /etc/passwd path
+ if override.ContainerEtcPasswdPath != "" {
+ passwdPath = override.ContainerEtcPasswdPath
+ }
+ // Check for an override for /etc/group path
+ if override.ContainerEtcGroupPath != "" {
+ groupPath = override.ContainerEtcGroupPath
+ }
+ }
+
+ // Check for an override default user
+ if override != nil && override.DefaultUser != nil {
+ defaultExecUser = override.DefaultUser
+ } else {
+ // Define a default container user
+ //defaultExecUser = &user.ExecUser{
+ // Uid: 0,
+ // Gid: 0,
+ // Home: "/",
+ defaultExecUser = nil
+
+ }
+
+ // Make sure the /etc/group and /etc/passwd destinations are not a symlink to something naughty
+ if passwdDest, err = securejoin.SecureJoin(containerMount, passwdPath); err != nil {
+ logrus.Debug(err)
+ return nil, err
+ }
+ if groupDest, err = securejoin.SecureJoin(containerMount, groupPath); err != nil {
+ logrus.Debug(err)
+ return nil, err
+ }
+ return user.GetExecUserPath(containerUser, defaultExecUser, passwdDest, groupDest)
+}
+
+// GetContainerGroups uses securejoin to get a list of numerical groupids from a container. Per the runc
+// function it calls: If a group name cannot be found, an error will be returned. If a group id cannot be found,
+// or the given group data is nil, the id will be returned as-is provided it is in the legal range.
+func GetContainerGroups(groups []string, containerMount string, override *Overrides) ([]uint32, error) {
+ var (
+ groupDest string
+ err error
+ uintgids []uint32
+ )
+
+ groupPath := etcgroup
+ if override != nil && override.ContainerEtcGroupPath != "" {
+ groupPath = override.ContainerEtcGroupPath
+ }
+
+ if groupDest, err = securejoin.SecureJoin(containerMount, groupPath); err != nil {
+ logrus.Debug(err)
+ return nil, err
+ }
+
+ gids, err := user.GetAdditionalGroupsPath(groups, groupDest)
+ if err != nil {
+ return nil, err
+ }
+ // For libpod, we want []uint32s
+ for _, gid := range gids {
+ uintgids = append(uintgids, uint32(gid))
+ }
+ return uintgids, nil
+}
+
+// GetUser takes a containermount path and user name or id and returns
+// a matching User structure from /etc/passwd. If it cannot locate a user
+// with the provided information, an ErrNoPasswdEntries is returned.
+func GetUser(containerMount, userIDorName string) (*user.User, error) {
+ var inputIsName bool
+ uid, err := strconv.Atoi(userIDorName)
+ if err != nil {
+ inputIsName = true
+ }
+ passwdDest, err := securejoin.SecureJoin(containerMount, etcpasswd)
+ if err != nil {
+ return nil, err
+ }
+ users, err := user.ParsePasswdFileFilter(passwdDest, func(u user.User) bool {
+ if inputIsName {
+ return u.Name == userIDorName
+ }
+ return u.Uid == uid
+ })
+ if err != nil {
+ return nil, err
+ }
+ if len(users) > 0 {
+ return &users[0], nil
+ }
+ return nil, user.ErrNoPasswdEntries
+}
+
+// GetGroup takes ac ontainermount path and a group name or id and returns
+// a match Group struct from /etc/group. if it cannot locate a group,
+// an ErrNoGroupEntries error is returned.
+func GetGroup(containerMount, groupIDorName string) (*user.Group, error) {
+ var inputIsName bool
+ gid, err := strconv.Atoi(groupIDorName)
+ if err != nil {
+ inputIsName = true
+ }
+
+ groupDest, err := securejoin.SecureJoin(containerMount, etcgroup)
+ if err != nil {
+ return nil, err
+ }
+
+ groups, err := user.ParseGroupFileFilter(groupDest, func(g user.Group) bool {
+ if inputIsName {
+ return g.Name == groupIDorName
+ }
+ return g.Gid == gid
+ })
+ if err != nil {
+ return nil, err
+ }
+ if len(groups) > 0 {
+ return &groups[0], nil
+ }
+ return nil, user.ErrNoGroupEntries
+}