Source file
src/os/user/lookup_unix.go
Documentation: os/user
1
2
3
4
5
6
7
8
9 package user
10
11 import (
12 "bufio"
13 "bytes"
14 "errors"
15 "io"
16 "os"
17 "strconv"
18 "strings"
19 )
20
21 const groupFile = "/etc/group"
22 const userFile = "/etc/passwd"
23
24 var colon = []byte{':'}
25
26 func init() {
27 groupImplemented = false
28 }
29
30
31 type lineFunc func(line []byte) (v interface{}, err error)
32
33
34
35
36
37
38
39 func readColonFile(r io.Reader, fn lineFunc, readCols int) (v interface{}, err error) {
40 rd := bufio.NewReader(r)
41
42
43 for {
44 var isPrefix bool
45 var wholeLine []byte
46
47
48
49
50 for {
51 var line []byte
52 line, isPrefix, err = rd.ReadLine()
53
54 if err != nil {
55
56
57 if err == io.EOF {
58 err = nil
59 }
60 return nil, err
61 }
62
63
64
65 if !isPrefix && len(wholeLine) == 0 {
66 wholeLine = line
67 break
68 }
69
70 wholeLine = append(wholeLine, line...)
71
72
73
74 if !isPrefix || bytes.Count(wholeLine, []byte{':'}) >= readCols {
75 break
76 }
77 }
78
79
80
81
82 wholeLine = bytes.TrimSpace(wholeLine)
83 if len(wholeLine) == 0 || wholeLine[0] == '#' {
84 continue
85 }
86 v, err = fn(wholeLine)
87 if v != nil || err != nil {
88 return
89 }
90
91
92 for ; isPrefix; _, isPrefix, err = rd.ReadLine() {
93 if err != nil {
94
95 if err == io.EOF {
96 err = nil
97 }
98 return nil, err
99 }
100 }
101 }
102 }
103
104 func matchGroupIndexValue(value string, idx int) lineFunc {
105 var leadColon string
106 if idx > 0 {
107 leadColon = ":"
108 }
109 substr := []byte(leadColon + value + ":")
110 return func(line []byte) (v interface{}, err error) {
111 if !bytes.Contains(line, substr) || bytes.Count(line, colon) < 3 {
112 return
113 }
114
115 parts := strings.SplitN(string(line), ":", 4)
116 if len(parts) < 4 || parts[0] == "" || parts[idx] != value ||
117
118
119
120
121 parts[0][0] == '+' || parts[0][0] == '-' {
122 return
123 }
124 if _, err := strconv.Atoi(parts[2]); err != nil {
125 return nil, nil
126 }
127 return &Group{Name: parts[0], Gid: parts[2]}, nil
128 }
129 }
130
131 func findGroupId(id string, r io.Reader) (*Group, error) {
132 if v, err := readColonFile(r, matchGroupIndexValue(id, 2), 3); err != nil {
133 return nil, err
134 } else if v != nil {
135 return v.(*Group), nil
136 }
137 return nil, UnknownGroupIdError(id)
138 }
139
140 func findGroupName(name string, r io.Reader) (*Group, error) {
141 if v, err := readColonFile(r, matchGroupIndexValue(name, 0), 3); err != nil {
142 return nil, err
143 } else if v != nil {
144 return v.(*Group), nil
145 }
146 return nil, UnknownGroupError(name)
147 }
148
149
150
151 func matchUserIndexValue(value string, idx int) lineFunc {
152 var leadColon string
153 if idx > 0 {
154 leadColon = ":"
155 }
156 substr := []byte(leadColon + value + ":")
157 return func(line []byte) (v interface{}, err error) {
158 if !bytes.Contains(line, substr) || bytes.Count(line, colon) < 6 {
159 return
160 }
161
162 parts := strings.SplitN(string(line), ":", 7)
163 if len(parts) < 6 || parts[idx] != value || parts[0] == "" ||
164 parts[0][0] == '+' || parts[0][0] == '-' {
165 return
166 }
167 if _, err := strconv.Atoi(parts[2]); err != nil {
168 return nil, nil
169 }
170 if _, err := strconv.Atoi(parts[3]); err != nil {
171 return nil, nil
172 }
173 u := &User{
174 Username: parts[0],
175 Uid: parts[2],
176 Gid: parts[3],
177 Name: parts[4],
178 HomeDir: parts[5],
179 }
180
181
182
183
184 if i := strings.Index(u.Name, ","); i >= 0 {
185 u.Name = u.Name[:i]
186 }
187 return u, nil
188 }
189 }
190
191 func findUserId(uid string, r io.Reader) (*User, error) {
192 i, e := strconv.Atoi(uid)
193 if e != nil {
194 return nil, errors.New("user: invalid userid " + uid)
195 }
196 if v, err := readColonFile(r, matchUserIndexValue(uid, 2), 6); err != nil {
197 return nil, err
198 } else if v != nil {
199 return v.(*User), nil
200 }
201 return nil, UnknownUserIdError(i)
202 }
203
204 func findUsername(name string, r io.Reader) (*User, error) {
205 if v, err := readColonFile(r, matchUserIndexValue(name, 0), 6); err != nil {
206 return nil, err
207 } else if v != nil {
208 return v.(*User), nil
209 }
210 return nil, UnknownUserError(name)
211 }
212
213 func lookupGroup(groupname string) (*Group, error) {
214 f, err := os.Open(groupFile)
215 if err != nil {
216 return nil, err
217 }
218 defer f.Close()
219 return findGroupName(groupname, f)
220 }
221
222 func lookupGroupId(id string) (*Group, error) {
223 f, err := os.Open(groupFile)
224 if err != nil {
225 return nil, err
226 }
227 defer f.Close()
228 return findGroupId(id, f)
229 }
230
231 func lookupUser(username string) (*User, error) {
232 f, err := os.Open(userFile)
233 if err != nil {
234 return nil, err
235 }
236 defer f.Close()
237 return findUsername(username, f)
238 }
239
240 func lookupUserId(uid string) (*User, error) {
241 f, err := os.Open(userFile)
242 if err != nil {
243 return nil, err
244 }
245 defer f.Close()
246 return findUserId(uid, f)
247 }
248
View as plain text