summaryrefslogtreecommitdiff
path: root/cmd/podman/user.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podman/user.go')
-rw-r--r--cmd/podman/user.go121
1 files changed, 121 insertions, 0 deletions
diff --git a/cmd/podman/user.go b/cmd/podman/user.go
new file mode 100644
index 000000000..3e2e308c5
--- /dev/null
+++ b/cmd/podman/user.go
@@ -0,0 +1,121 @@
+package main
+
+// #include <sys/types.h>
+// #include <grp.h>
+// #include <pwd.h>
+// #include <stdlib.h>
+// #include <stdio.h>
+// #include <string.h>
+// typedef FILE * pFILE;
+import "C"
+
+import (
+ "fmt"
+ "os/user"
+ "path/filepath"
+ "sync"
+ "syscall"
+ "unsafe"
+
+ "github.com/pkg/errors"
+)
+
+func fopenContainerFile(rootdir, filename string) (C.pFILE, error) {
+ var st, lst syscall.Stat_t
+
+ ctrfile := filepath.Join(rootdir, filename)
+ cctrfile := C.CString(ctrfile)
+ defer C.free(unsafe.Pointer(cctrfile))
+ mode := C.CString("r")
+ defer C.free(unsafe.Pointer(mode))
+ f, err := C.fopen(cctrfile, mode)
+ if f == nil || err != nil {
+ return nil, errors.Wrapf(err, "error opening %q", ctrfile)
+ }
+ if err = syscall.Fstat(int(C.fileno(f)), &st); err != nil {
+ return nil, errors.Wrapf(err, "fstat(%q)", ctrfile)
+ }
+ if err = syscall.Lstat(ctrfile, &lst); err != nil {
+ return nil, errors.Wrapf(err, "lstat(%q)", ctrfile)
+ }
+ if st.Dev != lst.Dev || st.Ino != lst.Ino {
+ return nil, errors.Errorf("%q is not a regular file", ctrfile)
+ }
+ return f, nil
+}
+
+var (
+ lookupUser, lookupGroup sync.Mutex
+)
+
+func lookupUserInContainer(rootdir, username string) (uint64, uint64, error) {
+ name := C.CString(username)
+ defer C.free(unsafe.Pointer(name))
+
+ f, err := fopenContainerFile(rootdir, "/etc/passwd")
+ if err != nil {
+ return 0, 0, err
+ }
+ defer C.fclose(f)
+
+ lookupUser.Lock()
+ defer lookupUser.Unlock()
+
+ pwd := C.fgetpwent(f)
+ for pwd != nil {
+ if C.strcmp(pwd.pw_name, name) != 0 {
+ pwd = C.fgetpwent(f)
+ continue
+ }
+ return uint64(pwd.pw_uid), uint64(pwd.pw_gid), nil
+ }
+
+ return 0, 0, user.UnknownUserError(fmt.Sprintf("error looking up user %q", username))
+}
+
+func lookupGroupForUIDInContainer(rootdir string, userid uint64) (string, uint64, error) {
+ f, err := fopenContainerFile(rootdir, "/etc/passwd")
+ if err != nil {
+ return "", 0, err
+ }
+ defer C.fclose(f)
+
+ lookupUser.Lock()
+ defer lookupUser.Unlock()
+
+ pwd := C.fgetpwent(f)
+ for pwd != nil {
+ if uint64(pwd.pw_uid) != userid {
+ pwd = C.fgetpwent(f)
+ continue
+ }
+ return C.GoString(pwd.pw_name), uint64(pwd.pw_gid), nil
+ }
+
+ return "", 0, user.UnknownUserError(fmt.Sprintf("error looking up user with UID %d", userid))
+}
+
+func lookupGroupInContainer(rootdir, groupname string) (uint64, error) {
+ name := C.CString(groupname)
+ defer C.free(unsafe.Pointer(name))
+
+ f, err := fopenContainerFile(rootdir, "/etc/group")
+ if err != nil {
+ return 0, err
+ }
+ defer C.fclose(f)
+
+ lookupGroup.Lock()
+ defer lookupGroup.Unlock()
+
+ grp := C.fgetgrent(f)
+ for grp != nil {
+ if C.strcmp(grp.gr_name, name) != 0 {
+ grp = C.fgetgrent(f)
+ continue
+ }
+ return uint64(grp.gr_gid), nil
+ }
+
+ return 0, user.UnknownGroupError(fmt.Sprintf("error looking up group %q", groupname))
+}