Commit | Line | Data |
---|---|---|
e2f34481 NJ |
1 | // SPDX-License-Identifier: LGPL-2.1+ |
2 | /* | |
3 | * Copyright (C) International Business Machines Corp., 2007,2008 | |
4 | * Author(s): Steve French (sfrench@us.ibm.com) | |
5 | * Copyright (C) 2020 Samsung Electronics Co., Ltd. | |
6 | * Author(s): Namjae Jeon <linkinjeon@kernel.org> | |
7 | */ | |
8 | ||
9 | #include <linux/fs.h> | |
10 | #include <linux/slab.h> | |
11 | #include <linux/string.h> | |
a793d79e | 12 | #include <linux/mnt_idmapping.h> |
e2f34481 NJ |
13 | |
14 | #include "smbacl.h" | |
15 | #include "smb_common.h" | |
16 | #include "server.h" | |
17 | #include "misc.h" | |
e2f34481 NJ |
18 | #include "mgmt/share_config.h" |
19 | ||
20 | static const struct smb_sid domain = {1, 4, {0, 0, 0, 0, 0, 5}, | |
21 | {cpu_to_le32(21), cpu_to_le32(1), cpu_to_le32(2), cpu_to_le32(3), | |
22 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; | |
23 | ||
24 | /* security id for everyone/world system group */ | |
25 | static const struct smb_sid creator_owner = { | |
26 | 1, 1, {0, 0, 0, 0, 0, 3}, {0} }; | |
27 | /* security id for everyone/world system group */ | |
28 | static const struct smb_sid creator_group = { | |
29 | 1, 1, {0, 0, 0, 0, 0, 3}, {cpu_to_le32(1)} }; | |
30 | ||
31 | /* security id for everyone/world system group */ | |
32 | static const struct smb_sid sid_everyone = { | |
33 | 1, 1, {0, 0, 0, 0, 0, 1}, {0} }; | |
34 | /* security id for Authenticated Users system group */ | |
35 | static const struct smb_sid sid_authusers = { | |
36 | 1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(11)} }; | |
37 | ||
38 | /* S-1-22-1 Unmapped Unix users */ | |
39 | static const struct smb_sid sid_unix_users = {1, 1, {0, 0, 0, 0, 0, 22}, | |
40 | {cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; | |
41 | ||
42 | /* S-1-22-2 Unmapped Unix groups */ | |
43 | static const struct smb_sid sid_unix_groups = { 1, 1, {0, 0, 0, 0, 0, 22}, | |
44 | {cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; | |
45 | ||
46 | /* | |
47 | * See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx | |
48 | */ | |
49 | ||
50 | /* S-1-5-88 MS NFS and Apple style UID/GID/mode */ | |
51 | ||
52 | /* S-1-5-88-1 Unix uid */ | |
53 | static const struct smb_sid sid_unix_NFS_users = { 1, 2, {0, 0, 0, 0, 0, 5}, | |
54 | {cpu_to_le32(88), | |
55 | cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; | |
56 | ||
57 | /* S-1-5-88-2 Unix gid */ | |
58 | static const struct smb_sid sid_unix_NFS_groups = { 1, 2, {0, 0, 0, 0, 0, 5}, | |
59 | {cpu_to_le32(88), | |
60 | cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; | |
61 | ||
62 | /* S-1-5-88-3 Unix mode */ | |
63 | static const struct smb_sid sid_unix_NFS_mode = { 1, 2, {0, 0, 0, 0, 0, 5}, | |
64 | {cpu_to_le32(88), | |
65 | cpu_to_le32(3), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; | |
66 | ||
67 | /* | |
68 | * if the two SIDs (roughly equivalent to a UUID for a user or group) are | |
69 | * the same returns zero, if they do not match returns non-zero. | |
70 | */ | |
64b39f4a | 71 | int compare_sids(const struct smb_sid *ctsid, const struct smb_sid *cwsid) |
e2f34481 NJ |
72 | { |
73 | int i; | |
74 | int num_subauth, num_sat, num_saw; | |
75 | ||
64b39f4a | 76 | if (!ctsid || !cwsid) |
e2f34481 NJ |
77 | return 1; |
78 | ||
79 | /* compare the revision */ | |
80 | if (ctsid->revision != cwsid->revision) { | |
81 | if (ctsid->revision > cwsid->revision) | |
82 | return 1; | |
83 | else | |
84 | return -1; | |
85 | } | |
86 | ||
87 | /* compare all of the six auth values */ | |
88 | for (i = 0; i < NUM_AUTHS; ++i) { | |
89 | if (ctsid->authority[i] != cwsid->authority[i]) { | |
90 | if (ctsid->authority[i] > cwsid->authority[i]) | |
91 | return 1; | |
92 | else | |
93 | return -1; | |
94 | } | |
95 | } | |
96 | ||
97 | /* compare all of the subauth values if any */ | |
98 | num_sat = ctsid->num_subauth; | |
99 | num_saw = cwsid->num_subauth; | |
100 | num_subauth = num_sat < num_saw ? num_sat : num_saw; | |
101 | if (num_subauth) { | |
102 | for (i = 0; i < num_subauth; ++i) { | |
103 | if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) { | |
104 | if (le32_to_cpu(ctsid->sub_auth[i]) > | |
64b39f4a | 105 | le32_to_cpu(cwsid->sub_auth[i])) |
e2f34481 NJ |
106 | return 1; |
107 | else | |
108 | return -1; | |
109 | } | |
110 | } | |
111 | } | |
112 | ||
113 | return 0; /* sids compare/match */ | |
114 | } | |
115 | ||
64b39f4a | 116 | static void smb_copy_sid(struct smb_sid *dst, const struct smb_sid *src) |
e2f34481 NJ |
117 | { |
118 | int i; | |
119 | ||
120 | dst->revision = src->revision; | |
121 | dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES); | |
122 | for (i = 0; i < NUM_AUTHS; ++i) | |
123 | dst->authority[i] = src->authority[i]; | |
124 | for (i = 0; i < dst->num_subauth; ++i) | |
125 | dst->sub_auth[i] = src->sub_auth[i]; | |
126 | } | |
127 | ||
128 | /* | |
129 | * change posix mode to reflect permissions | |
130 | * pmode is the existing mode (we only want to overwrite part of this | |
131 | * bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007 | |
132 | */ | |
133 | static umode_t access_flags_to_mode(struct smb_fattr *fattr, __le32 ace_flags, | |
070fb21e | 134 | int type) |
e2f34481 NJ |
135 | { |
136 | __u32 flags = le32_to_cpu(ace_flags); | |
137 | umode_t mode = 0; | |
138 | ||
139 | if (flags & GENERIC_ALL) { | |
140 | mode = 0777; | |
141 | ksmbd_debug(SMB, "all perms\n"); | |
142 | return mode; | |
143 | } | |
144 | ||
64b39f4a | 145 | if ((flags & GENERIC_READ) || (flags & FILE_READ_RIGHTS)) |
e2f34481 | 146 | mode = 0444; |
64b39f4a | 147 | if ((flags & GENERIC_WRITE) || (flags & FILE_WRITE_RIGHTS)) { |
e2f34481 NJ |
148 | mode |= 0222; |
149 | if (S_ISDIR(fattr->cf_mode)) | |
150 | mode |= 0111; | |
151 | } | |
64b39f4a | 152 | if ((flags & GENERIC_EXECUTE) || (flags & FILE_EXEC_RIGHTS)) |
e2f34481 NJ |
153 | mode |= 0111; |
154 | ||
64b39f4a | 155 | if (type == ACCESS_DENIED_ACE_TYPE || type == ACCESS_DENIED_OBJECT_ACE_TYPE) |
e2f34481 NJ |
156 | mode = ~mode; |
157 | ||
158 | ksmbd_debug(SMB, "access flags 0x%x mode now %04o\n", flags, mode); | |
159 | ||
160 | return mode; | |
161 | } | |
162 | ||
163 | /* | |
164 | * Generate access flags to reflect permissions mode is the existing mode. | |
165 | * This function is called for every ACE in the DACL whose SID matches | |
166 | * with either owner or group or everyone. | |
167 | */ | |
168 | static void mode_to_access_flags(umode_t mode, umode_t bits_to_use, | |
070fb21e | 169 | __u32 *pace_flags) |
e2f34481 NJ |
170 | { |
171 | /* reset access mask */ | |
172 | *pace_flags = 0x0; | |
173 | ||
174 | /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */ | |
175 | mode &= bits_to_use; | |
176 | ||
177 | /* | |
178 | * check for R/W/X UGO since we do not know whose flags | |
179 | * is this but we have cleared all the bits sans RWX for | |
180 | * either user or group or other as per bits_to_use | |
181 | */ | |
182 | if (mode & 0444) | |
183 | *pace_flags |= SET_FILE_READ_RIGHTS; | |
184 | if (mode & 0222) | |
185 | *pace_flags |= FILE_WRITE_RIGHTS; | |
186 | if (mode & 0111) | |
187 | *pace_flags |= SET_FILE_EXEC_RIGHTS; | |
188 | ||
189 | ksmbd_debug(SMB, "mode: %o, access flags now 0x%x\n", | |
070fb21e | 190 | mode, *pace_flags); |
e2f34481 NJ |
191 | } |
192 | ||
193 | static __u16 fill_ace_for_sid(struct smb_ace *pntace, | |
070fb21e NJ |
194 | const struct smb_sid *psid, int type, int flags, |
195 | umode_t mode, umode_t bits) | |
e2f34481 NJ |
196 | { |
197 | int i; | |
198 | __u16 size = 0; | |
199 | __u32 access_req = 0; | |
200 | ||
201 | pntace->type = type; | |
202 | pntace->flags = flags; | |
203 | mode_to_access_flags(mode, bits, &access_req); | |
204 | if (!access_req) | |
205 | access_req = SET_MINIMUM_RIGHTS; | |
206 | pntace->access_req = cpu_to_le32(access_req); | |
207 | ||
208 | pntace->sid.revision = psid->revision; | |
209 | pntace->sid.num_subauth = psid->num_subauth; | |
210 | for (i = 0; i < NUM_AUTHS; i++) | |
211 | pntace->sid.authority[i] = psid->authority[i]; | |
212 | for (i = 0; i < psid->num_subauth; i++) | |
213 | pntace->sid.sub_auth[i] = psid->sub_auth[i]; | |
214 | ||
215 | size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4); | |
216 | pntace->size = cpu_to_le16(size); | |
217 | ||
218 | return size; | |
219 | } | |
220 | ||
221 | void id_to_sid(unsigned int cid, uint sidtype, struct smb_sid *ssid) | |
222 | { | |
223 | switch (sidtype) { | |
224 | case SIDOWNER: | |
225 | smb_copy_sid(ssid, &server_conf.domain_sid); | |
226 | break; | |
227 | case SIDUNIX_USER: | |
228 | smb_copy_sid(ssid, &sid_unix_users); | |
229 | break; | |
230 | case SIDUNIX_GROUP: | |
231 | smb_copy_sid(ssid, &sid_unix_groups); | |
232 | break; | |
233 | case SIDCREATOR_OWNER: | |
234 | smb_copy_sid(ssid, &creator_owner); | |
235 | return; | |
236 | case SIDCREATOR_GROUP: | |
237 | smb_copy_sid(ssid, &creator_group); | |
238 | return; | |
239 | case SIDNFS_USER: | |
240 | smb_copy_sid(ssid, &sid_unix_NFS_users); | |
241 | break; | |
242 | case SIDNFS_GROUP: | |
243 | smb_copy_sid(ssid, &sid_unix_NFS_groups); | |
244 | break; | |
245 | case SIDNFS_MODE: | |
246 | smb_copy_sid(ssid, &sid_unix_NFS_mode); | |
247 | break; | |
248 | default: | |
249 | return; | |
250 | } | |
251 | ||
252 | /* RID */ | |
253 | ssid->sub_auth[ssid->num_subauth] = cpu_to_le32(cid); | |
254 | ssid->num_subauth++; | |
255 | } | |
256 | ||
af34983e HL |
257 | static int sid_to_id(struct user_namespace *user_ns, |
258 | struct smb_sid *psid, uint sidtype, | |
070fb21e | 259 | struct smb_fattr *fattr) |
e2f34481 NJ |
260 | { |
261 | int rc = -EINVAL; | |
262 | ||
263 | /* | |
264 | * If we have too many subauthorities, then something is really wrong. | |
265 | * Just return an error. | |
266 | */ | |
267 | if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) { | |
bde1694a NJ |
268 | pr_err("%s: %u subauthorities is too many!\n", |
269 | __func__, psid->num_subauth); | |
e2f34481 NJ |
270 | return -EIO; |
271 | } | |
272 | ||
273 | if (sidtype == SIDOWNER) { | |
274 | kuid_t uid; | |
275 | uid_t id; | |
276 | ||
277 | id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]); | |
44720713 | 278 | uid = mapped_kuid_user(user_ns, &init_user_ns, KUIDT_INIT(id)); |
4cf0ccd0 NJ |
279 | if (uid_valid(uid)) { |
280 | fattr->cf_uid = uid; | |
281 | rc = 0; | |
e2f34481 NJ |
282 | } |
283 | } else { | |
284 | kgid_t gid; | |
285 | gid_t id; | |
286 | ||
287 | id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]); | |
44720713 | 288 | gid = mapped_kgid_user(user_ns, &init_user_ns, KGIDT_INIT(id)); |
4cf0ccd0 NJ |
289 | if (gid_valid(gid)) { |
290 | fattr->cf_gid = gid; | |
291 | rc = 0; | |
e2f34481 NJ |
292 | } |
293 | } | |
294 | ||
295 | return rc; | |
296 | } | |
297 | ||
298 | void posix_state_to_acl(struct posix_acl_state *state, | |
070fb21e | 299 | struct posix_acl_entry *pace) |
e2f34481 NJ |
300 | { |
301 | int i; | |
302 | ||
303 | pace->e_tag = ACL_USER_OBJ; | |
304 | pace->e_perm = state->owner.allow; | |
305 | for (i = 0; i < state->users->n; i++) { | |
306 | pace++; | |
307 | pace->e_tag = ACL_USER; | |
308 | pace->e_uid = state->users->aces[i].uid; | |
309 | pace->e_perm = state->users->aces[i].perms.allow; | |
310 | } | |
311 | ||
312 | pace++; | |
313 | pace->e_tag = ACL_GROUP_OBJ; | |
314 | pace->e_perm = state->group.allow; | |
315 | ||
316 | for (i = 0; i < state->groups->n; i++) { | |
317 | pace++; | |
318 | pace->e_tag = ACL_GROUP; | |
319 | pace->e_gid = state->groups->aces[i].gid; | |
320 | pace->e_perm = state->groups->aces[i].perms.allow; | |
321 | } | |
322 | ||
323 | if (state->users->n || state->groups->n) { | |
324 | pace++; | |
325 | pace->e_tag = ACL_MASK; | |
326 | pace->e_perm = state->mask.allow; | |
327 | } | |
328 | ||
329 | pace++; | |
330 | pace->e_tag = ACL_OTHER; | |
331 | pace->e_perm = state->other.allow; | |
332 | } | |
333 | ||
334 | int init_acl_state(struct posix_acl_state *state, int cnt) | |
335 | { | |
336 | int alloc; | |
337 | ||
338 | memset(state, 0, sizeof(struct posix_acl_state)); | |
339 | /* | |
340 | * In the worst case, each individual acl could be for a distinct | |
341 | * named user or group, but we don't know which, so we allocate | |
342 | * enough space for either: | |
343 | */ | |
344 | alloc = sizeof(struct posix_ace_state_array) | |
64b39f4a | 345 | + cnt * sizeof(struct posix_user_ace_state); |
e2f34481 NJ |
346 | state->users = kzalloc(alloc, GFP_KERNEL); |
347 | if (!state->users) | |
348 | return -ENOMEM; | |
349 | state->groups = kzalloc(alloc, GFP_KERNEL); | |
350 | if (!state->groups) { | |
351 | kfree(state->users); | |
352 | return -ENOMEM; | |
353 | } | |
354 | return 0; | |
355 | } | |
356 | ||
357 | void free_acl_state(struct posix_acl_state *state) | |
358 | { | |
359 | kfree(state->users); | |
360 | kfree(state->groups); | |
361 | } | |
362 | ||
af34983e HL |
363 | static void parse_dacl(struct user_namespace *user_ns, |
364 | struct smb_acl *pdacl, char *end_of_acl, | |
070fb21e NJ |
365 | struct smb_sid *pownersid, struct smb_sid *pgrpsid, |
366 | struct smb_fattr *fattr) | |
e2f34481 NJ |
367 | { |
368 | int i, ret; | |
369 | int num_aces = 0; | |
8f77150c | 370 | unsigned int acl_size; |
e2f34481 NJ |
371 | char *acl_base; |
372 | struct smb_ace **ppace; | |
373 | struct posix_acl_entry *cf_pace, *cf_pdace; | |
374 | struct posix_acl_state acl_state, default_acl_state; | |
375 | umode_t mode = 0, acl_mode; | |
376 | bool owner_found = false, group_found = false, others_found = false; | |
377 | ||
378 | if (!pdacl) | |
379 | return; | |
380 | ||
381 | /* validate that we do not go past end of acl */ | |
8f77150c | 382 | if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl) || |
548e9ad3 | 383 | end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) { |
bde1694a | 384 | pr_err("ACL too small to parse DACL\n"); |
e2f34481 NJ |
385 | return; |
386 | } | |
387 | ||
388 | ksmbd_debug(SMB, "DACL revision %d size %d num aces %d\n", | |
070fb21e NJ |
389 | le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size), |
390 | le32_to_cpu(pdacl->num_aces)); | |
e2f34481 NJ |
391 | |
392 | acl_base = (char *)pdacl; | |
393 | acl_size = sizeof(struct smb_acl); | |
394 | ||
395 | num_aces = le32_to_cpu(pdacl->num_aces); | |
396 | if (num_aces <= 0) | |
397 | return; | |
398 | ||
399 | if (num_aces > ULONG_MAX / sizeof(struct smb_ace *)) | |
400 | return; | |
401 | ||
070fb21e | 402 | ppace = kmalloc_array(num_aces, sizeof(struct smb_ace *), GFP_KERNEL); |
e2f34481 NJ |
403 | if (!ppace) |
404 | return; | |
405 | ||
406 | ret = init_acl_state(&acl_state, num_aces); | |
407 | if (ret) | |
408 | return; | |
409 | ret = init_acl_state(&default_acl_state, num_aces); | |
410 | if (ret) { | |
411 | free_acl_state(&acl_state); | |
412 | return; | |
413 | } | |
414 | ||
415 | /* | |
416 | * reset rwx permissions for user/group/other. | |
417 | * Also, if num_aces is 0 i.e. DACL has no ACEs, | |
418 | * user/group/other have no permissions | |
419 | */ | |
420 | for (i = 0; i < num_aces; ++i) { | |
8f77150c HL |
421 | if (end_of_acl - acl_base < acl_size) |
422 | break; | |
423 | ||
64b39f4a | 424 | ppace[i] = (struct smb_ace *)(acl_base + acl_size); |
e2f34481 | 425 | acl_base = (char *)ppace[i]; |
8f77150c HL |
426 | acl_size = offsetof(struct smb_ace, sid) + |
427 | offsetof(struct smb_sid, sub_auth); | |
428 | ||
429 | if (end_of_acl - acl_base < acl_size || | |
430 | ppace[i]->sid.num_subauth > SID_MAX_SUB_AUTHORITIES || | |
431 | (end_of_acl - acl_base < | |
432 | acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth) || | |
433 | (le16_to_cpu(ppace[i]->size) < | |
434 | acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth)) | |
435 | break; | |
436 | ||
e2f34481 NJ |
437 | acl_size = le16_to_cpu(ppace[i]->size); |
438 | ppace[i]->access_req = | |
439 | smb_map_generic_desired_access(ppace[i]->access_req); | |
440 | ||
64b39f4a | 441 | if (!(compare_sids(&ppace[i]->sid, &sid_unix_NFS_mode))) { |
e2f34481 NJ |
442 | fattr->cf_mode = |
443 | le32_to_cpu(ppace[i]->sid.sub_auth[2]); | |
444 | break; | |
64b39f4a | 445 | } else if (!compare_sids(&ppace[i]->sid, pownersid)) { |
e2f34481 | 446 | acl_mode = access_flags_to_mode(fattr, |
070fb21e NJ |
447 | ppace[i]->access_req, |
448 | ppace[i]->type); | |
e2f34481 NJ |
449 | acl_mode &= 0700; |
450 | ||
451 | if (!owner_found) { | |
452 | mode &= ~(0700); | |
453 | mode |= acl_mode; | |
454 | } | |
455 | owner_found = true; | |
64b39f4a NJ |
456 | } else if (!compare_sids(&ppace[i]->sid, pgrpsid) || |
457 | ppace[i]->sid.sub_auth[ppace[i]->sid.num_subauth - 1] == | |
458 | DOMAIN_USER_RID_LE) { | |
e2f34481 | 459 | acl_mode = access_flags_to_mode(fattr, |
070fb21e NJ |
460 | ppace[i]->access_req, |
461 | ppace[i]->type); | |
e2f34481 NJ |
462 | acl_mode &= 0070; |
463 | if (!group_found) { | |
464 | mode &= ~(0070); | |
465 | mode |= acl_mode; | |
466 | } | |
467 | group_found = true; | |
64b39f4a | 468 | } else if (!compare_sids(&ppace[i]->sid, &sid_everyone)) { |
e2f34481 | 469 | acl_mode = access_flags_to_mode(fattr, |
070fb21e NJ |
470 | ppace[i]->access_req, |
471 | ppace[i]->type); | |
e2f34481 NJ |
472 | acl_mode &= 0007; |
473 | if (!others_found) { | |
474 | mode &= ~(0007); | |
475 | mode |= acl_mode; | |
476 | } | |
477 | others_found = true; | |
64b39f4a | 478 | } else if (!compare_sids(&ppace[i]->sid, &creator_owner)) { |
e2f34481 | 479 | continue; |
64b39f4a | 480 | } else if (!compare_sids(&ppace[i]->sid, &creator_group)) { |
e2f34481 | 481 | continue; |
64b39f4a | 482 | } else if (!compare_sids(&ppace[i]->sid, &sid_authusers)) { |
e2f34481 | 483 | continue; |
64b39f4a | 484 | } else { |
e2f34481 NJ |
485 | struct smb_fattr temp_fattr; |
486 | ||
487 | acl_mode = access_flags_to_mode(fattr, ppace[i]->access_req, | |
070fb21e | 488 | ppace[i]->type); |
e2f34481 | 489 | temp_fattr.cf_uid = INVALID_UID; |
af34983e | 490 | ret = sid_to_id(user_ns, &ppace[i]->sid, SIDOWNER, &temp_fattr); |
e2f34481 | 491 | if (ret || uid_eq(temp_fattr.cf_uid, INVALID_UID)) { |
bde1694a NJ |
492 | pr_err("%s: Error %d mapping Owner SID to uid\n", |
493 | __func__, ret); | |
e2f34481 NJ |
494 | continue; |
495 | } | |
496 | ||
497 | acl_state.owner.allow = ((acl_mode & 0700) >> 6) | 0004; | |
498 | acl_state.users->aces[acl_state.users->n].uid = | |
499 | temp_fattr.cf_uid; | |
500 | acl_state.users->aces[acl_state.users->n++].perms.allow = | |
501 | ((acl_mode & 0700) >> 6) | 0004; | |
502 | default_acl_state.owner.allow = ((acl_mode & 0700) >> 6) | 0004; | |
503 | default_acl_state.users->aces[default_acl_state.users->n].uid = | |
504 | temp_fattr.cf_uid; | |
505 | default_acl_state.users->aces[default_acl_state.users->n++].perms.allow = | |
506 | ((acl_mode & 0700) >> 6) | 0004; | |
507 | } | |
508 | } | |
509 | kfree(ppace); | |
510 | ||
511 | if (owner_found) { | |
512 | /* The owner must be set to at least read-only. */ | |
513 | acl_state.owner.allow = ((mode & 0700) >> 6) | 0004; | |
514 | acl_state.users->aces[acl_state.users->n].uid = fattr->cf_uid; | |
515 | acl_state.users->aces[acl_state.users->n++].perms.allow = | |
516 | ((mode & 0700) >> 6) | 0004; | |
517 | default_acl_state.owner.allow = ((mode & 0700) >> 6) | 0004; | |
518 | default_acl_state.users->aces[default_acl_state.users->n].uid = | |
519 | fattr->cf_uid; | |
520 | default_acl_state.users->aces[default_acl_state.users->n++].perms.allow = | |
521 | ((mode & 0700) >> 6) | 0004; | |
522 | } | |
523 | ||
524 | if (group_found) { | |
525 | acl_state.group.allow = (mode & 0070) >> 3; | |
526 | acl_state.groups->aces[acl_state.groups->n].gid = | |
527 | fattr->cf_gid; | |
528 | acl_state.groups->aces[acl_state.groups->n++].perms.allow = | |
529 | (mode & 0070) >> 3; | |
86df49e1 | 530 | default_acl_state.group.allow = (mode & 0070) >> 3; |
e2f34481 NJ |
531 | default_acl_state.groups->aces[default_acl_state.groups->n].gid = |
532 | fattr->cf_gid; | |
533 | default_acl_state.groups->aces[default_acl_state.groups->n++].perms.allow = | |
534 | (mode & 0070) >> 3; | |
535 | } | |
536 | ||
537 | if (others_found) { | |
538 | fattr->cf_mode &= ~(0007); | |
539 | fattr->cf_mode |= mode & 0007; | |
540 | ||
541 | acl_state.other.allow = mode & 0007; | |
542 | default_acl_state.other.allow = mode & 0007; | |
543 | } | |
544 | ||
545 | if (acl_state.users->n || acl_state.groups->n) { | |
546 | acl_state.mask.allow = 0x07; | |
777cad16 NJ |
547 | |
548 | if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) { | |
549 | fattr->cf_acls = | |
550 | posix_acl_alloc(acl_state.users->n + | |
551 | acl_state.groups->n + 4, GFP_KERNEL); | |
552 | if (fattr->cf_acls) { | |
553 | cf_pace = fattr->cf_acls->a_entries; | |
554 | posix_state_to_acl(&acl_state, cf_pace); | |
555 | } | |
e2f34481 NJ |
556 | } |
557 | } | |
558 | ||
559 | if (default_acl_state.users->n || default_acl_state.groups->n) { | |
560 | default_acl_state.mask.allow = 0x07; | |
777cad16 NJ |
561 | |
562 | if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) { | |
563 | fattr->cf_dacls = | |
564 | posix_acl_alloc(default_acl_state.users->n + | |
565 | default_acl_state.groups->n + 4, GFP_KERNEL); | |
566 | if (fattr->cf_dacls) { | |
567 | cf_pdace = fattr->cf_dacls->a_entries; | |
568 | posix_state_to_acl(&default_acl_state, cf_pdace); | |
569 | } | |
e2f34481 NJ |
570 | } |
571 | } | |
572 | free_acl_state(&acl_state); | |
573 | free_acl_state(&default_acl_state); | |
574 | } | |
575 | ||
af34983e HL |
576 | static void set_posix_acl_entries_dacl(struct user_namespace *user_ns, |
577 | struct smb_ace *pndace, | |
070fb21e NJ |
578 | struct smb_fattr *fattr, u32 *num_aces, |
579 | u16 *size, u32 nt_aces_num) | |
e2f34481 NJ |
580 | { |
581 | struct posix_acl_entry *pace; | |
582 | struct smb_sid *sid; | |
583 | struct smb_ace *ntace; | |
584 | int i, j; | |
585 | ||
586 | if (!fattr->cf_acls) | |
587 | goto posix_default_acl; | |
588 | ||
589 | pace = fattr->cf_acls->a_entries; | |
590 | for (i = 0; i < fattr->cf_acls->a_count; i++, pace++) { | |
591 | int flags = 0; | |
592 | ||
593 | sid = kmalloc(sizeof(struct smb_sid), GFP_KERNEL); | |
594 | if (!sid) | |
595 | break; | |
596 | ||
597 | if (pace->e_tag == ACL_USER) { | |
598 | uid_t uid; | |
599 | unsigned int sid_type = SIDOWNER; | |
600 | ||
0e844efe | 601 | uid = posix_acl_uid_translate(user_ns, pace); |
e2f34481 NJ |
602 | if (!uid) |
603 | sid_type = SIDUNIX_USER; | |
604 | id_to_sid(uid, sid_type, sid); | |
605 | } else if (pace->e_tag == ACL_GROUP) { | |
606 | gid_t gid; | |
607 | ||
0e844efe | 608 | gid = posix_acl_gid_translate(user_ns, pace); |
e2f34481 NJ |
609 | id_to_sid(gid, SIDUNIX_GROUP, sid); |
610 | } else if (pace->e_tag == ACL_OTHER && !nt_aces_num) { | |
611 | smb_copy_sid(sid, &sid_everyone); | |
612 | } else { | |
613 | kfree(sid); | |
614 | continue; | |
615 | } | |
616 | ntace = pndace; | |
617 | for (j = 0; j < nt_aces_num; j++) { | |
618 | if (ntace->sid.sub_auth[ntace->sid.num_subauth - 1] == | |
619 | sid->sub_auth[sid->num_subauth - 1]) | |
620 | goto pass_same_sid; | |
621 | ntace = (struct smb_ace *)((char *)ntace + | |
622 | le16_to_cpu(ntace->size)); | |
623 | } | |
624 | ||
625 | if (S_ISDIR(fattr->cf_mode) && pace->e_tag == ACL_OTHER) | |
626 | flags = 0x03; | |
627 | ||
64b39f4a | 628 | ntace = (struct smb_ace *)((char *)pndace + *size); |
e2f34481 NJ |
629 | *size += fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, flags, |
630 | pace->e_perm, 0777); | |
631 | (*num_aces)++; | |
632 | if (pace->e_tag == ACL_USER) | |
633 | ntace->access_req |= | |
634 | FILE_DELETE_LE | FILE_DELETE_CHILD_LE; | |
635 | ||
636 | if (S_ISDIR(fattr->cf_mode) && | |
64b39f4a NJ |
637 | (pace->e_tag == ACL_USER || pace->e_tag == ACL_GROUP)) { |
638 | ntace = (struct smb_ace *)((char *)pndace + *size); | |
e2f34481 NJ |
639 | *size += fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, |
640 | 0x03, pace->e_perm, 0777); | |
641 | (*num_aces)++; | |
642 | if (pace->e_tag == ACL_USER) | |
643 | ntace->access_req |= | |
644 | FILE_DELETE_LE | FILE_DELETE_CHILD_LE; | |
645 | } | |
646 | ||
647 | pass_same_sid: | |
648 | kfree(sid); | |
649 | } | |
650 | ||
651 | if (nt_aces_num) | |
652 | return; | |
653 | ||
654 | posix_default_acl: | |
655 | if (!fattr->cf_dacls) | |
656 | return; | |
657 | ||
658 | pace = fattr->cf_dacls->a_entries; | |
659 | for (i = 0; i < fattr->cf_dacls->a_count; i++, pace++) { | |
660 | sid = kmalloc(sizeof(struct smb_sid), GFP_KERNEL); | |
661 | if (!sid) | |
662 | break; | |
663 | ||
664 | if (pace->e_tag == ACL_USER) { | |
665 | uid_t uid; | |
666 | ||
0e844efe | 667 | uid = posix_acl_uid_translate(user_ns, pace); |
e2f34481 NJ |
668 | id_to_sid(uid, SIDCREATOR_OWNER, sid); |
669 | } else if (pace->e_tag == ACL_GROUP) { | |
670 | gid_t gid; | |
671 | ||
0e844efe | 672 | gid = posix_acl_gid_translate(user_ns, pace); |
e2f34481 NJ |
673 | id_to_sid(gid, SIDCREATOR_GROUP, sid); |
674 | } else { | |
675 | kfree(sid); | |
676 | continue; | |
677 | } | |
678 | ||
64b39f4a | 679 | ntace = (struct smb_ace *)((char *)pndace + *size); |
e2f34481 NJ |
680 | *size += fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, 0x0b, |
681 | pace->e_perm, 0777); | |
682 | (*num_aces)++; | |
683 | if (pace->e_tag == ACL_USER) | |
684 | ntace->access_req |= | |
685 | FILE_DELETE_LE | FILE_DELETE_CHILD_LE; | |
686 | kfree(sid); | |
687 | } | |
688 | } | |
689 | ||
af34983e HL |
690 | static void set_ntacl_dacl(struct user_namespace *user_ns, |
691 | struct smb_acl *pndacl, | |
692 | struct smb_acl *nt_dacl, | |
8f054118 | 693 | unsigned int aces_size, |
070fb21e NJ |
694 | const struct smb_sid *pownersid, |
695 | const struct smb_sid *pgrpsid, | |
696 | struct smb_fattr *fattr) | |
e2f34481 NJ |
697 | { |
698 | struct smb_ace *ntace, *pndace; | |
699 | int nt_num_aces = le32_to_cpu(nt_dacl->num_aces), num_aces = 0; | |
700 | unsigned short size = 0; | |
701 | int i; | |
702 | ||
703 | pndace = (struct smb_ace *)((char *)pndacl + sizeof(struct smb_acl)); | |
704 | if (nt_num_aces) { | |
705 | ntace = (struct smb_ace *)((char *)nt_dacl + sizeof(struct smb_acl)); | |
706 | for (i = 0; i < nt_num_aces; i++) { | |
8f054118 NJ |
707 | unsigned short nt_ace_size; |
708 | ||
709 | if (offsetof(struct smb_ace, access_req) > aces_size) | |
710 | break; | |
711 | ||
712 | nt_ace_size = le16_to_cpu(ntace->size); | |
713 | if (nt_ace_size > aces_size) | |
714 | break; | |
715 | ||
716 | memcpy((char *)pndace + size, ntace, nt_ace_size); | |
717 | size += nt_ace_size; | |
718 | aces_size -= nt_ace_size; | |
719 | ntace = (struct smb_ace *)((char *)ntace + nt_ace_size); | |
e2f34481 NJ |
720 | num_aces++; |
721 | } | |
722 | } | |
723 | ||
af34983e HL |
724 | set_posix_acl_entries_dacl(user_ns, pndace, fattr, |
725 | &num_aces, &size, nt_num_aces); | |
e2f34481 NJ |
726 | pndacl->num_aces = cpu_to_le32(num_aces); |
727 | pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size); | |
728 | } | |
729 | ||
af34983e HL |
730 | static void set_mode_dacl(struct user_namespace *user_ns, |
731 | struct smb_acl *pndacl, struct smb_fattr *fattr) | |
e2f34481 NJ |
732 | { |
733 | struct smb_ace *pace, *pndace; | |
734 | u32 num_aces = 0; | |
735 | u16 size = 0, ace_size = 0; | |
736 | uid_t uid; | |
737 | const struct smb_sid *sid; | |
738 | ||
739 | pace = pndace = (struct smb_ace *)((char *)pndacl + sizeof(struct smb_acl)); | |
740 | ||
741 | if (fattr->cf_acls) { | |
af34983e HL |
742 | set_posix_acl_entries_dacl(user_ns, pndace, fattr, |
743 | &num_aces, &size, num_aces); | |
e2f34481 NJ |
744 | goto out; |
745 | } | |
746 | ||
747 | /* owner RID */ | |
43205ca7 | 748 | uid = from_kuid(&init_user_ns, fattr->cf_uid); |
e2f34481 NJ |
749 | if (uid) |
750 | sid = &server_conf.domain_sid; | |
751 | else | |
752 | sid = &sid_unix_users; | |
753 | ace_size = fill_ace_for_sid(pace, sid, ACCESS_ALLOWED, 0, | |
070fb21e | 754 | fattr->cf_mode, 0700); |
e2f34481 | 755 | pace->sid.sub_auth[pace->sid.num_subauth++] = cpu_to_le32(uid); |
e2f34481 NJ |
756 | pace->size = cpu_to_le16(ace_size + 4); |
757 | size += le16_to_cpu(pace->size); | |
758 | pace = (struct smb_ace *)((char *)pndace + size); | |
759 | ||
760 | /* Group RID */ | |
761 | ace_size = fill_ace_for_sid(pace, &sid_unix_groups, | |
070fb21e | 762 | ACCESS_ALLOWED, 0, fattr->cf_mode, 0070); |
e2f34481 | 763 | pace->sid.sub_auth[pace->sid.num_subauth++] = |
43205ca7 | 764 | cpu_to_le32(from_kgid(&init_user_ns, fattr->cf_gid)); |
e2f34481 NJ |
765 | pace->size = cpu_to_le16(ace_size + 4); |
766 | size += le16_to_cpu(pace->size); | |
767 | pace = (struct smb_ace *)((char *)pndace + size); | |
768 | num_aces = 3; | |
769 | ||
770 | if (S_ISDIR(fattr->cf_mode)) { | |
771 | pace = (struct smb_ace *)((char *)pndace + size); | |
772 | ||
773 | /* creator owner */ | |
774 | size += fill_ace_for_sid(pace, &creator_owner, ACCESS_ALLOWED, | |
070fb21e | 775 | 0x0b, fattr->cf_mode, 0700); |
e2f34481 NJ |
776 | pace = (struct smb_ace *)((char *)pndace + size); |
777 | ||
778 | /* creator group */ | |
779 | size += fill_ace_for_sid(pace, &creator_group, ACCESS_ALLOWED, | |
070fb21e | 780 | 0x0b, fattr->cf_mode, 0070); |
e2f34481 NJ |
781 | pace = (struct smb_ace *)((char *)pndace + size); |
782 | num_aces = 5; | |
783 | } | |
784 | ||
785 | /* other */ | |
786 | size += fill_ace_for_sid(pace, &sid_everyone, ACCESS_ALLOWED, 0, | |
070fb21e | 787 | fattr->cf_mode, 0007); |
e2f34481 NJ |
788 | |
789 | out: | |
790 | pndacl->num_aces = cpu_to_le32(num_aces); | |
791 | pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size); | |
792 | } | |
793 | ||
794 | static int parse_sid(struct smb_sid *psid, char *end_of_acl) | |
795 | { | |
796 | /* | |
797 | * validate that we do not go past end of ACL - sid must be at least 8 | |
798 | * bytes long (assuming no sub-auths - e.g. the null SID | |
799 | */ | |
800 | if (end_of_acl < (char *)psid + 8) { | |
bde1694a | 801 | pr_err("ACL too small to parse SID %p\n", psid); |
e2f34481 NJ |
802 | return -EINVAL; |
803 | } | |
804 | ||
805 | return 0; | |
806 | } | |
807 | ||
808 | /* Convert CIFS ACL to POSIX form */ | |
af34983e HL |
809 | int parse_sec_desc(struct user_namespace *user_ns, struct smb_ntsd *pntsd, |
810 | int acl_len, struct smb_fattr *fattr) | |
e2f34481 NJ |
811 | { |
812 | int rc = 0; | |
813 | struct smb_sid *owner_sid_ptr, *group_sid_ptr; | |
814 | struct smb_acl *dacl_ptr; /* no need for SACL ptr */ | |
815 | char *end_of_acl = ((char *)pntsd) + acl_len; | |
816 | __u32 dacloffset; | |
548e9ad3 | 817 | int pntsd_type; |
e2f34481 | 818 | |
64b39f4a | 819 | if (!pntsd) |
e2f34481 NJ |
820 | return -EIO; |
821 | ||
8f77150c HL |
822 | if (acl_len < sizeof(struct smb_ntsd)) |
823 | return -EINVAL; | |
824 | ||
e2f34481 NJ |
825 | owner_sid_ptr = (struct smb_sid *)((char *)pntsd + |
826 | le32_to_cpu(pntsd->osidoffset)); | |
827 | group_sid_ptr = (struct smb_sid *)((char *)pntsd + | |
828 | le32_to_cpu(pntsd->gsidoffset)); | |
829 | dacloffset = le32_to_cpu(pntsd->dacloffset); | |
830 | dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset); | |
831 | ksmbd_debug(SMB, | |
070fb21e NJ |
832 | "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n", |
833 | pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset), | |
834 | le32_to_cpu(pntsd->gsidoffset), | |
835 | le32_to_cpu(pntsd->sacloffset), dacloffset); | |
e2f34481 | 836 | |
e2f34481 | 837 | pntsd_type = le16_to_cpu(pntsd->type); |
e2f34481 NJ |
838 | if (!(pntsd_type & DACL_PRESENT)) { |
839 | ksmbd_debug(SMB, "DACL_PRESENT in DACL type is not set\n"); | |
840 | return rc; | |
841 | } | |
842 | ||
843 | pntsd->type = cpu_to_le16(DACL_PRESENT); | |
844 | ||
845 | if (pntsd->osidoffset) { | |
846 | rc = parse_sid(owner_sid_ptr, end_of_acl); | |
847 | if (rc) { | |
bde1694a | 848 | pr_err("%s: Error %d parsing Owner SID\n", __func__, rc); |
e2f34481 NJ |
849 | return rc; |
850 | } | |
851 | ||
af34983e | 852 | rc = sid_to_id(user_ns, owner_sid_ptr, SIDOWNER, fattr); |
e2f34481 | 853 | if (rc) { |
bde1694a NJ |
854 | pr_err("%s: Error %d mapping Owner SID to uid\n", |
855 | __func__, rc); | |
e2f34481 NJ |
856 | owner_sid_ptr = NULL; |
857 | } | |
858 | } | |
859 | ||
860 | if (pntsd->gsidoffset) { | |
861 | rc = parse_sid(group_sid_ptr, end_of_acl); | |
862 | if (rc) { | |
bde1694a NJ |
863 | pr_err("%s: Error %d mapping Owner SID to gid\n", |
864 | __func__, rc); | |
e2f34481 NJ |
865 | return rc; |
866 | } | |
af34983e | 867 | rc = sid_to_id(user_ns, group_sid_ptr, SIDUNIX_GROUP, fattr); |
e2f34481 | 868 | if (rc) { |
bde1694a NJ |
869 | pr_err("%s: Error %d mapping Group SID to gid\n", |
870 | __func__, rc); | |
e2f34481 NJ |
871 | group_sid_ptr = NULL; |
872 | } | |
873 | } | |
874 | ||
070fb21e | 875 | if ((pntsd_type & (DACL_AUTO_INHERITED | DACL_AUTO_INHERIT_REQ)) == |
e2f34481 NJ |
876 | (DACL_AUTO_INHERITED | DACL_AUTO_INHERIT_REQ)) |
877 | pntsd->type |= cpu_to_le16(DACL_AUTO_INHERITED); | |
878 | if (pntsd_type & DACL_PROTECTED) | |
879 | pntsd->type |= cpu_to_le16(DACL_PROTECTED); | |
880 | ||
881 | if (dacloffset) { | |
af34983e HL |
882 | parse_dacl(user_ns, dacl_ptr, end_of_acl, |
883 | owner_sid_ptr, group_sid_ptr, fattr); | |
e2f34481 NJ |
884 | } |
885 | ||
886 | return 0; | |
887 | } | |
888 | ||
889 | /* Convert permission bits from mode to equivalent CIFS ACL */ | |
af34983e HL |
890 | int build_sec_desc(struct user_namespace *user_ns, |
891 | struct smb_ntsd *pntsd, struct smb_ntsd *ppntsd, | |
8f054118 | 892 | int ppntsd_size, int addition_info, __u32 *secdesclen, |
070fb21e | 893 | struct smb_fattr *fattr) |
e2f34481 NJ |
894 | { |
895 | int rc = 0; | |
896 | __u32 offset; | |
897 | struct smb_sid *owner_sid_ptr, *group_sid_ptr; | |
898 | struct smb_sid *nowner_sid_ptr, *ngroup_sid_ptr; | |
899 | struct smb_acl *dacl_ptr = NULL; /* no need for SACL ptr */ | |
900 | uid_t uid; | |
901 | gid_t gid; | |
902 | unsigned int sid_type = SIDOWNER; | |
903 | ||
904 | nowner_sid_ptr = kmalloc(sizeof(struct smb_sid), GFP_KERNEL); | |
905 | if (!nowner_sid_ptr) | |
906 | return -ENOMEM; | |
907 | ||
43205ca7 | 908 | uid = from_kuid(&init_user_ns, fattr->cf_uid); |
e2f34481 NJ |
909 | if (!uid) |
910 | sid_type = SIDUNIX_USER; | |
911 | id_to_sid(uid, sid_type, nowner_sid_ptr); | |
912 | ||
913 | ngroup_sid_ptr = kmalloc(sizeof(struct smb_sid), GFP_KERNEL); | |
914 | if (!ngroup_sid_ptr) { | |
915 | kfree(nowner_sid_ptr); | |
916 | return -ENOMEM; | |
917 | } | |
918 | ||
43205ca7 | 919 | gid = from_kgid(&init_user_ns, fattr->cf_gid); |
e2f34481 NJ |
920 | id_to_sid(gid, SIDUNIX_GROUP, ngroup_sid_ptr); |
921 | ||
922 | offset = sizeof(struct smb_ntsd); | |
923 | pntsd->sacloffset = 0; | |
924 | pntsd->revision = cpu_to_le16(1); | |
925 | pntsd->type = cpu_to_le16(SELF_RELATIVE); | |
926 | if (ppntsd) | |
927 | pntsd->type |= ppntsd->type; | |
928 | ||
929 | if (addition_info & OWNER_SECINFO) { | |
930 | pntsd->osidoffset = cpu_to_le32(offset); | |
931 | owner_sid_ptr = (struct smb_sid *)((char *)pntsd + offset); | |
932 | smb_copy_sid(owner_sid_ptr, nowner_sid_ptr); | |
933 | offset += 1 + 1 + 6 + (nowner_sid_ptr->num_subauth * 4); | |
934 | } | |
935 | ||
936 | if (addition_info & GROUP_SECINFO) { | |
937 | pntsd->gsidoffset = cpu_to_le32(offset); | |
938 | group_sid_ptr = (struct smb_sid *)((char *)pntsd + offset); | |
939 | smb_copy_sid(group_sid_ptr, ngroup_sid_ptr); | |
940 | offset += 1 + 1 + 6 + (ngroup_sid_ptr->num_subauth * 4); | |
941 | } | |
942 | ||
943 | if (addition_info & DACL_SECINFO) { | |
944 | pntsd->type |= cpu_to_le16(DACL_PRESENT); | |
945 | dacl_ptr = (struct smb_acl *)((char *)pntsd + offset); | |
946 | dacl_ptr->revision = cpu_to_le16(2); | |
947 | dacl_ptr->size = cpu_to_le16(sizeof(struct smb_acl)); | |
948 | dacl_ptr->num_aces = 0; | |
949 | ||
64b39f4a | 950 | if (!ppntsd) { |
af34983e | 951 | set_mode_dacl(user_ns, dacl_ptr, fattr); |
64b39f4a | 952 | } else { |
e2f34481 | 953 | struct smb_acl *ppdacl_ptr; |
8f054118 NJ |
954 | unsigned int dacl_offset = le32_to_cpu(ppntsd->dacloffset); |
955 | int ppdacl_size, ntacl_size = ppntsd_size - dacl_offset; | |
956 | ||
957 | if (!dacl_offset || | |
958 | (dacl_offset + sizeof(struct smb_acl) > ppntsd_size)) | |
959 | goto out; | |
960 | ||
961 | ppdacl_ptr = (struct smb_acl *)((char *)ppntsd + dacl_offset); | |
962 | ppdacl_size = le16_to_cpu(ppdacl_ptr->size); | |
963 | if (ppdacl_size > ntacl_size || | |
964 | ppdacl_size < sizeof(struct smb_acl)) | |
965 | goto out; | |
e2f34481 | 966 | |
af34983e | 967 | set_ntacl_dacl(user_ns, dacl_ptr, ppdacl_ptr, |
8f054118 NJ |
968 | ntacl_size - sizeof(struct smb_acl), |
969 | nowner_sid_ptr, ngroup_sid_ptr, | |
970 | fattr); | |
e2f34481 NJ |
971 | } |
972 | pntsd->dacloffset = cpu_to_le32(offset); | |
973 | offset += le16_to_cpu(dacl_ptr->size); | |
974 | } | |
975 | ||
976 | out: | |
977 | kfree(nowner_sid_ptr); | |
978 | kfree(ngroup_sid_ptr); | |
979 | *secdesclen = offset; | |
980 | return rc; | |
981 | } | |
982 | ||
983 | static void smb_set_ace(struct smb_ace *ace, const struct smb_sid *sid, u8 type, | |
070fb21e | 984 | u8 flags, __le32 access_req) |
e2f34481 NJ |
985 | { |
986 | ace->type = type; | |
987 | ace->flags = flags; | |
988 | ace->access_req = access_req; | |
989 | smb_copy_sid(&ace->sid, sid); | |
990 | ace->size = cpu_to_le16(1 + 1 + 2 + 4 + 1 + 1 + 6 + (sid->num_subauth * 4)); | |
991 | } | |
992 | ||
ef24c962 HL |
993 | int smb_inherit_dacl(struct ksmbd_conn *conn, |
994 | struct path *path, | |
070fb21e | 995 | unsigned int uid, unsigned int gid) |
e2f34481 NJ |
996 | { |
997 | const struct smb_sid *psid, *creator = NULL; | |
998 | struct smb_ace *parent_aces, *aces; | |
999 | struct smb_acl *parent_pdacl; | |
1000 | struct smb_ntsd *parent_pntsd = NULL; | |
1001 | struct smb_sid owner_sid, group_sid; | |
ef24c962 | 1002 | struct dentry *parent = path->dentry->d_parent; |
465d7204 | 1003 | struct user_namespace *user_ns = mnt_user_ns(path->mnt); |
8f054118 NJ |
1004 | int inherited_flags = 0, flags = 0, i, ace_cnt = 0, nt_size = 0, pdacl_size; |
1005 | int rc = 0, num_aces, dacloffset, pntsd_type, pntsd_size, acl_len, aces_size; | |
e2f34481 | 1006 | char *aces_base; |
ef24c962 | 1007 | bool is_dir = S_ISDIR(d_inode(path->dentry)->i_mode); |
e2f34481 | 1008 | |
8f054118 NJ |
1009 | pntsd_size = ksmbd_vfs_get_sd_xattr(conn, user_ns, |
1010 | parent, &parent_pntsd); | |
1011 | if (pntsd_size <= 0) | |
a9071e3c | 1012 | return -ENOENT; |
e2f34481 | 1013 | dacloffset = le32_to_cpu(parent_pntsd->dacloffset); |
8f054118 | 1014 | if (!dacloffset || (dacloffset + sizeof(struct smb_acl) > pntsd_size)) { |
a9071e3c NJ |
1015 | rc = -EINVAL; |
1016 | goto free_parent_pntsd; | |
1017 | } | |
e2f34481 NJ |
1018 | |
1019 | parent_pdacl = (struct smb_acl *)((char *)parent_pntsd + dacloffset); | |
8f054118 | 1020 | acl_len = pntsd_size - dacloffset; |
e2f34481 NJ |
1021 | num_aces = le32_to_cpu(parent_pdacl->num_aces); |
1022 | pntsd_type = le16_to_cpu(parent_pntsd->type); | |
8f054118 NJ |
1023 | pdacl_size = le16_to_cpu(parent_pdacl->size); |
1024 | ||
1025 | if (pdacl_size > acl_len || pdacl_size < sizeof(struct smb_acl)) { | |
1026 | rc = -EINVAL; | |
1027 | goto free_parent_pntsd; | |
1028 | } | |
e2f34481 NJ |
1029 | |
1030 | aces_base = kmalloc(sizeof(struct smb_ace) * num_aces * 2, GFP_KERNEL); | |
a9071e3c NJ |
1031 | if (!aces_base) { |
1032 | rc = -ENOMEM; | |
1033 | goto free_parent_pntsd; | |
1034 | } | |
e2f34481 NJ |
1035 | |
1036 | aces = (struct smb_ace *)aces_base; | |
1037 | parent_aces = (struct smb_ace *)((char *)parent_pdacl + | |
1038 | sizeof(struct smb_acl)); | |
8f054118 | 1039 | aces_size = acl_len - sizeof(struct smb_acl); |
e2f34481 NJ |
1040 | |
1041 | if (pntsd_type & DACL_AUTO_INHERITED) | |
1042 | inherited_flags = INHERITED_ACE; | |
1043 | ||
1044 | for (i = 0; i < num_aces; i++) { | |
8f054118 NJ |
1045 | int pace_size; |
1046 | ||
1047 | if (offsetof(struct smb_ace, access_req) > aces_size) | |
1048 | break; | |
1049 | ||
1050 | pace_size = le16_to_cpu(parent_aces->size); | |
1051 | if (pace_size > aces_size) | |
1052 | break; | |
1053 | ||
1054 | aces_size -= pace_size; | |
1055 | ||
e2f34481 NJ |
1056 | flags = parent_aces->flags; |
1057 | if (!smb_inherit_flags(flags, is_dir)) | |
1058 | goto pass; | |
1059 | if (is_dir) { | |
1060 | flags &= ~(INHERIT_ONLY_ACE | INHERITED_ACE); | |
1061 | if (!(flags & CONTAINER_INHERIT_ACE)) | |
1062 | flags |= INHERIT_ONLY_ACE; | |
1063 | if (flags & NO_PROPAGATE_INHERIT_ACE) | |
1064 | flags = 0; | |
64b39f4a | 1065 | } else { |
e2f34481 | 1066 | flags = 0; |
64b39f4a | 1067 | } |
e2f34481 NJ |
1068 | |
1069 | if (!compare_sids(&creator_owner, &parent_aces->sid)) { | |
1070 | creator = &creator_owner; | |
1071 | id_to_sid(uid, SIDOWNER, &owner_sid); | |
1072 | psid = &owner_sid; | |
1073 | } else if (!compare_sids(&creator_group, &parent_aces->sid)) { | |
1074 | creator = &creator_group; | |
1075 | id_to_sid(gid, SIDUNIX_GROUP, &group_sid); | |
1076 | psid = &group_sid; | |
1077 | } else { | |
1078 | creator = NULL; | |
1079 | psid = &parent_aces->sid; | |
1080 | } | |
1081 | ||
1082 | if (is_dir && creator && flags & CONTAINER_INHERIT_ACE) { | |
1083 | smb_set_ace(aces, psid, parent_aces->type, inherited_flags, | |
070fb21e | 1084 | parent_aces->access_req); |
e2f34481 NJ |
1085 | nt_size += le16_to_cpu(aces->size); |
1086 | ace_cnt++; | |
1087 | aces = (struct smb_ace *)((char *)aces + le16_to_cpu(aces->size)); | |
1088 | flags |= INHERIT_ONLY_ACE; | |
1089 | psid = creator; | |
64b39f4a | 1090 | } else if (is_dir && !(parent_aces->flags & NO_PROPAGATE_INHERIT_ACE)) { |
e2f34481 | 1091 | psid = &parent_aces->sid; |
64b39f4a | 1092 | } |
e2f34481 NJ |
1093 | |
1094 | smb_set_ace(aces, psid, parent_aces->type, flags | inherited_flags, | |
070fb21e | 1095 | parent_aces->access_req); |
e2f34481 NJ |
1096 | nt_size += le16_to_cpu(aces->size); |
1097 | aces = (struct smb_ace *)((char *)aces + le16_to_cpu(aces->size)); | |
1098 | ace_cnt++; | |
1099 | pass: | |
8f054118 | 1100 | parent_aces = (struct smb_ace *)((char *)parent_aces + pace_size); |
e2f34481 NJ |
1101 | } |
1102 | ||
1103 | if (nt_size > 0) { | |
1104 | struct smb_ntsd *pntsd; | |
1105 | struct smb_acl *pdacl; | |
1106 | struct smb_sid *powner_sid = NULL, *pgroup_sid = NULL; | |
1107 | int powner_sid_size = 0, pgroup_sid_size = 0, pntsd_size; | |
1108 | ||
1109 | if (parent_pntsd->osidoffset) { | |
1110 | powner_sid = (struct smb_sid *)((char *)parent_pntsd + | |
1111 | le32_to_cpu(parent_pntsd->osidoffset)); | |
1112 | powner_sid_size = 1 + 1 + 6 + (powner_sid->num_subauth * 4); | |
1113 | } | |
1114 | if (parent_pntsd->gsidoffset) { | |
1115 | pgroup_sid = (struct smb_sid *)((char *)parent_pntsd + | |
1116 | le32_to_cpu(parent_pntsd->gsidoffset)); | |
1117 | pgroup_sid_size = 1 + 1 + 6 + (pgroup_sid->num_subauth * 4); | |
1118 | } | |
1119 | ||
1120 | pntsd = kzalloc(sizeof(struct smb_ntsd) + powner_sid_size + | |
1121 | pgroup_sid_size + sizeof(struct smb_acl) + | |
1122 | nt_size, GFP_KERNEL); | |
1123 | if (!pntsd) { | |
1124 | rc = -ENOMEM; | |
a9071e3c | 1125 | goto free_aces_base; |
e2f34481 NJ |
1126 | } |
1127 | ||
1128 | pntsd->revision = cpu_to_le16(1); | |
1129 | pntsd->type = cpu_to_le16(SELF_RELATIVE | DACL_PRESENT); | |
1130 | if (le16_to_cpu(parent_pntsd->type) & DACL_AUTO_INHERITED) | |
1131 | pntsd->type |= cpu_to_le16(DACL_AUTO_INHERITED); | |
1132 | pntsd_size = sizeof(struct smb_ntsd); | |
1133 | pntsd->osidoffset = parent_pntsd->osidoffset; | |
1134 | pntsd->gsidoffset = parent_pntsd->gsidoffset; | |
1135 | pntsd->dacloffset = parent_pntsd->dacloffset; | |
1136 | ||
1137 | if (pntsd->osidoffset) { | |
1138 | struct smb_sid *owner_sid = (struct smb_sid *)((char *)pntsd + | |
1139 | le32_to_cpu(pntsd->osidoffset)); | |
1140 | memcpy(owner_sid, powner_sid, powner_sid_size); | |
1141 | pntsd_size += powner_sid_size; | |
1142 | } | |
1143 | ||
1144 | if (pntsd->gsidoffset) { | |
1145 | struct smb_sid *group_sid = (struct smb_sid *)((char *)pntsd + | |
1146 | le32_to_cpu(pntsd->gsidoffset)); | |
1147 | memcpy(group_sid, pgroup_sid, pgroup_sid_size); | |
1148 | pntsd_size += pgroup_sid_size; | |
1149 | } | |
1150 | ||
1151 | if (pntsd->dacloffset) { | |
1152 | struct smb_ace *pace; | |
1153 | ||
1154 | pdacl = (struct smb_acl *)((char *)pntsd + le32_to_cpu(pntsd->dacloffset)); | |
1155 | pdacl->revision = cpu_to_le16(2); | |
1156 | pdacl->size = cpu_to_le16(sizeof(struct smb_acl) + nt_size); | |
1157 | pdacl->num_aces = cpu_to_le32(ace_cnt); | |
1158 | pace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl)); | |
1159 | memcpy(pace, aces_base, nt_size); | |
1160 | pntsd_size += sizeof(struct smb_acl) + nt_size; | |
1161 | } | |
1162 | ||
465d7204 | 1163 | ksmbd_vfs_set_sd_xattr(conn, user_ns, |
af34983e | 1164 | path->dentry, pntsd, pntsd_size); |
e2f34481 | 1165 | kfree(pntsd); |
e2f34481 NJ |
1166 | } |
1167 | ||
a9071e3c | 1168 | free_aces_base: |
e2f34481 | 1169 | kfree(aces_base); |
a9071e3c NJ |
1170 | free_parent_pntsd: |
1171 | kfree(parent_pntsd); | |
e2f34481 NJ |
1172 | return rc; |
1173 | } | |
1174 | ||
1175 | bool smb_inherit_flags(int flags, bool is_dir) | |
1176 | { | |
1177 | if (!is_dir) | |
1178 | return (flags & OBJECT_INHERIT_ACE) != 0; | |
1179 | ||
1180 | if (flags & OBJECT_INHERIT_ACE && !(flags & NO_PROPAGATE_INHERIT_ACE)) | |
1181 | return true; | |
1182 | ||
1183 | if (flags & CONTAINER_INHERIT_ACE) | |
1184 | return true; | |
1185 | return false; | |
1186 | } | |
1187 | ||
ef24c962 | 1188 | int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path, |
070fb21e | 1189 | __le32 *pdaccess, int uid) |
e2f34481 | 1190 | { |
465d7204 | 1191 | struct user_namespace *user_ns = mnt_user_ns(path->mnt); |
e2f34481 NJ |
1192 | struct smb_ntsd *pntsd = NULL; |
1193 | struct smb_acl *pdacl; | |
1194 | struct posix_acl *posix_acls; | |
8f054118 | 1195 | int rc = 0, pntsd_size, acl_size, aces_size, pdacl_size, dacl_offset; |
e2f34481 NJ |
1196 | struct smb_sid sid; |
1197 | int granted = le32_to_cpu(*pdaccess & ~FILE_MAXIMAL_ACCESS_LE); | |
1198 | struct smb_ace *ace; | |
1199 | int i, found = 0; | |
1200 | unsigned int access_bits = 0; | |
1201 | struct smb_ace *others_ace = NULL; | |
1202 | struct posix_acl_entry *pa_entry; | |
1203 | unsigned int sid_type = SIDOWNER; | |
8f054118 | 1204 | unsigned short ace_size; |
e2f34481 NJ |
1205 | |
1206 | ksmbd_debug(SMB, "check permission using windows acl\n"); | |
8f054118 NJ |
1207 | pntsd_size = ksmbd_vfs_get_sd_xattr(conn, user_ns, |
1208 | path->dentry, &pntsd); | |
1209 | if (pntsd_size <= 0 || !pntsd) | |
1210 | goto err_out; | |
1211 | ||
1212 | dacl_offset = le32_to_cpu(pntsd->dacloffset); | |
1213 | if (!dacl_offset || | |
1214 | (dacl_offset + sizeof(struct smb_acl) > pntsd_size)) | |
1215 | goto err_out; | |
e2f34481 NJ |
1216 | |
1217 | pdacl = (struct smb_acl *)((char *)pntsd + le32_to_cpu(pntsd->dacloffset)); | |
8f054118 NJ |
1218 | acl_size = pntsd_size - dacl_offset; |
1219 | pdacl_size = le16_to_cpu(pdacl->size); | |
50355b0b | 1220 | |
8f054118 NJ |
1221 | if (pdacl_size > acl_size || pdacl_size < sizeof(struct smb_acl)) |
1222 | goto err_out; | |
50355b0b | 1223 | |
e2f34481 | 1224 | if (!pdacl->num_aces) { |
8f054118 | 1225 | if (!(pdacl_size - sizeof(struct smb_acl)) && |
e2f34481 NJ |
1226 | *pdaccess & ~(FILE_READ_CONTROL_LE | FILE_WRITE_DAC_LE)) { |
1227 | rc = -EACCES; | |
1228 | goto err_out; | |
1229 | } | |
8f054118 | 1230 | goto err_out; |
e2f34481 NJ |
1231 | } |
1232 | ||
1233 | if (*pdaccess & FILE_MAXIMAL_ACCESS_LE) { | |
1234 | granted = READ_CONTROL | WRITE_DAC | FILE_READ_ATTRIBUTES | | |
1235 | DELETE; | |
1236 | ||
1237 | ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl)); | |
8f054118 | 1238 | aces_size = acl_size - sizeof(struct smb_acl); |
e2f34481 | 1239 | for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) { |
8f054118 NJ |
1240 | if (offsetof(struct smb_ace, access_req) > aces_size) |
1241 | break; | |
1242 | ace_size = le16_to_cpu(ace->size); | |
1243 | if (ace_size > aces_size) | |
1244 | break; | |
1245 | aces_size -= ace_size; | |
e2f34481 | 1246 | granted |= le32_to_cpu(ace->access_req); |
64b39f4a | 1247 | ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace->size)); |
e2f34481 NJ |
1248 | } |
1249 | ||
1250 | if (!pdacl->num_aces) | |
1251 | granted = GENERIC_ALL_FLAGS; | |
1252 | } | |
1253 | ||
1254 | if (!uid) | |
1255 | sid_type = SIDUNIX_USER; | |
1256 | id_to_sid(uid, sid_type, &sid); | |
1257 | ||
1258 | ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl)); | |
8f054118 | 1259 | aces_size = acl_size - sizeof(struct smb_acl); |
e2f34481 | 1260 | for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) { |
8f054118 NJ |
1261 | if (offsetof(struct smb_ace, access_req) > aces_size) |
1262 | break; | |
1263 | ace_size = le16_to_cpu(ace->size); | |
1264 | if (ace_size > aces_size) | |
1265 | break; | |
1266 | aces_size -= ace_size; | |
1267 | ||
e2f34481 NJ |
1268 | if (!compare_sids(&sid, &ace->sid) || |
1269 | !compare_sids(&sid_unix_NFS_mode, &ace->sid)) { | |
1270 | found = 1; | |
1271 | break; | |
1272 | } | |
1273 | if (!compare_sids(&sid_everyone, &ace->sid)) | |
1274 | others_ace = ace; | |
1275 | ||
64b39f4a | 1276 | ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace->size)); |
e2f34481 NJ |
1277 | } |
1278 | ||
1279 | if (*pdaccess & FILE_MAXIMAL_ACCESS_LE && found) { | |
1280 | granted = READ_CONTROL | WRITE_DAC | FILE_READ_ATTRIBUTES | | |
1281 | DELETE; | |
1282 | ||
1283 | granted |= le32_to_cpu(ace->access_req); | |
1284 | ||
1285 | if (!pdacl->num_aces) | |
1286 | granted = GENERIC_ALL_FLAGS; | |
1287 | } | |
1288 | ||
777cad16 NJ |
1289 | if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) { |
1290 | posix_acls = get_acl(d_inode(path->dentry), ACL_TYPE_ACCESS); | |
1291 | if (posix_acls && !found) { | |
1292 | unsigned int id = -1; | |
1293 | ||
1294 | pa_entry = posix_acls->a_entries; | |
1295 | for (i = 0; i < posix_acls->a_count; i++, pa_entry++) { | |
1296 | if (pa_entry->e_tag == ACL_USER) | |
0e844efe | 1297 | id = posix_acl_uid_translate(user_ns, pa_entry); |
777cad16 | 1298 | else if (pa_entry->e_tag == ACL_GROUP) |
0e844efe | 1299 | id = posix_acl_gid_translate(user_ns, pa_entry); |
777cad16 NJ |
1300 | else |
1301 | continue; | |
1302 | ||
1303 | if (id == uid) { | |
1304 | mode_to_access_flags(pa_entry->e_perm, | |
1305 | 0777, | |
1306 | &access_bits); | |
1307 | if (!access_bits) | |
1308 | access_bits = | |
1309 | SET_MINIMUM_RIGHTS; | |
d21a580d | 1310 | posix_acl_release(posix_acls); |
777cad16 NJ |
1311 | goto check_access_bits; |
1312 | } | |
e2f34481 NJ |
1313 | } |
1314 | } | |
777cad16 NJ |
1315 | if (posix_acls) |
1316 | posix_acl_release(posix_acls); | |
e2f34481 | 1317 | } |
e2f34481 NJ |
1318 | |
1319 | if (!found) { | |
64b39f4a | 1320 | if (others_ace) { |
e2f34481 | 1321 | ace = others_ace; |
64b39f4a | 1322 | } else { |
e2f34481 NJ |
1323 | ksmbd_debug(SMB, "Can't find corresponding sid\n"); |
1324 | rc = -EACCES; | |
1325 | goto err_out; | |
1326 | } | |
1327 | } | |
1328 | ||
1329 | switch (ace->type) { | |
1330 | case ACCESS_ALLOWED_ACE_TYPE: | |
1331 | access_bits = le32_to_cpu(ace->access_req); | |
1332 | break; | |
1333 | case ACCESS_DENIED_ACE_TYPE: | |
1334 | case ACCESS_DENIED_CALLBACK_ACE_TYPE: | |
1335 | access_bits = le32_to_cpu(~ace->access_req); | |
1336 | break; | |
1337 | } | |
1338 | ||
1339 | check_access_bits: | |
070fb21e NJ |
1340 | if (granted & |
1341 | ~(access_bits | FILE_READ_ATTRIBUTES | READ_CONTROL | WRITE_DAC | DELETE)) { | |
e2f34481 | 1342 | ksmbd_debug(SMB, "Access denied with winACL, granted : %x, access_req : %x\n", |
070fb21e | 1343 | granted, le32_to_cpu(ace->access_req)); |
e2f34481 NJ |
1344 | rc = -EACCES; |
1345 | goto err_out; | |
1346 | } | |
1347 | ||
1348 | *pdaccess = cpu_to_le32(granted); | |
1349 | err_out: | |
1350 | kfree(pntsd); | |
1351 | return rc; | |
1352 | } | |
1353 | ||
1354 | int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon, | |
ef24c962 | 1355 | struct path *path, struct smb_ntsd *pntsd, int ntsd_len, |
070fb21e | 1356 | bool type_check) |
e2f34481 NJ |
1357 | { |
1358 | int rc; | |
1359 | struct smb_fattr fattr = {{0}}; | |
ef24c962 | 1360 | struct inode *inode = d_inode(path->dentry); |
465d7204 | 1361 | struct user_namespace *user_ns = mnt_user_ns(path->mnt); |
e70e392f | 1362 | struct iattr newattrs; |
e2f34481 NJ |
1363 | |
1364 | fattr.cf_uid = INVALID_UID; | |
1365 | fattr.cf_gid = INVALID_GID; | |
1366 | fattr.cf_mode = inode->i_mode; | |
1367 | ||
465d7204 | 1368 | rc = parse_sec_desc(user_ns, pntsd, ntsd_len, &fattr); |
e2f34481 NJ |
1369 | if (rc) |
1370 | goto out; | |
1371 | ||
e70e392f NJ |
1372 | newattrs.ia_valid = ATTR_CTIME; |
1373 | if (!uid_eq(fattr.cf_uid, INVALID_UID)) { | |
1374 | newattrs.ia_valid |= ATTR_UID; | |
1375 | newattrs.ia_uid = fattr.cf_uid; | |
1376 | } | |
1377 | if (!gid_eq(fattr.cf_gid, INVALID_GID)) { | |
1378 | newattrs.ia_valid |= ATTR_GID; | |
1379 | newattrs.ia_gid = fattr.cf_gid; | |
1380 | } | |
1381 | newattrs.ia_valid |= ATTR_MODE; | |
1382 | newattrs.ia_mode = (inode->i_mode & ~0777) | (fattr.cf_mode & 0777); | |
1383 | ||
465d7204 | 1384 | ksmbd_vfs_remove_acl_xattrs(user_ns, path->dentry); |
e2f34481 | 1385 | /* Update posix acls */ |
777cad16 | 1386 | if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && fattr.cf_dacls) { |
465d7204 | 1387 | rc = set_posix_acl(user_ns, inode, |
af34983e | 1388 | ACL_TYPE_ACCESS, fattr.cf_acls); |
28a5d3de CB |
1389 | if (rc < 0) |
1390 | ksmbd_debug(SMB, | |
1391 | "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n", | |
1392 | rc); | |
1393 | if (S_ISDIR(inode->i_mode) && fattr.cf_dacls) { | |
465d7204 | 1394 | rc = set_posix_acl(user_ns, inode, |
67d1c432 | 1395 | ACL_TYPE_DEFAULT, fattr.cf_dacls); |
28a5d3de CB |
1396 | if (rc) |
1397 | ksmbd_debug(SMB, | |
1398 | "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n", | |
1399 | rc); | |
1400 | } | |
e2f34481 NJ |
1401 | } |
1402 | ||
28a5d3de CB |
1403 | inode_lock(inode); |
1404 | rc = notify_change(user_ns, path->dentry, &newattrs, NULL); | |
1405 | inode_unlock(inode); | |
1406 | if (rc) | |
1407 | goto out; | |
1408 | ||
e2f34481 NJ |
1409 | /* Check it only calling from SD BUFFER context */ |
1410 | if (type_check && !(le16_to_cpu(pntsd->type) & DACL_PRESENT)) | |
1411 | goto out; | |
1412 | ||
64b39f4a | 1413 | if (test_share_config_flag(tcon->share_conf, KSMBD_SHARE_FLAG_ACL_XATTR)) { |
e2f34481 | 1414 | /* Update WinACL in xattr */ |
465d7204 HL |
1415 | ksmbd_vfs_remove_sd_xattrs(user_ns, path->dentry); |
1416 | ksmbd_vfs_set_sd_xattr(conn, user_ns, | |
af34983e | 1417 | path->dentry, pntsd, ntsd_len); |
e2f34481 NJ |
1418 | } |
1419 | ||
1420 | out: | |
1421 | posix_acl_release(fattr.cf_acls); | |
1422 | posix_acl_release(fattr.cf_dacls); | |
1423 | mark_inode_dirty(inode); | |
1424 | return rc; | |
1425 | } | |
1426 | ||
1427 | void ksmbd_init_domain(u32 *sub_auth) | |
1428 | { | |
1429 | int i; | |
1430 | ||
1431 | memcpy(&server_conf.domain_sid, &domain, sizeof(struct smb_sid)); | |
1432 | for (i = 0; i < 3; ++i) | |
1433 | server_conf.domain_sid.sub_auth[i + 1] = cpu_to_le32(sub_auth[i]); | |
1434 | } |