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