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