Source file
src/os/user/user_windows_test.go
1
2
3
4
5 package user
6
7 import (
8 "crypto/rand"
9 "encoding/base64"
10 "errors"
11 "fmt"
12 "internal/syscall/windows"
13 "internal/testenv"
14 "os"
15 "os/exec"
16 "runtime"
17 "strconv"
18 "syscall"
19 "testing"
20 "unsafe"
21 )
22
23
24
25
26 func windowsTestAccount(t *testing.T) (syscall.Token, *User) {
27 if testenv.Builder() == "" {
28
29
30
31
32 t.Skip("skipping non-hermetic test outside of Go builders")
33 }
34 const testUserName = "GoStdTestUser01"
35 var password [33]byte
36 rand.Read(password[:])
37
38 pwd := base64.StdEncoding.EncodeToString(password[:]) + "_-As@!%*(1)4#2"
39 name, err := syscall.UTF16PtrFromString(testUserName)
40 if err != nil {
41 t.Fatal(err)
42 }
43 pwd16, err := syscall.UTF16PtrFromString(pwd)
44 if err != nil {
45 t.Fatal(err)
46 }
47 userInfo := windows.UserInfo1{
48 Name: name,
49 Password: pwd16,
50 Priv: windows.USER_PRIV_USER,
51 }
52
53 err = windows.NetUserAdd(nil, 1, (*byte)(unsafe.Pointer(&userInfo)), nil)
54 if errors.Is(err, syscall.ERROR_ACCESS_DENIED) {
55 t.Skip("skipping test; don't have permission to create user")
56 }
57 if errors.Is(err, windows.NERR_UserExists) {
58
59 if err = windows.NetUserDel(nil, name); err != nil {
60 t.Fatal(err)
61 }
62 if err = windows.NetUserAdd(nil, 1, (*byte)(unsafe.Pointer(&userInfo)), nil); err != nil {
63 t.Fatal(err)
64 }
65 } else if err != nil {
66 t.Fatal(err)
67 }
68 t.Cleanup(func() {
69 if err = windows.NetUserDel(nil, name); err != nil {
70 if !errors.Is(err, windows.NERR_UserNotFound) {
71 t.Fatal(err)
72 }
73 }
74 })
75 domain, err := syscall.UTF16PtrFromString(".")
76 if err != nil {
77 t.Fatal(err)
78 }
79 const LOGON32_PROVIDER_DEFAULT = 0
80 const LOGON32_LOGON_INTERACTIVE = 2
81 var token syscall.Token
82 if err = windows.LogonUser(name, domain, pwd16, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &token); err != nil {
83 t.Fatal(err)
84 }
85 t.Cleanup(func() {
86 token.Close()
87 })
88 usr, err := Lookup(testUserName)
89 if err != nil {
90 t.Fatal(err)
91 }
92 return token, usr
93 }
94
95 func TestImpersonatedSelf(t *testing.T) {
96 runtime.LockOSThread()
97 defer runtime.UnlockOSThread()
98
99 want, err := current()
100 if err != nil {
101 t.Fatal(err)
102 }
103
104 levels := []uint32{
105 windows.SecurityAnonymous,
106 windows.SecurityIdentification,
107 windows.SecurityImpersonation,
108 windows.SecurityDelegation,
109 }
110 for _, level := range levels {
111 t.Run(strconv.Itoa(int(level)), func(t *testing.T) {
112 if err = windows.ImpersonateSelf(level); err != nil {
113 t.Fatal(err)
114 }
115 defer windows.RevertToSelf()
116
117 got, err := current()
118 if level == windows.SecurityAnonymous {
119
120
121 if err == nil {
122 t.Fatal("expected error")
123 }
124 return
125 }
126 if err != nil {
127 t.Fatal(err)
128 }
129 compare(t, want, got)
130 })
131 }
132 }
133
134 func TestImpersonated(t *testing.T) {
135 runtime.LockOSThread()
136 defer runtime.UnlockOSThread()
137
138 want, err := current()
139 if err != nil {
140 t.Fatal(err)
141 }
142
143
144 token, _ := windowsTestAccount(t)
145
146
147 if err = windows.ImpersonateLoggedOnUser(token); err != nil {
148 t.Fatal(err)
149 }
150 defer func() {
151 err = windows.RevertToSelf()
152 if err != nil {
153
154 panic(err)
155 }
156 }()
157
158 got, err := current()
159 if err != nil {
160 t.Fatal(err)
161 }
162 compare(t, want, got)
163 }
164
165 func TestCurrentNetapi32(t *testing.T) {
166 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
167
168
169 Current()
170
171
172 netapi32, err := syscall.UTF16PtrFromString("netapi32.dll")
173 if err != nil {
174 fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
175 os.Exit(9)
176 return
177 }
178 mod, _ := windows.GetModuleHandle(netapi32)
179 if mod != 0 {
180 fmt.Fprintf(os.Stderr, "netapi32.dll is loaded\n")
181 os.Exit(9)
182 return
183 }
184 os.Exit(0)
185 return
186 }
187 exe := testenv.Executable(t)
188 cmd := testenv.CleanCmdEnv(exec.Command(exe, "-test.run=^TestCurrentNetapi32$"))
189 cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1")
190 out, err := cmd.CombinedOutput()
191 if err != nil {
192 t.Fatalf("%v\n%s", err, out)
193 }
194 }
195
196 func TestGroupIdsTestUser(t *testing.T) {
197
198 _, user := windowsTestAccount(t)
199
200 gids, err := user.GroupIds()
201 if err != nil {
202 t.Fatal(err)
203 }
204
205 if err != nil {
206 t.Fatalf("%+v.GroupIds(): %v", user, err)
207 }
208 if !containsID(gids, user.Gid) {
209 t.Errorf("%+v.GroupIds() = %v; does not contain user GID %s", user, gids, user.Gid)
210 }
211 }
212
213 var serviceAccounts = []struct {
214 sid string
215 name string
216 }{
217 {"S-1-5-18", "NT AUTHORITY\\SYSTEM"},
218 {"S-1-5-19", "NT AUTHORITY\\LOCAL SERVICE"},
219 {"S-1-5-20", "NT AUTHORITY\\NETWORK SERVICE"},
220 }
221
222 func TestLookupServiceAccount(t *testing.T) {
223 t.Parallel()
224 for _, tt := range serviceAccounts {
225 u, err := Lookup(tt.name)
226 if err != nil {
227 t.Errorf("Lookup(%q): %v", tt.name, err)
228 continue
229 }
230 if u.Uid != tt.sid {
231 t.Errorf("unexpected uid for %q; got %q, want %q", u.Name, u.Uid, tt.sid)
232 }
233 }
234 }
235
236 func TestLookupIdServiceAccount(t *testing.T) {
237 t.Parallel()
238 for _, tt := range serviceAccounts {
239 u, err := LookupId(tt.sid)
240 if err != nil {
241 t.Errorf("LookupId(%q): %v", tt.sid, err)
242 continue
243 }
244 if u.Gid != tt.sid {
245 t.Errorf("unexpected gid for %q; got %q, want %q", u.Name, u.Gid, tt.sid)
246 }
247 if u.Username != tt.name {
248 t.Errorf("unexpected user name for %q; got %q, want %q", u.Gid, u.Username, tt.name)
249 }
250 }
251 }
252
253 func TestLookupGroupServiceAccount(t *testing.T) {
254 t.Parallel()
255 for _, tt := range serviceAccounts {
256 u, err := LookupGroup(tt.name)
257 if err != nil {
258 t.Errorf("LookupGroup(%q): %v", tt.name, err)
259 continue
260 }
261 if u.Gid != tt.sid {
262 t.Errorf("unexpected gid for %q; got %q, want %q", u.Name, u.Gid, tt.sid)
263 }
264 }
265 }
266
267 func TestLookupGroupIdServiceAccount(t *testing.T) {
268 t.Parallel()
269 for _, tt := range serviceAccounts {
270 u, err := LookupGroupId(tt.sid)
271 if err != nil {
272 t.Errorf("LookupGroupId(%q): %v", tt.sid, err)
273 continue
274 }
275 if u.Gid != tt.sid {
276 t.Errorf("unexpected gid for %q; got %q, want %q", u.Name, u.Gid, tt.sid)
277 }
278 }
279 }
280
View as plain text