]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - fs/cifs/cifsacl.c
Merge branch 'for-3.17-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj...
[mirror_ubuntu-bionic-kernel.git] / fs / cifs / cifsacl.c
CommitLineData
bcb02034
SF
1/*
2 * fs/cifs/cifsacl.c
3 *
8b1327f6 4 * Copyright (C) International Business Machines Corp., 2007,2008
bcb02034
SF
5 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for mapping CIFS/NTFS ACLs
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
65874007 24#include <linux/fs.h>
5a0e3ad6 25#include <linux/slab.h>
4d79dba0
SP
26#include <linux/string.h>
27#include <linux/keyctl.h>
28#include <linux/key-type.h>
29#include <keys/user-type.h>
65874007
SF
30#include "cifspdu.h"
31#include "cifsglob.h"
d0d66c44 32#include "cifsacl.h"
65874007
SF
33#include "cifsproto.h"
34#include "cifs_debug.h"
65874007 35
2fbc2f17 36/* security id for everyone/world system group */
e01b6400
SP
37static const struct cifs_sid sid_everyone = {
38 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
2fbc2f17
SP
39/* security id for Authenticated Users system group */
40static const struct cifs_sid sid_authusers = {
4f61258f 41 1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11)} };
bcb02034 42/* group users */
ad7a2926 43static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
d0d66c44 44
b1a6dc21 45static const struct cred *root_cred;
9409ae58 46
4d79dba0 47static int
cf7f601c 48cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
4d79dba0
SP
49{
50 char *payload;
51
41a9f1f6
JL
52 /*
53 * If the payload is less than or equal to the size of a pointer, then
54 * an allocation here is wasteful. Just copy the data directly to the
55 * payload.value union member instead.
56 *
57 * With this however, you must check the datalen before trying to
58 * dereference payload.data!
59 */
1f630680 60 if (prep->datalen <= sizeof(key->payload)) {
41a9f1f6
JL
61 key->payload.value = 0;
62 memcpy(&key->payload.value, prep->data, prep->datalen);
63 key->datalen = prep->datalen;
64 return 0;
65 }
f7f7c185 66 payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
4d79dba0
SP
67 if (!payload)
68 return -ENOMEM;
69
4d79dba0 70 key->payload.data = payload;
cf7f601c 71 key->datalen = prep->datalen;
4d79dba0
SP
72 return 0;
73}
74
75static inline void
76cifs_idmap_key_destroy(struct key *key)
77{
1f630680 78 if (key->datalen > sizeof(key->payload))
41a9f1f6 79 kfree(key->payload.data);
4d79dba0
SP
80}
81
b1a6dc21 82static struct key_type cifs_idmap_key_type = {
c4aca0c0 83 .name = "cifs.idmap",
4d79dba0
SP
84 .instantiate = cifs_idmap_key_instantiate,
85 .destroy = cifs_idmap_key_destroy,
86 .describe = user_describe,
87 .match = user_match,
88};
89
faa65f07
JL
90static char *
91sid_to_key_str(struct cifs_sid *sidptr, unsigned int type)
9409ae58 92{
faa65f07 93 int i, len;
ee13b2ba 94 unsigned int saval;
faa65f07 95 char *sidstr, *strptr;
193cdd8a 96 unsigned long long id_auth_val;
9409ae58 97
faa65f07
JL
98 /* 3 bytes for prefix */
99 sidstr = kmalloc(3 + SID_STRING_BASE_SIZE +
100 (SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth),
101 GFP_KERNEL);
102 if (!sidstr)
103 return sidstr;
9409ae58 104
faa65f07
JL
105 strptr = sidstr;
106 len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g',
107 sidptr->revision);
108 strptr += len;
9409ae58 109
193cdd8a
JL
110 /* The authority field is a single 48-bit number */
111 id_auth_val = (unsigned long long)sidptr->authority[5];
112 id_auth_val |= (unsigned long long)sidptr->authority[4] << 8;
113 id_auth_val |= (unsigned long long)sidptr->authority[3] << 16;
114 id_auth_val |= (unsigned long long)sidptr->authority[2] << 24;
115 id_auth_val |= (unsigned long long)sidptr->authority[1] << 32;
116 id_auth_val |= (unsigned long long)sidptr->authority[0] << 48;
117
118 /*
119 * MS-DTYP states that if the authority is >= 2^32, then it should be
120 * expressed as a hex value.
121 */
122 if (id_auth_val <= UINT_MAX)
123 len = sprintf(strptr, "-%llu", id_auth_val);
124 else
125 len = sprintf(strptr, "-0x%llx", id_auth_val);
126
127 strptr += len;
9409ae58
SP
128
129 for (i = 0; i < sidptr->num_subauth; ++i) {
130 saval = le32_to_cpu(sidptr->sub_auth[i]);
faa65f07
JL
131 len = sprintf(strptr, "-%u", saval);
132 strptr += len;
9409ae58 133 }
faa65f07
JL
134
135 return sidstr;
9409ae58
SP
136}
137
436bb435
JL
138/*
139 * if the two SIDs (roughly equivalent to a UUID for a user or group) are
140 * the same returns zero, if they do not match returns non-zero.
141 */
142static int
143compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
144{
145 int i;
146 int num_subauth, num_sat, num_saw;
147
148 if ((!ctsid) || (!cwsid))
149 return 1;
150
151 /* compare the revision */
152 if (ctsid->revision != cwsid->revision) {
153 if (ctsid->revision > cwsid->revision)
154 return 1;
155 else
156 return -1;
157 }
158
159 /* compare all of the six auth values */
160 for (i = 0; i < NUM_AUTHS; ++i) {
161 if (ctsid->authority[i] != cwsid->authority[i]) {
162 if (ctsid->authority[i] > cwsid->authority[i])
163 return 1;
164 else
165 return -1;
166 }
167 }
168
169 /* compare all of the subauth values if any */
170 num_sat = ctsid->num_subauth;
171 num_saw = cwsid->num_subauth;
172 num_subauth = num_sat < num_saw ? num_sat : num_saw;
173 if (num_subauth) {
174 for (i = 0; i < num_subauth; ++i) {
175 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
176 if (le32_to_cpu(ctsid->sub_auth[i]) >
177 le32_to_cpu(cwsid->sub_auth[i]))
178 return 1;
179 else
180 return -1;
181 }
182 }
183 }
184
185 return 0; /* sids compare/match */
186}
187
36960e44
JL
188static void
189cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
190{
36f87ee7
JL
191 int i;
192
193 dst->revision = src->revision;
30c9d6cc 194 dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES);
36f87ee7
JL
195 for (i = 0; i < NUM_AUTHS; ++i)
196 dst->authority[i] = src->authority[i];
197 for (i = 0; i < dst->num_subauth; ++i)
198 dst->sub_auth[i] = src->sub_auth[i];
36960e44
JL
199}
200
9409ae58 201static int
faa65f07 202id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
9409ae58 203{
faa65f07 204 int rc;
21fed0d5 205 struct key *sidkey;
2ae03025
JL
206 struct cifs_sid *ksid;
207 unsigned int ksid_size;
faa65f07 208 char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
21fed0d5 209 const struct cred *saved_cred;
21fed0d5 210
faa65f07
JL
211 rc = snprintf(desc, sizeof(desc), "%ci:%u",
212 sidtype == SIDOWNER ? 'o' : 'g', cid);
213 if (rc >= sizeof(desc))
214 return -EINVAL;
21fed0d5 215
faa65f07
JL
216 rc = 0;
217 saved_cred = override_creds(root_cred);
218 sidkey = request_key(&cifs_idmap_key_type, desc, "");
219 if (IS_ERR(sidkey)) {
21fed0d5 220 rc = -EINVAL;
f96637be
JP
221 cifs_dbg(FYI, "%s: Can't map %cid %u to a SID\n",
222 __func__, sidtype == SIDOWNER ? 'u' : 'g', cid);
faa65f07
JL
223 goto out_revert_creds;
224 } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
225 rc = -EIO;
f96637be
JP
226 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
227 __func__, sidkey->datalen);
2ae03025 228 goto invalidate_key;
21fed0d5 229 }
2ae03025 230
1f630680
JL
231 /*
232 * A sid is usually too large to be embedded in payload.value, but if
233 * there are no subauthorities and the host has 8-byte pointers, then
234 * it could be.
235 */
236 ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
237 (struct cifs_sid *)&sidkey->payload.value :
238 (struct cifs_sid *)sidkey->payload.data;
239
2ae03025
JL
240 ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
241 if (ksid_size > sidkey->datalen) {
242 rc = -EIO;
f96637be
JP
243 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu, ksid_size=%u)\n",
244 __func__, sidkey->datalen, ksid_size);
2ae03025
JL
245 goto invalidate_key;
246 }
1f630680 247
2ae03025 248 cifs_copy_sid(ssid, ksid);
faa65f07
JL
249out_key_put:
250 key_put(sidkey);
251out_revert_creds:
252 revert_creds(saved_cred);
21fed0d5 253 return rc;
2ae03025
JL
254
255invalidate_key:
256 key_invalidate(sidkey);
257 goto out_key_put;
21fed0d5
SP
258}
259
9409ae58
SP
260static int
261sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
262 struct cifs_fattr *fattr, uint sidtype)
263{
264 int rc;
faa65f07
JL
265 struct key *sidkey;
266 char *sidstr;
9409ae58 267 const struct cred *saved_cred;
8abf2775
EB
268 kuid_t fuid = cifs_sb->mnt_uid;
269 kgid_t fgid = cifs_sb->mnt_gid;
9409ae58
SP
270
271 /*
faa65f07
JL
272 * If we have too many subauthorities, then something is really wrong.
273 * Just return an error.
9409ae58 274 */
faa65f07 275 if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
f96637be
JP
276 cifs_dbg(FYI, "%s: %u subauthorities is too many!\n",
277 __func__, psid->num_subauth);
faa65f07 278 return -EIO;
9409ae58
SP
279 }
280
faa65f07
JL
281 sidstr = sid_to_key_str(psid, sidtype);
282 if (!sidstr)
283 return -ENOMEM;
284
285 saved_cred = override_creds(root_cred);
286 sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
287 if (IS_ERR(sidkey)) {
288 rc = -EINVAL;
f96637be
JP
289 cifs_dbg(FYI, "%s: Can't map SID %s to a %cid\n",
290 __func__, sidstr, sidtype == SIDOWNER ? 'u' : 'g');
faa65f07
JL
291 goto out_revert_creds;
292 }
293
294 /*
295 * FIXME: Here we assume that uid_t and gid_t are same size. It's
296 * probably a safe assumption but might be better to check based on
297 * sidtype.
298 */
355958f2 299 BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
41a9f1f6 300 if (sidkey->datalen != sizeof(uid_t)) {
faa65f07 301 rc = -EIO;
f96637be
JP
302 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
303 __func__, sidkey->datalen);
2ae03025 304 key_invalidate(sidkey);
faa65f07 305 goto out_key_put;
9409ae58
SP
306 }
307
8abf2775
EB
308 if (sidtype == SIDOWNER) {
309 kuid_t uid;
310 uid_t id;
311 memcpy(&id, &sidkey->payload.value, sizeof(uid_t));
312 uid = make_kuid(&init_user_ns, id);
313 if (uid_valid(uid))
314 fuid = uid;
315 } else {
316 kgid_t gid;
317 gid_t id;
318 memcpy(&id, &sidkey->payload.value, sizeof(gid_t));
319 gid = make_kgid(&init_user_ns, id);
320 if (gid_valid(gid))
321 fgid = gid;
322 }
faa65f07
JL
323
324out_key_put:
325 key_put(sidkey);
326out_revert_creds:
327 revert_creds(saved_cred);
328 kfree(sidstr);
9409ae58 329
faa65f07
JL
330 /*
331 * Note that we return 0 here unconditionally. If the mapping
332 * fails then we just fall back to using the mnt_uid/mnt_gid.
333 */
334 if (sidtype == SIDOWNER)
335 fattr->cf_uid = fuid;
336 else
337 fattr->cf_gid = fgid;
9409ae58
SP
338 return 0;
339}
340
4d79dba0
SP
341int
342init_cifs_idmap(void)
343{
344 struct cred *cred;
345 struct key *keyring;
346 int ret;
347
f96637be
JP
348 cifs_dbg(FYI, "Registering the %s key type\n",
349 cifs_idmap_key_type.name);
4d79dba0
SP
350
351 /* create an override credential set with a special thread keyring in
352 * which requests are cached
353 *
354 * this is used to prevent malicious redirections from being installed
355 * with add_key().
356 */
357 cred = prepare_kernel_cred(NULL);
358 if (!cred)
359 return -ENOMEM;
360
8e3028b9
EB
361 keyring = keyring_alloc(".cifs_idmap",
362 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
f8aa23a5
DH
363 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
364 KEY_USR_VIEW | KEY_USR_READ,
365 KEY_ALLOC_NOT_IN_QUOTA, NULL);
4d79dba0
SP
366 if (IS_ERR(keyring)) {
367 ret = PTR_ERR(keyring);
368 goto failed_put_cred;
369 }
370
4d79dba0
SP
371 ret = register_key_type(&cifs_idmap_key_type);
372 if (ret < 0)
373 goto failed_put_key;
374
375 /* instruct request_key() to use this special keyring as a cache for
376 * the results it looks up */
700920eb 377 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
4d79dba0
SP
378 cred->thread_keyring = keyring;
379 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
380 root_cred = cred;
381
f96637be 382 cifs_dbg(FYI, "cifs idmap keyring: %d\n", key_serial(keyring));
4d79dba0
SP
383 return 0;
384
385failed_put_key:
386 key_put(keyring);
387failed_put_cred:
388 put_cred(cred);
389 return ret;
390}
391
392void
393exit_cifs_idmap(void)
394{
395 key_revoke(root_cred->thread_keyring);
396 unregister_key_type(&cifs_idmap_key_type);
397 put_cred(root_cred);
f96637be 398 cifs_dbg(FYI, "Unregistered %s key type\n", cifs_idmap_key_type.name);
4d79dba0
SP
399}
400
97837582
SF
401/* copy ntsd, owner sid, and group sid from a security descriptor to another */
402static void copy_sec_desc(const struct cifs_ntsd *pntsd,
403 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
404{
97837582
SF
405 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
406 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
407
408 /* copy security descriptor control portion */
409 pnntsd->revision = pntsd->revision;
410 pnntsd->type = pntsd->type;
411 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
412 pnntsd->sacloffset = 0;
413 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
414 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
415
416 /* copy owner sid */
417 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
418 le32_to_cpu(pntsd->osidoffset));
419 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
36960e44 420 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
97837582
SF
421
422 /* copy group sid */
423 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
424 le32_to_cpu(pntsd->gsidoffset));
425 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
426 sizeof(struct cifs_sid));
36960e44 427 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
97837582
SF
428
429 return;
430}
431
432
630f3f0c
SF
433/*
434 change posix mode to reflect permissions
435 pmode is the existing mode (we only want to overwrite part of this
436 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
437*/
9b5e6857 438static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
15b03959 439 umode_t *pbits_to_set)
630f3f0c 440{
9b5e6857 441 __u32 flags = le32_to_cpu(ace_flags);
15b03959 442 /* the order of ACEs is important. The canonical order is to begin with
ce06c9f0 443 DENY entries followed by ALLOW, otherwise an allow entry could be
15b03959 444 encountered first, making the subsequent deny entry like "dead code"
ce06c9f0 445 which would be superflous since Windows stops when a match is made
15b03959
SF
446 for the operation you are trying to perform for your user */
447
448 /* For deny ACEs we change the mask so that subsequent allow access
449 control entries do not turn on the bits we are denying */
450 if (type == ACCESS_DENIED) {
ad7a2926 451 if (flags & GENERIC_ALL)
15b03959 452 *pbits_to_set &= ~S_IRWXUGO;
ad7a2926 453
9b5e6857
AV
454 if ((flags & GENERIC_WRITE) ||
455 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
15b03959 456 *pbits_to_set &= ~S_IWUGO;
9b5e6857
AV
457 if ((flags & GENERIC_READ) ||
458 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
15b03959 459 *pbits_to_set &= ~S_IRUGO;
9b5e6857
AV
460 if ((flags & GENERIC_EXECUTE) ||
461 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
15b03959
SF
462 *pbits_to_set &= ~S_IXUGO;
463 return;
464 } else if (type != ACCESS_ALLOWED) {
f96637be 465 cifs_dbg(VFS, "unknown access control type %d\n", type);
15b03959
SF
466 return;
467 }
468 /* else ACCESS_ALLOWED type */
630f3f0c 469
9b5e6857 470 if (flags & GENERIC_ALL) {
15b03959 471 *pmode |= (S_IRWXUGO & (*pbits_to_set));
f96637be 472 cifs_dbg(NOISY, "all perms\n");
d61e5808
SF
473 return;
474 }
9b5e6857
AV
475 if ((flags & GENERIC_WRITE) ||
476 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
15b03959 477 *pmode |= (S_IWUGO & (*pbits_to_set));
9b5e6857
AV
478 if ((flags & GENERIC_READ) ||
479 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
15b03959 480 *pmode |= (S_IRUGO & (*pbits_to_set));
9b5e6857
AV
481 if ((flags & GENERIC_EXECUTE) ||
482 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
15b03959 483 *pmode |= (S_IXUGO & (*pbits_to_set));
630f3f0c 484
f96637be 485 cifs_dbg(NOISY, "access flags 0x%x mode now 0x%x\n", flags, *pmode);
630f3f0c
SF
486 return;
487}
488
ce06c9f0
SF
489/*
490 Generate access flags to reflect permissions mode is the existing mode.
491 This function is called for every ACE in the DACL whose SID matches
492 with either owner or group or everyone.
493*/
494
495static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
496 __u32 *pace_flags)
497{
498 /* reset access mask */
499 *pace_flags = 0x0;
500
501 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
502 mode &= bits_to_use;
503
504 /* check for R/W/X UGO since we do not know whose flags
505 is this but we have cleared all the bits sans RWX for
506 either user or group or other as per bits_to_use */
507 if (mode & S_IRUGO)
508 *pace_flags |= SET_FILE_READ_RIGHTS;
509 if (mode & S_IWUGO)
510 *pace_flags |= SET_FILE_WRITE_RIGHTS;
511 if (mode & S_IXUGO)
512 *pace_flags |= SET_FILE_EXEC_RIGHTS;
513
f96637be
JP
514 cifs_dbg(NOISY, "mode: 0x%x, access flags now 0x%x\n",
515 mode, *pace_flags);
ce06c9f0
SF
516 return;
517}
518
2b210adc 519static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
97837582
SF
520 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
521{
522 int i;
523 __u16 size = 0;
524 __u32 access_req = 0;
525
526 pntace->type = ACCESS_ALLOWED;
527 pntace->flags = 0x0;
528 mode_to_access_flags(nmode, bits, &access_req);
529 if (!access_req)
530 access_req = SET_MINIMUM_RIGHTS;
531 pntace->access_req = cpu_to_le32(access_req);
532
533 pntace->sid.revision = psid->revision;
534 pntace->sid.num_subauth = psid->num_subauth;
852e2295 535 for (i = 0; i < NUM_AUTHS; i++)
97837582
SF
536 pntace->sid.authority[i] = psid->authority[i];
537 for (i = 0; i < psid->num_subauth; i++)
538 pntace->sid.sub_auth[i] = psid->sub_auth[i];
539
540 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
541 pntace->size = cpu_to_le16(size);
542
ef571cad 543 return size;
97837582
SF
544}
545
297647c2 546
953f8681
SF
547#ifdef CONFIG_CIFS_DEBUG2
548static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
d0d66c44 549{
d0d66c44 550 int num_subauth;
d0d66c44
SP
551
552 /* validate that we do not go past end of acl */
297647c2 553
44093ca2 554 if (le16_to_cpu(pace->size) < 16) {
f96637be 555 cifs_dbg(VFS, "ACE too small %d\n", le16_to_cpu(pace->size));
44093ca2
SF
556 return;
557 }
558
559 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
f96637be 560 cifs_dbg(VFS, "ACL too small to parse ACE\n");
d0d66c44 561 return;
44093ca2 562 }
d0d66c44 563
44093ca2 564 num_subauth = pace->sid.num_subauth;
d0d66c44 565 if (num_subauth) {
8f18c131 566 int i;
f96637be
JP
567 cifs_dbg(FYI, "ACE revision %d num_auth %d type %d flags %d size %d\n",
568 pace->sid.revision, pace->sid.num_subauth, pace->type,
569 pace->flags, le16_to_cpu(pace->size));
d12fd121 570 for (i = 0; i < num_subauth; ++i) {
f96637be
JP
571 cifs_dbg(FYI, "ACE sub_auth[%d]: 0x%x\n",
572 i, le32_to_cpu(pace->sid.sub_auth[i]));
d12fd121
SF
573 }
574
575 /* BB add length check to make sure that we do not have huge
576 num auths and therefore go off the end */
d12fd121
SF
577 }
578
579 return;
580}
953f8681 581#endif
d12fd121 582
d0d66c44 583
a750e77c 584static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
d61e5808 585 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
0b8f18e3 586 struct cifs_fattr *fattr)
d0d66c44
SP
587{
588 int i;
589 int num_aces = 0;
590 int acl_size;
591 char *acl_base;
d0d66c44
SP
592 struct cifs_ace **ppace;
593
594 /* BB need to add parm so we can store the SID BB */
595
2b83457b
SF
596 if (!pdacl) {
597 /* no DACL in the security descriptor, set
598 all the permissions for user/group/other */
0b8f18e3 599 fattr->cf_mode |= S_IRWXUGO;
2b83457b
SF
600 return;
601 }
602
d0d66c44 603 /* validate that we do not go past end of acl */
af6f4612 604 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
f96637be 605 cifs_dbg(VFS, "ACL too small to parse DACL\n");
d0d66c44
SP
606 return;
607 }
608
f96637be
JP
609 cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
610 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
611 le32_to_cpu(pdacl->num_aces));
d0d66c44 612
7505e052
SF
613 /* reset rwx permissions for user/group/other.
614 Also, if num_aces is 0 i.e. DACL has no ACEs,
615 user/group/other have no permissions */
0b8f18e3 616 fattr->cf_mode &= ~(S_IRWXUGO);
7505e052 617
d0d66c44
SP
618 acl_base = (char *)pdacl;
619 acl_size = sizeof(struct cifs_acl);
620
adbc0358 621 num_aces = le32_to_cpu(pdacl->num_aces);
a5ff3769 622 if (num_aces > 0) {
15b03959
SF
623 umode_t user_mask = S_IRWXU;
624 umode_t group_mask = S_IRWXG;
2fbc2f17 625 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
15b03959 626
7250170c
DC
627 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
628 return;
d0d66c44
SP
629 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
630 GFP_KERNEL);
f96637be 631 if (!ppace)
8132b65b 632 return;
d0d66c44 633
d0d66c44 634 for (i = 0; i < num_aces; ++i) {
44093ca2 635 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
953f8681
SF
636#ifdef CONFIG_CIFS_DEBUG2
637 dump_ace(ppace[i], end_of_acl);
638#endif
9409ae58 639 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
e01b6400 640 access_flags_to_mode(ppace[i]->access_req,
15b03959 641 ppace[i]->type,
0b8f18e3 642 &fattr->cf_mode,
15b03959 643 &user_mask);
9409ae58 644 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
e01b6400 645 access_flags_to_mode(ppace[i]->access_req,
15b03959 646 ppace[i]->type,
0b8f18e3 647 &fattr->cf_mode,
15b03959 648 &group_mask);
9409ae58 649 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
e01b6400 650 access_flags_to_mode(ppace[i]->access_req,
15b03959 651 ppace[i]->type,
0b8f18e3 652 &fattr->cf_mode,
15b03959 653 &other_mask);
9409ae58 654 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
2fbc2f17
SP
655 access_flags_to_mode(ppace[i]->access_req,
656 ppace[i]->type,
657 &fattr->cf_mode,
658 &other_mask);
659
e01b6400 660
44093ca2 661/* memcpy((void *)(&(cifscred->aces[i])),
d12fd121
SF
662 (void *)ppace[i],
663 sizeof(struct cifs_ace)); */
d0d66c44 664
44093ca2
SF
665 acl_base = (char *)ppace[i];
666 acl_size = le16_to_cpu(ppace[i]->size);
d0d66c44
SP
667 }
668
669 kfree(ppace);
d0d66c44
SP
670 }
671
672 return;
673}
674
bcb02034 675
97837582
SF
676static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
677 struct cifs_sid *pgrpsid, __u64 nmode)
678{
2b210adc 679 u16 size = 0;
97837582
SF
680 struct cifs_acl *pnndacl;
681
682 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
683
684 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
685 pownersid, nmode, S_IRWXU);
686 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
687 pgrpsid, nmode, S_IRWXG);
688 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
689 &sid_everyone, nmode, S_IRWXO);
690
691 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
d9f382ef 692 pndacl->num_aces = cpu_to_le32(3);
97837582 693
ef571cad 694 return 0;
97837582
SF
695}
696
697
bcb02034
SF
698static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
699{
700 /* BB need to add parm so we can store the SID BB */
701
b9c7a2bb
SF
702 /* validate that we do not go past end of ACL - sid must be at least 8
703 bytes long (assuming no sub-auths - e.g. the null SID */
704 if (end_of_acl < (char *)psid + 8) {
f96637be 705 cifs_dbg(VFS, "ACL too small to parse SID %p\n", psid);
bcb02034
SF
706 return -EINVAL;
707 }
d0d66c44 708
bcb02034 709#ifdef CONFIG_CIFS_DEBUG2
fc03d8a5 710 if (psid->num_subauth) {
8f18c131 711 int i;
f96637be
JP
712 cifs_dbg(FYI, "SID revision %d num_auth %d\n",
713 psid->revision, psid->num_subauth);
bcb02034 714
af6f4612 715 for (i = 0; i < psid->num_subauth; i++) {
f96637be
JP
716 cifs_dbg(FYI, "SID sub_auth[%d]: 0x%x\n",
717 i, le32_to_cpu(psid->sub_auth[i]));
d0d66c44
SP
718 }
719
d12fd121 720 /* BB add length check to make sure that we do not have huge
d0d66c44 721 num auths and therefore go off the end */
f96637be
JP
722 cifs_dbg(FYI, "RID 0x%x\n",
723 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
d0d66c44 724 }
fc03d8a5 725#endif
d0d66c44 726
bcb02034
SF
727 return 0;
728}
729
d0d66c44 730
bcb02034 731/* Convert CIFS ACL to POSIX form */
9409ae58
SP
732static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
733 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
bcb02034 734{
9409ae58 735 int rc = 0;
bcb02034
SF
736 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
737 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
bcb02034 738 char *end_of_acl = ((char *)pntsd) + acl_len;
7505e052 739 __u32 dacloffset;
bcb02034 740
0b8f18e3 741 if (pntsd == NULL)
b9c7a2bb
SF
742 return -EIO;
743
bcb02034 744 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
af6f4612 745 le32_to_cpu(pntsd->osidoffset));
bcb02034 746 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
af6f4612 747 le32_to_cpu(pntsd->gsidoffset));
7505e052 748 dacloffset = le32_to_cpu(pntsd->dacloffset);
63d2583f 749 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
f96637be 750 cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n",
af6f4612
SF
751 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
752 le32_to_cpu(pntsd->gsidoffset),
b6b38f70 753 le32_to_cpu(pntsd->sacloffset), dacloffset);
b9c7a2bb 754/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
bcb02034 755 rc = parse_sid(owner_sid_ptr, end_of_acl);
9409ae58 756 if (rc) {
f96637be 757 cifs_dbg(FYI, "%s: Error %d parsing Owner SID\n", __func__, rc);
9409ae58
SP
758 return rc;
759 }
760 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
761 if (rc) {
f96637be
JP
762 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to uid\n",
763 __func__, rc);
bcb02034 764 return rc;
9409ae58 765 }
bcb02034
SF
766
767 rc = parse_sid(group_sid_ptr, end_of_acl);
9409ae58 768 if (rc) {
f96637be
JP
769 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to gid\n",
770 __func__, rc);
bcb02034 771 return rc;
9409ae58
SP
772 }
773 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
774 if (rc) {
f96637be
JP
775 cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n",
776 __func__, rc);
9409ae58
SP
777 return rc;
778 }
bcb02034 779
7505e052
SF
780 if (dacloffset)
781 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
0b8f18e3 782 group_sid_ptr, fattr);
7505e052 783 else
f96637be 784 cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
d0d66c44 785
9409ae58 786 return rc;
bcb02034 787}
b9c7a2bb 788
97837582
SF
789/* Convert permission bits from mode to equivalent CIFS ACL */
790static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
8abf2775 791 __u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid, int *aclflag)
97837582
SF
792{
793 int rc = 0;
794 __u32 dacloffset;
795 __u32 ndacloffset;
796 __u32 sidsoffset;
797 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
a5ff3769 798 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
97837582
SF
799 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
800 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
801
a5ff3769
SP
802 if (nmode != NO_CHANGE_64) { /* chmod */
803 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
97837582 804 le32_to_cpu(pntsd->osidoffset));
a5ff3769 805 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
97837582 806 le32_to_cpu(pntsd->gsidoffset));
a5ff3769
SP
807 dacloffset = le32_to_cpu(pntsd->dacloffset);
808 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
809 ndacloffset = sizeof(struct cifs_ntsd);
810 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
811 ndacl_ptr->revision = dacl_ptr->revision;
812 ndacl_ptr->size = 0;
813 ndacl_ptr->num_aces = 0;
814
815 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
816 nmode);
817 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
818 /* copy sec desc control portion & owner and group sids */
819 copy_sec_desc(pntsd, pnntsd, sidsoffset);
820 *aclflag = CIFS_ACL_DACL;
821 } else {
822 memcpy(pnntsd, pntsd, secdesclen);
8abf2775
EB
823 if (uid_valid(uid)) { /* chown */
824 uid_t id;
a5ff3769
SP
825 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
826 le32_to_cpu(pnntsd->osidoffset));
827 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
828 GFP_KERNEL);
829 if (!nowner_sid_ptr)
830 return -ENOMEM;
8abf2775
EB
831 id = from_kuid(&init_user_ns, uid);
832 rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr);
a5ff3769 833 if (rc) {
f96637be
JP
834 cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n",
835 __func__, rc, id);
a5ff3769
SP
836 kfree(nowner_sid_ptr);
837 return rc;
838 }
36960e44 839 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
a5ff3769
SP
840 kfree(nowner_sid_ptr);
841 *aclflag = CIFS_ACL_OWNER;
842 }
8abf2775
EB
843 if (gid_valid(gid)) { /* chgrp */
844 gid_t id;
a5ff3769
SP
845 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
846 le32_to_cpu(pnntsd->gsidoffset));
847 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
848 GFP_KERNEL);
849 if (!ngroup_sid_ptr)
850 return -ENOMEM;
8abf2775
EB
851 id = from_kgid(&init_user_ns, gid);
852 rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr);
a5ff3769 853 if (rc) {
f96637be
JP
854 cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n",
855 __func__, rc, id);
a5ff3769
SP
856 kfree(ngroup_sid_ptr);
857 return rc;
858 }
36960e44 859 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
a5ff3769
SP
860 kfree(ngroup_sid_ptr);
861 *aclflag = CIFS_ACL_GROUP;
862 }
863 }
97837582 864
ef571cad 865 return rc;
97837582
SF
866}
867
42eacf9e
SF
868struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
869 const struct cifs_fid *cifsfid, u32 *pacllen)
b9c7a2bb 870{
b9c7a2bb 871 struct cifs_ntsd *pntsd = NULL;
6d5786a3
PS
872 unsigned int xid;
873 int rc;
7ffec372
JL
874 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
875
876 if (IS_ERR(tlink))
987b21d7 877 return ERR_CAST(tlink);
b9c7a2bb 878
6d5786a3 879 xid = get_xid();
42eacf9e
SF
880 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd,
881 pacllen);
6d5786a3 882 free_xid(xid);
b9c7a2bb 883
7ffec372 884 cifs_put_tlink(tlink);
b9c7a2bb 885
f96637be 886 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
987b21d7
SP
887 if (rc)
888 return ERR_PTR(rc);
1bf4072d
CH
889 return pntsd;
890}
8b1327f6 891
1bf4072d
CH
892static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
893 const char *path, u32 *pacllen)
894{
895 struct cifs_ntsd *pntsd = NULL;
896 int oplock = 0;
6d5786a3
PS
897 unsigned int xid;
898 int rc, create_options = 0;
96daf2b0 899 struct cifs_tcon *tcon;
7ffec372 900 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
d81b8a40
PS
901 struct cifs_fid fid;
902 struct cifs_open_parms oparms;
7ffec372
JL
903
904 if (IS_ERR(tlink))
987b21d7 905 return ERR_CAST(tlink);
b9c7a2bb 906
7ffec372 907 tcon = tlink_tcon(tlink);
6d5786a3 908 xid = get_xid();
1bf4072d 909
3d3ea8e6
SP
910 if (backup_cred(cifs_sb))
911 create_options |= CREATE_OPEN_BACKUP_INTENT;
912
d81b8a40
PS
913 oparms.tcon = tcon;
914 oparms.cifs_sb = cifs_sb;
915 oparms.desired_access = READ_CONTROL;
916 oparms.create_options = create_options;
917 oparms.disposition = FILE_OPEN;
918 oparms.path = path;
919 oparms.fid = &fid;
920 oparms.reconnect = false;
921
922 rc = CIFS_open(xid, &oparms, &oplock, NULL);
987b21d7 923 if (!rc) {
d81b8a40
PS
924 rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen);
925 CIFSSMBClose(xid, tcon, fid.netfid);
b9c7a2bb
SF
926 }
927
7ffec372 928 cifs_put_tlink(tlink);
6d5786a3 929 free_xid(xid);
987b21d7 930
f96637be 931 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
987b21d7
SP
932 if (rc)
933 return ERR_PTR(rc);
7505e052
SF
934 return pntsd;
935}
936
1bf4072d 937/* Retrieve an ACL from the server */
fbeba8bb 938struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
1bf4072d
CH
939 struct inode *inode, const char *path,
940 u32 *pacllen)
941{
942 struct cifs_ntsd *pntsd = NULL;
943 struct cifsFileInfo *open_file = NULL;
944
945 if (inode)
6508d904 946 open_file = find_readable_file(CIFS_I(inode), true);
1bf4072d
CH
947 if (!open_file)
948 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
949
42eacf9e 950 pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen);
6ab409b5 951 cifsFileInfo_put(open_file);
1bf4072d
CH
952 return pntsd;
953}
954
a5ff3769
SP
955 /* Set an ACL on the server */
956int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
957 struct inode *inode, const char *path, int aclflag)
b96d31a6
CH
958{
959 int oplock = 0;
6d5786a3
PS
960 unsigned int xid;
961 int rc, access_flags, create_options = 0;
96daf2b0 962 struct cifs_tcon *tcon;
a5ff3769 963 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
7ffec372 964 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
d81b8a40
PS
965 struct cifs_fid fid;
966 struct cifs_open_parms oparms;
97837582 967
7ffec372
JL
968 if (IS_ERR(tlink))
969 return PTR_ERR(tlink);
970
971 tcon = tlink_tcon(tlink);
6d5786a3 972 xid = get_xid();
97837582 973
3d3ea8e6
SP
974 if (backup_cred(cifs_sb))
975 create_options |= CREATE_OPEN_BACKUP_INTENT;
976
a5ff3769
SP
977 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
978 access_flags = WRITE_OWNER;
979 else
980 access_flags = WRITE_DAC;
981
d81b8a40
PS
982 oparms.tcon = tcon;
983 oparms.cifs_sb = cifs_sb;
984 oparms.desired_access = access_flags;
985 oparms.create_options = create_options;
986 oparms.disposition = FILE_OPEN;
987 oparms.path = path;
988 oparms.fid = &fid;
989 oparms.reconnect = false;
990
991 rc = CIFS_open(xid, &oparms, &oplock, NULL);
b96d31a6 992 if (rc) {
f96637be 993 cifs_dbg(VFS, "Unable to open file to set ACL\n");
b96d31a6 994 goto out;
97837582
SF
995 }
996
d81b8a40 997 rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag);
f96637be 998 cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc);
97837582 999
d81b8a40 1000 CIFSSMBClose(xid, tcon, fid.netfid);
7ffec372 1001out:
6d5786a3 1002 free_xid(xid);
7ffec372 1003 cifs_put_tlink(tlink);
b96d31a6
CH
1004 return rc;
1005}
97837582 1006
7505e052 1007/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
987b21d7 1008int
0b8f18e3 1009cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
42eacf9e
SF
1010 struct inode *inode, const char *path,
1011 const struct cifs_fid *pfid)
7505e052
SF
1012{
1013 struct cifs_ntsd *pntsd = NULL;
1014 u32 acllen = 0;
1015 int rc = 0;
42eacf9e
SF
1016 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1017 struct cifs_tcon *tcon;
7505e052 1018
f96637be 1019 cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
1bf4072d 1020
42eacf9e
SF
1021 if (IS_ERR(tlink))
1022 return PTR_ERR(tlink);
1023 tcon = tlink_tcon(tlink);
7505e052 1024
42eacf9e
SF
1025 if (pfid && (tcon->ses->server->ops->get_acl_by_fid))
1026 pntsd = tcon->ses->server->ops->get_acl_by_fid(cifs_sb, pfid,
1027 &acllen);
1028 else if (tcon->ses->server->ops->get_acl)
1029 pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
1030 &acllen);
1031 else {
1032 cifs_put_tlink(tlink);
1033 return -EOPNOTSUPP;
1034 }
7505e052 1035 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
987b21d7
SP
1036 if (IS_ERR(pntsd)) {
1037 rc = PTR_ERR(pntsd);
f96637be 1038 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
987b21d7 1039 } else {
9409ae58 1040 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
987b21d7
SP
1041 kfree(pntsd);
1042 if (rc)
f96637be 1043 cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
987b21d7 1044 }
7505e052 1045
42eacf9e
SF
1046 cifs_put_tlink(tlink);
1047
987b21d7 1048 return rc;
b9c7a2bb 1049}
953f8681 1050
7505e052 1051/* Convert mode bits to an ACL so we can update the ACL on the server */
a5ff3769
SP
1052int
1053id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
8abf2775 1054 kuid_t uid, kgid_t gid)
953f8681
SF
1055{
1056 int rc = 0;
a5ff3769 1057 int aclflag = CIFS_ACL_DACL; /* default flag to set */
cce246ee 1058 __u32 secdesclen = 0;
97837582
SF
1059 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1060 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
83e3bc23
SF
1061 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1062 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1063 struct cifs_tcon *tcon;
1064
1065 if (IS_ERR(tlink))
1066 return PTR_ERR(tlink);
1067 tcon = tlink_tcon(tlink);
953f8681 1068
f96637be 1069 cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
953f8681
SF
1070
1071 /* Get the security descriptor */
83e3bc23
SF
1072
1073 if (tcon->ses->server->ops->get_acl == NULL) {
1074 cifs_put_tlink(tlink);
1075 return -EOPNOTSUPP;
1076 }
1077
1078 pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
1079 &secdesclen);
987b21d7
SP
1080 if (IS_ERR(pntsd)) {
1081 rc = PTR_ERR(pntsd);
f96637be 1082 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
83e3bc23
SF
1083 cifs_put_tlink(tlink);
1084 return rc;
c78cd838 1085 }
7505e052 1086
c78cd838
JL
1087 /*
1088 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1089 * as chmod disables ACEs and set the security descriptor. Allocate
1090 * memory for the smb header, set security descriptor request security
1091 * descriptor parameters, and secuirty descriptor itself
1092 */
7ee0b4c6 1093 secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN);
c78cd838
JL
1094 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1095 if (!pnntsd) {
c78cd838 1096 kfree(pntsd);
83e3bc23 1097 cifs_put_tlink(tlink);
c78cd838
JL
1098 return -ENOMEM;
1099 }
97837582 1100
c78cd838
JL
1101 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1102 &aclflag);
97837582 1103
f96637be 1104 cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
97837582 1105
83e3bc23
SF
1106 if (tcon->ses->server->ops->set_acl == NULL)
1107 rc = -EOPNOTSUPP;
1108
c78cd838
JL
1109 if (!rc) {
1110 /* Set the security descriptor */
83e3bc23
SF
1111 rc = tcon->ses->server->ops->set_acl(pnntsd, secdesclen, inode,
1112 path, aclflag);
f96637be 1113 cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
97837582 1114 }
83e3bc23 1115 cifs_put_tlink(tlink);
97837582 1116
c78cd838
JL
1117 kfree(pnntsd);
1118 kfree(pntsd);
ef571cad 1119 return rc;
953f8681 1120}