Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(812)

Delta Between Two Patch Sets: src/pkg/os/user/lookup_unix.go

Issue 13454043: os/user: group lookup functions
Left Patch Set: Created 10 years, 7 months ago
Right Patch Set: diff -r 2aef8fd83bbd https://code.google.com/p/go Created 10 years, 7 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Right: Side by side diff | Download
LEFTRIGHT
(no file at all)
1 // Copyright 2011 The Go Authors. All rights reserved. 1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 // +build darwin freebsd linux netbsd openbsd 5 // +build darwin freebsd linux netbsd openbsd
6 // +build cgo 6 // +build cgo
7 7
8 package user 8 package user
9 9
10 import ( 10 import (
11 "fmt" 11 "fmt"
12 "runtime" 12 "runtime"
13 "strconv" 13 "strconv"
14 "strings" 14 "strings"
15 "syscall" 15 "syscall"
16 "unsafe" 16 "unsafe"
17 ) 17 )
18 18
19 /* 19 /*
20 #include <unistd.h> 20 #include <unistd.h>
21 #include <sys/types.h> 21 #include <sys/types.h>
22 #include <pwd.h> 22 #include <pwd.h>
23 #include <grp.h>
23 #include <stdlib.h> 24 #include <stdlib.h>
24 25
25 static int mygetpwuid_r(int uid, struct passwd *pwd, 26 static int mygetpwuid_r(int uid, struct passwd *pwd,
26 char *buf, size_t buflen, struct passwd **result) { 27 char *buf, size_t buflen, struct passwd **result) {
27 return getpwuid_r(uid, pwd, buf, buflen, result); 28 return getpwuid_r(uid, pwd, buf, buflen, result);
28 } 29 }
30
31 static int mygetgrgid_r(int gid, struct group *grp,
32 char *buf, size_t buflen, struct group **result) {
33 return getgrgid_r(gid, grp, buf, buflen, result);
34 }
35
36 static int mygetgrouplist(const char *user, gid_t group, gid_t *groups,
37 int *ngroups) {
38 return getgrouplist(user, group, (gid_t *)groups, ngroups);
39 }
40
41 static inline gid_t group_at(int i, gid_t *groups) {
42 return groups[i];
43 }
44 static inline char **next_member(char **members) { return members + 1; }
29 */ 45 */
30 import "C" 46 import "C"
31 47
48 const (
49 userBuffer = iota
50 groupBuffer
51 )
52
32 func current() (*User, error) { 53 func current() (*User, error) {
33 » return lookupUnix(syscall.Getuid(), "", false) 54 » return lookupUnixUser(syscall.Getuid(), "", false)
34 } 55 }
35 56
36 func lookup(username string) (*User, error) { 57 func lookupUser(username string) (*User, error) {
37 » return lookupUnix(-1, username, true) 58 » return lookupUnixUser(-1, username, true)
38 } 59 }
39 60
40 func lookupId(uid string) (*User, error) { 61 func lookupUserId(uid string) (*User, error) {
41 i, e := strconv.Atoi(uid) 62 i, e := strconv.Atoi(uid)
42 if e != nil { 63 if e != nil {
43 return nil, e 64 return nil, e
44 } 65 }
45 » return lookupUnix(i, "", false) 66 » return lookupUnixUser(i, "", false)
46 } 67 }
47 68
48 func lookupUnix(uid int, username string, lookupByName bool) (*User, error) { 69 func lookupUnixUser(uid int, username string, lookupByName bool) (*User, error) {
49 var pwd C.struct_passwd 70 var pwd C.struct_passwd
50 var result *C.struct_passwd 71 var result *C.struct_passwd
51 72
52 » var bufSize C.long 73 » buf, bufSize, err := allocBuffer(userBuffer)
53 » if runtime.GOOS == "freebsd" { 74 » if err != nil {
54 » » // FreeBSD doesn't have _SC_GETPW_R_SIZE_MAX 75 » » return nil, err
55 » » // and just returns -1. So just use the same 76 » }
56 » » // size that Linux returns
57 » » bufSize = 1024
58 » } else {
59 » » bufSize = C.sysconf(C._SC_GETPW_R_SIZE_MAX)
60 » » if bufSize <= 0 || bufSize > 1<<20 {
61 » » » return nil, fmt.Errorf("user: unreasonable _SC_GETPW_R_S IZE_MAX of %d", bufSize)
62 » » }
63 » }
64 » buf := C.malloc(C.size_t(bufSize))
65 defer C.free(buf) 77 defer C.free(buf)
78
66 var rv C.int 79 var rv C.int
67 if lookupByName { 80 if lookupByName {
68 nameC := C.CString(username) 81 nameC := C.CString(username)
69 defer C.free(unsafe.Pointer(nameC)) 82 defer C.free(unsafe.Pointer(nameC))
70 rv = C.getpwnam_r(nameC, 83 rv = C.getpwnam_r(nameC,
71 &pwd, 84 &pwd,
72 (*C.char)(buf), 85 (*C.char)(buf),
73 C.size_t(bufSize), 86 C.size_t(bufSize),
74 &result) 87 &result)
75 if rv != 0 { 88 if rv != 0 {
(...skipping 27 matching lines...) Expand all
103 } 116 }
104 // The pw_gecos field isn't quite standardized. Some docs 117 // The pw_gecos field isn't quite standardized. Some docs
105 // say: "It is expected to be a comma separated list of 118 // say: "It is expected to be a comma separated list of
106 // personal data where the first item is the full name of the 119 // personal data where the first item is the full name of the
107 // user." 120 // user."
108 if i := strings.Index(u.Name, ","); i >= 0 { 121 if i := strings.Index(u.Name, ","); i >= 0 {
109 u.Name = u.Name[:i] 122 u.Name = u.Name[:i]
110 } 123 }
111 return u, nil 124 return u, nil
112 } 125 }
126
127 func currentGroup() (*Group, error) {
128 return lookupUnixGroup(syscall.Getgid(), "", false, buildGroup)
129 }
130
131 func lookupGroup(groupname string) (*Group, error) {
132 return lookupUnixGroup(-1, groupname, true, buildGroup)
133 }
134
135 func lookupGroupId(gid string) (*Group, error) {
136 i, e := strconv.Atoi(gid)
137 if e != nil {
138 return nil, e
139 }
140 return lookupUnixGroup(i, "", false, buildGroup)
141 }
142
143 func lookupUnixGroup(gid int, groupname string, lookupByName bool, f func(*C.str uct_group) *Group) (*Group, error) {
144 var grp C.struct_group
145 var result *C.struct_group
146
147 buf, bufSize, err := allocBuffer(groupBuffer)
148 if err != nil {
149 return nil, err
150 }
151 defer C.free(buf)
152
153 if lookupByName {
154 nameC := C.CString(groupname)
155 defer C.free(unsafe.Pointer(nameC))
156 rv := C.getgrnam_r(nameC,
157 &grp,
158 (*C.char)(buf),
159 C.size_t(bufSize),
160 &result)
161 if rv != 0 {
162 return nil, fmt.Errorf("group: lookup groupname %s: %s", groupname, syscall.Errno(rv))
163 }
164 if result == nil {
165 return nil, UnknownGroupError(groupname)
166 }
167 } else {
168 // mygetgrgid_r is a wrapper around getgrgid_r to
169 // to avoid using gid_t because C.gid_t(gid) for
170 // unknown reasons doesn't work on linux.
171 rv := C.mygetgrgid_r(C.int(gid),
172 &grp,
173 (*C.char)(buf),
174 C.size_t(bufSize),
175 &result)
176 if rv != 0 {
177 return nil, fmt.Errorf("group: lookup groupid %d: %s", g id, syscall.Errno(rv))
178 }
179 if result == nil {
180 return nil, UnknownGroupIdError(gid)
181 }
182 }
183 g := f(&grp)
184 return g, nil
185 }
186
187 func buildGroup(grp *C.struct_group) *Group {
188 g := &Group{
189 Gid: strconv.Itoa(int(grp.gr_gid)),
190 Name: C.GoString(grp.gr_name),
191 }
192 return g
193 }
194
195 func userInGroup(u *User, g *Group) (bool, error) {
196 if u.Gid == g.Gid {
197 return true, nil
198 }
199 gid, err := strconv.Atoi(g.Gid)
200 if err != nil {
201 return false, err
202 }
203
204 nameC := C.CString(u.Username)
205 defer C.free(unsafe.Pointer(nameC))
206 groupC := C.gid_t(gid)
207 ngroupsC := C.int(0)
208
209 C.mygetgrouplist(nameC, groupC, nil, &ngroupsC)
210 ngroups := int(ngroupsC)
211
212 groups := C.malloc(C.size_t(int(unsafe.Sizeof(groupC)) * ngroups))
213 defer C.free(groups)
214
215 rv := C.mygetgrouplist(nameC, groupC, (*C.gid_t)(groups), &ngroupsC)
216 if rv == -1 {
217 return false, fmt.Errorf("user: membership of %s in %s: %s", u.U sername, g.Name, syscall.Errno(rv))
218 }
219
220 ngroups = int(ngroupsC)
221 for i := 0; i < ngroups; i++ {
222 gid := C.group_at(C.int(i), (*C.gid_t)(groups))
223 if g.Gid == strconv.Itoa(int(gid)) {
224 return true, nil
225 }
226 }
227 return false, nil
228 }
229
230 func groupMembers(g *Group) ([]string, error) {
231 var members []string
232 gid, err := strconv.Atoi(g.Gid)
233 if err != nil {
234 return nil, err
235 }
236
237 _, err = lookupUnixGroup(gid, "", false, func(grp *C.struct_group) *Grou p {
238 cmem := grp.gr_mem
239 for *cmem != nil {
240 members = append(members, C.GoString(*cmem))
241 cmem = C.next_member(cmem)
242 }
243 return g
244 })
245 if err != nil {
246 return nil, err
247 }
248
249 return members, nil
250 }
251
252 func allocBuffer(bufType int) (unsafe.Pointer, C.long, error) {
253 var bufSize C.long
254 if runtime.GOOS == "freebsd" {
255 // FreeBSD doesn't have _SC_GETPW_R_SIZE_MAX
256 // or SC_GETGR_R_SIZE_MAX and just returns -1.
257 // So just use the same size that Linux returns
258 bufSize = 1024
259 } else {
260 var size C.int
261 var constName string
262 switch bufType {
263 case userBuffer:
264 size = C._SC_GETPW_R_SIZE_MAX
265 constName = "_SC_GETPW_R_SIZE_MAX"
266 case groupBuffer:
267 size = C._SC_GETGR_R_SIZE_MAX
268 constName = "_SC_GETGR_R_SIZE_MAX"
269 }
270 bufSize = C.sysconf(size)
271 if bufSize <= 0 || bufSize > 1<<20 {
272 return nil, bufSize, fmt.Errorf("user: unreasonable %s o f %d", constName, bufSize)
273 }
274 }
275 return C.malloc(C.size_t(bufSize)), bufSize, nil
276 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b