Source file
src/os/user/cgo_lookup_unix.go
1
2
3
4
5
6
7 package user
8
9 import (
10 "fmt"
11 "runtime"
12 "strconv"
13 "strings"
14 "syscall"
15 "unsafe"
16 )
17
18 func current() (*User, error) {
19 return lookupUnixUid(syscall.Getuid())
20 }
21
22 func lookupUser(username string) (*User, error) {
23 var pwd _C_struct_passwd
24 var found bool
25 nameC := make([]byte, len(username)+1)
26 copy(nameC, username)
27
28 err := retryWithBuffer(userBuffer, func(buf []byte) syscall.Errno {
29 var errno syscall.Errno
30 pwd, found, errno = _C_getpwnam_r((*_C_char)(unsafe.Pointer(&nameC[0])),
31 (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf)))
32 return errno
33 })
34 if err == syscall.ENOENT || (err == nil && !found) {
35 return nil, UnknownUserError(username)
36 }
37 if err != nil {
38 return nil, fmt.Errorf("user: lookup username %s: %v", username, err)
39 }
40 return buildUser(&pwd), err
41 }
42
43 func lookupUserId(uid string) (*User, error) {
44 i, e := strconv.Atoi(uid)
45 if e != nil {
46 return nil, e
47 }
48 return lookupUnixUid(i)
49 }
50
51 func lookupUnixUid(uid int) (*User, error) {
52 var pwd _C_struct_passwd
53 var found bool
54
55 err := retryWithBuffer(userBuffer, func(buf []byte) syscall.Errno {
56 var errno syscall.Errno
57 pwd, found, errno = _C_getpwuid_r(_C_uid_t(uid),
58 (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf)))
59 return errno
60 })
61 if err == syscall.ENOENT || (err == nil && !found) {
62 return nil, UnknownUserIdError(uid)
63 }
64 if err != nil {
65 return nil, fmt.Errorf("user: lookup userid %d: %v", uid, err)
66 }
67 return buildUser(&pwd), nil
68 }
69
70 func buildUser(pwd *_C_struct_passwd) *User {
71 u := &User{
72 Uid: strconv.FormatUint(uint64(_C_pw_uid(pwd)), 10),
73 Gid: strconv.FormatUint(uint64(_C_pw_gid(pwd)), 10),
74 Username: _C_GoString(_C_pw_name(pwd)),
75 Name: _C_GoString(_C_pw_gecos(pwd)),
76 HomeDir: _C_GoString(_C_pw_dir(pwd)),
77 }
78
79
80
81
82 u.Name, _, _ = strings.Cut(u.Name, ",")
83 return u
84 }
85
86 func lookupGroup(groupname string) (*Group, error) {
87 var grp _C_struct_group
88 var found bool
89
90 cname := make([]byte, len(groupname)+1)
91 copy(cname, groupname)
92
93 err := retryWithBuffer(groupBuffer, func(buf []byte) syscall.Errno {
94 var errno syscall.Errno
95 grp, found, errno = _C_getgrnam_r((*_C_char)(unsafe.Pointer(&cname[0])),
96 (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf)))
97 return errno
98 })
99 if err == syscall.ENOENT || (err == nil && !found) {
100 return nil, UnknownGroupError(groupname)
101 }
102 if err != nil {
103 return nil, fmt.Errorf("user: lookup groupname %s: %v", groupname, err)
104 }
105 return buildGroup(&grp), nil
106 }
107
108 func lookupGroupId(gid string) (*Group, error) {
109 i, e := strconv.Atoi(gid)
110 if e != nil {
111 return nil, e
112 }
113 return lookupUnixGid(i)
114 }
115
116 func lookupUnixGid(gid int) (*Group, error) {
117 var grp _C_struct_group
118 var found bool
119
120 err := retryWithBuffer(groupBuffer, func(buf []byte) syscall.Errno {
121 var errno syscall.Errno
122 grp, found, errno = _C_getgrgid_r(_C_gid_t(gid),
123 (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf)))
124 return syscall.Errno(errno)
125 })
126 if err == syscall.ENOENT || (err == nil && !found) {
127 return nil, UnknownGroupIdError(strconv.Itoa(gid))
128 }
129 if err != nil {
130 return nil, fmt.Errorf("user: lookup groupid %d: %v", gid, err)
131 }
132 return buildGroup(&grp), nil
133 }
134
135 func buildGroup(grp *_C_struct_group) *Group {
136 g := &Group{
137 Gid: strconv.Itoa(int(_C_gr_gid(grp))),
138 Name: _C_GoString(_C_gr_name(grp)),
139 }
140 return g
141 }
142
143 type bufferKind _C_int
144
145 var (
146 userBuffer = bufferKind(_C__SC_GETPW_R_SIZE_MAX)
147 groupBuffer = bufferKind(_C__SC_GETGR_R_SIZE_MAX)
148 )
149
150 func (k bufferKind) initialSize() _C_size_t {
151 sz := _C_sysconf(_C_int(k))
152 if sz == -1 {
153
154
155
156 return 1024
157 }
158 if !isSizeReasonable(int64(sz)) {
159
160 return maxBufferSize
161 }
162 return _C_size_t(sz)
163 }
164
165
166
167
168 func retryWithBuffer(kind bufferKind, f func([]byte) syscall.Errno) error {
169 buf := make([]byte, kind.initialSize())
170 for {
171 errno := f(buf)
172 if errno == 0 {
173 return nil
174 } else if runtime.GOOS == "aix" && errno+1 == 0 {
175
176
177 } else if errno != syscall.ERANGE {
178 return errno
179 }
180 newSize := len(buf) * 2
181 if !isSizeReasonable(int64(newSize)) {
182 return fmt.Errorf("internal buffer exceeds %d bytes", maxBufferSize)
183 }
184 buf = make([]byte, newSize)
185 }
186 }
187
188 const maxBufferSize = 1 << 20
189
190 func isSizeReasonable(sz int64) bool {
191 return sz > 0 && sz <= maxBufferSize
192 }
193
194
195 func structPasswdForNegativeTest() _C_struct_passwd {
196 sp := _C_struct_passwd{}
197 *_C_pw_uidp(&sp) = 1<<32 - 2
198 *_C_pw_gidp(&sp) = 1<<32 - 3
199 return sp
200 }
201
View as plain text