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; | |
f65fadb0 | 100 | num_subauth = min(num_sat, num_saw); |
e2f34481 NJ |
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 | ||
4d7ca409 | 257 | static int sid_to_id(struct mnt_idmap *idmap, |
af34983e | 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]); | |
276a3f7c | 278 | uid = KUIDT_INIT(id); |
4d7ca409 | 279 | uid = from_vfsuid(idmap, &init_user_ns, VFSUIDT_INIT(uid)); |
4cf0ccd0 NJ |
280 | if (uid_valid(uid)) { |
281 | fattr->cf_uid = uid; | |
282 | rc = 0; | |
e2f34481 NJ |
283 | } |
284 | } else { | |
285 | kgid_t gid; | |
286 | gid_t id; | |
287 | ||
288 | id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]); | |
276a3f7c | 289 | gid = KGIDT_INIT(id); |
4d7ca409 | 290 | gid = from_vfsgid(idmap, &init_user_ns, VFSGIDT_INIT(gid)); |
4cf0ccd0 NJ |
291 | if (gid_valid(gid)) { |
292 | fattr->cf_gid = gid; | |
293 | rc = 0; | |
e2f34481 NJ |
294 | } |
295 | } | |
296 | ||
297 | return rc; | |
298 | } | |
299 | ||
300 | void posix_state_to_acl(struct posix_acl_state *state, | |
070fb21e | 301 | struct posix_acl_entry *pace) |
e2f34481 NJ |
302 | { |
303 | int i; | |
304 | ||
305 | pace->e_tag = ACL_USER_OBJ; | |
306 | pace->e_perm = state->owner.allow; | |
307 | for (i = 0; i < state->users->n; i++) { | |
308 | pace++; | |
309 | pace->e_tag = ACL_USER; | |
310 | pace->e_uid = state->users->aces[i].uid; | |
311 | pace->e_perm = state->users->aces[i].perms.allow; | |
312 | } | |
313 | ||
314 | pace++; | |
315 | pace->e_tag = ACL_GROUP_OBJ; | |
316 | pace->e_perm = state->group.allow; | |
317 | ||
318 | for (i = 0; i < state->groups->n; i++) { | |
319 | pace++; | |
320 | pace->e_tag = ACL_GROUP; | |
321 | pace->e_gid = state->groups->aces[i].gid; | |
322 | pace->e_perm = state->groups->aces[i].perms.allow; | |
323 | } | |
324 | ||
325 | if (state->users->n || state->groups->n) { | |
326 | pace++; | |
327 | pace->e_tag = ACL_MASK; | |
328 | pace->e_perm = state->mask.allow; | |
329 | } | |
330 | ||
331 | pace++; | |
332 | pace->e_tag = ACL_OTHER; | |
333 | pace->e_perm = state->other.allow; | |
334 | } | |
335 | ||
336 | int init_acl_state(struct posix_acl_state *state, int cnt) | |
337 | { | |
338 | int alloc; | |
339 | ||
340 | memset(state, 0, sizeof(struct posix_acl_state)); | |
341 | /* | |
342 | * In the worst case, each individual acl could be for a distinct | |
343 | * named user or group, but we don't know which, so we allocate | |
344 | * enough space for either: | |
345 | */ | |
346 | alloc = sizeof(struct posix_ace_state_array) | |
64b39f4a | 347 | + cnt * sizeof(struct posix_user_ace_state); |
e2f34481 NJ |
348 | state->users = kzalloc(alloc, GFP_KERNEL); |
349 | if (!state->users) | |
350 | return -ENOMEM; | |
351 | state->groups = kzalloc(alloc, GFP_KERNEL); | |
352 | if (!state->groups) { | |
353 | kfree(state->users); | |
354 | return -ENOMEM; | |
355 | } | |
356 | return 0; | |
357 | } | |
358 | ||
359 | void free_acl_state(struct posix_acl_state *state) | |
360 | { | |
361 | kfree(state->users); | |
362 | kfree(state->groups); | |
363 | } | |
364 | ||
4d7ca409 | 365 | static void parse_dacl(struct mnt_idmap *idmap, |
af34983e | 366 | struct smb_acl *pdacl, char *end_of_acl, |
070fb21e NJ |
367 | struct smb_sid *pownersid, struct smb_sid *pgrpsid, |
368 | struct smb_fattr *fattr) | |
e2f34481 NJ |
369 | { |
370 | int i, ret; | |
371 | int num_aces = 0; | |
8f77150c | 372 | unsigned int acl_size; |
e2f34481 NJ |
373 | char *acl_base; |
374 | struct smb_ace **ppace; | |
375 | struct posix_acl_entry *cf_pace, *cf_pdace; | |
376 | struct posix_acl_state acl_state, default_acl_state; | |
377 | umode_t mode = 0, acl_mode; | |
378 | bool owner_found = false, group_found = false, others_found = false; | |
379 | ||
380 | if (!pdacl) | |
381 | return; | |
382 | ||
383 | /* validate that we do not go past end of acl */ | |
8f77150c | 384 | if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl) || |
548e9ad3 | 385 | end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) { |
bde1694a | 386 | pr_err("ACL too small to parse DACL\n"); |
e2f34481 NJ |
387 | return; |
388 | } | |
389 | ||
390 | ksmbd_debug(SMB, "DACL revision %d size %d num aces %d\n", | |
070fb21e NJ |
391 | le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size), |
392 | le32_to_cpu(pdacl->num_aces)); | |
e2f34481 NJ |
393 | |
394 | acl_base = (char *)pdacl; | |
395 | acl_size = sizeof(struct smb_acl); | |
396 | ||
397 | num_aces = le32_to_cpu(pdacl->num_aces); | |
398 | if (num_aces <= 0) | |
399 | return; | |
400 | ||
401 | if (num_aces > ULONG_MAX / sizeof(struct smb_ace *)) | |
402 | return; | |
403 | ||
070fb21e | 404 | ppace = kmalloc_array(num_aces, sizeof(struct smb_ace *), GFP_KERNEL); |
e2f34481 NJ |
405 | if (!ppace) |
406 | return; | |
407 | ||
408 | ret = init_acl_state(&acl_state, num_aces); | |
409 | if (ret) | |
410 | return; | |
411 | ret = init_acl_state(&default_acl_state, num_aces); | |
412 | if (ret) { | |
413 | free_acl_state(&acl_state); | |
414 | return; | |
415 | } | |
416 | ||
417 | /* | |
418 | * reset rwx permissions for user/group/other. | |
419 | * Also, if num_aces is 0 i.e. DACL has no ACEs, | |
420 | * user/group/other have no permissions | |
421 | */ | |
422 | for (i = 0; i < num_aces; ++i) { | |
8f77150c HL |
423 | if (end_of_acl - acl_base < acl_size) |
424 | break; | |
425 | ||
64b39f4a | 426 | ppace[i] = (struct smb_ace *)(acl_base + acl_size); |
e2f34481 | 427 | acl_base = (char *)ppace[i]; |
8f77150c HL |
428 | acl_size = offsetof(struct smb_ace, sid) + |
429 | offsetof(struct smb_sid, sub_auth); | |
430 | ||
431 | if (end_of_acl - acl_base < acl_size || | |
432 | ppace[i]->sid.num_subauth > SID_MAX_SUB_AUTHORITIES || | |
433 | (end_of_acl - acl_base < | |
434 | acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth) || | |
435 | (le16_to_cpu(ppace[i]->size) < | |
436 | acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth)) | |
437 | break; | |
438 | ||
e2f34481 NJ |
439 | acl_size = le16_to_cpu(ppace[i]->size); |
440 | ppace[i]->access_req = | |
441 | smb_map_generic_desired_access(ppace[i]->access_req); | |
442 | ||
64b39f4a | 443 | if (!(compare_sids(&ppace[i]->sid, &sid_unix_NFS_mode))) { |
e2f34481 NJ |
444 | fattr->cf_mode = |
445 | le32_to_cpu(ppace[i]->sid.sub_auth[2]); | |
446 | break; | |
64b39f4a | 447 | } else if (!compare_sids(&ppace[i]->sid, pownersid)) { |
e2f34481 | 448 | acl_mode = access_flags_to_mode(fattr, |
070fb21e NJ |
449 | ppace[i]->access_req, |
450 | ppace[i]->type); | |
e2f34481 NJ |
451 | acl_mode &= 0700; |
452 | ||
453 | if (!owner_found) { | |
454 | mode &= ~(0700); | |
455 | mode |= acl_mode; | |
456 | } | |
457 | owner_found = true; | |
64b39f4a NJ |
458 | } else if (!compare_sids(&ppace[i]->sid, pgrpsid) || |
459 | ppace[i]->sid.sub_auth[ppace[i]->sid.num_subauth - 1] == | |
460 | DOMAIN_USER_RID_LE) { | |
e2f34481 | 461 | acl_mode = access_flags_to_mode(fattr, |
070fb21e NJ |
462 | ppace[i]->access_req, |
463 | ppace[i]->type); | |
e2f34481 NJ |
464 | acl_mode &= 0070; |
465 | if (!group_found) { | |
466 | mode &= ~(0070); | |
467 | mode |= acl_mode; | |
468 | } | |
469 | group_found = true; | |
64b39f4a | 470 | } else if (!compare_sids(&ppace[i]->sid, &sid_everyone)) { |
e2f34481 | 471 | acl_mode = access_flags_to_mode(fattr, |
070fb21e NJ |
472 | ppace[i]->access_req, |
473 | ppace[i]->type); | |
e2f34481 NJ |
474 | acl_mode &= 0007; |
475 | if (!others_found) { | |
476 | mode &= ~(0007); | |
477 | mode |= acl_mode; | |
478 | } | |
479 | others_found = true; | |
64b39f4a | 480 | } else if (!compare_sids(&ppace[i]->sid, &creator_owner)) { |
e2f34481 | 481 | continue; |
64b39f4a | 482 | } else if (!compare_sids(&ppace[i]->sid, &creator_group)) { |
e2f34481 | 483 | continue; |
64b39f4a | 484 | } else if (!compare_sids(&ppace[i]->sid, &sid_authusers)) { |
e2f34481 | 485 | continue; |
64b39f4a | 486 | } else { |
e2f34481 NJ |
487 | struct smb_fattr temp_fattr; |
488 | ||
489 | acl_mode = access_flags_to_mode(fattr, ppace[i]->access_req, | |
070fb21e | 490 | ppace[i]->type); |
e2f34481 | 491 | temp_fattr.cf_uid = INVALID_UID; |
4d7ca409 | 492 | ret = sid_to_id(idmap, &ppace[i]->sid, SIDOWNER, &temp_fattr); |
e2f34481 | 493 | if (ret || uid_eq(temp_fattr.cf_uid, INVALID_UID)) { |
bde1694a NJ |
494 | pr_err("%s: Error %d mapping Owner SID to uid\n", |
495 | __func__, ret); | |
e2f34481 NJ |
496 | continue; |
497 | } | |
498 | ||
499 | acl_state.owner.allow = ((acl_mode & 0700) >> 6) | 0004; | |
500 | acl_state.users->aces[acl_state.users->n].uid = | |
501 | temp_fattr.cf_uid; | |
502 | acl_state.users->aces[acl_state.users->n++].perms.allow = | |
503 | ((acl_mode & 0700) >> 6) | 0004; | |
504 | default_acl_state.owner.allow = ((acl_mode & 0700) >> 6) | 0004; | |
505 | default_acl_state.users->aces[default_acl_state.users->n].uid = | |
506 | temp_fattr.cf_uid; | |
507 | default_acl_state.users->aces[default_acl_state.users->n++].perms.allow = | |
508 | ((acl_mode & 0700) >> 6) | 0004; | |
509 | } | |
510 | } | |
511 | kfree(ppace); | |
512 | ||
513 | if (owner_found) { | |
514 | /* The owner must be set to at least read-only. */ | |
515 | acl_state.owner.allow = ((mode & 0700) >> 6) | 0004; | |
516 | acl_state.users->aces[acl_state.users->n].uid = fattr->cf_uid; | |
517 | acl_state.users->aces[acl_state.users->n++].perms.allow = | |
518 | ((mode & 0700) >> 6) | 0004; | |
519 | default_acl_state.owner.allow = ((mode & 0700) >> 6) | 0004; | |
520 | default_acl_state.users->aces[default_acl_state.users->n].uid = | |
521 | fattr->cf_uid; | |
522 | default_acl_state.users->aces[default_acl_state.users->n++].perms.allow = | |
523 | ((mode & 0700) >> 6) | 0004; | |
524 | } | |
525 | ||
526 | if (group_found) { | |
527 | acl_state.group.allow = (mode & 0070) >> 3; | |
528 | acl_state.groups->aces[acl_state.groups->n].gid = | |
529 | fattr->cf_gid; | |
530 | acl_state.groups->aces[acl_state.groups->n++].perms.allow = | |
531 | (mode & 0070) >> 3; | |
86df49e1 | 532 | default_acl_state.group.allow = (mode & 0070) >> 3; |
e2f34481 NJ |
533 | default_acl_state.groups->aces[default_acl_state.groups->n].gid = |
534 | fattr->cf_gid; | |
535 | default_acl_state.groups->aces[default_acl_state.groups->n++].perms.allow = | |
536 | (mode & 0070) >> 3; | |
537 | } | |
538 | ||
539 | if (others_found) { | |
540 | fattr->cf_mode &= ~(0007); | |
541 | fattr->cf_mode |= mode & 0007; | |
542 | ||
543 | acl_state.other.allow = mode & 0007; | |
544 | default_acl_state.other.allow = mode & 0007; | |
545 | } | |
546 | ||
547 | if (acl_state.users->n || acl_state.groups->n) { | |
548 | acl_state.mask.allow = 0x07; | |
777cad16 NJ |
549 | |
550 | if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) { | |
551 | fattr->cf_acls = | |
552 | posix_acl_alloc(acl_state.users->n + | |
553 | acl_state.groups->n + 4, GFP_KERNEL); | |
554 | if (fattr->cf_acls) { | |
555 | cf_pace = fattr->cf_acls->a_entries; | |
556 | posix_state_to_acl(&acl_state, cf_pace); | |
557 | } | |
e2f34481 NJ |
558 | } |
559 | } | |
560 | ||
561 | if (default_acl_state.users->n || default_acl_state.groups->n) { | |
562 | default_acl_state.mask.allow = 0x07; | |
777cad16 NJ |
563 | |
564 | if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) { | |
565 | fattr->cf_dacls = | |
566 | posix_acl_alloc(default_acl_state.users->n + | |
567 | default_acl_state.groups->n + 4, GFP_KERNEL); | |
568 | if (fattr->cf_dacls) { | |
569 | cf_pdace = fattr->cf_dacls->a_entries; | |
570 | posix_state_to_acl(&default_acl_state, cf_pdace); | |
571 | } | |
e2f34481 NJ |
572 | } |
573 | } | |
574 | free_acl_state(&acl_state); | |
575 | free_acl_state(&default_acl_state); | |
576 | } | |
577 | ||
4d7ca409 | 578 | static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap, |
af34983e | 579 | struct smb_ace *pndace, |
070fb21e NJ |
580 | struct smb_fattr *fattr, u32 *num_aces, |
581 | u16 *size, u32 nt_aces_num) | |
e2f34481 NJ |
582 | { |
583 | struct posix_acl_entry *pace; | |
584 | struct smb_sid *sid; | |
585 | struct smb_ace *ntace; | |
586 | int i, j; | |
587 | ||
588 | if (!fattr->cf_acls) | |
589 | goto posix_default_acl; | |
590 | ||
591 | pace = fattr->cf_acls->a_entries; | |
592 | for (i = 0; i < fattr->cf_acls->a_count; i++, pace++) { | |
593 | int flags = 0; | |
594 | ||
595 | sid = kmalloc(sizeof(struct smb_sid), GFP_KERNEL); | |
596 | if (!sid) | |
597 | break; | |
598 | ||
599 | if (pace->e_tag == ACL_USER) { | |
600 | uid_t uid; | |
601 | unsigned int sid_type = SIDOWNER; | |
602 | ||
4d7ca409 | 603 | uid = posix_acl_uid_translate(idmap, pace); |
e2f34481 NJ |
604 | if (!uid) |
605 | sid_type = SIDUNIX_USER; | |
606 | id_to_sid(uid, sid_type, sid); | |
607 | } else if (pace->e_tag == ACL_GROUP) { | |
608 | gid_t gid; | |
609 | ||
4d7ca409 | 610 | gid = posix_acl_gid_translate(idmap, pace); |
e2f34481 NJ |
611 | id_to_sid(gid, SIDUNIX_GROUP, sid); |
612 | } else if (pace->e_tag == ACL_OTHER && !nt_aces_num) { | |
613 | smb_copy_sid(sid, &sid_everyone); | |
614 | } else { | |
615 | kfree(sid); | |
616 | continue; | |
617 | } | |
618 | ntace = pndace; | |
619 | for (j = 0; j < nt_aces_num; j++) { | |
620 | if (ntace->sid.sub_auth[ntace->sid.num_subauth - 1] == | |
621 | sid->sub_auth[sid->num_subauth - 1]) | |
622 | goto pass_same_sid; | |
623 | ntace = (struct smb_ace *)((char *)ntace + | |
624 | le16_to_cpu(ntace->size)); | |
625 | } | |
626 | ||
627 | if (S_ISDIR(fattr->cf_mode) && pace->e_tag == ACL_OTHER) | |
628 | flags = 0x03; | |
629 | ||
64b39f4a | 630 | ntace = (struct smb_ace *)((char *)pndace + *size); |
e2f34481 NJ |
631 | *size += fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, flags, |
632 | pace->e_perm, 0777); | |
633 | (*num_aces)++; | |
634 | if (pace->e_tag == ACL_USER) | |
635 | ntace->access_req |= | |
636 | FILE_DELETE_LE | FILE_DELETE_CHILD_LE; | |
637 | ||
638 | if (S_ISDIR(fattr->cf_mode) && | |
64b39f4a NJ |
639 | (pace->e_tag == ACL_USER || pace->e_tag == ACL_GROUP)) { |
640 | ntace = (struct smb_ace *)((char *)pndace + *size); | |
e2f34481 NJ |
641 | *size += fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, |
642 | 0x03, pace->e_perm, 0777); | |
643 | (*num_aces)++; | |
644 | if (pace->e_tag == ACL_USER) | |
645 | ntace->access_req |= | |
646 | FILE_DELETE_LE | FILE_DELETE_CHILD_LE; | |
647 | } | |
648 | ||
649 | pass_same_sid: | |
650 | kfree(sid); | |
651 | } | |
652 | ||
653 | if (nt_aces_num) | |
654 | return; | |
655 | ||
656 | posix_default_acl: | |
657 | if (!fattr->cf_dacls) | |
658 | return; | |
659 | ||
660 | pace = fattr->cf_dacls->a_entries; | |
661 | for (i = 0; i < fattr->cf_dacls->a_count; i++, pace++) { | |
662 | sid = kmalloc(sizeof(struct smb_sid), GFP_KERNEL); | |
663 | if (!sid) | |
664 | break; | |
665 | ||
666 | if (pace->e_tag == ACL_USER) { | |
667 | uid_t uid; | |
668 | ||
4d7ca409 | 669 | uid = posix_acl_uid_translate(idmap, pace); |
e2f34481 NJ |
670 | id_to_sid(uid, SIDCREATOR_OWNER, sid); |
671 | } else if (pace->e_tag == ACL_GROUP) { | |
672 | gid_t gid; | |
673 | ||
4d7ca409 | 674 | gid = posix_acl_gid_translate(idmap, pace); |
e2f34481 NJ |
675 | id_to_sid(gid, SIDCREATOR_GROUP, sid); |
676 | } else { | |
677 | kfree(sid); | |
678 | continue; | |
679 | } | |
680 | ||
64b39f4a | 681 | ntace = (struct smb_ace *)((char *)pndace + *size); |
e2f34481 NJ |
682 | *size += fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, 0x0b, |
683 | pace->e_perm, 0777); | |
684 | (*num_aces)++; | |
685 | if (pace->e_tag == ACL_USER) | |
686 | ntace->access_req |= | |
687 | FILE_DELETE_LE | FILE_DELETE_CHILD_LE; | |
688 | kfree(sid); | |
689 | } | |
690 | } | |
691 | ||
4d7ca409 | 692 | static void set_ntacl_dacl(struct mnt_idmap *idmap, |
af34983e HL |
693 | struct smb_acl *pndacl, |
694 | struct smb_acl *nt_dacl, | |
8f054118 | 695 | unsigned int aces_size, |
070fb21e NJ |
696 | const struct smb_sid *pownersid, |
697 | const struct smb_sid *pgrpsid, | |
698 | struct smb_fattr *fattr) | |
e2f34481 NJ |
699 | { |
700 | struct smb_ace *ntace, *pndace; | |
701 | int nt_num_aces = le32_to_cpu(nt_dacl->num_aces), num_aces = 0; | |
702 | unsigned short size = 0; | |
703 | int i; | |
704 | ||
705 | pndace = (struct smb_ace *)((char *)pndacl + sizeof(struct smb_acl)); | |
706 | if (nt_num_aces) { | |
707 | ntace = (struct smb_ace *)((char *)nt_dacl + sizeof(struct smb_acl)); | |
708 | for (i = 0; i < nt_num_aces; i++) { | |
8f054118 NJ |
709 | unsigned short nt_ace_size; |
710 | ||
711 | if (offsetof(struct smb_ace, access_req) > aces_size) | |
712 | break; | |
713 | ||
714 | nt_ace_size = le16_to_cpu(ntace->size); | |
715 | if (nt_ace_size > aces_size) | |
716 | break; | |
717 | ||
718 | memcpy((char *)pndace + size, ntace, nt_ace_size); | |
719 | size += nt_ace_size; | |
720 | aces_size -= nt_ace_size; | |
721 | ntace = (struct smb_ace *)((char *)ntace + nt_ace_size); | |
e2f34481 NJ |
722 | num_aces++; |
723 | } | |
724 | } | |
725 | ||
4d7ca409 | 726 | set_posix_acl_entries_dacl(idmap, pndace, fattr, |
af34983e | 727 | &num_aces, &size, nt_num_aces); |
e2f34481 NJ |
728 | pndacl->num_aces = cpu_to_le32(num_aces); |
729 | pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size); | |
730 | } | |
731 | ||
4d7ca409 | 732 | static void set_mode_dacl(struct mnt_idmap *idmap, |
af34983e | 733 | struct smb_acl *pndacl, struct smb_fattr *fattr) |
e2f34481 NJ |
734 | { |
735 | struct smb_ace *pace, *pndace; | |
736 | u32 num_aces = 0; | |
737 | u16 size = 0, ace_size = 0; | |
738 | uid_t uid; | |
739 | const struct smb_sid *sid; | |
740 | ||
741 | pace = pndace = (struct smb_ace *)((char *)pndacl + sizeof(struct smb_acl)); | |
742 | ||
743 | if (fattr->cf_acls) { | |
4d7ca409 | 744 | set_posix_acl_entries_dacl(idmap, pndace, fattr, |
af34983e | 745 | &num_aces, &size, num_aces); |
e2f34481 NJ |
746 | goto out; |
747 | } | |
748 | ||
749 | /* owner RID */ | |
43205ca7 | 750 | uid = from_kuid(&init_user_ns, fattr->cf_uid); |
e2f34481 NJ |
751 | if (uid) |
752 | sid = &server_conf.domain_sid; | |
753 | else | |
754 | sid = &sid_unix_users; | |
755 | ace_size = fill_ace_for_sid(pace, sid, ACCESS_ALLOWED, 0, | |
070fb21e | 756 | fattr->cf_mode, 0700); |
e2f34481 | 757 | pace->sid.sub_auth[pace->sid.num_subauth++] = cpu_to_le32(uid); |
e2f34481 NJ |
758 | pace->size = cpu_to_le16(ace_size + 4); |
759 | size += le16_to_cpu(pace->size); | |
760 | pace = (struct smb_ace *)((char *)pndace + size); | |
761 | ||
762 | /* Group RID */ | |
763 | ace_size = fill_ace_for_sid(pace, &sid_unix_groups, | |
070fb21e | 764 | ACCESS_ALLOWED, 0, fattr->cf_mode, 0070); |
e2f34481 | 765 | pace->sid.sub_auth[pace->sid.num_subauth++] = |
43205ca7 | 766 | cpu_to_le32(from_kgid(&init_user_ns, fattr->cf_gid)); |
e2f34481 NJ |
767 | pace->size = cpu_to_le16(ace_size + 4); |
768 | size += le16_to_cpu(pace->size); | |
769 | pace = (struct smb_ace *)((char *)pndace + size); | |
770 | num_aces = 3; | |
771 | ||
772 | if (S_ISDIR(fattr->cf_mode)) { | |
773 | pace = (struct smb_ace *)((char *)pndace + size); | |
774 | ||
775 | /* creator owner */ | |
776 | size += fill_ace_for_sid(pace, &creator_owner, ACCESS_ALLOWED, | |
070fb21e | 777 | 0x0b, fattr->cf_mode, 0700); |
e2f34481 NJ |
778 | pace = (struct smb_ace *)((char *)pndace + size); |
779 | ||
780 | /* creator group */ | |
781 | size += fill_ace_for_sid(pace, &creator_group, ACCESS_ALLOWED, | |
070fb21e | 782 | 0x0b, fattr->cf_mode, 0070); |
e2f34481 NJ |
783 | pace = (struct smb_ace *)((char *)pndace + size); |
784 | num_aces = 5; | |
785 | } | |
786 | ||
787 | /* other */ | |
788 | size += fill_ace_for_sid(pace, &sid_everyone, ACCESS_ALLOWED, 0, | |
070fb21e | 789 | fattr->cf_mode, 0007); |
e2f34481 NJ |
790 | |
791 | out: | |
792 | pndacl->num_aces = cpu_to_le32(num_aces); | |
793 | pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size); | |
794 | } | |
795 | ||
796 | static int parse_sid(struct smb_sid *psid, char *end_of_acl) | |
797 | { | |
798 | /* | |
799 | * validate that we do not go past end of ACL - sid must be at least 8 | |
800 | * bytes long (assuming no sub-auths - e.g. the null SID | |
801 | */ | |
802 | if (end_of_acl < (char *)psid + 8) { | |
bde1694a | 803 | pr_err("ACL too small to parse SID %p\n", psid); |
e2f34481 NJ |
804 | return -EINVAL; |
805 | } | |
806 | ||
807 | return 0; | |
808 | } | |
809 | ||
810 | /* Convert CIFS ACL to POSIX form */ | |
4d7ca409 | 811 | int parse_sec_desc(struct mnt_idmap *idmap, struct smb_ntsd *pntsd, |
af34983e | 812 | int acl_len, struct smb_fattr *fattr) |
e2f34481 NJ |
813 | { |
814 | int rc = 0; | |
815 | struct smb_sid *owner_sid_ptr, *group_sid_ptr; | |
816 | struct smb_acl *dacl_ptr; /* no need for SACL ptr */ | |
817 | char *end_of_acl = ((char *)pntsd) + acl_len; | |
818 | __u32 dacloffset; | |
548e9ad3 | 819 | int pntsd_type; |
e2f34481 | 820 | |
64b39f4a | 821 | if (!pntsd) |
e2f34481 NJ |
822 | return -EIO; |
823 | ||
8f77150c HL |
824 | if (acl_len < sizeof(struct smb_ntsd)) |
825 | return -EINVAL; | |
826 | ||
e2f34481 NJ |
827 | owner_sid_ptr = (struct smb_sid *)((char *)pntsd + |
828 | le32_to_cpu(pntsd->osidoffset)); | |
829 | group_sid_ptr = (struct smb_sid *)((char *)pntsd + | |
830 | le32_to_cpu(pntsd->gsidoffset)); | |
831 | dacloffset = le32_to_cpu(pntsd->dacloffset); | |
832 | dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset); | |
833 | ksmbd_debug(SMB, | |
070fb21e NJ |
834 | "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n", |
835 | pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset), | |
836 | le32_to_cpu(pntsd->gsidoffset), | |
837 | le32_to_cpu(pntsd->sacloffset), dacloffset); | |
e2f34481 | 838 | |
e2f34481 | 839 | pntsd_type = le16_to_cpu(pntsd->type); |
e2f34481 NJ |
840 | if (!(pntsd_type & DACL_PRESENT)) { |
841 | ksmbd_debug(SMB, "DACL_PRESENT in DACL type is not set\n"); | |
842 | return rc; | |
843 | } | |
844 | ||
845 | pntsd->type = cpu_to_le16(DACL_PRESENT); | |
846 | ||
847 | if (pntsd->osidoffset) { | |
848 | rc = parse_sid(owner_sid_ptr, end_of_acl); | |
849 | if (rc) { | |
bde1694a | 850 | pr_err("%s: Error %d parsing Owner SID\n", __func__, rc); |
e2f34481 NJ |
851 | return rc; |
852 | } | |
853 | ||
4d7ca409 | 854 | rc = sid_to_id(idmap, owner_sid_ptr, SIDOWNER, fattr); |
e2f34481 | 855 | if (rc) { |
bde1694a NJ |
856 | pr_err("%s: Error %d mapping Owner SID to uid\n", |
857 | __func__, rc); | |
e2f34481 NJ |
858 | owner_sid_ptr = NULL; |
859 | } | |
860 | } | |
861 | ||
862 | if (pntsd->gsidoffset) { | |
863 | rc = parse_sid(group_sid_ptr, end_of_acl); | |
864 | if (rc) { | |
bde1694a NJ |
865 | pr_err("%s: Error %d mapping Owner SID to gid\n", |
866 | __func__, rc); | |
e2f34481 NJ |
867 | return rc; |
868 | } | |
4d7ca409 | 869 | rc = sid_to_id(idmap, group_sid_ptr, SIDUNIX_GROUP, fattr); |
e2f34481 | 870 | if (rc) { |
bde1694a NJ |
871 | pr_err("%s: Error %d mapping Group SID to gid\n", |
872 | __func__, rc); | |
e2f34481 NJ |
873 | group_sid_ptr = NULL; |
874 | } | |
875 | } | |
876 | ||
070fb21e | 877 | if ((pntsd_type & (DACL_AUTO_INHERITED | DACL_AUTO_INHERIT_REQ)) == |
e2f34481 NJ |
878 | (DACL_AUTO_INHERITED | DACL_AUTO_INHERIT_REQ)) |
879 | pntsd->type |= cpu_to_le16(DACL_AUTO_INHERITED); | |
880 | if (pntsd_type & DACL_PROTECTED) | |
881 | pntsd->type |= cpu_to_le16(DACL_PROTECTED); | |
882 | ||
883 | if (dacloffset) { | |
4d7ca409 | 884 | parse_dacl(idmap, dacl_ptr, end_of_acl, |
af34983e | 885 | owner_sid_ptr, group_sid_ptr, fattr); |
e2f34481 NJ |
886 | } |
887 | ||
888 | return 0; | |
889 | } | |
890 | ||
891 | /* Convert permission bits from mode to equivalent CIFS ACL */ | |
4d7ca409 | 892 | int build_sec_desc(struct mnt_idmap *idmap, |
af34983e | 893 | struct smb_ntsd *pntsd, struct smb_ntsd *ppntsd, |
8f054118 | 894 | int ppntsd_size, int addition_info, __u32 *secdesclen, |
070fb21e | 895 | struct smb_fattr *fattr) |
e2f34481 NJ |
896 | { |
897 | int rc = 0; | |
898 | __u32 offset; | |
899 | struct smb_sid *owner_sid_ptr, *group_sid_ptr; | |
900 | struct smb_sid *nowner_sid_ptr, *ngroup_sid_ptr; | |
901 | struct smb_acl *dacl_ptr = NULL; /* no need for SACL ptr */ | |
902 | uid_t uid; | |
903 | gid_t gid; | |
904 | unsigned int sid_type = SIDOWNER; | |
905 | ||
906 | nowner_sid_ptr = kmalloc(sizeof(struct smb_sid), GFP_KERNEL); | |
907 | if (!nowner_sid_ptr) | |
908 | return -ENOMEM; | |
909 | ||
43205ca7 | 910 | uid = from_kuid(&init_user_ns, fattr->cf_uid); |
e2f34481 NJ |
911 | if (!uid) |
912 | sid_type = SIDUNIX_USER; | |
913 | id_to_sid(uid, sid_type, nowner_sid_ptr); | |
914 | ||
915 | ngroup_sid_ptr = kmalloc(sizeof(struct smb_sid), GFP_KERNEL); | |
916 | if (!ngroup_sid_ptr) { | |
917 | kfree(nowner_sid_ptr); | |
918 | return -ENOMEM; | |
919 | } | |
920 | ||
43205ca7 | 921 | gid = from_kgid(&init_user_ns, fattr->cf_gid); |
e2f34481 NJ |
922 | id_to_sid(gid, SIDUNIX_GROUP, ngroup_sid_ptr); |
923 | ||
924 | offset = sizeof(struct smb_ntsd); | |
925 | pntsd->sacloffset = 0; | |
926 | pntsd->revision = cpu_to_le16(1); | |
927 | pntsd->type = cpu_to_le16(SELF_RELATIVE); | |
928 | if (ppntsd) | |
929 | pntsd->type |= ppntsd->type; | |
930 | ||
931 | if (addition_info & OWNER_SECINFO) { | |
932 | pntsd->osidoffset = cpu_to_le32(offset); | |
933 | owner_sid_ptr = (struct smb_sid *)((char *)pntsd + offset); | |
934 | smb_copy_sid(owner_sid_ptr, nowner_sid_ptr); | |
935 | offset += 1 + 1 + 6 + (nowner_sid_ptr->num_subauth * 4); | |
936 | } | |
937 | ||
938 | if (addition_info & GROUP_SECINFO) { | |
939 | pntsd->gsidoffset = cpu_to_le32(offset); | |
940 | group_sid_ptr = (struct smb_sid *)((char *)pntsd + offset); | |
941 | smb_copy_sid(group_sid_ptr, ngroup_sid_ptr); | |
942 | offset += 1 + 1 + 6 + (ngroup_sid_ptr->num_subauth * 4); | |
943 | } | |
944 | ||
945 | if (addition_info & DACL_SECINFO) { | |
946 | pntsd->type |= cpu_to_le16(DACL_PRESENT); | |
947 | dacl_ptr = (struct smb_acl *)((char *)pntsd + offset); | |
948 | dacl_ptr->revision = cpu_to_le16(2); | |
949 | dacl_ptr->size = cpu_to_le16(sizeof(struct smb_acl)); | |
950 | dacl_ptr->num_aces = 0; | |
951 | ||
64b39f4a | 952 | if (!ppntsd) { |
4d7ca409 | 953 | set_mode_dacl(idmap, dacl_ptr, fattr); |
64b39f4a | 954 | } else { |
e2f34481 | 955 | struct smb_acl *ppdacl_ptr; |
8f054118 NJ |
956 | unsigned int dacl_offset = le32_to_cpu(ppntsd->dacloffset); |
957 | int ppdacl_size, ntacl_size = ppntsd_size - dacl_offset; | |
958 | ||
959 | if (!dacl_offset || | |
960 | (dacl_offset + sizeof(struct smb_acl) > ppntsd_size)) | |
961 | goto out; | |
962 | ||
963 | ppdacl_ptr = (struct smb_acl *)((char *)ppntsd + dacl_offset); | |
964 | ppdacl_size = le16_to_cpu(ppdacl_ptr->size); | |
965 | if (ppdacl_size > ntacl_size || | |
966 | ppdacl_size < sizeof(struct smb_acl)) | |
967 | goto out; | |
e2f34481 | 968 | |
4d7ca409 | 969 | set_ntacl_dacl(idmap, dacl_ptr, ppdacl_ptr, |
8f054118 NJ |
970 | ntacl_size - sizeof(struct smb_acl), |
971 | nowner_sid_ptr, ngroup_sid_ptr, | |
972 | fattr); | |
e2f34481 NJ |
973 | } |
974 | pntsd->dacloffset = cpu_to_le32(offset); | |
975 | offset += le16_to_cpu(dacl_ptr->size); | |
976 | } | |
977 | ||
978 | out: | |
979 | kfree(nowner_sid_ptr); | |
980 | kfree(ngroup_sid_ptr); | |
981 | *secdesclen = offset; | |
982 | return rc; | |
983 | } | |
984 | ||
985 | static void smb_set_ace(struct smb_ace *ace, const struct smb_sid *sid, u8 type, | |
070fb21e | 986 | u8 flags, __le32 access_req) |
e2f34481 NJ |
987 | { |
988 | ace->type = type; | |
989 | ace->flags = flags; | |
990 | ace->access_req = access_req; | |
991 | smb_copy_sid(&ace->sid, sid); | |
992 | ace->size = cpu_to_le16(1 + 1 + 2 + 4 + 1 + 1 + 6 + (sid->num_subauth * 4)); | |
993 | } | |
994 | ||
ef24c962 | 995 | int smb_inherit_dacl(struct ksmbd_conn *conn, |
c22180a5 | 996 | const struct path *path, |
070fb21e | 997 | unsigned int uid, unsigned int gid) |
e2f34481 NJ |
998 | { |
999 | const struct smb_sid *psid, *creator = NULL; | |
1000 | struct smb_ace *parent_aces, *aces; | |
1001 | struct smb_acl *parent_pdacl; | |
1002 | struct smb_ntsd *parent_pntsd = NULL; | |
1003 | struct smb_sid owner_sid, group_sid; | |
ef24c962 | 1004 | struct dentry *parent = path->dentry->d_parent; |
4609e1f1 | 1005 | struct mnt_idmap *idmap = mnt_idmap(path->mnt); |
8f054118 NJ |
1006 | int inherited_flags = 0, flags = 0, i, ace_cnt = 0, nt_size = 0, pdacl_size; |
1007 | int rc = 0, num_aces, dacloffset, pntsd_type, pntsd_size, acl_len, aces_size; | |
e2f34481 | 1008 | char *aces_base; |
ef24c962 | 1009 | bool is_dir = S_ISDIR(d_inode(path->dentry)->i_mode); |
e2f34481 | 1010 | |
4609e1f1 | 1011 | pntsd_size = ksmbd_vfs_get_sd_xattr(conn, idmap, |
8f054118 NJ |
1012 | parent, &parent_pntsd); |
1013 | if (pntsd_size <= 0) | |
a9071e3c | 1014 | return -ENOENT; |
e2f34481 | 1015 | dacloffset = le32_to_cpu(parent_pntsd->dacloffset); |
8f054118 | 1016 | if (!dacloffset || (dacloffset + sizeof(struct smb_acl) > pntsd_size)) { |
a9071e3c NJ |
1017 | rc = -EINVAL; |
1018 | goto free_parent_pntsd; | |
1019 | } | |
e2f34481 NJ |
1020 | |
1021 | parent_pdacl = (struct smb_acl *)((char *)parent_pntsd + dacloffset); | |
8f054118 | 1022 | acl_len = pntsd_size - dacloffset; |
e2f34481 NJ |
1023 | num_aces = le32_to_cpu(parent_pdacl->num_aces); |
1024 | pntsd_type = le16_to_cpu(parent_pntsd->type); | |
8f054118 NJ |
1025 | pdacl_size = le16_to_cpu(parent_pdacl->size); |
1026 | ||
1027 | if (pdacl_size > acl_len || pdacl_size < sizeof(struct smb_acl)) { | |
1028 | rc = -EINVAL; | |
1029 | goto free_parent_pntsd; | |
1030 | } | |
e2f34481 NJ |
1031 | |
1032 | aces_base = kmalloc(sizeof(struct smb_ace) * num_aces * 2, GFP_KERNEL); | |
a9071e3c NJ |
1033 | if (!aces_base) { |
1034 | rc = -ENOMEM; | |
1035 | goto free_parent_pntsd; | |
1036 | } | |
e2f34481 NJ |
1037 | |
1038 | aces = (struct smb_ace *)aces_base; | |
1039 | parent_aces = (struct smb_ace *)((char *)parent_pdacl + | |
1040 | sizeof(struct smb_acl)); | |
8f054118 | 1041 | aces_size = acl_len - sizeof(struct smb_acl); |
e2f34481 NJ |
1042 | |
1043 | if (pntsd_type & DACL_AUTO_INHERITED) | |
1044 | inherited_flags = INHERITED_ACE; | |
1045 | ||
1046 | for (i = 0; i < num_aces; i++) { | |
8f054118 NJ |
1047 | int pace_size; |
1048 | ||
1049 | if (offsetof(struct smb_ace, access_req) > aces_size) | |
1050 | break; | |
1051 | ||
1052 | pace_size = le16_to_cpu(parent_aces->size); | |
1053 | if (pace_size > aces_size) | |
1054 | break; | |
1055 | ||
1056 | aces_size -= pace_size; | |
1057 | ||
e2f34481 NJ |
1058 | flags = parent_aces->flags; |
1059 | if (!smb_inherit_flags(flags, is_dir)) | |
1060 | goto pass; | |
1061 | if (is_dir) { | |
1062 | flags &= ~(INHERIT_ONLY_ACE | INHERITED_ACE); | |
1063 | if (!(flags & CONTAINER_INHERIT_ACE)) | |
1064 | flags |= INHERIT_ONLY_ACE; | |
1065 | if (flags & NO_PROPAGATE_INHERIT_ACE) | |
1066 | flags = 0; | |
64b39f4a | 1067 | } else { |
e2f34481 | 1068 | flags = 0; |
64b39f4a | 1069 | } |
e2f34481 NJ |
1070 | |
1071 | if (!compare_sids(&creator_owner, &parent_aces->sid)) { | |
1072 | creator = &creator_owner; | |
1073 | id_to_sid(uid, SIDOWNER, &owner_sid); | |
1074 | psid = &owner_sid; | |
1075 | } else if (!compare_sids(&creator_group, &parent_aces->sid)) { | |
1076 | creator = &creator_group; | |
1077 | id_to_sid(gid, SIDUNIX_GROUP, &group_sid); | |
1078 | psid = &group_sid; | |
1079 | } else { | |
1080 | creator = NULL; | |
1081 | psid = &parent_aces->sid; | |
1082 | } | |
1083 | ||
1084 | if (is_dir && creator && flags & CONTAINER_INHERIT_ACE) { | |
1085 | smb_set_ace(aces, psid, parent_aces->type, inherited_flags, | |
070fb21e | 1086 | parent_aces->access_req); |
e2f34481 NJ |
1087 | nt_size += le16_to_cpu(aces->size); |
1088 | ace_cnt++; | |
1089 | aces = (struct smb_ace *)((char *)aces + le16_to_cpu(aces->size)); | |
1090 | flags |= INHERIT_ONLY_ACE; | |
1091 | psid = creator; | |
64b39f4a | 1092 | } else if (is_dir && !(parent_aces->flags & NO_PROPAGATE_INHERIT_ACE)) { |
e2f34481 | 1093 | psid = &parent_aces->sid; |
64b39f4a | 1094 | } |
e2f34481 NJ |
1095 | |
1096 | smb_set_ace(aces, psid, parent_aces->type, flags | inherited_flags, | |
070fb21e | 1097 | parent_aces->access_req); |
e2f34481 NJ |
1098 | nt_size += le16_to_cpu(aces->size); |
1099 | aces = (struct smb_ace *)((char *)aces + le16_to_cpu(aces->size)); | |
1100 | ace_cnt++; | |
1101 | pass: | |
8f054118 | 1102 | parent_aces = (struct smb_ace *)((char *)parent_aces + pace_size); |
e2f34481 NJ |
1103 | } |
1104 | ||
1105 | if (nt_size > 0) { | |
1106 | struct smb_ntsd *pntsd; | |
1107 | struct smb_acl *pdacl; | |
1108 | struct smb_sid *powner_sid = NULL, *pgroup_sid = NULL; | |
1109 | int powner_sid_size = 0, pgroup_sid_size = 0, pntsd_size; | |
1110 | ||
1111 | if (parent_pntsd->osidoffset) { | |
1112 | powner_sid = (struct smb_sid *)((char *)parent_pntsd + | |
1113 | le32_to_cpu(parent_pntsd->osidoffset)); | |
1114 | powner_sid_size = 1 + 1 + 6 + (powner_sid->num_subauth * 4); | |
1115 | } | |
1116 | if (parent_pntsd->gsidoffset) { | |
1117 | pgroup_sid = (struct smb_sid *)((char *)parent_pntsd + | |
1118 | le32_to_cpu(parent_pntsd->gsidoffset)); | |
1119 | pgroup_sid_size = 1 + 1 + 6 + (pgroup_sid->num_subauth * 4); | |
1120 | } | |
1121 | ||
1122 | pntsd = kzalloc(sizeof(struct smb_ntsd) + powner_sid_size + | |
1123 | pgroup_sid_size + sizeof(struct smb_acl) + | |
1124 | nt_size, GFP_KERNEL); | |
1125 | if (!pntsd) { | |
1126 | rc = -ENOMEM; | |
a9071e3c | 1127 | goto free_aces_base; |
e2f34481 NJ |
1128 | } |
1129 | ||
1130 | pntsd->revision = cpu_to_le16(1); | |
1131 | pntsd->type = cpu_to_le16(SELF_RELATIVE | DACL_PRESENT); | |
1132 | if (le16_to_cpu(parent_pntsd->type) & DACL_AUTO_INHERITED) | |
1133 | pntsd->type |= cpu_to_le16(DACL_AUTO_INHERITED); | |
1134 | pntsd_size = sizeof(struct smb_ntsd); | |
1135 | pntsd->osidoffset = parent_pntsd->osidoffset; | |
1136 | pntsd->gsidoffset = parent_pntsd->gsidoffset; | |
1137 | pntsd->dacloffset = parent_pntsd->dacloffset; | |
1138 | ||
1139 | if (pntsd->osidoffset) { | |
1140 | struct smb_sid *owner_sid = (struct smb_sid *)((char *)pntsd + | |
1141 | le32_to_cpu(pntsd->osidoffset)); | |
1142 | memcpy(owner_sid, powner_sid, powner_sid_size); | |
1143 | pntsd_size += powner_sid_size; | |
1144 | } | |
1145 | ||
1146 | if (pntsd->gsidoffset) { | |
1147 | struct smb_sid *group_sid = (struct smb_sid *)((char *)pntsd + | |
1148 | le32_to_cpu(pntsd->gsidoffset)); | |
1149 | memcpy(group_sid, pgroup_sid, pgroup_sid_size); | |
1150 | pntsd_size += pgroup_sid_size; | |
1151 | } | |
1152 | ||
1153 | if (pntsd->dacloffset) { | |
1154 | struct smb_ace *pace; | |
1155 | ||
1156 | pdacl = (struct smb_acl *)((char *)pntsd + le32_to_cpu(pntsd->dacloffset)); | |
1157 | pdacl->revision = cpu_to_le16(2); | |
1158 | pdacl->size = cpu_to_le16(sizeof(struct smb_acl) + nt_size); | |
1159 | pdacl->num_aces = cpu_to_le32(ace_cnt); | |
1160 | pace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl)); | |
1161 | memcpy(pace, aces_base, nt_size); | |
1162 | pntsd_size += sizeof(struct smb_acl) + nt_size; | |
1163 | } | |
1164 | ||
40b268d3 | 1165 | ksmbd_vfs_set_sd_xattr(conn, idmap, path, pntsd, pntsd_size); |
e2f34481 | 1166 | kfree(pntsd); |
e2f34481 NJ |
1167 | } |
1168 | ||
a9071e3c | 1169 | free_aces_base: |
e2f34481 | 1170 | kfree(aces_base); |
a9071e3c NJ |
1171 | free_parent_pntsd: |
1172 | kfree(parent_pntsd); | |
e2f34481 NJ |
1173 | return rc; |
1174 | } | |
1175 | ||
1176 | bool smb_inherit_flags(int flags, bool is_dir) | |
1177 | { | |
1178 | if (!is_dir) | |
1179 | return (flags & OBJECT_INHERIT_ACE) != 0; | |
1180 | ||
1181 | if (flags & OBJECT_INHERIT_ACE && !(flags & NO_PROPAGATE_INHERIT_ACE)) | |
1182 | return true; | |
1183 | ||
1184 | if (flags & CONTAINER_INHERIT_ACE) | |
1185 | return true; | |
1186 | return false; | |
1187 | } | |
1188 | ||
c22180a5 | 1189 | int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path, |
070fb21e | 1190 | __le32 *pdaccess, int uid) |
e2f34481 | 1191 | { |
4609e1f1 | 1192 | struct mnt_idmap *idmap = mnt_idmap(path->mnt); |
e2f34481 NJ |
1193 | struct smb_ntsd *pntsd = NULL; |
1194 | struct smb_acl *pdacl; | |
1195 | struct posix_acl *posix_acls; | |
8f054118 | 1196 | int rc = 0, pntsd_size, acl_size, aces_size, pdacl_size, dacl_offset; |
e2f34481 NJ |
1197 | struct smb_sid sid; |
1198 | int granted = le32_to_cpu(*pdaccess & ~FILE_MAXIMAL_ACCESS_LE); | |
1199 | struct smb_ace *ace; | |
1200 | int i, found = 0; | |
1201 | unsigned int access_bits = 0; | |
1202 | struct smb_ace *others_ace = NULL; | |
1203 | struct posix_acl_entry *pa_entry; | |
1204 | unsigned int sid_type = SIDOWNER; | |
8f054118 | 1205 | unsigned short ace_size; |
e2f34481 NJ |
1206 | |
1207 | ksmbd_debug(SMB, "check permission using windows acl\n"); | |
4609e1f1 | 1208 | pntsd_size = ksmbd_vfs_get_sd_xattr(conn, idmap, |
8f054118 NJ |
1209 | path->dentry, &pntsd); |
1210 | if (pntsd_size <= 0 || !pntsd) | |
1211 | goto err_out; | |
1212 | ||
1213 | dacl_offset = le32_to_cpu(pntsd->dacloffset); | |
1214 | if (!dacl_offset || | |
1215 | (dacl_offset + sizeof(struct smb_acl) > pntsd_size)) | |
1216 | goto err_out; | |
e2f34481 NJ |
1217 | |
1218 | pdacl = (struct smb_acl *)((char *)pntsd + le32_to_cpu(pntsd->dacloffset)); | |
8f054118 NJ |
1219 | acl_size = pntsd_size - dacl_offset; |
1220 | pdacl_size = le16_to_cpu(pdacl->size); | |
50355b0b | 1221 | |
8f054118 NJ |
1222 | if (pdacl_size > acl_size || pdacl_size < sizeof(struct smb_acl)) |
1223 | goto err_out; | |
50355b0b | 1224 | |
e2f34481 | 1225 | if (!pdacl->num_aces) { |
8f054118 | 1226 | if (!(pdacl_size - sizeof(struct smb_acl)) && |
e2f34481 NJ |
1227 | *pdaccess & ~(FILE_READ_CONTROL_LE | FILE_WRITE_DAC_LE)) { |
1228 | rc = -EACCES; | |
1229 | goto err_out; | |
1230 | } | |
8f054118 | 1231 | goto err_out; |
e2f34481 NJ |
1232 | } |
1233 | ||
1234 | if (*pdaccess & FILE_MAXIMAL_ACCESS_LE) { | |
1235 | granted = READ_CONTROL | WRITE_DAC | FILE_READ_ATTRIBUTES | | |
1236 | DELETE; | |
1237 | ||
1238 | ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl)); | |
8f054118 | 1239 | aces_size = acl_size - sizeof(struct smb_acl); |
e2f34481 | 1240 | for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) { |
8f054118 NJ |
1241 | if (offsetof(struct smb_ace, access_req) > aces_size) |
1242 | break; | |
1243 | ace_size = le16_to_cpu(ace->size); | |
1244 | if (ace_size > aces_size) | |
1245 | break; | |
1246 | aces_size -= ace_size; | |
e2f34481 | 1247 | granted |= le32_to_cpu(ace->access_req); |
64b39f4a | 1248 | ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace->size)); |
e2f34481 NJ |
1249 | } |
1250 | ||
1251 | if (!pdacl->num_aces) | |
1252 | granted = GENERIC_ALL_FLAGS; | |
1253 | } | |
1254 | ||
1255 | if (!uid) | |
1256 | sid_type = SIDUNIX_USER; | |
1257 | id_to_sid(uid, sid_type, &sid); | |
1258 | ||
1259 | ace = (struct smb_ace *)((char *)pdacl + sizeof(struct smb_acl)); | |
8f054118 | 1260 | aces_size = acl_size - sizeof(struct smb_acl); |
e2f34481 | 1261 | for (i = 0; i < le32_to_cpu(pdacl->num_aces); i++) { |
8f054118 NJ |
1262 | if (offsetof(struct smb_ace, access_req) > aces_size) |
1263 | break; | |
1264 | ace_size = le16_to_cpu(ace->size); | |
1265 | if (ace_size > aces_size) | |
1266 | break; | |
1267 | aces_size -= ace_size; | |
1268 | ||
e2f34481 NJ |
1269 | if (!compare_sids(&sid, &ace->sid) || |
1270 | !compare_sids(&sid_unix_NFS_mode, &ace->sid)) { | |
1271 | found = 1; | |
1272 | break; | |
1273 | } | |
1274 | if (!compare_sids(&sid_everyone, &ace->sid)) | |
1275 | others_ace = ace; | |
1276 | ||
64b39f4a | 1277 | ace = (struct smb_ace *)((char *)ace + le16_to_cpu(ace->size)); |
e2f34481 NJ |
1278 | } |
1279 | ||
1280 | if (*pdaccess & FILE_MAXIMAL_ACCESS_LE && found) { | |
1281 | granted = READ_CONTROL | WRITE_DAC | FILE_READ_ATTRIBUTES | | |
1282 | DELETE; | |
1283 | ||
1284 | granted |= le32_to_cpu(ace->access_req); | |
1285 | ||
1286 | if (!pdacl->num_aces) | |
1287 | granted = GENERIC_ALL_FLAGS; | |
1288 | } | |
1289 | ||
777cad16 | 1290 | if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) { |
cac2f8b8 | 1291 | posix_acls = get_inode_acl(d_inode(path->dentry), ACL_TYPE_ACCESS); |
25933573 | 1292 | if (!IS_ERR_OR_NULL(posix_acls) && !found) { |
777cad16 NJ |
1293 | unsigned int id = -1; |
1294 | ||
1295 | pa_entry = posix_acls->a_entries; | |
1296 | for (i = 0; i < posix_acls->a_count; i++, pa_entry++) { | |
1297 | if (pa_entry->e_tag == ACL_USER) | |
4d7ca409 | 1298 | id = posix_acl_uid_translate(idmap, pa_entry); |
777cad16 | 1299 | else if (pa_entry->e_tag == ACL_GROUP) |
4d7ca409 | 1300 | id = posix_acl_gid_translate(idmap, pa_entry); |
777cad16 NJ |
1301 | else |
1302 | continue; | |
1303 | ||
1304 | if (id == uid) { | |
1305 | mode_to_access_flags(pa_entry->e_perm, | |
1306 | 0777, | |
1307 | &access_bits); | |
1308 | if (!access_bits) | |
1309 | access_bits = | |
1310 | SET_MINIMUM_RIGHTS; | |
d21a580d | 1311 | posix_acl_release(posix_acls); |
777cad16 NJ |
1312 | goto check_access_bits; |
1313 | } | |
e2f34481 NJ |
1314 | } |
1315 | } | |
25933573 | 1316 | if (!IS_ERR_OR_NULL(posix_acls)) |
777cad16 | 1317 | posix_acl_release(posix_acls); |
e2f34481 | 1318 | } |
e2f34481 NJ |
1319 | |
1320 | if (!found) { | |
64b39f4a | 1321 | if (others_ace) { |
e2f34481 | 1322 | ace = others_ace; |
64b39f4a | 1323 | } else { |
e2f34481 NJ |
1324 | ksmbd_debug(SMB, "Can't find corresponding sid\n"); |
1325 | rc = -EACCES; | |
1326 | goto err_out; | |
1327 | } | |
1328 | } | |
1329 | ||
1330 | switch (ace->type) { | |
1331 | case ACCESS_ALLOWED_ACE_TYPE: | |
1332 | access_bits = le32_to_cpu(ace->access_req); | |
1333 | break; | |
1334 | case ACCESS_DENIED_ACE_TYPE: | |
1335 | case ACCESS_DENIED_CALLBACK_ACE_TYPE: | |
1336 | access_bits = le32_to_cpu(~ace->access_req); | |
1337 | break; | |
1338 | } | |
1339 | ||
1340 | check_access_bits: | |
070fb21e NJ |
1341 | if (granted & |
1342 | ~(access_bits | FILE_READ_ATTRIBUTES | READ_CONTROL | WRITE_DAC | DELETE)) { | |
e2f34481 | 1343 | ksmbd_debug(SMB, "Access denied with winACL, granted : %x, access_req : %x\n", |
070fb21e | 1344 | granted, le32_to_cpu(ace->access_req)); |
e2f34481 NJ |
1345 | rc = -EACCES; |
1346 | goto err_out; | |
1347 | } | |
1348 | ||
1349 | *pdaccess = cpu_to_le32(granted); | |
1350 | err_out: | |
1351 | kfree(pntsd); | |
1352 | return rc; | |
1353 | } | |
1354 | ||
1355 | int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon, | |
c22180a5 | 1356 | const struct path *path, struct smb_ntsd *pntsd, int ntsd_len, |
070fb21e | 1357 | bool type_check) |
e2f34481 NJ |
1358 | { |
1359 | int rc; | |
1360 | struct smb_fattr fattr = {{0}}; | |
ef24c962 | 1361 | struct inode *inode = d_inode(path->dentry); |
abf08576 | 1362 | struct mnt_idmap *idmap = mnt_idmap(path->mnt); |
e70e392f | 1363 | struct iattr newattrs; |
e2f34481 NJ |
1364 | |
1365 | fattr.cf_uid = INVALID_UID; | |
1366 | fattr.cf_gid = INVALID_GID; | |
1367 | fattr.cf_mode = inode->i_mode; | |
1368 | ||
4d7ca409 | 1369 | rc = parse_sec_desc(idmap, pntsd, ntsd_len, &fattr); |
e2f34481 NJ |
1370 | if (rc) |
1371 | goto out; | |
1372 | ||
e70e392f NJ |
1373 | newattrs.ia_valid = ATTR_CTIME; |
1374 | if (!uid_eq(fattr.cf_uid, INVALID_UID)) { | |
1375 | newattrs.ia_valid |= ATTR_UID; | |
1376 | newattrs.ia_uid = fattr.cf_uid; | |
1377 | } | |
1378 | if (!gid_eq(fattr.cf_gid, INVALID_GID)) { | |
1379 | newattrs.ia_valid |= ATTR_GID; | |
1380 | newattrs.ia_gid = fattr.cf_gid; | |
1381 | } | |
1382 | newattrs.ia_valid |= ATTR_MODE; | |
1383 | newattrs.ia_mode = (inode->i_mode & ~0777) | (fattr.cf_mode & 0777); | |
1384 | ||
40b268d3 | 1385 | ksmbd_vfs_remove_acl_xattrs(idmap, path); |
e2f34481 | 1386 | /* Update posix acls */ |
777cad16 | 1387 | if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && fattr.cf_dacls) { |
13e83a49 | 1388 | rc = set_posix_acl(idmap, path->dentry, |
af34983e | 1389 | ACL_TYPE_ACCESS, fattr.cf_acls); |
28a5d3de CB |
1390 | if (rc < 0) |
1391 | ksmbd_debug(SMB, | |
1392 | "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n", | |
1393 | rc); | |
1394 | if (S_ISDIR(inode->i_mode) && fattr.cf_dacls) { | |
13e83a49 | 1395 | rc = set_posix_acl(idmap, path->dentry, |
67d1c432 | 1396 | ACL_TYPE_DEFAULT, fattr.cf_dacls); |
28a5d3de CB |
1397 | if (rc) |
1398 | ksmbd_debug(SMB, | |
1399 | "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n", | |
1400 | rc); | |
1401 | } | |
e2f34481 NJ |
1402 | } |
1403 | ||
28a5d3de | 1404 | inode_lock(inode); |
abf08576 | 1405 | rc = notify_change(idmap, path->dentry, &newattrs, NULL); |
28a5d3de CB |
1406 | inode_unlock(inode); |
1407 | if (rc) | |
1408 | goto out; | |
1409 | ||
e2f34481 NJ |
1410 | /* Check it only calling from SD BUFFER context */ |
1411 | if (type_check && !(le16_to_cpu(pntsd->type) & DACL_PRESENT)) | |
1412 | goto out; | |
1413 | ||
64b39f4a | 1414 | if (test_share_config_flag(tcon->share_conf, KSMBD_SHARE_FLAG_ACL_XATTR)) { |
e2f34481 | 1415 | /* Update WinACL in xattr */ |
40b268d3 NJ |
1416 | ksmbd_vfs_remove_sd_xattrs(idmap, path); |
1417 | ksmbd_vfs_set_sd_xattr(conn, idmap, path, pntsd, ntsd_len); | |
e2f34481 NJ |
1418 | } |
1419 | ||
1420 | out: | |
1421 | posix_acl_release(fattr.cf_acls); | |
1422 | posix_acl_release(fattr.cf_dacls); | |
e2f34481 NJ |
1423 | return rc; |
1424 | } | |
1425 | ||
1426 | void ksmbd_init_domain(u32 *sub_auth) | |
1427 | { | |
1428 | int i; | |
1429 | ||
1430 | memcpy(&server_conf.domain_sid, &domain, sizeof(struct smb_sid)); | |
1431 | for (i = 0; i < 3; ++i) | |
1432 | server_conf.domain_sid.sub_auth[i + 1] = cpu_to_le32(sub_auth[i]); | |
1433 | } |