diff options
Diffstat (limited to 'vendor/github.com/fsouza/go-dockerclient/external/github.com/opencontainers/runc/libcontainer/user/user.go')
-rw-r--r-- | vendor/github.com/fsouza/go-dockerclient/external/github.com/opencontainers/runc/libcontainer/user/user.go | 418 |
1 files changed, 0 insertions, 418 deletions
diff --git a/vendor/github.com/fsouza/go-dockerclient/external/github.com/opencontainers/runc/libcontainer/user/user.go b/vendor/github.com/fsouza/go-dockerclient/external/github.com/opencontainers/runc/libcontainer/user/user.go deleted file mode 100644 index e6375ea..0000000 --- a/vendor/github.com/fsouza/go-dockerclient/external/github.com/opencontainers/runc/libcontainer/user/user.go +++ /dev/null | |||
@@ -1,418 +0,0 @@ | |||
1 | package user | ||
2 | |||
3 | import ( | ||
4 | "bufio" | ||
5 | "fmt" | ||
6 | "io" | ||
7 | "os" | ||
8 | "strconv" | ||
9 | "strings" | ||
10 | ) | ||
11 | |||
12 | const ( | ||
13 | minId = 0 | ||
14 | maxId = 1<<31 - 1 //for 32-bit systems compatibility | ||
15 | ) | ||
16 | |||
17 | var ( | ||
18 | ErrRange = fmt.Errorf("Uids and gids must be in range %d-%d", minId, maxId) | ||
19 | ) | ||
20 | |||
21 | type User struct { | ||
22 | Name string | ||
23 | Pass string | ||
24 | Uid int | ||
25 | Gid int | ||
26 | Gecos string | ||
27 | Home string | ||
28 | Shell string | ||
29 | } | ||
30 | |||
31 | type Group struct { | ||
32 | Name string | ||
33 | Pass string | ||
34 | Gid int | ||
35 | List []string | ||
36 | } | ||
37 | |||
38 | func parseLine(line string, v ...interface{}) { | ||
39 | if line == "" { | ||
40 | return | ||
41 | } | ||
42 | |||
43 | parts := strings.Split(line, ":") | ||
44 | for i, p := range parts { | ||
45 | if len(v) <= i { | ||
46 | // if we have more "parts" than we have places to put them, bail for great "tolerance" of naughty configuration files | ||
47 | break | ||
48 | } | ||
49 | |||
50 | switch e := v[i].(type) { | ||
51 | case *string: | ||
52 | // "root", "adm", "/bin/bash" | ||
53 | *e = p | ||
54 | case *int: | ||
55 | // "0", "4", "1000" | ||
56 | // ignore string to int conversion errors, for great "tolerance" of naughty configuration files | ||
57 | *e, _ = strconv.Atoi(p) | ||
58 | case *[]string: | ||
59 | // "", "root", "root,adm,daemon" | ||
60 | if p != "" { | ||
61 | *e = strings.Split(p, ",") | ||
62 | } else { | ||
63 | *e = []string{} | ||
64 | } | ||
65 | default: | ||
66 | // panic, because this is a programming/logic error, not a runtime one | ||
67 | panic("parseLine expects only pointers! argument " + strconv.Itoa(i) + " is not a pointer!") | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | |||
72 | func ParsePasswdFile(path string) ([]User, error) { | ||
73 | passwd, err := os.Open(path) | ||
74 | if err != nil { | ||
75 | return nil, err | ||
76 | } | ||
77 | defer passwd.Close() | ||
78 | return ParsePasswd(passwd) | ||
79 | } | ||
80 | |||
81 | func ParsePasswd(passwd io.Reader) ([]User, error) { | ||
82 | return ParsePasswdFilter(passwd, nil) | ||
83 | } | ||
84 | |||
85 | func ParsePasswdFileFilter(path string, filter func(User) bool) ([]User, error) { | ||
86 | passwd, err := os.Open(path) | ||
87 | if err != nil { | ||
88 | return nil, err | ||
89 | } | ||
90 | defer passwd.Close() | ||
91 | return ParsePasswdFilter(passwd, filter) | ||
92 | } | ||
93 | |||
94 | func ParsePasswdFilter(r io.Reader, filter func(User) bool) ([]User, error) { | ||
95 | if r == nil { | ||
96 | return nil, fmt.Errorf("nil source for passwd-formatted data") | ||
97 | } | ||
98 | |||
99 | var ( | ||
100 | s = bufio.NewScanner(r) | ||
101 | out = []User{} | ||
102 | ) | ||
103 | |||
104 | for s.Scan() { | ||
105 | if err := s.Err(); err != nil { | ||
106 | return nil, err | ||
107 | } | ||
108 | |||
109 | text := strings.TrimSpace(s.Text()) | ||
110 | if text == "" { | ||
111 | continue | ||
112 | } | ||
113 | |||
114 | // see: man 5 passwd | ||
115 | // name:password:UID:GID:GECOS:directory:shell | ||
116 | // Name:Pass:Uid:Gid:Gecos:Home:Shell | ||
117 | // root:x:0:0:root:/root:/bin/bash | ||
118 | // adm:x:3:4:adm:/var/adm:/bin/false | ||
119 | p := User{} | ||
120 | parseLine( | ||
121 | text, | ||
122 | &p.Name, &p.Pass, &p.Uid, &p.Gid, &p.Gecos, &p.Home, &p.Shell, | ||
123 | ) | ||
124 | |||
125 | if filter == nil || filter(p) { | ||
126 | out = append(out, p) | ||
127 | } | ||
128 | } | ||
129 | |||
130 | return out, nil | ||
131 | } | ||
132 | |||
133 | func ParseGroupFile(path string) ([]Group, error) { | ||
134 | group, err := os.Open(path) | ||
135 | if err != nil { | ||
136 | return nil, err | ||
137 | } | ||
138 | defer group.Close() | ||
139 | return ParseGroup(group) | ||
140 | } | ||
141 | |||
142 | func ParseGroup(group io.Reader) ([]Group, error) { | ||
143 | return ParseGroupFilter(group, nil) | ||
144 | } | ||
145 | |||
146 | func ParseGroupFileFilter(path string, filter func(Group) bool) ([]Group, error) { | ||
147 | group, err := os.Open(path) | ||
148 | if err != nil { | ||
149 | return nil, err | ||
150 | } | ||
151 | defer group.Close() | ||
152 | return ParseGroupFilter(group, filter) | ||
153 | } | ||
154 | |||
155 | func ParseGroupFilter(r io.Reader, filter func(Group) bool) ([]Group, error) { | ||
156 | if r == nil { | ||
157 | return nil, fmt.Errorf("nil source for group-formatted data") | ||
158 | } | ||
159 | |||
160 | var ( | ||
161 | s = bufio.NewScanner(r) | ||
162 | out = []Group{} | ||
163 | ) | ||
164 | |||
165 | for s.Scan() { | ||
166 | if err := s.Err(); err != nil { | ||
167 | return nil, err | ||
168 | } | ||
169 | |||
170 | text := s.Text() | ||
171 | if text == "" { | ||
172 | continue | ||
173 | } | ||
174 | |||
175 | // see: man 5 group | ||
176 | // group_name:password:GID:user_list | ||
177 | // Name:Pass:Gid:List | ||
178 | // root:x:0:root | ||
179 | // adm:x:4:root,adm,daemon | ||
180 | p := Group{} | ||
181 | parseLine( | ||
182 | text, | ||
183 | &p.Name, &p.Pass, &p.Gid, &p.List, | ||
184 | ) | ||
185 | |||
186 | if filter == nil || filter(p) { | ||
187 | out = append(out, p) | ||
188 | } | ||
189 | } | ||
190 | |||
191 | return out, nil | ||
192 | } | ||
193 | |||
194 | type ExecUser struct { | ||
195 | Uid, Gid int | ||
196 | Sgids []int | ||
197 | Home string | ||
198 | } | ||
199 | |||
200 | // GetExecUserPath is a wrapper for GetExecUser. It reads data from each of the | ||
201 | // given file paths and uses that data as the arguments to GetExecUser. If the | ||
202 | // files cannot be opened for any reason, the error is ignored and a nil | ||
203 | // io.Reader is passed instead. | ||
204 | func GetExecUserPath(userSpec string, defaults *ExecUser, passwdPath, groupPath string) (*ExecUser, error) { | ||
205 | passwd, err := os.Open(passwdPath) | ||
206 | if err != nil { | ||
207 | passwd = nil | ||
208 | } else { | ||
209 | defer passwd.Close() | ||
210 | } | ||
211 | |||
212 | group, err := os.Open(groupPath) | ||
213 | if err != nil { | ||
214 | group = nil | ||
215 | } else { | ||
216 | defer group.Close() | ||
217 | } | ||
218 | |||
219 | return GetExecUser(userSpec, defaults, passwd, group) | ||
220 | } | ||
221 | |||
222 | // GetExecUser parses a user specification string (using the passwd and group | ||
223 | // readers as sources for /etc/passwd and /etc/group data, respectively). In | ||
224 | // the case of blank fields or missing data from the sources, the values in | ||
225 | // defaults is used. | ||
226 | // | ||
227 | // GetExecUser will return an error if a user or group literal could not be | ||
228 | // found in any entry in passwd and group respectively. | ||
229 | // | ||
230 | // Examples of valid user specifications are: | ||
231 | // * "" | ||
232 | // * "user" | ||
233 | // * "uid" | ||
234 | // * "user:group" | ||
235 | // * "uid:gid | ||
236 | // * "user:gid" | ||
237 | // * "uid:group" | ||
238 | func GetExecUser(userSpec string, defaults *ExecUser, passwd, group io.Reader) (*ExecUser, error) { | ||
239 | var ( | ||
240 | userArg, groupArg string | ||
241 | name string | ||
242 | ) | ||
243 | |||
244 | if defaults == nil { | ||
245 | defaults = new(ExecUser) | ||
246 | } | ||
247 | |||
248 | // Copy over defaults. | ||
249 | user := &ExecUser{ | ||
250 | Uid: defaults.Uid, | ||
251 | Gid: defaults.Gid, | ||
252 | Sgids: defaults.Sgids, | ||
253 | Home: defaults.Home, | ||
254 | } | ||
255 | |||
256 | // Sgids slice *cannot* be nil. | ||
257 | if user.Sgids == nil { | ||
258 | user.Sgids = []int{} | ||
259 | } | ||
260 | |||
261 | // allow for userArg to have either "user" syntax, or optionally "user:group" syntax | ||
262 | parseLine(userSpec, &userArg, &groupArg) | ||
263 | |||
264 | users, err := ParsePasswdFilter(passwd, func(u User) bool { | ||
265 | if userArg == "" { | ||
266 | return u.Uid == user.Uid | ||
267 | } | ||
268 | return u.Name == userArg || strconv.Itoa(u.Uid) == userArg | ||
269 | }) | ||
270 | if err != nil && passwd != nil { | ||
271 | if userArg == "" { | ||
272 | userArg = strconv.Itoa(user.Uid) | ||
273 | } | ||
274 | return nil, fmt.Errorf("Unable to find user %v: %v", userArg, err) | ||
275 | } | ||
276 | |||
277 | haveUser := users != nil && len(users) > 0 | ||
278 | if haveUser { | ||
279 | // if we found any user entries that matched our filter, let's take the first one as "correct" | ||
280 | name = users[0].Name | ||
281 | user.Uid = users[0].Uid | ||
282 | user.Gid = users[0].Gid | ||
283 | user.Home = users[0].Home | ||
284 | } else if userArg != "" { | ||
285 | // we asked for a user but didn't find them... let's check to see if we wanted a numeric user | ||
286 | user.Uid, err = strconv.Atoi(userArg) | ||
287 | if err != nil { | ||
288 | // not numeric - we have to bail | ||
289 | return nil, fmt.Errorf("Unable to find user %v", userArg) | ||
290 | } | ||
291 | |||
292 | // Must be inside valid uid range. | ||
293 | if user.Uid < minId || user.Uid > maxId { | ||
294 | return nil, ErrRange | ||
295 | } | ||
296 | |||
297 | // if userArg couldn't be found in /etc/passwd but is numeric, just roll with it - this is legit | ||
298 | } | ||
299 | |||
300 | if groupArg != "" || name != "" { | ||
301 | groups, err := ParseGroupFilter(group, func(g Group) bool { | ||
302 | // Explicit group format takes precedence. | ||
303 | if groupArg != "" { | ||
304 | return g.Name == groupArg || strconv.Itoa(g.Gid) == groupArg | ||
305 | } | ||
306 | |||
307 | // Check if user is a member. | ||
308 | for _, u := range g.List { | ||
309 | if u == name { | ||
310 | return true | ||
311 | } | ||
312 | } | ||
313 | |||
314 | return false | ||
315 | }) | ||
316 | if err != nil && group != nil { | ||
317 | return nil, fmt.Errorf("Unable to find groups for user %v: %v", users[0].Name, err) | ||
318 | } | ||
319 | |||
320 | haveGroup := groups != nil && len(groups) > 0 | ||
321 | if groupArg != "" { | ||
322 | if haveGroup { | ||
323 | // if we found any group entries that matched our filter, let's take the first one as "correct" | ||
324 | user.Gid = groups[0].Gid | ||
325 | } else { | ||
326 | // we asked for a group but didn't find id... let's check to see if we wanted a numeric group | ||
327 | user.Gid, err = strconv.Atoi(groupArg) | ||
328 | if err != nil { | ||
329 | // not numeric - we have to bail | ||
330 | return nil, fmt.Errorf("Unable to find group %v", groupArg) | ||
331 | } | ||
332 | |||
333 | // Ensure gid is inside gid range. | ||
334 | if user.Gid < minId || user.Gid > maxId { | ||
335 | return nil, ErrRange | ||
336 | } | ||
337 | |||
338 | // if groupArg couldn't be found in /etc/group but is numeric, just roll with it - this is legit | ||
339 | } | ||
340 | } else if haveGroup { | ||
341 | // If implicit group format, fill supplementary gids. | ||
342 | user.Sgids = make([]int, len(groups)) | ||
343 | for i, group := range groups { | ||
344 | user.Sgids[i] = group.Gid | ||
345 | } | ||
346 | } | ||
347 | } | ||
348 | |||
349 | return user, nil | ||
350 | } | ||
351 | |||
352 | // GetAdditionalGroups looks up a list of groups by name or group id | ||
353 | // against the given /etc/group formatted data. If a group name cannot | ||
354 | // be found, an error will be returned. If a group id cannot be found, | ||
355 | // or the given group data is nil, the id will be returned as-is | ||
356 | // provided it is in the legal range. | ||
357 | func GetAdditionalGroups(additionalGroups []string, group io.Reader) ([]int, error) { | ||
358 | var groups = []Group{} | ||
359 | if group != nil { | ||
360 | var err error | ||
361 | groups, err = ParseGroupFilter(group, func(g Group) bool { | ||
362 | for _, ag := range additionalGroups { | ||
363 | if g.Name == ag || strconv.Itoa(g.Gid) == ag { | ||
364 | return true | ||
365 | } | ||
366 | } | ||
367 | return false | ||
368 | }) | ||
369 | if err != nil { | ||
370 | return nil, fmt.Errorf("Unable to find additional groups %v: %v", additionalGroups, err) | ||
371 | } | ||
372 | } | ||
373 | |||
374 | gidMap := make(map[int]struct{}) | ||
375 | for _, ag := range additionalGroups { | ||
376 | var found bool | ||
377 | for _, g := range groups { | ||
378 | // if we found a matched group either by name or gid, take the | ||
379 | // first matched as correct | ||
380 | if g.Name == ag || strconv.Itoa(g.Gid) == ag { | ||
381 | if _, ok := gidMap[g.Gid]; !ok { | ||
382 | gidMap[g.Gid] = struct{}{} | ||
383 | found = true | ||
384 | break | ||
385 | } | ||
386 | } | ||
387 | } | ||
388 | // we asked for a group but didn't find it. let's check to see | ||
389 | // if we wanted a numeric group | ||
390 | if !found { | ||
391 | gid, err := strconv.Atoi(ag) | ||
392 | if err != nil { | ||
393 | return nil, fmt.Errorf("Unable to find group %s", ag) | ||
394 | } | ||
395 | // Ensure gid is inside gid range. | ||
396 | if gid < minId || gid > maxId { | ||
397 | return nil, ErrRange | ||
398 | } | ||
399 | gidMap[gid] = struct{}{} | ||
400 | } | ||
401 | } | ||
402 | gids := []int{} | ||
403 | for gid := range gidMap { | ||
404 | gids = append(gids, gid) | ||
405 | } | ||
406 | return gids, nil | ||
407 | } | ||
408 | |||
409 | // GetAdditionalGroupsPath is a wrapper around GetAdditionalGroups | ||
410 | // that opens the groupPath given and gives it as an argument to | ||
411 | // GetAdditionalGroups. | ||
412 | func GetAdditionalGroupsPath(additionalGroups []string, groupPath string) ([]int, error) { | ||
413 | group, err := os.Open(groupPath) | ||
414 | if err == nil { | ||
415 | defer group.Close() | ||
416 | } | ||
417 | return GetAdditionalGroups(additionalGroups, group) | ||
418 | } | ||