diff options
author | Daniel J Walsh <dwalsh@redhat.com> | 2021-12-16 09:24:24 -0500 |
---|---|---|
committer | Daniel J Walsh <dwalsh@redhat.com> | 2021-12-23 07:51:27 -0500 |
commit | e8c06fac97f56ccc710584731d8b52ed58fbd2dd (patch) | |
tree | a9ec6546c64a0ae393cda0290256977a63da8eed /libpod | |
parent | a7f1c05366c86a05e247049f8837b4aadc54fc50 (diff) | |
download | podman-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.go | 2 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 63 | ||||
-rw-r--r-- | libpod/options.go | 11 |
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 { |