summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
authorDaniel J Walsh <dwalsh@redhat.com>2021-12-16 09:24:24 -0500
committerDaniel J Walsh <dwalsh@redhat.com>2021-12-23 07:51:27 -0500
commite8c06fac97f56ccc710584731d8b52ed58fbd2dd (patch)
treea9ec6546c64a0ae393cda0290256977a63da8eed /libpod
parenta7f1c05366c86a05e247049f8837b4aadc54fc50 (diff)
downloadpodman-e8c06fac97f56ccc710584731d8b52ed58fbd2dd.tar.gz
podman-e8c06fac97f56ccc710584731d8b52ed58fbd2dd.tar.bz2
podman-e8c06fac97f56ccc710584731d8b52ed58fbd2dd.zip
Allow users to add host user accounts to /etc/passwd
Some containers require certain user account(s) to exist within the container when they are run. This option will allow callers to add a bunch of passwd entries from the host to the container even if the entries are not in the local /etc/passwd file on the host. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1935831 Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container_config.go2
-rw-r--r--libpod/container_internal_linux.go63
-rw-r--r--libpod/options.go11
3 files changed, 69 insertions, 7 deletions
diff --git a/libpod/container_config.go b/libpod/container_config.go
index db65063b5..a43fd632b 100644
--- a/libpod/container_config.go
+++ b/libpod/container_config.go
@@ -198,6 +198,8 @@ type ContainerSecurityConfig struct {
// Groups are additional groups to add the container's user to. These
// are resolved within the container using the container's /etc/passwd.
Groups []string `json:"groups,omitempty"`
+ // HostUsers are a list of host user accounts to add to /etc/passwd
+ HostUsers []string `json:"HostUsers,omitempty"`
// AddCurrentUserPasswdEntry indicates that Libpod should ensure that
// the container's /etc/passwd contains an entry for the user running
// Libpod - mostly used in rootless containers where the user running
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 62e198d7c..7745646b6 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -305,13 +305,40 @@ func (c *Container) getUserOverrides() *lookup.Overrides {
return &overrides
}
+func lookupHostUser(name string) (*runcuser.ExecUser, error) {
+ var execUser runcuser.ExecUser
+ // Lookup User on host
+ u, err := util.LookupUser(name)
+ if err != nil {
+ return &execUser, err
+ }
+ uid, err := strconv.ParseUint(u.Uid, 8, 32)
+ if err != nil {
+ return &execUser, err
+ }
+
+ gid, err := strconv.ParseUint(u.Gid, 8, 32)
+ if err != nil {
+ return &execUser, err
+ }
+ execUser.Uid = int(uid)
+ execUser.Gid = int(gid)
+ execUser.Home = u.HomeDir
+ return &execUser, nil
+}
+
// Generate spec for a container
// Accepts a map of the container's dependencies
func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
overrides := c.getUserOverrides()
execUser, err := lookup.GetUserGroupInfo(c.state.Mountpoint, c.config.User, overrides)
if err != nil {
- return nil, err
+ if util.StringInSlice(c.config.User, c.config.HostUsers) {
+ execUser, err = lookupHostUser(c.config.User)
+ }
+ if err != nil {
+ return nil, err
+ }
}
g := generate.NewFromSpec(c.config.Spec)
@@ -2348,12 +2375,25 @@ func (c *Container) generateUserGroupEntry(addedGID int) (string, int, error) {
// /etc/passwd via AddCurrentUserPasswdEntry (though this does not trigger if
// the user in question already exists in /etc/passwd) or the UID to be added
// is 0).
+// 3. The user specified additional host user accounts to add the the /etc/passwd file
// Returns password entry (as a string that can be appended to /etc/passwd) and
// any error that occurred.
func (c *Container) generatePasswdEntry() (string, error) {
passwdString := ""
addedUID := 0
+ for _, userid := range c.config.HostUsers {
+ // Lookup User on host
+ u, err := util.LookupUser(userid)
+ if err != nil {
+ return "", err
+ }
+ entry, err := c.userPasswdEntry(u)
+ if err != nil {
+ return "", err
+ }
+ passwdString += entry
+ }
if c.config.AddCurrentUserPasswdEntry {
entry, uid, _, err := c.generateCurrentUserPasswdEntry()
if err != nil {
@@ -2386,17 +2426,25 @@ func (c *Container) generateCurrentUserPasswdEntry() (string, int, int, error) {
if err != nil {
return "", 0, 0, errors.Wrapf(err, "failed to get current user")
}
+ pwd, err := c.userPasswdEntry(u)
+ if err != nil {
+ return "", 0, 0, err
+ }
+
+ return pwd, uid, rootless.GetRootlessGID(), nil
+}
+func (c *Container) userPasswdEntry(u *user.User) (string, error) {
// Lookup the user to see if it exists in the container image.
- _, err = lookup.GetUser(c.state.Mountpoint, u.Username)
+ _, err := lookup.GetUser(c.state.Mountpoint, u.Username)
if err != runcuser.ErrNoPasswdEntries {
- return "", 0, 0, err
+ return "", err
}
// Lookup the UID to see if it exists in the container image.
_, err = lookup.GetUser(c.state.Mountpoint, u.Uid)
if err != runcuser.ErrNoPasswdEntries {
- return "", 0, 0, err
+ return "", err
}
// If the user's actual home directory exists, or was mounted in - use
@@ -2430,7 +2478,7 @@ func (c *Container) generateCurrentUserPasswdEntry() (string, int, int, error) {
c.config.Spec.Process.Env = append(c.config.Spec.Process.Env, fmt.Sprintf("HOME=%s", homeDir))
}
- return fmt.Sprintf("%s:*:%s:%s:%s:%s:/bin/sh\n", u.Username, u.Uid, u.Gid, u.Name, homeDir), uid, rootless.GetRootlessGID(), nil
+ return fmt.Sprintf("%s:*:%s:%s:%s:%s:/bin/sh\n", u.Username, u.Uid, u.Gid, u.Name, homeDir), nil
}
// generateUserPasswdEntry generates an /etc/passwd entry for the container user
@@ -2485,7 +2533,7 @@ func (c *Container) generateUserPasswdEntry(addedUID int) (string, int, int, err
// generatePasswdAndGroup generates container-specific passwd and group files
// iff g.config.User is a number or we are configured to make a passwd entry for
-// the current user.
+// the current user or the user specified HostsUsers
// Returns path to file to mount at /etc/passwd, path to file to mount at
// /etc/group, and any error that occurred. If no passwd/group file were
// required, the empty string will be returned for those path (this may occur
@@ -2496,7 +2544,8 @@ func (c *Container) generateUserPasswdEntry(addedUID int) (string, int, int, err
// with a bind mount). This is done in cases where the container is *not*
// read-only. In this case, the function will return nothing ("", "", nil).
func (c *Container) generatePasswdAndGroup() (string, string, error) {
- if !c.config.AddCurrentUserPasswdEntry && c.config.User == "" {
+ if !c.config.AddCurrentUserPasswdEntry && c.config.User == "" &&
+ len(c.config.HostUsers) == 0 {
return "", "", nil
}
diff --git a/libpod/options.go b/libpod/options.go
index 85d7b4689..204f2a457 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1768,6 +1768,17 @@ func WithPidFile(pidFile string) CtrCreateOption {
}
}
+// WithHostUsers indicates host users to add to /etc/passwd
+func WithHostUsers(hostUsers []string) CtrCreateOption {
+ return func(ctr *Container) error {
+ if ctr.valid {
+ return define.ErrCtrFinalized
+ }
+ ctr.config.HostUsers = hostUsers
+ return nil
+ }
+}
+
// WithInitCtrType indicates the container is a initcontainer
func WithInitCtrType(containerType string) CtrCreateOption {
return func(ctr *Container) error {