@@ -29,6 +29,8 @@ import (
29
29
30
30
"k8s.io/apimachinery/pkg/util/wait"
31
31
"k8s.io/klog/v2"
32
+
33
+ "golang.org/x/sys/windows"
32
34
)
33
35
34
36
const (
@@ -88,6 +90,160 @@ func IsUnixDomainSocket(filePath string) (bool, error) {
88
90
return true , nil
89
91
}
90
92
93
+ // On Windows os.Mkdir all doesn't set any permissions so call the Chown function below to set
94
+ // permissions once the directory is created.
95
+ func MkdirAll (path string , perm os.FileMode ) error {
96
+ klog .V (6 ).InfoS ("Function MkdirAll starts" , "path" , path , "perm" , perm )
97
+ err := os .MkdirAll (path , perm )
98
+ if err != nil {
99
+ return fmt .Errorf ("Error creating directory %s: %v" , path , err )
100
+ }
101
+
102
+ err = Chmod (path , perm )
103
+ if err != nil {
104
+ return fmt .Errorf ("Error setting permissions for directory %s: %v" , path , err )
105
+ }
106
+
107
+ return nil
108
+ }
109
+
110
+ const (
111
+ // These aren't defined in the syscall package for Windows :(
112
+ USER_READ = 0x100
113
+ USER_WRITE = 0x80
114
+ USER_EXECUTE = 0x40
115
+ GROUP_READ = 0x20
116
+ GROUP_WRITE = 0x10
117
+ GROUP_EXECUTE = 0x8
118
+ OTHERS_READ = 0x4
119
+ OTHERS_WRITE = 0x2
120
+ OTHERS_EXECUTE = 0x1
121
+ USER_ALL = USER_READ | USER_WRITE | USER_EXECUTE
122
+ GROUP_ALL = GROUP_READ | GROUP_WRITE | GROUP_EXECUTE
123
+ OTHERS_ALL = OTHERS_READ | OTHERS_WRITE | OTHERS_EXECUTE
124
+ )
125
+
126
+ // On Windows os.Chmod only sets the read-only flag on files, so we need to use Windows APIs to set the desired access on files / directories.
127
+ // The OWNER mode will set file permissions for the file owner SID, the GROUP mode will set file permissions for the file group SID,
128
+ // and the OTHERS mode will set file permissions for BUILTIN\Users.
129
+ // Please note that Windows containers can be run as one of two user accounts; ContainerUser or ContainerAdministrator.
130
+ // Containers run as ContainerAdministrator will inherit permissions from BUILTIN\Administrators,
131
+ // while containers run as ContainerUser will inherit permissions from BUILTIN\Users.
132
+ // Windows containers do not have the ability to run as a custom user account that is known to the host so the OTHERS group mode
133
+ // is used to grant / deny permissions of files on the hosts to the ContainerUser account.
134
+ func Chmod (path string , filemode os.FileMode ) error {
135
+ klog .V (6 ).InfoS ("Function Chmod starts" , "path" , path , "filemode" , filemode )
136
+ // Get security descriptor for the file
137
+ sd , err := windows .GetNamedSecurityInfo (
138
+ path ,
139
+ windows .SE_FILE_OBJECT ,
140
+ windows .DACL_SECURITY_INFORMATION | windows .PROTECTED_DACL_SECURITY_INFORMATION | windows .OWNER_SECURITY_INFORMATION | windows .GROUP_SECURITY_INFORMATION )
141
+ if err != nil {
142
+ return fmt .Errorf ("Error getting security descriptor for file %s: %v" , path , err )
143
+ }
144
+
145
+ // Get owner SID from the security descriptor for assigning USER permissions
146
+ owner , _ , err := sd .Owner ()
147
+ if err != nil {
148
+ return fmt .Errorf ("Error getting owner SID for file %s: %v" , path , err )
149
+ }
150
+ ownerString := owner .String ()
151
+
152
+ // Get the group SID from the security descriptor for assigning GROUP permissions
153
+ group , _ , err := sd .Group ()
154
+ if err != nil {
155
+ return fmt .Errorf ("Error getting group SID for file %s: %v" , path , err )
156
+ }
157
+ groupString := group .String ()
158
+
159
+ mask := uint32 (windows .ACCESS_MASK (filemode ))
160
+
161
+ // Build a new Discretionary Access Control List (DACL) with the desired permissions using
162
+ //the Security Descriptor Definition Language (SDDL) format.
163
+ // https://learn.microsoft.com/windows/win32/secauthz/security-descriptor-definition-language
164
+ // the DACL is a list of Access Control Entries (ACEs) where each ACE represents the permissions (Allow or Deny) for a specific SID.
165
+ // Each ACE has the following format:
166
+ // (AceType;AceFlags;Rights;ObjectGuid;InheritObjectGuid;AccountSid)
167
+ // We can leave ObjectGuid and InheritObjectGuid empty for our purposes.
168
+
169
+ dacl := "D:"
170
+
171
+ // build the owner ACE
172
+ dacl += "(A;OICI;"
173
+ if mask & USER_ALL == USER_ALL {
174
+ dacl += "FA"
175
+ } else {
176
+ if mask & USER_READ == USER_READ {
177
+ dacl += "FR"
178
+ }
179
+ if mask & USER_WRITE == USER_WRITE {
180
+ dacl += "FW"
181
+ }
182
+ if mask & USER_EXECUTE == USER_EXECUTE {
183
+ dacl += "FX"
184
+ }
185
+ }
186
+ dacl += ";;;" + ownerString + ")"
187
+
188
+ // Build the group ACE
189
+ dacl += "(A;OICI;"
190
+ if mask & GROUP_ALL == GROUP_ALL {
191
+ dacl += "FA"
192
+ } else {
193
+ if mask & GROUP_READ == GROUP_READ {
194
+ dacl += "FR"
195
+ }
196
+ if mask & GROUP_WRITE == GROUP_WRITE {
197
+ dacl += "FW"
198
+ }
199
+ if mask & GROUP_EXECUTE == GROUP_EXECUTE {
200
+ dacl += "FX"
201
+ }
202
+ }
203
+ dacl += ";;;" + groupString + ")"
204
+
205
+ // Build the others ACE
206
+ dacl += "(A;OICI;"
207
+ if mask & OTHERS_ALL == OTHERS_ALL {
208
+ dacl += "FA"
209
+ } else {
210
+ if mask & OTHERS_READ == OTHERS_READ {
211
+ dacl += "FR"
212
+ }
213
+ if mask & OTHERS_WRITE == OTHERS_WRITE {
214
+ dacl += "FW"
215
+ }
216
+ if mask & OTHERS_EXECUTE == OTHERS_EXECUTE {
217
+ dacl += "FX"
218
+ }
219
+ }
220
+ dacl += ";;;BU)"
221
+
222
+ klog .V (6 ).InfoS ("Setting new DACL for path" , "path" , path , "dacl" , dacl )
223
+
224
+ // create a new security descriptor from the DACL string
225
+ newSD , err := windows .SecurityDescriptorFromString (dacl )
226
+ if err != nil {
227
+ return fmt .Errorf ("Error creating new security descriptor from DACL string: %v" , err )
228
+ }
229
+
230
+ // get the DACL in binary format from the newly created security descriptor
231
+ newDACL , _ , err := newSD .DACL ()
232
+ if err != nil {
233
+ return fmt .Errorf ("Error getting DACL from new security descriptor: %v" , err )
234
+ }
235
+
236
+ // Write the new security descriptor to the file
237
+ return windows .SetNamedSecurityInfo (
238
+ path ,
239
+ windows .SE_FILE_OBJECT ,
240
+ windows .DACL_SECURITY_INFORMATION | windows .PROTECTED_DACL_SECURITY_INFORMATION ,
241
+ nil , // owner SID
242
+ nil , // group SID
243
+ newDACL ,
244
+ nil ) // SACL
245
+ }
246
+
91
247
// IsAbs returns whether the given path is absolute or not.
92
248
// On Windows, filepath.IsAbs will not return True for paths prefixed with a slash, even
93
249
// though they can be used as absolute paths (https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats).
0 commit comments