golang.org/x/sys@v0.9.0/windows/syscall_windows_test.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package windows_test 6 7 import ( 8 "bufio" 9 "bytes" 10 "debug/pe" 11 "errors" 12 "fmt" 13 "io/ioutil" 14 "math/rand" 15 "os" 16 "path/filepath" 17 "runtime" 18 "strconv" 19 "strings" 20 "syscall" 21 "testing" 22 "time" 23 "unsafe" 24 25 "golang.org/x/sys/internal/unsafeheader" 26 "golang.org/x/sys/windows" 27 ) 28 29 func TestWin32finddata(t *testing.T) { 30 dir, err := ioutil.TempDir("", "go-build") 31 if err != nil { 32 t.Fatalf("failed to create temp directory: %v", err) 33 } 34 defer os.RemoveAll(dir) 35 36 path := filepath.Join(dir, "long_name.and_extension") 37 f, err := os.Create(path) 38 if err != nil { 39 t.Fatalf("failed to create %v: %v", path, err) 40 } 41 f.Close() 42 43 type X struct { 44 fd windows.Win32finddata 45 got byte 46 pad [10]byte // to protect ourselves 47 48 } 49 var want byte = 2 // it is unlikely to have this character in the filename 50 x := X{got: want} 51 52 pathp, _ := windows.UTF16PtrFromString(path) 53 h, err := windows.FindFirstFile(pathp, &(x.fd)) 54 if err != nil { 55 t.Fatalf("FindFirstFile failed: %v", err) 56 } 57 err = windows.FindClose(h) 58 if err != nil { 59 t.Fatalf("FindClose failed: %v", err) 60 } 61 62 if x.got != want { 63 t.Fatalf("memory corruption: want=%d got=%d", want, x.got) 64 } 65 } 66 67 func TestFormatMessage(t *testing.T) { 68 dll := windows.MustLoadDLL("netevent.dll") 69 70 const TITLE_SC_MESSAGE_BOX uint32 = 0xC0001B75 71 const flags uint32 = syscall.FORMAT_MESSAGE_FROM_HMODULE | syscall.FORMAT_MESSAGE_ARGUMENT_ARRAY | syscall.FORMAT_MESSAGE_IGNORE_INSERTS 72 buf := make([]uint16, 300) 73 _, err := windows.FormatMessage(flags, uintptr(dll.Handle), TITLE_SC_MESSAGE_BOX, 0, buf, nil) 74 if err != nil { 75 t.Fatalf("FormatMessage for handle=%x and errno=%x failed: %v", dll.Handle, TITLE_SC_MESSAGE_BOX, err) 76 } 77 } 78 79 func abort(funcname string, err error) { 80 panic(funcname + " failed: " + err.Error()) 81 } 82 83 func ExampleLoadLibrary() { 84 h, err := windows.LoadLibrary("kernel32.dll") 85 if err != nil { 86 abort("LoadLibrary", err) 87 } 88 defer windows.FreeLibrary(h) 89 proc, err := windows.GetProcAddress(h, "GetVersion") 90 if err != nil { 91 abort("GetProcAddress", err) 92 } 93 r, _, _ := syscall.Syscall(uintptr(proc), 0, 0, 0, 0) 94 major := byte(r) 95 minor := uint8(r >> 8) 96 build := uint16(r >> 16) 97 print("windows version ", major, ".", minor, " (Build ", build, ")\n") 98 } 99 100 func TestTOKEN_ALL_ACCESS(t *testing.T) { 101 if windows.TOKEN_ALL_ACCESS != 0xF01FF { 102 t.Errorf("TOKEN_ALL_ACCESS = %x, want 0xF01FF", windows.TOKEN_ALL_ACCESS) 103 } 104 } 105 106 func TestCreateWellKnownSid(t *testing.T) { 107 sid, err := windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid) 108 if err != nil { 109 t.Fatalf("Unable to create well known sid for administrators: %v", err) 110 } 111 if got, want := sid.String(), "S-1-5-32-544"; got != want { 112 t.Fatalf("Builtin Administrators SID = %s, want %s", got, want) 113 } 114 } 115 116 func TestPseudoTokens(t *testing.T) { 117 version, err := windows.GetVersion() 118 if err != nil { 119 t.Fatal(err) 120 } 121 if ((version&0xffff)>>8)|((version&0xff)<<8) < 0x0602 { 122 return 123 } 124 125 realProcessToken, err := windows.OpenCurrentProcessToken() 126 if err != nil { 127 t.Fatal(err) 128 } 129 defer realProcessToken.Close() 130 realProcessUser, err := realProcessToken.GetTokenUser() 131 if err != nil { 132 t.Fatal(err) 133 } 134 135 pseudoProcessToken := windows.GetCurrentProcessToken() 136 pseudoProcessUser, err := pseudoProcessToken.GetTokenUser() 137 if err != nil { 138 t.Fatal(err) 139 } 140 if !windows.EqualSid(realProcessUser.User.Sid, pseudoProcessUser.User.Sid) { 141 t.Fatal("The real process token does not have the same as the pseudo process token") 142 } 143 144 runtime.LockOSThread() 145 defer runtime.UnlockOSThread() 146 147 err = windows.RevertToSelf() 148 if err != nil { 149 t.Fatal(err) 150 } 151 152 pseudoThreadToken := windows.GetCurrentThreadToken() 153 _, err = pseudoThreadToken.GetTokenUser() 154 if err != windows.ERROR_NO_TOKEN { 155 t.Fatal("Expected an empty thread token") 156 } 157 pseudoThreadEffectiveToken := windows.GetCurrentThreadEffectiveToken() 158 pseudoThreadEffectiveUser, err := pseudoThreadEffectiveToken.GetTokenUser() 159 if err != nil { 160 t.Fatal(nil) 161 } 162 if !windows.EqualSid(realProcessUser.User.Sid, pseudoThreadEffectiveUser.User.Sid) { 163 t.Fatal("The real process token does not have the same as the pseudo thread effective token, even though we aren't impersonating") 164 } 165 166 err = windows.ImpersonateSelf(windows.SecurityImpersonation) 167 if err != nil { 168 t.Fatal(err) 169 } 170 defer windows.RevertToSelf() 171 pseudoThreadUser, err := pseudoThreadToken.GetTokenUser() 172 if err != nil { 173 t.Fatal(err) 174 } 175 if !windows.EqualSid(realProcessUser.User.Sid, pseudoThreadUser.User.Sid) { 176 t.Fatal("The real process token does not have the same as the pseudo thread token after impersonating self") 177 } 178 } 179 180 func TestGUID(t *testing.T) { 181 guid, err := windows.GenerateGUID() 182 if err != nil { 183 t.Fatal(err) 184 } 185 if guid.Data1 == 0 && guid.Data2 == 0 && guid.Data3 == 0 && guid.Data4 == [8]byte{} { 186 t.Fatal("Got an all zero GUID, which is overwhelmingly unlikely") 187 } 188 want := fmt.Sprintf("{%08X-%04X-%04X-%04X-%012X}", guid.Data1, guid.Data2, guid.Data3, guid.Data4[:2], guid.Data4[2:]) 189 got := guid.String() 190 if got != want { 191 t.Fatalf("String = %q; want %q", got, want) 192 } 193 guid2, err := windows.GUIDFromString(got) 194 if err != nil { 195 t.Fatal(err) 196 } 197 if guid2 != guid { 198 t.Fatalf("Did not parse string back to original GUID = %q; want %q", guid2, guid) 199 } 200 _, err = windows.GUIDFromString("not-a-real-guid") 201 if err != syscall.Errno(windows.CO_E_CLASSSTRING) { 202 t.Fatalf("Bad GUID string error = %v; want CO_E_CLASSSTRING", err) 203 } 204 } 205 206 func TestKnownFolderPath(t *testing.T) { 207 token, err := windows.OpenCurrentProcessToken() 208 if err != nil { 209 t.Fatal(err) 210 } 211 defer token.Close() 212 profileDir, err := token.GetUserProfileDirectory() 213 if err != nil { 214 t.Fatal(err) 215 } 216 want := filepath.Join(profileDir, "Desktop") 217 got, err := windows.KnownFolderPath(windows.FOLDERID_Desktop, windows.KF_FLAG_DEFAULT) 218 if err != nil { 219 t.Fatal(err) 220 } 221 if want != got { 222 t.Fatalf("Path = %q; want %q", got, want) 223 } 224 } 225 226 func TestRtlGetVersion(t *testing.T) { 227 version := windows.RtlGetVersion() 228 major, minor, build := windows.RtlGetNtVersionNumbers() 229 // Go is not explictly added to the application compatibility database, so 230 // these two functions should return the same thing. 231 if version.MajorVersion != major || version.MinorVersion != minor || version.BuildNumber != build { 232 t.Fatalf("%d.%d.%d != %d.%d.%d", version.MajorVersion, version.MinorVersion, version.BuildNumber, major, minor, build) 233 } 234 } 235 236 func TestGetNamedSecurityInfo(t *testing.T) { 237 path, err := windows.GetSystemDirectory() 238 if err != nil { 239 t.Fatal(err) 240 } 241 sd, err := windows.GetNamedSecurityInfo(path, windows.SE_FILE_OBJECT, windows.OWNER_SECURITY_INFORMATION) 242 if err != nil { 243 t.Fatal(err) 244 } 245 if !sd.IsValid() { 246 t.Fatal("Invalid security descriptor") 247 } 248 sdOwner, _, err := sd.Owner() 249 if err != nil { 250 t.Fatal(err) 251 } 252 if !sdOwner.IsValid() { 253 t.Fatal("Invalid security descriptor owner") 254 } 255 } 256 257 func TestGetSecurityInfo(t *testing.T) { 258 sd, err := windows.GetSecurityInfo(windows.CurrentProcess(), windows.SE_KERNEL_OBJECT, windows.DACL_SECURITY_INFORMATION) 259 if err != nil { 260 t.Fatal(err) 261 } 262 if !sd.IsValid() { 263 t.Fatal("Invalid security descriptor") 264 } 265 sdStr := sd.String() 266 if !strings.HasPrefix(sdStr, "D:(A;") { 267 t.Fatalf("DACL = %q; want D:(A;...", sdStr) 268 } 269 } 270 271 func TestSddlConversion(t *testing.T) { 272 sd, err := windows.SecurityDescriptorFromString("O:BA") 273 if err != nil { 274 t.Fatal(err) 275 } 276 if !sd.IsValid() { 277 t.Fatal("Invalid security descriptor") 278 } 279 sdOwner, _, err := sd.Owner() 280 if err != nil { 281 t.Fatal(err) 282 } 283 if !sdOwner.IsValid() { 284 t.Fatal("Invalid security descriptor owner") 285 } 286 if !sdOwner.IsWellKnown(windows.WinBuiltinAdministratorsSid) { 287 t.Fatalf("Owner = %q; want S-1-5-32-544", sdOwner) 288 } 289 } 290 291 func TestBuildSecurityDescriptor(t *testing.T) { 292 const want = "O:SYD:(A;;GA;;;BA)" 293 294 adminSid, err := windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid) 295 if err != nil { 296 t.Fatal(err) 297 } 298 systemSid, err := windows.CreateWellKnownSid(windows.WinLocalSystemSid) 299 if err != nil { 300 t.Fatal(err) 301 } 302 303 access := []windows.EXPLICIT_ACCESS{{ 304 AccessPermissions: windows.GENERIC_ALL, 305 AccessMode: windows.GRANT_ACCESS, 306 Trustee: windows.TRUSTEE{ 307 TrusteeForm: windows.TRUSTEE_IS_SID, 308 TrusteeType: windows.TRUSTEE_IS_GROUP, 309 TrusteeValue: windows.TrusteeValueFromSID(adminSid), 310 }, 311 }} 312 owner := &windows.TRUSTEE{ 313 TrusteeForm: windows.TRUSTEE_IS_SID, 314 TrusteeType: windows.TRUSTEE_IS_USER, 315 TrusteeValue: windows.TrusteeValueFromSID(systemSid), 316 } 317 318 sd, err := windows.BuildSecurityDescriptor(owner, nil, access, nil, nil) 319 if err != nil { 320 t.Fatal(err) 321 } 322 sd, err = sd.ToAbsolute() 323 if err != nil { 324 t.Fatal(err) 325 } 326 err = sd.SetSACL(nil, false, false) 327 if err != nil { 328 t.Fatal(err) 329 } 330 if got := sd.String(); got != want { 331 t.Fatalf("SD = %q; want %q", got, want) 332 } 333 sd, err = sd.ToSelfRelative() 334 if err != nil { 335 t.Fatal(err) 336 } 337 if got := sd.String(); got != want { 338 t.Fatalf("SD = %q; want %q", got, want) 339 } 340 341 sd, err = windows.NewSecurityDescriptor() 342 if err != nil { 343 t.Fatal(err) 344 } 345 acl, err := windows.ACLFromEntries(access, nil) 346 if err != nil { 347 t.Fatal(err) 348 } 349 err = sd.SetDACL(acl, true, false) 350 if err != nil { 351 t.Fatal(err) 352 } 353 err = sd.SetOwner(systemSid, false) 354 if err != nil { 355 t.Fatal(err) 356 } 357 if got := sd.String(); got != want { 358 t.Fatalf("SD = %q; want %q", got, want) 359 } 360 sd, err = sd.ToSelfRelative() 361 if err != nil { 362 t.Fatal(err) 363 } 364 if got := sd.String(); got != want { 365 t.Fatalf("SD = %q; want %q", got, want) 366 } 367 } 368 369 func TestGetDiskFreeSpaceEx(t *testing.T) { 370 cwd, err := windows.UTF16PtrFromString(".") 371 if err != nil { 372 t.Fatalf(`failed to call UTF16PtrFromString("."): %v`, err) 373 } 374 var freeBytesAvailableToCaller, totalNumberOfBytes, totalNumberOfFreeBytes uint64 375 if err := windows.GetDiskFreeSpaceEx(cwd, &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes); err != nil { 376 t.Fatalf("failed to call GetDiskFreeSpaceEx: %v", err) 377 } 378 379 if freeBytesAvailableToCaller == 0 { 380 t.Errorf("freeBytesAvailableToCaller: got 0; want > 0") 381 } 382 if totalNumberOfBytes == 0 { 383 t.Errorf("totalNumberOfBytes: got 0; want > 0") 384 } 385 if totalNumberOfFreeBytes == 0 { 386 t.Errorf("totalNumberOfFreeBytes: got 0; want > 0") 387 } 388 } 389 390 func TestGetPreferredUILanguages(t *testing.T) { 391 tab := map[string]func(flags uint32) ([]string, error){ 392 "GetProcessPreferredUILanguages": windows.GetProcessPreferredUILanguages, 393 "GetThreadPreferredUILanguages": windows.GetThreadPreferredUILanguages, 394 "GetUserPreferredUILanguages": windows.GetUserPreferredUILanguages, 395 "GetSystemPreferredUILanguages": windows.GetSystemPreferredUILanguages, 396 } 397 for fName, f := range tab { 398 lang, err := f(windows.MUI_LANGUAGE_ID) 399 if err != nil { 400 t.Errorf(`failed to call %v(MUI_LANGUAGE_ID): %v`, fName, err) 401 } 402 for _, l := range lang { 403 _, err := strconv.ParseUint(l, 16, 16) 404 if err != nil { 405 t.Errorf(`%v(MUI_LANGUAGE_ID) returned unexpected LANGID: %v`, fName, l) 406 } 407 } 408 409 lang, err = f(windows.MUI_LANGUAGE_NAME) 410 if err != nil { 411 t.Errorf(`failed to call %v(MUI_LANGUAGE_NAME): %v`, fName, err) 412 } 413 } 414 } 415 416 func TestProcessWorkingSetSizeEx(t *testing.T) { 417 // Grab a handle to the current process 418 hProcess := windows.CurrentProcess() 419 420 // Allocate memory to store the result of the query 421 var minimumWorkingSetSize, maximumWorkingSetSize uintptr 422 423 // Make the system-call 424 var flag uint32 425 windows.GetProcessWorkingSetSizeEx(hProcess, &minimumWorkingSetSize, &maximumWorkingSetSize, &flag) 426 427 // Set the new limits to the current ones 428 if err := windows.SetProcessWorkingSetSizeEx(hProcess, minimumWorkingSetSize, maximumWorkingSetSize, flag); err != nil { 429 t.Error(err) 430 } 431 } 432 433 func TestJobObjectInfo(t *testing.T) { 434 jo, err := windows.CreateJobObject(nil, nil) 435 if err != nil { 436 t.Fatalf("CreateJobObject failed: %v", err) 437 } 438 defer windows.CloseHandle(jo) 439 440 var info windows.JOBOBJECT_EXTENDED_LIMIT_INFORMATION 441 442 err = windows.QueryInformationJobObject(jo, windows.JobObjectExtendedLimitInformation, 443 uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)), nil) 444 if err != nil { 445 t.Fatalf("QueryInformationJobObject failed: %v", err) 446 } 447 448 const wantMemLimit = 4 * 1024 449 450 info.BasicLimitInformation.LimitFlags |= windows.JOB_OBJECT_LIMIT_PROCESS_MEMORY 451 info.ProcessMemoryLimit = wantMemLimit 452 _, err = windows.SetInformationJobObject(jo, windows.JobObjectExtendedLimitInformation, 453 uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info))) 454 if err != nil { 455 t.Fatalf("SetInformationJobObject failed: %v", err) 456 } 457 458 err = windows.QueryInformationJobObject(jo, windows.JobObjectExtendedLimitInformation, 459 uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)), nil) 460 if err != nil { 461 t.Fatalf("QueryInformationJobObject failed: %v", err) 462 } 463 464 if have := info.ProcessMemoryLimit; wantMemLimit != have { 465 t.Errorf("ProcessMemoryLimit is wrong: want %v have %v", wantMemLimit, have) 466 } 467 } 468 469 func TestIsWow64Process2(t *testing.T) { 470 var processMachine, nativeMachine uint16 471 err := windows.IsWow64Process2(windows.CurrentProcess(), &processMachine, &nativeMachine) 472 if errors.Is(err, windows.ERROR_PROC_NOT_FOUND) { 473 maj, min, build := windows.RtlGetNtVersionNumbers() 474 if maj < 10 || (maj == 10 && min == 0 && build < 17763) { 475 t.Skip("not available on older versions of Windows") 476 return 477 } 478 } 479 if err != nil { 480 t.Fatalf("IsWow64Process2 failed: %v", err) 481 } 482 if processMachine == pe.IMAGE_FILE_MACHINE_UNKNOWN { 483 processMachine = nativeMachine 484 } 485 switch { 486 case processMachine == pe.IMAGE_FILE_MACHINE_AMD64 && runtime.GOARCH == "amd64": 487 case processMachine == pe.IMAGE_FILE_MACHINE_I386 && runtime.GOARCH == "386": 488 case processMachine == pe.IMAGE_FILE_MACHINE_ARMNT && runtime.GOARCH == "arm": 489 case processMachine == pe.IMAGE_FILE_MACHINE_ARM64 && runtime.GOARCH == "arm64": 490 default: 491 t.Errorf("IsWow64Process2 is wrong: want %v have %v", runtime.GOARCH, processMachine) 492 } 493 } 494 495 func TestNTStatusString(t *testing.T) { 496 want := "The name limit for the local computer network adapter card was exceeded." 497 got := windows.STATUS_TOO_MANY_NAMES.Error() 498 if want != got { 499 t.Errorf("NTStatus.Error did not return an expected error string - want %q; got %q", want, got) 500 } 501 } 502 503 func TestNTStatusConversion(t *testing.T) { 504 want := windows.ERROR_TOO_MANY_NAMES 505 got := windows.STATUS_TOO_MANY_NAMES.Errno() 506 if want != got { 507 t.Errorf("NTStatus.Errno = %q (0x%x); want %q (0x%x)", got.Error(), got, want.Error(), want) 508 } 509 } 510 511 func TestPEBFilePath(t *testing.T) { 512 peb := windows.RtlGetCurrentPeb() 513 if peb == nil || peb.Ldr == nil { 514 t.Error("unable to retrieve PEB with valid Ldr") 515 } 516 var entry *windows.LDR_DATA_TABLE_ENTRY 517 for cur := peb.Ldr.InMemoryOrderModuleList.Flink; cur != &peb.Ldr.InMemoryOrderModuleList; cur = cur.Flink { 518 e := (*windows.LDR_DATA_TABLE_ENTRY)(unsafe.Pointer(uintptr(unsafe.Pointer(cur)) - unsafe.Offsetof(windows.LDR_DATA_TABLE_ENTRY{}.InMemoryOrderLinks))) 519 if e.DllBase == peb.ImageBaseAddress { 520 entry = e 521 break 522 } 523 } 524 if entry == nil { 525 t.Error("unable to find Ldr entry for current process") 526 } 527 osPath, err := os.Executable() 528 if err != nil { 529 t.Errorf("unable to get path to current executable: %v", err) 530 } 531 pebPath := entry.FullDllName.String() 532 if osPath != pebPath { 533 t.Errorf("peb.Ldr.{entry}.FullDllName = %#q; want %#q", pebPath, osPath) 534 } 535 paramPath := peb.ProcessParameters.ImagePathName.String() 536 if osPath != paramPath { 537 t.Errorf("peb.ProcessParameters.ImagePathName.{entry}.ImagePathName = %#q; want %#q", paramPath, osPath) 538 } 539 osCwd, err := os.Getwd() 540 if err != nil { 541 t.Errorf("unable to get working directory: %v", err) 542 } 543 osCwd = filepath.Clean(osCwd) 544 paramCwd := filepath.Clean(peb.ProcessParameters.CurrentDirectory.DosPath.String()) 545 if paramCwd != osCwd { 546 t.Errorf("peb.ProcessParameters.CurrentDirectory.DosPath = %#q; want %#q", paramCwd, osCwd) 547 } 548 } 549 550 func TestResourceExtraction(t *testing.T) { 551 system32, err := windows.GetSystemDirectory() 552 if err != nil { 553 t.Errorf("unable to find system32 directory: %v", err) 554 } 555 cmd, err := windows.LoadLibrary(filepath.Join(system32, "cmd.exe")) 556 if err != nil { 557 t.Errorf("unable to load cmd.exe: %v", err) 558 } 559 defer windows.FreeLibrary(cmd) 560 rsrc, err := windows.FindResource(cmd, windows.CREATEPROCESS_MANIFEST_RESOURCE_ID, windows.RT_MANIFEST) 561 if err != nil { 562 t.Errorf("unable to find cmd.exe manifest resource: %v", err) 563 } 564 manifest, err := windows.LoadResourceData(cmd, rsrc) 565 if err != nil { 566 t.Errorf("unable to load cmd.exe manifest resource data: %v", err) 567 } 568 if !bytes.Contains(manifest, []byte("</assembly>")) { 569 t.Errorf("did not find </assembly> in manifest") 570 } 571 } 572 573 func TestCommandLineRecomposition(t *testing.T) { 574 const ( 575 maxCharsPerArg = 35 576 maxArgsPerTrial = 80 577 doubleQuoteProb = 4 578 singleQuoteProb = 1 579 backSlashProb = 3 580 spaceProb = 1 581 trials = 1000 582 ) 583 randString := func(l int) []rune { 584 s := make([]rune, l) 585 for i := range s { 586 s[i] = rand.Int31() 587 } 588 return s 589 } 590 mungeString := func(s []rune, char rune, timesInTen int) { 591 if timesInTen < rand.Intn(10)+1 || len(s) == 0 { 592 return 593 } 594 s[rand.Intn(len(s))] = char 595 } 596 argStorage := make([]string, maxArgsPerTrial+1) 597 for i := 0; i < trials; i++ { 598 args := argStorage[:rand.Intn(maxArgsPerTrial)+2] 599 args[0] = "valid-filename-for-arg0" 600 for j := 1; j < len(args); j++ { 601 arg := randString(rand.Intn(maxCharsPerArg + 1)) 602 mungeString(arg, '"', doubleQuoteProb) 603 mungeString(arg, '\'', singleQuoteProb) 604 mungeString(arg, '\\', backSlashProb) 605 mungeString(arg, ' ', spaceProb) 606 args[j] = string(arg) 607 } 608 commandLine := windows.ComposeCommandLine(args) 609 decomposedArgs, err := windows.DecomposeCommandLine(commandLine) 610 if err != nil { 611 t.Errorf("Unable to decompose %#q made from %v: %v", commandLine, args, err) 612 continue 613 } 614 if len(decomposedArgs) != len(args) { 615 t.Errorf("Incorrect decomposition length from %v to %#q to %v", args, commandLine, decomposedArgs) 616 continue 617 } 618 badMatches := make([]int, 0, len(args)) 619 for i := range args { 620 if args[i] != decomposedArgs[i] { 621 badMatches = append(badMatches, i) 622 } 623 } 624 if len(badMatches) != 0 { 625 t.Errorf("Incorrect decomposition at indices %v from %v to %#q to %v", badMatches, args, commandLine, decomposedArgs) 626 continue 627 } 628 } 629 630 // check that windows.DecomposeCommandLine returns error for strings with NUL 631 testsWithNUL := []string{ 632 "\x00abcd", 633 "ab\x00cd", 634 "abcd\x00", 635 "\x00abcd\x00", 636 "\x00ab\x00cd\x00", 637 "\x00\x00\x00", 638 } 639 for _, test := range testsWithNUL { 640 _, err := windows.DecomposeCommandLine(test) 641 if err == nil { 642 t.Errorf("Failed to return error while decomposing %#q string with NUL inside", test) 643 } 644 } 645 } 646 647 func TestWinVerifyTrust(t *testing.T) { 648 evsignedfile := `.\testdata\ev-signed-file.exe` 649 evsignedfile16, err := windows.UTF16PtrFromString(evsignedfile) 650 if err != nil { 651 t.Fatalf("unable to get utf16 of %s: %v", evsignedfile, err) 652 } 653 data := &windows.WinTrustData{ 654 Size: uint32(unsafe.Sizeof(windows.WinTrustData{})), 655 UIChoice: windows.WTD_UI_NONE, 656 RevocationChecks: windows.WTD_REVOKE_NONE, // No revocation checking, in case the tests don't have network connectivity. 657 UnionChoice: windows.WTD_CHOICE_FILE, 658 StateAction: windows.WTD_STATEACTION_VERIFY, 659 FileOrCatalogOrBlobOrSgnrOrCert: unsafe.Pointer(&windows.WinTrustFileInfo{ 660 Size: uint32(unsafe.Sizeof(windows.WinTrustFileInfo{})), 661 FilePath: evsignedfile16, 662 }), 663 } 664 verifyErr := windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data) 665 data.StateAction = windows.WTD_STATEACTION_CLOSE 666 closeErr := windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data) 667 if verifyErr != nil { 668 t.Errorf("%s did not verify: %v", evsignedfile, verifyErr) 669 } 670 if closeErr != nil { 671 t.Errorf("unable to free verification resources: %v", closeErr) 672 } 673 674 // Now that we've verified the legitimate file verifies, let's corrupt it and see if it correctly fails. 675 676 dir, err := ioutil.TempDir("", "go-build") 677 if err != nil { 678 t.Fatalf("failed to create temp directory: %v", err) 679 } 680 defer os.RemoveAll(dir) 681 corruptedEvsignedfile := filepath.Join(dir, "corrupted-file") 682 evsignedfileBytes, err := ioutil.ReadFile(evsignedfile) 683 if err != nil { 684 t.Fatalf("unable to read %s bytes: %v", evsignedfile, err) 685 } 686 if len(evsignedfileBytes) > 0 { 687 evsignedfileBytes[len(evsignedfileBytes)/2-1]++ 688 } 689 err = ioutil.WriteFile(corruptedEvsignedfile, evsignedfileBytes, 0755) 690 if err != nil { 691 t.Fatalf("unable to write corrupted ntoskrnl.exe bytes: %v", err) 692 } 693 evsignedfile16, err = windows.UTF16PtrFromString(corruptedEvsignedfile) 694 if err != nil { 695 t.Fatalf("unable to get utf16 of ntoskrnl.exe: %v", err) 696 } 697 data = &windows.WinTrustData{ 698 Size: uint32(unsafe.Sizeof(windows.WinTrustData{})), 699 UIChoice: windows.WTD_UI_NONE, 700 RevocationChecks: windows.WTD_REVOKE_NONE, // No revocation checking, in case the tests don't have network connectivity. 701 UnionChoice: windows.WTD_CHOICE_FILE, 702 StateAction: windows.WTD_STATEACTION_VERIFY, 703 FileOrCatalogOrBlobOrSgnrOrCert: unsafe.Pointer(&windows.WinTrustFileInfo{ 704 Size: uint32(unsafe.Sizeof(windows.WinTrustFileInfo{})), 705 FilePath: evsignedfile16, 706 }), 707 } 708 verifyErr = windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data) 709 data.StateAction = windows.WTD_STATEACTION_CLOSE 710 closeErr = windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data) 711 if verifyErr != windows.Errno(windows.TRUST_E_BAD_DIGEST) { 712 t.Errorf("%s did not fail to verify as expected: %v", corruptedEvsignedfile, verifyErr) 713 } 714 if closeErr != nil { 715 t.Errorf("unable to free verification resources: %v", closeErr) 716 } 717 718 } 719 720 func TestEnumProcesses(t *testing.T) { 721 var ( 722 pids [2]uint32 723 outSize uint32 724 ) 725 err := windows.EnumProcesses(pids[:], &outSize) 726 if err != nil { 727 t.Fatalf("unable to enumerate processes: %v", err) 728 } 729 730 // Regression check for go.dev/issue/60223 731 if outSize != 8 { 732 t.Errorf("unexpected bytes returned: %d", outSize) 733 } 734 // Most likely, this should be [0, 4]. 735 // 0 is the system idle pseudo-process. 4 is the initial system process ID. 736 // This test expects that at least one of the PIDs is not 0. 737 if pids[0] == 0 && pids[1] == 0 { 738 t.Errorf("all PIDs are 0") 739 } 740 } 741 742 func TestProcessModules(t *testing.T) { 743 process, err := windows.GetCurrentProcess() 744 if err != nil { 745 t.Fatalf("unable to get current process: %v", err) 746 } 747 // NB: Assume that we're always the first module. This technically isn't documented anywhere (that I could find), but seems to always hold. 748 var module windows.Handle 749 var cbNeeded uint32 750 err = windows.EnumProcessModules(process, &module, uint32(unsafe.Sizeof(module)), &cbNeeded) 751 if err != nil { 752 t.Fatalf("EnumProcessModules failed: %v", err) 753 } 754 755 var moduleEx windows.Handle 756 err = windows.EnumProcessModulesEx(process, &moduleEx, uint32(unsafe.Sizeof(moduleEx)), &cbNeeded, windows.LIST_MODULES_DEFAULT) 757 if err != nil { 758 t.Fatalf("EnumProcessModulesEx failed: %v", err) 759 } 760 if module != moduleEx { 761 t.Fatalf("module from EnumProcessModules does not match EnumProcessModulesEx: %v != %v", module, moduleEx) 762 } 763 764 exePath, err := os.Executable() 765 if err != nil { 766 t.Fatalf("unable to get current executable path: %v", err) 767 } 768 769 modulePathUTF16 := make([]uint16, len(exePath)+1) 770 err = windows.GetModuleFileNameEx(process, module, &modulePathUTF16[0], uint32(len(modulePathUTF16))) 771 if err != nil { 772 t.Fatalf("GetModuleFileNameEx failed: %v", err) 773 } 774 775 modulePath := windows.UTF16ToString(modulePathUTF16) 776 if modulePath != exePath { 777 t.Fatalf("module does not match executable for GetModuleFileNameEx: %s != %s", modulePath, exePath) 778 } 779 780 err = windows.GetModuleBaseName(process, module, &modulePathUTF16[0], uint32(len(modulePathUTF16))) 781 if err != nil { 782 t.Fatalf("GetModuleBaseName failed: %v", err) 783 } 784 785 modulePath = windows.UTF16ToString(modulePathUTF16) 786 baseExePath := filepath.Base(exePath) 787 if modulePath != baseExePath { 788 t.Fatalf("module does not match executable for GetModuleBaseName: %s != %s", modulePath, baseExePath) 789 } 790 791 var moduleInfo windows.ModuleInfo 792 err = windows.GetModuleInformation(process, module, &moduleInfo, uint32(unsafe.Sizeof(moduleInfo))) 793 if err != nil { 794 t.Fatalf("GetModuleInformation failed: %v", err) 795 } 796 797 peFile, err := pe.Open(exePath) 798 if err != nil { 799 t.Fatalf("unable to open current executable: %v", err) 800 } 801 defer peFile.Close() 802 803 var peSizeOfImage uint32 804 switch runtime.GOARCH { 805 case "amd64", "arm64": 806 peSizeOfImage = peFile.OptionalHeader.(*pe.OptionalHeader64).SizeOfImage 807 case "386", "arm": 808 peSizeOfImage = peFile.OptionalHeader.(*pe.OptionalHeader32).SizeOfImage 809 default: 810 t.Fatalf("unable to test GetModuleInformation on arch %v", runtime.GOARCH) 811 } 812 813 if moduleInfo.SizeOfImage != peSizeOfImage { 814 t.Fatalf("module size does not match executable: %v != %v", moduleInfo.SizeOfImage, peSizeOfImage) 815 } 816 } 817 818 func TestQueryWorkingSetEx(t *testing.T) { 819 var a int 820 821 process := windows.CurrentProcess() 822 information := windows.PSAPI_WORKING_SET_EX_INFORMATION{ 823 VirtualAddress: windows.Pointer(unsafe.Pointer(&a)), 824 } 825 infos := []windows.PSAPI_WORKING_SET_EX_INFORMATION{information} 826 827 cb := uint32(uintptr(len(infos)) * unsafe.Sizeof(infos[0])) 828 if err := windows.QueryWorkingSetEx(process, uintptr(unsafe.Pointer(&infos[0])), cb); err != nil { 829 t.Fatalf("%+v", err) 830 } 831 832 if !infos[0].VirtualAttributes.Valid() { 833 t.Errorf("memory location not valid") 834 } 835 } 836 837 func TestReadWriteProcessMemory(t *testing.T) { 838 testBuffer := []byte{0xBA, 0xAD, 0xF0, 0x0D} 839 840 process, err := windows.GetCurrentProcess() 841 if err != nil { 842 t.Fatalf("unable to get current process: %v", err) 843 } 844 845 buffer := make([]byte, len(testBuffer)) 846 err = windows.ReadProcessMemory(process, uintptr(unsafe.Pointer(&testBuffer[0])), &buffer[0], uintptr(len(buffer)), nil) 847 if err != nil { 848 t.Errorf("ReadProcessMemory failed: %v", err) 849 } 850 if !bytes.Equal(testBuffer, buffer) { 851 t.Errorf("bytes read does not match buffer: 0x%X != 0x%X", testBuffer, buffer) 852 } 853 854 buffer = []byte{0xDE, 0xAD, 0xBE, 0xEF} 855 err = windows.WriteProcessMemory(process, uintptr(unsafe.Pointer(&testBuffer[0])), &buffer[0], uintptr(len(buffer)), nil) 856 if err != nil { 857 t.Errorf("WriteProcessMemory failed: %v", err) 858 } 859 if !bytes.Equal(testBuffer, buffer) { 860 t.Errorf("bytes written does not match buffer: 0x%X != 0x%X", testBuffer, buffer) 861 } 862 } 863 864 func TestSystemModuleVersions(t *testing.T) { 865 var modules []windows.RTL_PROCESS_MODULE_INFORMATION 866 for bufferSize := uint32(128 * 1024); ; { 867 moduleBuffer := make([]byte, bufferSize) 868 err := windows.NtQuerySystemInformation(windows.SystemModuleInformation, unsafe.Pointer(&moduleBuffer[0]), bufferSize, &bufferSize) 869 switch err { 870 case windows.STATUS_INFO_LENGTH_MISMATCH: 871 continue 872 case nil: 873 break 874 default: 875 t.Error(err) 876 return 877 } 878 mods := (*windows.RTL_PROCESS_MODULES)(unsafe.Pointer(&moduleBuffer[0])) 879 hdr := (*unsafeheader.Slice)(unsafe.Pointer(&modules)) 880 hdr.Data = unsafe.Pointer(&mods.Modules[0]) 881 hdr.Len = int(mods.NumberOfModules) 882 hdr.Cap = int(mods.NumberOfModules) 883 break 884 } 885 for i := range modules { 886 moduleName := windows.ByteSliceToString(modules[i].FullPathName[modules[i].OffsetToFileName:]) 887 driverPath := `\\?\GLOBALROOT` + windows.ByteSliceToString(modules[i].FullPathName[:]) 888 var zero windows.Handle 889 infoSize, err := windows.GetFileVersionInfoSize(driverPath, &zero) 890 if err != nil { 891 if err != windows.ERROR_FILE_NOT_FOUND { 892 t.Error(err) 893 } 894 continue 895 } 896 versionInfo := make([]byte, infoSize) 897 err = windows.GetFileVersionInfo(driverPath, 0, infoSize, unsafe.Pointer(&versionInfo[0])) 898 if err != nil && err != windows.ERROR_FILE_NOT_FOUND { 899 t.Error(err) 900 continue 901 } 902 var fixedInfo *windows.VS_FIXEDFILEINFO 903 fixedInfoLen := uint32(unsafe.Sizeof(*fixedInfo)) 904 err = windows.VerQueryValue(unsafe.Pointer(&versionInfo[0]), `\`, (unsafe.Pointer)(&fixedInfo), &fixedInfoLen) 905 if err != nil { 906 t.Error(err) 907 continue 908 } 909 t.Logf("%s: v%d.%d.%d.%d", moduleName, 910 (fixedInfo.FileVersionMS>>16)&0xff, 911 (fixedInfo.FileVersionMS>>0)&0xff, 912 (fixedInfo.FileVersionLS>>16)&0xff, 913 (fixedInfo.FileVersionLS>>0)&0xff) 914 } 915 } 916 917 type fileRenameInformation struct { 918 ReplaceIfExists uint32 919 RootDirectory windows.Handle 920 FileNameLength uint32 921 FileName [1]uint16 922 } 923 924 func TestNtCreateFileAndNtSetInformationFile(t *testing.T) { 925 var iosb windows.IO_STATUS_BLOCK 926 var allocSize int64 = 0 927 // Open test directory with NtCreateFile. 928 testDirPath := t.TempDir() 929 objectName, err := windows.NewNTUnicodeString("\\??\\" + testDirPath) 930 if err != nil { 931 t.Fatal(err) 932 } 933 oa := &windows.OBJECT_ATTRIBUTES{ 934 ObjectName: objectName, 935 } 936 oa.Length = uint32(unsafe.Sizeof(*oa)) 937 var testDirHandle windows.Handle 938 err = windows.NtCreateFile(&testDirHandle, windows.FILE_GENERIC_READ|windows.FILE_GENERIC_WRITE, oa, &iosb, 939 &allocSize, 0, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, windows.FILE_OPEN, 940 windows.FILE_DIRECTORY_FILE, 0, 0) 941 if err != nil { 942 t.Fatalf("NtCreateFile(%v) failed: %v", testDirPath, err) 943 } 944 defer windows.CloseHandle(testDirHandle) 945 // Create a file in test directory with NtCreateFile. 946 fileName := "filename" 947 filePath := filepath.Join(testDirPath, fileName) 948 objectName, err = windows.NewNTUnicodeString(fileName) 949 if err != nil { 950 t.Fatal(err) 951 } 952 oa.RootDirectory = testDirHandle 953 oa.ObjectName = objectName 954 var fileHandle windows.Handle 955 err = windows.NtCreateFile(&fileHandle, windows.FILE_GENERIC_READ|windows.FILE_GENERIC_WRITE|windows.DELETE, oa, &iosb, 956 &allocSize, 0, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, windows.FILE_CREATE, 957 0, 0, 0) 958 if err != nil { 959 t.Fatalf("NtCreateFile(%v) failed: %v", filePath, err) 960 } 961 defer windows.CloseHandle(fileHandle) 962 _, err = os.Stat(filePath) 963 if err != nil { 964 t.Fatalf("cannot stat file created with NtCreatefile: %v", err) 965 } 966 // Rename file with NtSetInformationFile. 967 newName := "newname" 968 newPath := filepath.Join(testDirPath, newName) 969 newNameUTF16, err := windows.UTF16FromString(newName) 970 if err != nil { 971 t.Fatal(err) 972 } 973 fileNameLen := len(newNameUTF16)*2 - 2 974 var dummyFileRenameInfo fileRenameInformation 975 bufferSize := int(unsafe.Offsetof(dummyFileRenameInfo.FileName)) + fileNameLen 976 buffer := make([]byte, bufferSize) 977 typedBufferPtr := (*fileRenameInformation)(unsafe.Pointer(&buffer[0])) 978 typedBufferPtr.ReplaceIfExists = windows.FILE_RENAME_REPLACE_IF_EXISTS | windows.FILE_RENAME_POSIX_SEMANTICS 979 typedBufferPtr.FileNameLength = uint32(fileNameLen) 980 copy((*[windows.MAX_LONG_PATH]uint16)(unsafe.Pointer(&typedBufferPtr.FileName[0]))[:fileNameLen/2:fileNameLen/2], newNameUTF16) 981 err = windows.NtSetInformationFile(fileHandle, &iosb, &buffer[0], uint32(bufferSize), windows.FileRenameInformation) 982 if err != nil { 983 t.Fatalf("NtSetInformationFile(%v) failed: %v", newPath, err) 984 } 985 _, err = os.Stat(newPath) 986 if err != nil { 987 t.Fatalf("cannot stat rename target %v: %v", newPath, err) 988 } 989 } 990 991 var deviceClassNetGUID = &windows.GUID{0x4d36e972, 0xe325, 0x11ce, [8]byte{0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}} 992 var deviceInterfaceNetGUID = &windows.GUID{0xcac88484, 0x7515, 0x4c03, [8]byte{0x82, 0xe6, 0x71, 0xa8, 0x7a, 0xba, 0xc3, 0x61}} 993 994 func TestListLoadedNetworkDevices(t *testing.T) { 995 devInfo, err := windows.SetupDiGetClassDevsEx(deviceClassNetGUID, "", 0, windows.DIGCF_PRESENT, 0, "") 996 if err != nil { 997 t.Fatal(err) 998 } 999 defer devInfo.Close() 1000 for i := 0; ; i++ { 1001 devInfoData, err := devInfo.EnumDeviceInfo(i) 1002 if err != nil { 1003 if err == windows.ERROR_NO_MORE_ITEMS { 1004 break 1005 } 1006 continue 1007 } 1008 friendlyName, err := devInfo.DeviceRegistryProperty(devInfoData, windows.SPDRP_DEVICEDESC) 1009 if err != nil { 1010 t.Fatal(err) 1011 } 1012 var status, problemCode uint32 1013 err = windows.CM_Get_DevNode_Status(&status, &problemCode, devInfoData.DevInst, 0) 1014 if err != nil || (status&windows.DN_DRIVER_LOADED|windows.DN_STARTED) != windows.DN_DRIVER_LOADED|windows.DN_STARTED { 1015 continue 1016 } 1017 instanceId, err := devInfo.DeviceInstanceID(devInfoData) 1018 if err != nil { 1019 t.Fatal(err) 1020 } 1021 interfaces, err := windows.CM_Get_Device_Interface_List(instanceId, deviceInterfaceNetGUID, windows.CM_GET_DEVICE_INTERFACE_LIST_PRESENT) 1022 if err != nil || len(interfaces) == 0 { 1023 continue 1024 } 1025 t.Logf("%s - %s", friendlyName, interfaces[0]) 1026 } 1027 } 1028 1029 func TestListWireGuardDrivers(t *testing.T) { 1030 devInfo, err := windows.SetupDiCreateDeviceInfoListEx(deviceClassNetGUID, 0, "") 1031 if err != nil { 1032 t.Fatal(err) 1033 } 1034 defer devInfo.Close() 1035 devInfoData, err := devInfo.CreateDeviceInfo("WireGuard", deviceClassNetGUID, "", 0, windows.DICD_GENERATE_ID) 1036 if err != nil { 1037 t.Fatal(err) 1038 } 1039 err = devInfo.SetDeviceRegistryProperty(devInfoData, windows.SPDRP_HARDWAREID, []byte("W\x00i\x00r\x00e\x00G\x00u\x00a\x00r\x00d\x00\x00\x00\x00\x00")) 1040 if err != nil { 1041 t.Fatal(err) 1042 } 1043 err = devInfo.BuildDriverInfoList(devInfoData, windows.SPDIT_COMPATDRIVER) 1044 if err != nil { 1045 t.Fatal(err) 1046 } 1047 defer devInfo.DestroyDriverInfoList(devInfoData, windows.SPDIT_COMPATDRIVER) 1048 for i := 0; ; i++ { 1049 drvInfoData, err := devInfo.EnumDriverInfo(devInfoData, windows.SPDIT_COMPATDRIVER, i) 1050 if err != nil { 1051 if err == windows.ERROR_NO_MORE_ITEMS { 1052 break 1053 } 1054 continue 1055 } 1056 drvInfoDetailData, err := devInfo.DriverInfoDetail(devInfoData, drvInfoData) 1057 if err != nil { 1058 t.Error(err) 1059 continue 1060 } 1061 t.Logf("%s - %s", drvInfoData.Description(), drvInfoDetailData.InfFileName()) 1062 } 1063 } 1064 1065 func TestProcThreadAttributeHandleList(t *testing.T) { 1066 const sentinel = "the gopher dance" 1067 system32, err := windows.GetSystemDirectory() 1068 if err != nil { 1069 t.Fatal(err) 1070 } 1071 executable16, err := windows.UTF16PtrFromString(filepath.Join(system32, "cmd.exe")) 1072 if err != nil { 1073 t.Fatal(err) 1074 } 1075 args16, err := windows.UTF16PtrFromString(windows.ComposeCommandLine([]string{"/c", "echo " + sentinel})) 1076 if err != nil { 1077 t.Fatal(err) 1078 } 1079 attributeList, err := windows.NewProcThreadAttributeList(1) 1080 if err != nil { 1081 t.Fatal(err) 1082 } 1083 defer attributeList.Delete() 1084 si := &windows.StartupInfoEx{ 1085 StartupInfo: windows.StartupInfo{Cb: uint32(unsafe.Sizeof(windows.StartupInfoEx{}))}, 1086 ProcThreadAttributeList: attributeList.List(), 1087 } 1088 pipeR, pipeW, err := os.Pipe() 1089 if err != nil { 1090 t.Fatal(err) 1091 } 1092 defer pipeR.Close() 1093 defer pipeW.Close() 1094 func() { 1095 // We allocate handles in a closure to provoke a UaF in the case of attributeList.Update being buggy. 1096 handles := []windows.Handle{windows.Handle(pipeW.Fd())} 1097 attributeList.Update(windows.PROC_THREAD_ATTRIBUTE_HANDLE_LIST, unsafe.Pointer(&handles[0]), uintptr(len(handles))*unsafe.Sizeof(handles[0])) 1098 si.Flags |= windows.STARTF_USESTDHANDLES 1099 si.StdOutput = handles[0] 1100 // Go 1.16's pipe handles aren't inheritable, so mark it explicitly as such here. 1101 windows.SetHandleInformation(handles[0], windows.HANDLE_FLAG_INHERIT, windows.HANDLE_FLAG_INHERIT) 1102 }() 1103 pi := new(windows.ProcessInformation) 1104 err = windows.CreateProcess(executable16, args16, nil, nil, true, windows.CREATE_DEFAULT_ERROR_MODE|windows.CREATE_UNICODE_ENVIRONMENT|windows.EXTENDED_STARTUPINFO_PRESENT, nil, nil, &si.StartupInfo, pi) 1105 if err != nil { 1106 t.Fatal(err) 1107 } 1108 defer windows.CloseHandle(pi.Thread) 1109 defer windows.CloseHandle(pi.Process) 1110 pipeR.SetReadDeadline(time.Now().Add(time.Minute)) 1111 out, _, err := bufio.NewReader(pipeR).ReadLine() 1112 if err != nil { 1113 t.Fatal(err) 1114 } 1115 if string(out) != sentinel { 1116 t.Fatalf("got %q; want %q", out, sentinel) 1117 } 1118 } 1119 1120 func TestWSALookupService(t *testing.T) { 1121 var flags uint32 = windows.LUP_CONTAINERS 1122 flags |= windows.LUP_RETURN_NAME 1123 flags |= windows.LUP_RETURN_ADDR 1124 1125 var querySet windows.WSAQUERYSET 1126 querySet.NameSpace = windows.NS_BTH 1127 querySet.Size = uint32(unsafe.Sizeof(windows.WSAQUERYSET{})) 1128 1129 var handle windows.Handle 1130 err := windows.WSALookupServiceBegin(&querySet, flags, &handle) 1131 if err != nil { 1132 if errors.Is(err, windows.WSASERVICE_NOT_FOUND) { 1133 t.Skip("WSA Service not found, so skip this test") 1134 } 1135 t.Fatal(err) 1136 } 1137 1138 defer windows.WSALookupServiceEnd(handle) 1139 1140 n := int32(unsafe.Sizeof(windows.WSAQUERYSET{})) 1141 buf := make([]byte, n) 1142 items_loop: 1143 for { 1144 q := (*windows.WSAQUERYSET)(unsafe.Pointer(&buf[0])) 1145 err := windows.WSALookupServiceNext(handle, flags, &n, q) 1146 switch err { 1147 case windows.WSA_E_NO_MORE, windows.WSAENOMORE: 1148 // no more data available - break the loop 1149 break items_loop 1150 case windows.WSAEFAULT: 1151 // buffer is too small - reallocate and try again 1152 buf = make([]byte, n) 1153 case nil: 1154 // found a record - display the item and fetch next item 1155 var addr string 1156 for _, e := range q.SaBuffer.RemoteAddr.Sockaddr.Addr.Data { 1157 if e != 0 { 1158 addr += fmt.Sprintf("%x", e) 1159 } 1160 } 1161 t.Logf("%s -> %s\n", windows.UTF16PtrToString(q.ServiceInstanceName), addr) 1162 1163 default: 1164 t.Fatal(err) 1165 } 1166 } 1167 }