Source file src/os/user/cgo_lookup_unix.go
1
2
3
4
5
6
7
8 package user
9
10 import (
11 "fmt"
12 "strconv"
13 "strings"
14 "syscall"
15 "unsafe"
16 )
17
18
46 import "C"
47
48 func current() (*User, error) {
49 return lookupUnixUid(syscall.Getuid())
50 }
51
52 func lookupUser(username string) (*User, error) {
53 var pwd C.struct_passwd
54 var result *C.struct_passwd
55 nameC := make([]byte, len(username)+1)
56 copy(nameC, username)
57
58 buf := alloc(userBuffer)
59 defer buf.free()
60
61 err := retryWithBuffer(buf, func() syscall.Errno {
62
63
64
65
66 return syscall.Errno(C.mygetpwnam_r((*C.char)(unsafe.Pointer(&nameC[0])),
67 &pwd,
68 (*C.char)(buf.ptr),
69 C.size_t(buf.size),
70 &result))
71 })
72 if err != nil {
73 return nil, fmt.Errorf("user: lookup username %s: %v", username, err)
74 }
75 if result == nil {
76 return nil, UnknownUserError(username)
77 }
78 return buildUser(&pwd), err
79 }
80
81 func lookupUserId(uid string) (*User, error) {
82 i, e := strconv.Atoi(uid)
83 if e != nil {
84 return nil, e
85 }
86 return lookupUnixUid(i)
87 }
88
89 func lookupUnixUid(uid int) (*User, error) {
90 var pwd C.struct_passwd
91 var result *C.struct_passwd
92
93 buf := alloc(userBuffer)
94 defer buf.free()
95
96 err := retryWithBuffer(buf, func() syscall.Errno {
97
98
99 return syscall.Errno(C.mygetpwuid_r(C.int(uid),
100 &pwd,
101 (*C.char)(buf.ptr),
102 C.size_t(buf.size),
103 &result))
104 })
105 if err != nil {
106 return nil, fmt.Errorf("user: lookup userid %d: %v", uid, err)
107 }
108 if result == nil {
109 return nil, UnknownUserIdError(uid)
110 }
111 return buildUser(&pwd), nil
112 }
113
114 func buildUser(pwd *C.struct_passwd) *User {
115 u := &User{
116 Uid: strconv.FormatUint(uint64(pwd.pw_uid), 10),
117 Gid: strconv.FormatUint(uint64(pwd.pw_gid), 10),
118 Username: C.GoString(pwd.pw_name),
119 Name: C.GoString(pwd.pw_gecos),
120 HomeDir: C.GoString(pwd.pw_dir),
121 }
122
123
124
125
126 if i := strings.Index(u.Name, ","); i >= 0 {
127 u.Name = u.Name[:i]
128 }
129 return u
130 }
131
132 func currentGroup() (*Group, error) {
133 return lookupUnixGid(syscall.Getgid())
134 }
135
136 func lookupGroup(groupname string) (*Group, error) {
137 var grp C.struct_group
138 var result *C.struct_group
139
140 buf := alloc(groupBuffer)
141 defer buf.free()
142 cname := make([]byte, len(groupname)+1)
143 copy(cname, groupname)
144
145 err := retryWithBuffer(buf, func() syscall.Errno {
146 return syscall.Errno(C.mygetgrnam_r((*C.char)(unsafe.Pointer(&cname[0])),
147 &grp,
148 (*C.char)(buf.ptr),
149 C.size_t(buf.size),
150 &result))
151 })
152 if err != nil {
153 return nil, fmt.Errorf("user: lookup groupname %s: %v", groupname, err)
154 }
155 if result == nil {
156 return nil, UnknownGroupError(groupname)
157 }
158 return buildGroup(&grp), nil
159 }
160
161 func lookupGroupId(gid string) (*Group, error) {
162 i, e := strconv.Atoi(gid)
163 if e != nil {
164 return nil, e
165 }
166 return lookupUnixGid(i)
167 }
168
169 func lookupUnixGid(gid int) (*Group, error) {
170 var grp C.struct_group
171 var result *C.struct_group
172
173 buf := alloc(groupBuffer)
174 defer buf.free()
175
176 err := retryWithBuffer(buf, func() syscall.Errno {
177
178
179 return syscall.Errno(C.mygetgrgid_r(C.int(gid),
180 &grp,
181 (*C.char)(buf.ptr),
182 C.size_t(buf.size),
183 &result))
184 })
185 if err != nil {
186 return nil, fmt.Errorf("user: lookup groupid %d: %v", gid, err)
187 }
188 if result == nil {
189 return nil, UnknownGroupIdError(strconv.Itoa(gid))
190 }
191 return buildGroup(&grp), nil
192 }
193
194 func buildGroup(grp *C.struct_group) *Group {
195 g := &Group{
196 Gid: strconv.Itoa(int(grp.gr_gid)),
197 Name: C.GoString(grp.gr_name),
198 }
199 return g
200 }
201
202 type bufferKind C.int
203
204 const (
205 userBuffer = bufferKind(C._SC_GETPW_R_SIZE_MAX)
206 groupBuffer = bufferKind(C._SC_GETGR_R_SIZE_MAX)
207 )
208
209 func (k bufferKind) initialSize() C.size_t {
210 sz := C.sysconf(C.int(k))
211 if sz == -1 {
212
213
214
215 return 1024
216 }
217 if !isSizeReasonable(int64(sz)) {
218
219 return maxBufferSize
220 }
221 return C.size_t(sz)
222 }
223
224 type memBuffer struct {
225 ptr unsafe.Pointer
226 size C.size_t
227 }
228
229 func alloc(kind bufferKind) *memBuffer {
230 sz := kind.initialSize()
231 return &memBuffer{
232 ptr: C.malloc(sz),
233 size: sz,
234 }
235 }
236
237 func (mb *memBuffer) resize(newSize C.size_t) {
238 mb.ptr = C.realloc(mb.ptr, newSize)
239 mb.size = newSize
240 }
241
242 func (mb *memBuffer) free() {
243 C.free(mb.ptr)
244 }
245
246
247
248
249 func retryWithBuffer(buf *memBuffer, f func() syscall.Errno) error {
250 for {
251 errno := f()
252 if errno == 0 {
253 return nil
254 } else if errno != syscall.ERANGE {
255 return errno
256 }
257 newSize := buf.size * 2
258 if !isSizeReasonable(int64(newSize)) {
259 return fmt.Errorf("internal buffer exceeds %d bytes", maxBufferSize)
260 }
261 buf.resize(newSize)
262 }
263 }
264
265 const maxBufferSize = 1 << 20
266
267 func isSizeReasonable(sz int64) bool {
268 return sz > 0 && sz <= maxBufferSize
269 }
270
271
272 func structPasswdForNegativeTest() C.struct_passwd {
273 sp := C.struct_passwd{}
274 sp.pw_uid = 1<<32 - 2
275 sp.pw_gid = 1<<32 - 3
276 return sp
277 }
278
View as plain text