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