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

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

Issue 4589049: code review 4589049: os/user: group lookup functions
Left Patch Set: Created 12 years, 9 months ago
Right Patch Set: diff -r 17e26defe7bc https://go.googlecode.com/hg/ Created 12 years, 9 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 package user 5 package user
6 6
7 import ( 7 import (
8 "fmt" 8 "fmt"
9 "os" 9 "os"
10 "runtime" 10 "runtime"
11 "strings" 11 "strings"
12 "unsafe" 12 "unsafe"
13 ) 13 )
14 14
15 /* 15 /*
16 #include <unistd.h> 16 #include <unistd.h>
17 #include <sys/types.h> 17 #include <sys/types.h>
18 #include <pwd.h> 18 #include <pwd.h>
19 #include <grp.h>
19 #include <stdlib.h> 20 #include <stdlib.h>
20 21
21 static int mygetpwuid_r(int uid, struct passwd *pwd, 22 static int mygetpwuid_r(int uid, struct passwd *pwd,
22 char *buf, size_t buflen, struct passwd **result) { 23 char *buf, size_t buflen, struct passwd **result) {
23 return getpwuid_r(uid, pwd, buf, buflen, result); 24 return getpwuid_r(uid, pwd, buf, buflen, result);
24 } 25 }
26
27 static int mygetgrgid_r(int gid, struct group *grp,
28 char *buf, size_t buflen, struct group **result) {
29 return getgrgid_r(gid, grp, buf, buflen, result);
30 }
31
32 static int mygetgrouplist(const char *user, gid_t group, gid_t *groups,
33 int *ngroups) {
34 return getgrouplist(user, group, (gid_t *)groups, ngroups);
35 }
36
37 static inline gid_t group_at(int i, gid_t *groups) {
38 return groups[i];
39 }
40 static inline char **next_member(char **members) { return members + 1; }
25 */ 41 */
26 import "C" 42 import "C"
27 43
28 // Lookup looks up a user by username. If the user cannot be found, 44 // Lookup looks up a user by username. If the user cannot be found,
29 // the returned error is of type UnknownUserError. 45 // the returned error is of type UnknownUserError.
30 func Lookup(username string) (*User, os.Error) { 46 func Lookup(username string) (*User, os.Error) {
31 » return lookup(-1, username, true) 47 » u, err := lookupUser(username, buildUser)
48 » if err != nil {
49 » » return nil, err
50 » }
51 » return u, nil
32 } 52 }
33 53
34 // LookupId looks up a user by userid. If the user cannot be found, 54 // LookupId looks up a user by userid. If the user cannot be found,
35 // the returned error is of type UnknownUserIdError. 55 // the returned error is of type UnknownUserIdError.
36 func LookupId(uid int) (*User, os.Error) { 56 func LookupId(uid int) (*User, os.Error) {
37 » return lookup(uid, "", false) 57 » u, err := lookupUserId(uid, buildUser)
38 } 58 » if err != nil {
39 59 » » return nil, err
40 func lookup(uid int, username string, lookupByName bool) (*User, os.Error) { 60 » }
61 » return u, nil
62 }
63
64 // In indicates whether the user is a member of the given group.
65 func (u *User) In(g *Group) (bool, os.Error) {
66 » if u.Gid == g.Gid {
67 » » return true, nil
68 » }
69
70 » nameC := C.CString(u.Username)
71 » defer C.free(unsafe.Pointer(nameC))
72 » groupC := C.gid_t(u.Gid)
73 » ngroupsC := C.int(0)
74
75 » C.mygetgrouplist(nameC, groupC, nil, &ngroupsC)
76 » ngroups := int(ngroupsC)
77
78 » groups := C.malloc(C.size_t(int(unsafe.Sizeof(groupC)) * ngroups))
79 » defer C.free(groups)
80
81 » rv := C.mygetgrouplist(nameC, groupC, (*C.gid_t)(groups), &ngroupsC)
82 » if rv == -1 {
83 » » return false, fmt.Errorf("user: membership of %s in %s: %s", u.U sername, g.Name, os.Errno(rv))
84 » }
85
86 » ngroups = int(ngroupsC)
87 » for i := 0; i < ngroups; i++ {
88 » » gid := C.group_at(C.int(i), (*C.gid_t)(groups))
89 » » if g.Gid == int(gid) {
90 » » » return true, nil
91 » » }
92 » }
93 » return false, nil
94 }
95
96 // LookupGroup looks up a group by groupname. If the group cannot
97 // be found, the returned error is of type UnknownGroupError.
98 func LookupGroup(groupname string) (*Group, os.Error) {
99 » g, err := lookupGroup(groupname, buildGroup)
100 » if err != nil {
101 » » return nil, err
102 » }
103 » return g, nil
104 }
105
106 // LookupGroupId looks up a group by groupid. If the group cannot
107 // be found, the returned error is of type UnknownGroupIdError.
108 func LookupGroupId(gid int) (*Group, os.Error) {
brainman 2013/03/01 00:54:33 s/int/string/
109 » g, err := lookupGroupId(gid, buildGroup)
110 » if err != nil {
111 » » return nil, err
112 » }
113 » return g, nil
114 }
115
116 // Members returns the list of members of the group.
117 func (g *Group) Members() ([]string, os.Error) {
118 » var members []string
119
120 » _, err := lookupGroupId(g.Gid, func(grp *C.struct_group) *Group {
121 » » cmem := grp.gr_mem
122 » » for *cmem != nil {
123 » » » members = append(members, C.GoString(*cmem))
124 » » » cmem = C.next_member(cmem)
125 » » }
126 » » return g
127 » })
128 » if err != nil {
129 » » return nil, err
130 » }
131
132 » return members, nil
133 }
134
135 const (
136 » userBuffer = iota
137 » groupBuffer
138 )
139
140 func lookupUser(username string, f func(*C.struct_passwd) *User) (*User, os.Erro r) {
41 var pwd C.struct_passwd 141 var pwd C.struct_passwd
42 var result *C.struct_passwd 142 var result *C.struct_passwd
43 143
44 » var bufSize C.long 144 » buf, bufSize, err := allocBuffer(userBuffer)
45 » if runtime.GOOS == "freebsd" { 145 » if err != nil {
46 » » // FreeBSD doesn't have _SC_GETPW_R_SIZE_MAX 146 » » return nil, err
47 » » // and just returns -1. So just use the same 147 » }
48 » » // size that Linux returns
49 » » bufSize = 1024
50 » } else {
51 » » bufSize = C.sysconf(C._SC_GETPW_R_SIZE_MAX)
52 » » if bufSize <= 0 || bufSize > 1<<20 {
53 » » » return nil, fmt.Errorf("user: unreasonable _SC_GETPW_R_S IZE_MAX of %d", bufSize)
54 » » }
55 » }
56 » buf := C.malloc(C.size_t(bufSize))
57 defer C.free(buf) 148 defer C.free(buf)
58 » var rv C.int 149
59 » if lookupByName { 150 » nameC := C.CString(username)
60 » » nameC := C.CString(username) 151 » defer C.free(unsafe.Pointer(nameC))
61 » » defer C.free(unsafe.Pointer(nameC)) 152 » rv := C.getpwnam_r(nameC,
62 » » rv = C.getpwnam_r(nameC, 153 » » &pwd,
63 » » » &pwd, 154 » » (*C.char)(buf),
64 » » » (*C.char)(buf), 155 » » C.size_t(bufSize),
65 » » » C.size_t(bufSize), 156 » » &result)
66 » » » &result) 157 » if rv != 0 {
67 » » if rv != 0 { 158 » » return nil, fmt.Errorf("user: lookup username %s: %s", username, os.Errno(rv))
68 » » » return nil, fmt.Errorf("user: lookup username %s: %s", u sername, os.Errno(rv)) 159 » }
69 » » } 160 » if result == nil {
70 » » if result == nil { 161 » » return nil, UnknownUserError(username)
71 » » » return nil, UnknownUserError(username) 162 » }
72 » » } 163 » u := f(&pwd)
73 » } else { 164 » return u, nil
74 » » // mygetpwuid_r is a wrapper around getpwuid_r to 165 }
75 » » // to avoid using uid_t because C.uid_t(uid) for 166
76 » » // unknown reasons doesn't work on linux. 167 func lookupUserId(uid int, f func(*C.struct_passwd) *User) (*User, os.Error) {
77 » » rv = C.mygetpwuid_r(C.int(uid), 168 » var pwd C.struct_passwd
78 » » » &pwd, 169 » var result *C.struct_passwd
79 » » » (*C.char)(buf), 170
80 » » » C.size_t(bufSize), 171 » buf, bufSize, err := allocBuffer(userBuffer)
81 » » » &result) 172 » if err != nil {
82 » » if rv != 0 { 173 » » return nil, err
83 » » » return nil, fmt.Errorf("user: lookup userid %d: %s", uid , os.Errno(rv)) 174 » }
84 » » } 175 » defer C.free(buf)
85 » » if result == nil { 176
86 » » » return nil, UnknownUserIdError(uid) 177 » // mygetpwuid_r is a wrapper around getpwuid_r to
87 » » } 178 » // to avoid using uid_t because C.uid_t(uid) for
88 » } 179 » // unknown reasons doesn't work on linux.
180 » rv := C.mygetpwuid_r(C.int(uid),
181 » » &pwd,
182 » » (*C.char)(buf),
183 » » C.size_t(bufSize),
184 » » &result)
185 » if rv != 0 {
186 » » return nil, fmt.Errorf("user: lookup userid %d: %s", uid, os.Err no(rv))
187 » }
188 » if result == nil {
189 » » return nil, UnknownUserIdError(uid)
190 » }
191 » u := f(&pwd)
192 » return u, nil
193 }
194
195 func buildUser(pwd *C.struct_passwd) *User {
89 u := &User{ 196 u := &User{
90 Uid: int(pwd.pw_uid), 197 Uid: int(pwd.pw_uid),
91 Gid: int(pwd.pw_gid), 198 Gid: int(pwd.pw_gid),
92 Username: C.GoString(pwd.pw_name), 199 Username: C.GoString(pwd.pw_name),
93 Name: C.GoString(pwd.pw_gecos), 200 Name: C.GoString(pwd.pw_gecos),
94 HomeDir: C.GoString(pwd.pw_dir), 201 HomeDir: C.GoString(pwd.pw_dir),
95 } 202 }
96 // The pw_gecos field isn't quite standardized. Some docs 203 // The pw_gecos field isn't quite standardized. Some docs
97 // say: "It is expected to be a comma separated list of 204 // say: "It is expected to be a comma separated list of
98 // personal data where the first item is the full name of the 205 // personal data where the first item is the full name of the
99 // user." 206 // user."
100 if i := strings.Index(u.Name, ","); i >= 0 { 207 if i := strings.Index(u.Name, ","); i >= 0 {
101 u.Name = u.Name[:i] 208 u.Name = u.Name[:i]
102 } 209 }
103 » return u, nil 210 » return u
104 } 211 }
212
213 func lookupGroup(groupname string, f func(*C.struct_group) *Group) (*Group, os.E rror) {
214 » var grp C.struct_group
215 » var result *C.struct_group
216
217 » buf, bufSize, err := allocBuffer(groupBuffer)
218 » if err != nil {
219 » » return nil, err
220 » }
221 » defer C.free(buf)
222
223 » nameC := C.CString(groupname)
224 » defer C.free(unsafe.Pointer(nameC))
225 » rv := C.getgrnam_r(nameC,
226 » » &grp,
227 » » (*C.char)(buf),
228 » » C.size_t(bufSize),
229 » » &result)
230 » if rv != 0 {
231 » » return nil, fmt.Errorf("group: lookup groupname %s: %s", groupna me, os.Errno(rv))
232 » }
233 » if result == nil {
234 » » return nil, UnknownGroupError(groupname)
235 » }
236 » g := f(&grp)
237 » return g, nil
238 }
239
240 func lookupGroupId(gid int, f func(*C.struct_group) *Group) (*Group, os.Error) {
241 » var grp C.struct_group
242 » var result *C.struct_group
243
244 » buf, bufSize, err := allocBuffer(groupBuffer)
245 » if err != nil {
246 » » return nil, err
247 » }
248 » defer C.free(buf)
249
250 » // mygetgrgid_r is a wrapper around getgrgid_r to
251 » // to avoid using gid_t because C.gid_t(gid) for
252 » // unknown reasons doesn't work on linux.
253 » rv := C.mygetgrgid_r(C.int(gid),
254 » » &grp,
255 » » (*C.char)(buf),
256 » » C.size_t(bufSize),
257 » » &result)
258 » if rv != 0 {
259 » » return nil, fmt.Errorf("group: lookup groupid %d: %s", gid, os.E rrno(rv))
260 » }
261 » if result == nil {
262 » » return nil, UnknownGroupIdError(gid)
263 » }
264 » g := f(&grp)
265 » return g, nil
266 }
267
268 func buildGroup(grp *C.struct_group) *Group {
269 » g := &Group{
270 » » Gid: int(grp.gr_gid),
271 » » Name: C.GoString(grp.gr_name),
272 » }
273 » return g
274 }
275
276 func allocBuffer(bufType int) (unsafe.Pointer, C.long, os.Error) {
277 » var bufSize C.long
278 » if runtime.GOOS == "freebsd" {
279 » » // FreeBSD doesn't have _SC_GETPW_R_SIZE_MAX
280 » » // or SC_GETGR_R_SIZE_MAX and just returns -1.
281 » » // So just use the same size that Linux returns
282 » » bufSize = 1024
283 » } else {
284 » » var size C.int
285 » » var constName string
286 » » switch bufType {
287 » » case userBuffer:
288 » » » size = C._SC_GETPW_R_SIZE_MAX
289 » » » constName = "_SC_GETPW_R_SIZE_MAX"
290 » » case groupBuffer:
291 » » » size = C._SC_GETGR_R_SIZE_MAX
292 » » » constName = "_SC_GETGR_R_SIZE_MAX"
293 » » }
294 » » bufSize = C.sysconf(size)
295 » » if bufSize <= 0 || bufSize > 1<<20 {
296 » » » return nil, bufSize, fmt.Errorf("user: unreasonable %s o f %d", constName, bufSize)
297 » » }
298 » }
299 » return C.malloc(C.size_t(bufSize)), bufSize, nil
300 }
LEFTRIGHT

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