122 lines
2.7 KiB
Go
122 lines
2.7 KiB
Go
|
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))
|
||
|
}
|