Skip to content

Instantly share code, notes, and snippets.

@denisoster
Created July 23, 2022 12:44
Show Gist options
  • Save denisoster/88a013adca06a9ca6e2af44a0e8dc591 to your computer and use it in GitHub Desktop.
Save denisoster/88a013adca06a9ca6e2af44a0e8dc591 to your computer and use it in GitHub Desktop.
Podman with support Name Service Switch
Index: vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go b/vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go
--- a/vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go (revision 932822ab4b4d937de75228638b2916885fff444a)
+++ b/vendor/github.com/opencontainers/runc/libcontainer/user/lookup_unix.go (date 1658575026063)
@@ -6,9 +6,15 @@
import (
"io"
"os"
+ "fmt"
+ "sync"
+ "bytes"
+ "os/exec"
+ "path/filepath"
"strconv"
"golang.org/x/sys/unix"
+ "github.com/containers/storage/pkg/system"
)
// Unix-specific path to the passwd and group formatted files.
@@ -17,12 +23,17 @@
unixGroupPath = "/etc/group"
)
+var (
+ entOnce sync.Once
+ getentCmd string
+)
+
// LookupUser looks up a user by their username in /etc/passwd. If the user
// cannot be found (or there is no /etc/passwd file on the filesystem), then
// LookupUser returns an error.
-func LookupUser(username string) (User, error) {
- return lookupUserFunc(func(u User) bool {
- return u.Name == username
+func LookupUser(name string) (User, error) {
+ return getentUser(name, func(u User) bool {
+ return u.Name == name
})
}
@@ -30,40 +41,17 @@
// be found (or there is no /etc/passwd file on the filesystem), then LookupId
// returns an error.
func LookupUid(uid int) (User, error) {
- return lookupUserFunc(func(u User) bool {
+ return getentUser(string(uid), func(u User) bool {
return u.Uid == uid
})
}
-func lookupUserFunc(filter func(u User) bool) (User, error) {
- // Get operating system-specific passwd reader-closer.
- passwd, err := GetPasswd()
- if err != nil {
- return User{}, err
- }
- defer passwd.Close()
-
- // Get the users.
- users, err := ParsePasswdFilter(passwd, filter)
- if err != nil {
- return User{}, err
- }
-
- // No user entries found.
- if len(users) == 0 {
- return User{}, ErrNoPasswdEntries
- }
-
- // Assume the first entry is the "correct" one.
- return users[0], nil
-}
-
// LookupGroup looks up a group by its name in /etc/group. If the group cannot
// be found (or there is no /etc/group file on the filesystem), then LookupGroup
// returns an error.
-func LookupGroup(groupname string) (Group, error) {
- return lookupGroupFunc(func(g Group) bool {
- return g.Name == groupname
+func LookupGroup(name string) (Group, error) {
+ return getentGroup(fmt.Sprintf("%s %s", "group", name), func(g Group) bool {
+ return g.Name == name
})
}
@@ -71,34 +59,100 @@
// be found (or there is no /etc/group file on the filesystem), then LookupGid
// returns an error.
func LookupGid(gid int) (Group, error) {
- return lookupGroupFunc(func(g Group) bool {
+ return getentGroup(fmt.Sprintf("%s %d", "group", gid), func(g Group) bool {
return g.Gid == gid
})
}
-func lookupGroupFunc(filter func(g Group) bool) (Group, error) {
- // Get operating system-specific group reader-closer.
- group, err := GetGroup()
+func getentUser(value string, filter func(u User) bool) (User, error) {
+ passwd, err := callGetent("passwd", value)
+
+ if err != nil {
+ return User{}, err
+ }
+
+ users, err := ParsePasswdFilter(passwd, filter)
+
+ if err != nil {
+ return User{}, err
+ }
+
+ if len(users) == 0 {
+ return User{}, fmt.Errorf("getent failed to find passwd entry for %q", value)
+ }
+
+ return users[0], nil
+}
+
+func getentGroup(value string, filter func(g Group) bool) (Group, error) {
+ group, err := callGetent("group", value)
+
if err != nil {
return Group{}, err
}
- defer group.Close()
- // Get the users.
groups, err := ParseGroupFilter(group, filter)
+
if err != nil {
return Group{}, err
}
- // No user entries found.
if len(groups) == 0 {
- return Group{}, ErrNoGroupEntries
+ return Group{}, fmt.Errorf("getent failed to find groups entry for %q", value)
}
- // Assume the first entry is the "correct" one.
return groups[0], nil
}
+func callGetent(database string, key string) (io.Reader, error) {
+ entOnce.Do(func() { getentCmd, _ = resolveBinary("getent") })
+ // if no `getent` command on host, can't do anything else
+ if getentCmd == "" {
+ return nil, fmt.Errorf("unable to find getent command")
+ }
+ out, err := execCmd(getentCmd, database, key)
+ if err != nil {
+ exitCode, errC := system.GetExitCode(err)
+ if errC != nil {
+ return nil, err
+ }
+ switch exitCode {
+ case 1:
+ return nil, fmt.Errorf("getent reported invalid parameters/database unknown")
+ case 2:
+ return nil, fmt.Errorf("getent unable to find entry %q in %s database", key, database)
+ case 3:
+ return nil, fmt.Errorf("getent database doesn't support enumeration")
+ default:
+ return nil, err
+ }
+
+ }
+ return bytes.NewReader(out), nil
+}
+
+func resolveBinary(binname string) (string, error) {
+ binaryPath, err := exec.LookPath(binname)
+ if err != nil {
+ return "", err
+ }
+ resolvedPath, err := filepath.EvalSymlinks(binaryPath)
+ if err != nil {
+ return "", err
+ }
+ // only return no error if the final resolved binary basename
+ // matches what was searched for
+ if filepath.Base(resolvedPath) == binname {
+ return resolvedPath, nil
+ }
+ return "", fmt.Errorf("Binary %q does not resolve to a binary of that name in $PATH (%q)", binname, resolvedPath)
+}
+
+func execCmd(cmd string, arg ...string) ([]byte, error) {
+ execCmd := exec.Command(cmd, arg...)
+ return execCmd.CombinedOutput()
+}
+
func GetPasswdPath() (string, error) {
return unixPasswdPath, nil
}
# Maintainer: Morten Linderud <foxboron@archlinux.org>
# Maintainer: David Runge <dvzrv@archlinux.org>
# Contributor: Bartłomiej Piotrowski <bpiotrowski@archlinux.org>
pkgbase=podman
pkgname=(podman podman-docker)
pkgver=4.1.1
pkgrel=3
pkgdesc='Tool and library for running OCI-based containers in pods'
arch=(x86_64)
url='https://github.com/containers/podman'
license=(Apache)
makedepends=(apparmor btrfs-progs catatonit device-mapper go go-md2man git gpgme libseccomp systemd)
# https://github.com/containers/podman/issues/13297
options=(!lto)
source=(git+$url#tag=v$pkgver?signed
nsswitch.patch
)
sha256sums=('SKIP'
'SKIP')
prepare() {
cd $pkgname
patch --strip=1 --input="${srcdir}/nsswitch.patch"
}
pkgver() {
cd $pkgname
git describe --tags | sed 's/^v//;s/-/+/g'
}
build() {
# NOTE: the BUILDTAGS may change over time
export BUILDTAGS='apparmor seccomp systemd'
export CGO_CPPFLAGS="${CPPFLAGS}"
export CGO_CFLAGS="${CFLAGS}"
export CGO_CXXFLAGS="${CXXFLAGS}"
export CGO_LDFLAGS="${LDFLAGS}"
export GOFLAGS="-buildmode=pie -trimpath"
make EXTRA_LDFLAGS='-s -w -linkmode=external' -C $pkgbase
make docker-docs -C $pkgbase
}
package_podman() {
depends=(catatonit conmon containers-common crun iptables libdevmapper.so
libgpgme.so libseccomp.so slirp4netns)
optdepends=(
'apparmor: for AppArmor support'
'btrfs-progs: support btrfs backend devices'
'netavark: for a new container-network-stack implementation'
'podman-compose: for docker-compose compatibility'
'podman-docker: for Docker-compatible CLI'
)
make install install.completions DESTDIR="$pkgdir" PREFIX=/usr LIBEXECDIR=/usr/lib -C $pkgbase
# remove man pages provided by containers-common
rm -rvf "$pkgdir/usr/share/man/man5"
}
package_podman-docker() {
pkgdesc='Emulate Docker CLI using podman'
depends=(podman)
conflicts=(docker)
provides=(docker)
make -j1 install.docker-full DESTDIR="$pkgdir" PREFIX=/usr -C $pkgbase
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment