1
2
3
4 package security
5
6 import (
7 "fmt"
8 "os"
9 "syscall"
10 "unsafe"
11 )
12
13 type (
14 accessMask uint32
15 accessMode uint32
16 desiredAccess uint32
17 inheritMode uint32
18 objectType uint32
19 shareMode uint32
20 securityInformation uint32
21 trusteeForm uint32
22 trusteeType uint32
23 )
24
25 type explicitAccess struct {
26 accessPermissions accessMask
27 accessMode accessMode
28 inheritance inheritMode
29 trustee trustee
30 }
31
32 type trustee struct {
33 multipleTrustee *trustee
34 multipleTrusteeOperation int32
35 trusteeForm trusteeForm
36 trusteeType trusteeType
37 name uintptr
38 }
39
40 const (
41 AccessMaskNone accessMask = 0
42 AccessMaskRead accessMask = 1 << 31
43 AccessMaskWrite accessMask = 1 << 30
44 AccessMaskExecute accessMask = 1 << 29
45 AccessMaskAll accessMask = 1 << 28
46
47 accessMaskDesiredPermission = AccessMaskRead
48
49 accessModeGrant accessMode = 1
50
51 desiredAccessReadControl desiredAccess = 0x20000
52 desiredAccessWriteDac desiredAccess = 0x40000
53
54 gvmga = "GrantVmGroupAccess:"
55
56 inheritModeNoInheritance inheritMode = 0x0
57 inheritModeSubContainersAndObjectsInherit inheritMode = 0x3
58
59 objectTypeFileObject objectType = 0x1
60
61 securityInformationDACL securityInformation = 0x4
62
63 shareModeRead shareMode = 0x1
64 shareModeWrite shareMode = 0x2
65
66
67 sidVmGroup = "S-1-5-83-0"
68
69 trusteeFormIsSid trusteeForm = 0
70
71 trusteeTypeWellKnownGroup trusteeType = 5
72 )
73
74
75
76
77
78 func GrantVmGroupAccess(name string) error {
79 return GrantVmGroupAccessWithMask(name, accessMaskDesiredPermission)
80 }
81
82
83
84 func GrantVmGroupAccessWithMask(name string, access accessMask) error {
85 if access == 0 || access<<4 != 0 {
86 return fmt.Errorf("invalid access mask: 0x%08x", access)
87 }
88
89 s, err := os.Stat(name)
90 if err != nil {
91 return fmt.Errorf("%s os.Stat %s: %w", gvmga, name, err)
92 }
93
94
95 fd, err := createFile(name, s.IsDir())
96 if err != nil {
97 return err
98 }
99 defer func() {
100 _ = syscall.CloseHandle(fd)
101 }()
102
103
104 ot := objectTypeFileObject
105 si := securityInformationDACL
106 sd := uintptr(0)
107 origDACL := uintptr(0)
108 if err := getSecurityInfo(fd, uint32(ot), uint32(si), nil, nil, &origDACL, nil, &sd); err != nil {
109 return fmt.Errorf("%s GetSecurityInfo %s: %w", gvmga, name, err)
110 }
111 defer func() {
112 _, _ = syscall.LocalFree((syscall.Handle)(unsafe.Pointer(sd)))
113 }()
114
115
116
117 newDACL, err := generateDACLWithAcesAdded(name, s.IsDir(), access, origDACL)
118 if err != nil {
119 return err
120 }
121 defer func() {
122 _, _ = syscall.LocalFree((syscall.Handle)(unsafe.Pointer(newDACL)))
123 }()
124
125
126 if err := setSecurityInfo(fd, uint32(ot), uint32(si), uintptr(0), uintptr(0), newDACL, uintptr(0)); err != nil {
127 return fmt.Errorf("%s SetSecurityInfo %s: %w", gvmga, name, err)
128 }
129
130 return nil
131 }
132
133
134
135 func createFile(name string, isDir bool) (syscall.Handle, error) {
136 namep, err := syscall.UTF16FromString(name)
137 if err != nil {
138 return 0, fmt.Errorf("syscall.UTF16FromString %s: %w", name, err)
139 }
140 da := uint32(desiredAccessReadControl | desiredAccessWriteDac)
141 sm := uint32(shareModeRead | shareModeWrite)
142 fa := uint32(syscall.FILE_ATTRIBUTE_NORMAL)
143 if isDir {
144 fa = uint32(fa | syscall.FILE_FLAG_BACKUP_SEMANTICS)
145 }
146 fd, err := syscall.CreateFile(&namep[0], da, sm, nil, syscall.OPEN_EXISTING, fa, 0)
147 if err != nil {
148 return 0, fmt.Errorf("%s syscall.CreateFile %s: %w", gvmga, name, err)
149 }
150 return fd, nil
151 }
152
153
154
155 func generateDACLWithAcesAdded(name string, isDir bool, desiredAccess accessMask, origDACL uintptr) (uintptr, error) {
156
157 sid, err := syscall.StringToSid(sidVmGroup)
158 if err != nil {
159 return 0, fmt.Errorf("%s syscall.StringToSid %s %s: %w", gvmga, name, sidVmGroup, err)
160 }
161
162 inheritance := inheritModeNoInheritance
163 if isDir {
164 inheritance = inheritModeSubContainersAndObjectsInherit
165 }
166
167 eaArray := []explicitAccess{
168 {
169 accessPermissions: desiredAccess,
170 accessMode: accessModeGrant,
171 inheritance: inheritance,
172 trustee: trustee{
173 trusteeForm: trusteeFormIsSid,
174 trusteeType: trusteeTypeWellKnownGroup,
175 name: uintptr(unsafe.Pointer(sid)),
176 },
177 },
178 }
179
180 modifiedDACL := uintptr(0)
181 if err := setEntriesInAcl(uintptr(uint32(1)), uintptr(unsafe.Pointer(&eaArray[0])), origDACL, &modifiedDACL); err != nil {
182 return 0, fmt.Errorf("%s SetEntriesInAcl %s: %w", gvmga, name, err)
183 }
184
185 return modifiedDACL, nil
186 }
187
View as plain text