1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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))
}
|