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