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