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