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