diff options
Diffstat (limited to 'cmd/kpod/user.go')
-rw-r--r-- | cmd/kpod/user.go | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/cmd/kpod/user.go b/cmd/kpod/user.go new file mode 100644 index 000000000..3e2e308c5 --- /dev/null +++ b/cmd/kpod/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)) +} |