2023-01-27 21:37:20 +00:00
|
|
|
// Copyright (c) Tailscale Inc & AUTHORS
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
2022-11-24 22:51:19 +00:00
|
|
|
|
|
|
|
package winutil
|
|
|
|
|
|
|
|
import (
|
2023-05-09 21:51:20 +00:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
2022-11-24 22:51:19 +00:00
|
|
|
"testing"
|
2023-05-09 21:51:20 +00:00
|
|
|
|
|
|
|
"golang.org/x/exp/maps"
|
|
|
|
"golang.org/x/sys/windows/registry"
|
2022-11-24 22:51:19 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
localSystemSID = "S-1-5-18"
|
|
|
|
networkSID = "S-1-5-2"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestLookupPseudoUser(t *testing.T) {
|
|
|
|
localSystem, err := LookupPseudoUser(localSystemSID)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("LookupPseudoUser(%q) error: %v", localSystemSID, err)
|
|
|
|
}
|
|
|
|
if localSystem.Gid != localSystemSID {
|
|
|
|
t.Errorf("incorrect Gid, got %q, want %q", localSystem.Gid, localSystemSID)
|
|
|
|
}
|
|
|
|
t.Logf("localSystem: %v", localSystem)
|
|
|
|
|
|
|
|
// networkSID is a built-in known group but not a pseudo-user.
|
|
|
|
_, err = LookupPseudoUser(networkSID)
|
|
|
|
if err == nil {
|
|
|
|
t.Errorf("LookupPseudoUser(%q) unexpectedly succeeded", networkSID)
|
|
|
|
}
|
|
|
|
}
|
2023-05-09 21:51:20 +00:00
|
|
|
|
|
|
|
func makeLongBinaryValue() []byte {
|
|
|
|
buf := make([]byte, maxBinaryValueLen*2)
|
|
|
|
for i, _ := range buf {
|
|
|
|
buf[i] = byte(i % 0xFF)
|
|
|
|
}
|
|
|
|
return buf
|
|
|
|
}
|
|
|
|
|
|
|
|
var testData = map[string]any{
|
|
|
|
"": "I am the default",
|
|
|
|
"StringEmpty": "",
|
|
|
|
"StringShort": "Hello",
|
|
|
|
"StringLong": strings.Repeat("7", initialValueBufLen+1),
|
|
|
|
"MultiStringEmpty": []string{},
|
|
|
|
"MultiStringSingle": []string{"Foo"},
|
|
|
|
"MultiStringSingleEmpty": []string{""},
|
|
|
|
"MultiString": []string{"Foo", "Bar", "Baz"},
|
|
|
|
"MultiStringWithEmptyBeginning": []string{"", "Foo", "Bar"},
|
|
|
|
"MultiStringWithEmptyMiddle": []string{"Foo", "", "Bar"},
|
|
|
|
"MultiStringWithEmptyEnd": []string{"Foo", "Bar", ""},
|
|
|
|
"DWord": uint32(0x12345678),
|
|
|
|
"QWord": uint64(0x123456789abcdef0),
|
|
|
|
"BinaryEmpty": []byte{},
|
|
|
|
"BinaryShort": []byte{0x01, 0x02, 0x03, 0x04},
|
|
|
|
"BinaryLong": makeLongBinaryValue(),
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
keyNameTest = `SOFTWARE\Tailscale Test`
|
|
|
|
subKeyNameTest = "SubKey"
|
|
|
|
)
|
|
|
|
|
|
|
|
func setValues(t *testing.T, k registry.Key) {
|
|
|
|
for vk, v := range testData {
|
|
|
|
var err error
|
|
|
|
switch tv := v.(type) {
|
|
|
|
case string:
|
|
|
|
err = k.SetStringValue(vk, tv)
|
|
|
|
case []string:
|
|
|
|
err = k.SetStringsValue(vk, tv)
|
|
|
|
case uint32:
|
|
|
|
err = k.SetDWordValue(vk, tv)
|
|
|
|
case uint64:
|
|
|
|
err = k.SetQWordValue(vk, tv)
|
|
|
|
case []byte:
|
|
|
|
err = k.SetBinaryValue(vk, tv)
|
|
|
|
default:
|
|
|
|
t.Fatalf("Unknown type")
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Error setting %q: %v", vk, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRegistrySupportInfo(t *testing.T) {
|
|
|
|
// Make sure the key doesn't exist yet
|
|
|
|
k, err := registry.OpenKey(registry.CURRENT_USER, keyNameTest, registry.READ)
|
|
|
|
switch {
|
|
|
|
case err == nil:
|
|
|
|
k.Close()
|
|
|
|
t.Fatalf("Test key already exists")
|
|
|
|
case !errors.Is(err, registry.ErrNotExist):
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func() {
|
|
|
|
k, _, err := registry.CreateKey(registry.CURRENT_USER, keyNameTest, registry.WRITE)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Error creating test key: %v", err)
|
|
|
|
}
|
|
|
|
defer k.Close()
|
|
|
|
|
|
|
|
setValues(t, k)
|
|
|
|
|
|
|
|
sk, _, err := registry.CreateKey(k, subKeyNameTest, registry.WRITE)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Error creating test subkey: %v", err)
|
|
|
|
}
|
|
|
|
defer sk.Close()
|
|
|
|
|
|
|
|
setValues(t, sk)
|
|
|
|
}()
|
|
|
|
|
|
|
|
t.Cleanup(func() {
|
|
|
|
registry.DeleteKey(registry.CURRENT_USER, keyNameTest+"\\"+subKeyNameTest)
|
|
|
|
registry.DeleteKey(registry.CURRENT_USER, keyNameTest)
|
|
|
|
})
|
|
|
|
|
|
|
|
wantValuesData := maps.Clone(testData)
|
|
|
|
wantValuesData["BinaryLong"] = (wantValuesData["BinaryLong"].([]byte))[:maxBinaryValueLen]
|
|
|
|
|
|
|
|
wantKeyData := make(map[string]any)
|
|
|
|
maps.Copy(wantKeyData, wantValuesData)
|
|
|
|
wantSubKeyData := make(map[string]any)
|
|
|
|
maps.Copy(wantSubKeyData, wantValuesData)
|
|
|
|
wantKeyData[subKeyNameTest] = wantSubKeyData
|
|
|
|
|
|
|
|
wantData := map[string]any{
|
|
|
|
"HKCU\\" + keyNameTest: wantKeyData,
|
|
|
|
}
|
|
|
|
|
|
|
|
gotData, err := getRegistrySupportInfo(registry.CURRENT_USER, []string{keyNameTest})
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("getRegistrySupportInfo error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
want, got := fmt.Sprintf("%#v", wantData), fmt.Sprintf("%#v", gotData)
|
|
|
|
if want != got {
|
|
|
|
t.Errorf("Compare error: want\n%s,\ngot %s", want, got)
|
|
|
|
}
|
|
|
|
}
|