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