github.com/Serizao/go-winio@v0.0.0-20230906082528-f02f7f4ad6e8/pkg/security/grantvmgroupaccess_test.go (about) 1 //go:build windows 2 // +build windows 3 4 package security 5 6 import ( 7 "os" 8 "path/filepath" 9 "regexp" 10 "strings" 11 "testing" 12 13 exec "golang.org/x/sys/execabs" 14 ) 15 16 const ( 17 vmAccountName = `NT VIRTUAL MACHINE\\Virtual Machines` 18 vmAccountSID = "S-1-5-83-0" 19 ) 20 21 // TestGrantVmGroupAccess verifies for the three case of a file, a directory, 22 // and a file in a directory that the appropriate ACEs are set, including 23 // inheritance in the second two examples. These are the expected ACES. Is 24 // verified by running icacls and comparing output. 25 // 26 // File: 27 // S-1-15-3-1024-2268835264-3721307629-241982045-173645152-1490879176-104643441-2915960892-1612460704:(R,W) 28 // S-1-5-83-1-3166535780-1122986932-343720105-43916321:(R,W) 29 // 30 // Directory: 31 // S-1-15-3-1024-2268835264-3721307629-241982045-173645152-1490879176-104643441-2915960892-1612460704:(OI)(CI)(R,W) 32 // S-1-5-83-1-3166535780-1122986932-343720105-43916321:(OI)(CI)(R,W) 33 // 34 // File in directory (inherited): 35 // S-1-15-3-1024-2268835264-3721307629-241982045-173645152-1490879176-104643441-2915960892-1612460704:(I)(R,W) 36 // S-1-5-83-1-3166535780-1122986932-343720105-43916321:(I)(R,W) 37 38 func TestGrantVmGroupAccess(t *testing.T) { 39 f, err := os.CreateTemp("", "gvmgafile") 40 if err != nil { 41 t.Fatal(err) 42 } 43 defer func() { 44 f.Close() 45 os.Remove(f.Name()) 46 }() 47 48 d := t.TempDir() 49 find, err := os.Create(filepath.Join(d, "find.txt")) 50 if err != nil { 51 t.Fatal(err) 52 } 53 defer find.Close() 54 55 if err := GrantVmGroupAccess(f.Name()); err != nil { 56 t.Fatal(err) 57 } 58 59 if err := GrantVmGroupAccess(d); err != nil { 60 t.Fatal(err) 61 } 62 63 verifyVMAccountDACLs(t, 64 f.Name(), 65 []string{`(R)`}, 66 ) 67 68 // Two items here: 69 // - One explicit read only. 70 // - Other applies to this folder, subfolders and files 71 // (OI): object inherit 72 // (CI): container inherit 73 // (IO): inherit only 74 // (GR): generic read 75 // 76 // In properties for the directory, advanced security settings, this will 77 // show as a single line "Allow/Virtual Machines/Read/Inherited from none/This folder, subfolder and files 78 verifyVMAccountDACLs(t, 79 d, 80 []string{`(R)`, `(OI)(CI)(IO)(GR)`}, 81 ) 82 83 verifyVMAccountDACLs(t, 84 find.Name(), 85 []string{`(I)(R)`}, 86 ) 87 } 88 89 func verifyVMAccountDACLs(t *testing.T, name string, permissions []string) { 90 t.Helper() 91 92 cmd := exec.Command("icacls", name) 93 outb, err := cmd.CombinedOutput() 94 if err != nil { 95 t.Fatal(err) 96 } 97 out := string(outb) 98 99 for _, p := range permissions { 100 // Avoid '(' and ')' being part of match groups 101 p = strings.Replace(p, "(", "\\(", -1) 102 p = strings.Replace(p, ")", "\\)", -1) 103 104 nameToCheck := vmAccountName + ":" + p 105 sidToCheck := vmAccountSID + ":" + p 106 107 rxName := regexp.MustCompile(nameToCheck) 108 rxSID := regexp.MustCompile(sidToCheck) 109 110 matchesName := rxName.FindAllStringIndex(out, -1) 111 matchesSID := rxSID.FindAllStringIndex(out, -1) 112 113 if len(matchesName) != 1 && len(matchesSID) != 1 { 114 t.Fatalf("expected one match for %s or %s\n%s", nameToCheck, sidToCheck, out) 115 } 116 } 117 }